comparison src/image-load.c @ 1008:68b0cb6ca8f0

use mmaped files image loader implemented new interface for extracting raw previews experiments with previews support in SVN version of Exiv2
author nadvornik
date Thu, 28 Aug 2008 22:26:09 +0000
parents 4fe8f9656107
children dd311dae857a
comparison
equal deleted inserted replaced
1007:4303ee1e88ec 1008:68b0cb6ca8f0
17 #include "exif.h" 17 #include "exif.h"
18 #include "filedata.h" 18 #include "filedata.h"
19 #include "ui_fileops.h" 19 #include "ui_fileops.h"
20 20
21 #include <fcntl.h> 21 #include <fcntl.h>
22 #include <sys/mman.h>
22 23
23 24
24 static const gchar *image_loader_path(ImageLoader *il) 25 static const gchar *image_loader_path(ImageLoader *il)
25 { 26 {
26 if (il->fd) 27 if (il->fd)
153 image_loader_sync_pixbuf(il); 154 image_loader_sync_pixbuf(il);
154 g_object_unref(G_OBJECT(il->loader)); 155 g_object_unref(G_OBJECT(il->loader));
155 il->loader = NULL; 156 il->loader = NULL;
156 } 157 }
157 158
158 if (il->load_fd != -1) 159 if (il->mapped_file)
159 { 160 {
160 close(il->load_fd); 161 if (il->preview)
161 il->load_fd = -1; 162 {
163 exif_free_preview(il->mapped_file);
164 }
165 else
166 {
167 munmap(il->mapped_file, il->bytes_total);
168 }
169 il->mapped_file = NULL;
162 } 170 }
163 171
164 il->done = TRUE; 172 il->done = TRUE;
165 } 173 }
166 174
206 if (il->idle_id == -1) return FALSE; 214 if (il->idle_id == -1) return FALSE;
207 215
208 c = il->idle_read_loop_count ? il->idle_read_loop_count : 1; 216 c = il->idle_read_loop_count ? il->idle_read_loop_count : 1;
209 while (c > 0) 217 while (c > 0)
210 { 218 {
211 b = read(il->load_fd, il->read_buffer, il->read_buffer_size); 219 b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read);
212 220
213 if (b == 0) 221 if (b == 0)
214 { 222 {
215 image_loader_done(il); 223 image_loader_done(il);
216 return FALSE; 224 return FALSE;
217 } 225 }
218 226
219 if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->read_buffer, b, NULL))) 227 if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->mapped_file + il->bytes_read, b, NULL)))
220 { 228 {
221 image_loader_error(il); 229 image_loader_error(il);
222 return FALSE; 230 return FALSE;
223 } 231 }
224 232
236 } 244 }
237 245
238 static gint image_loader_begin(ImageLoader *il) 246 static gint image_loader_begin(ImageLoader *il)
239 { 247 {
240 gint b; 248 gint b;
241 guint offset = 0;
242 249
243 if (!il->loader || il->pixbuf) return FALSE; 250 if (!il->loader || il->pixbuf) return FALSE;
244 251
245 b = read(il->load_fd, il->read_buffer, il->read_buffer_size); 252 b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read);
246
247 if (b > 0 &&
248 format_raw_img_exif_offsets_fd(il->load_fd, image_loader_path(il), il->read_buffer, b, &offset, NULL))
249 {
250 DEBUG_1("Raw file %s contains embedded image", image_loader_path(il));
251
252 b = read(il->load_fd, il->read_buffer, il->read_buffer_size);
253 }
254 253
255 if (b < 1) 254 if (b < 1)
256 { 255 {
257 image_loader_stop(il); 256 image_loader_stop(il);
258 return FALSE; 257 return FALSE;
259 } 258 }
260 259
261 if (!gdk_pixbuf_loader_write(il->loader, il->read_buffer, b, NULL)) 260 if (!gdk_pixbuf_loader_write(il->loader, il->mapped_file + il->bytes_read, b, NULL))
262 { 261 {
263 image_loader_stop(il); 262 image_loader_stop(il);
264 return FALSE; 263 return FALSE;
265 } 264 }
266 265
267 il->bytes_read += b + offset; 266 il->bytes_read += b;
268 267
269 /* read until size is known */ 268 /* read until size is known */
270 while (il->loader && !gdk_pixbuf_loader_get_pixbuf(il->loader) && b > 0) 269 while (il->loader && !gdk_pixbuf_loader_get_pixbuf(il->loader) && b > 0)
271 { 270 {
272 b = read(il->load_fd, il->read_buffer, il->read_buffer_size); 271 b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read);
273 if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->read_buffer, b, NULL))) 272 if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->mapped_file + il->bytes_read, b, NULL)))
274 { 273 {
275 image_loader_stop(il); 274 image_loader_stop(il);
276 return FALSE; 275 return FALSE;
277 } 276 }
278 il->bytes_read += b; 277 il->bytes_read += b;
305 static gint image_loader_setup(ImageLoader *il) 304 static gint image_loader_setup(ImageLoader *il)
306 { 305 {
307 struct stat st; 306 struct stat st;
308 gchar *pathl; 307 gchar *pathl;
309 308
310 if (!il || il->load_fd != -1 || il->loader) return FALSE; 309 if (!il || il->loader || il->mapped_file) return FALSE;
311 310
312 pathl = path_from_utf8(image_loader_path(il)); 311 il->mapped_file = NULL;
313 il->load_fd = open(pathl, O_RDONLY | O_NONBLOCK); 312
314 g_free(pathl); 313 if (il->fd)
315 if (il->load_fd == -1) return FALSE; 314 {
316 315 ExifData *exif = exif_read_fd(il->fd);
317 if (fstat(il->load_fd, &st) == 0) 316
318 { 317 il->mapped_file = exif_get_preview(exif, &il->bytes_total);
319 il->bytes_total = st.st_size; 318
320 } 319 if (il->mapped_file)
320 {
321 il->preview = TRUE;
322 DEBUG_1("Raw file %s contains embedded image", image_loader_path(il));
323 }
324 exif_free_fd(il->fd, exif);
325 }
326
327
328 if (!il->mapped_file)
329 {
330 /* normal file */
331 gint load_fd;
332
333 pathl = path_from_utf8(image_loader_path(il));
334 load_fd = open(pathl, O_RDONLY | O_NONBLOCK);
335 g_free(pathl);
336 if (load_fd == -1) return FALSE;
337
338 if (fstat(load_fd, &st) == 0)
339 {
340 il->bytes_total = st.st_size;
341 }
342 else
343 {
344 close(load_fd);
345 return FALSE;
346 }
347
348 il->mapped_file = mmap(0, il->bytes_total, PROT_READ|PROT_WRITE, MAP_PRIVATE, load_fd, 0);
349 close(load_fd);
350 if (il->mapped_file == MAP_FAILED)
351 {
352 il->mapped_file = 0;
353 return FALSE;
354 }
355 il->preview = FALSE;
356 }
357
321 358
322 il->loader = gdk_pixbuf_loader_new(); 359 il->loader = gdk_pixbuf_loader_new();
323 g_signal_connect(G_OBJECT(il->loader), "area_updated", 360 g_signal_connect(G_OBJECT(il->loader), "area_updated",
324 G_CALLBACK(image_loader_area_updated_cb), il); 361 G_CALLBACK(image_loader_area_updated_cb), il);
325 g_signal_connect(G_OBJECT(il->loader), "size_prepared", 362 g_signal_connect(G_OBJECT(il->loader), "size_prepared",
344 il->pixbuf = NULL; 381 il->pixbuf = NULL;
345 il->idle_id = -1; 382 il->idle_id = -1;
346 il->idle_priority = G_PRIORITY_DEFAULT_IDLE; 383 il->idle_priority = G_PRIORITY_DEFAULT_IDLE;
347 il->done = FALSE; 384 il->done = FALSE;
348 il->loader = NULL; 385 il->loader = NULL;
349 il->load_fd = -1;
350 386
351 il->bytes_read = 0; 387 il->bytes_read = 0;
352 il->bytes_total = 0; 388 il->bytes_total = 0;
353 389
354 il->idle_done_id = -1; 390 il->idle_done_id = -1;
355 391
356 il->idle_read_loop_count = options->image.idle_read_loop_count; 392 il->idle_read_loop_count = options->image.idle_read_loop_count;
357 il->read_buffer_size = options->image.read_buffer_size; 393 il->read_buffer_size = options->image.read_buffer_size;
358 il->read_buffer = g_new(guchar, il->read_buffer_size); 394 il->mapped_file = NULL;
359 395
360 il->requested_width = 0; 396 il->requested_width = 0;
361 il->requested_height = 0; 397 il->requested_height = 0;
362 il->shrunk = FALSE; 398 il->shrunk = FALSE;
363 DEBUG_1("new image loader %p, bufsize=%u idle_loop=%u", il, il->read_buffer_size, il->idle_read_loop_count); 399 DEBUG_1("new image loader %p, bufsize=%u idle_loop=%u", il, il->read_buffer_size, il->idle_read_loop_count);
381 image_loader_stop(il); 417 image_loader_stop(il);
382 if (il->idle_done_id != -1) g_source_remove(il->idle_done_id); 418 if (il->idle_done_id != -1) g_source_remove(il->idle_done_id);
383 if (il->pixbuf) gdk_pixbuf_unref(il->pixbuf); 419 if (il->pixbuf) gdk_pixbuf_unref(il->pixbuf);
384 if (il->fd) file_data_unref(il->fd); 420 if (il->fd) file_data_unref(il->fd);
385 if (il->path) g_free(il->path); 421 if (il->path) g_free(il->path);
386 if (il->read_buffer) g_free(il->read_buffer);
387 DEBUG_1("freeing image loader %p bytes_read=%d", il, il->bytes_read); 422 DEBUG_1("freeing image loader %p bytes_read=%d", il, il->bytes_read);
388 g_free(il); 423 g_free(il);
389 } 424 }
390 425
391 /* don't forget to gdk_pixbuf_ref() it if you want to use it after image_loader_free() */ 426 /* don't forget to gdk_pixbuf_ref() it if you want to use it after image_loader_free() */