Ref #744: Support Canon cr3 files
[geeqie.git] / src / image-load.c
1 /*
2  * Copyright (C) 2004 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "main.h"
23 #include "image-load.h"
24 #include "image_load_cr3.h"
25 #include "image_load_gdk.h"
26 #include "image_load_jpeg.h"
27 #include "image_load_tiff.h"
28 #include "image_load_dds.h"
29 #include "image_load_djvu.h"
30 #include "image_load_pdf.h"
31 #include "image_load_psd.h"
32 #include "image_load_heif.h"
33 #include "image_load_ffmpegthumbnailer.h"
34 #include "image_load_collection.h"
35 #include "image_load_webp.h"
36 #include "image_load_j2k.h"
37 #include "image_load_svgz.h"
38
39 #include "exif.h"
40 #include "filedata.h"
41 #include "ui_fileops.h"
42 #include "gq-marshal.h"
43
44 #include <fcntl.h>
45 #include <sys/mman.h>
46
47 #define IMAGE_LOADER_READ_BUFFER_SIZE_DEFAULT   4096
48 #define IMAGE_LOADER_IDLE_READ_LOOP_COUNT_DEFAULT       1
49
50
51 /**************************************************************************************/
52 /* image loader class */
53
54
55 enum {
56         SIGNAL_AREA_READY = 0,
57         SIGNAL_ERROR,
58         SIGNAL_DONE,
59         SIGNAL_PERCENT,
60         SIGNAL_SIZE,
61         SIGNAL_COUNT
62 };
63
64 static guint signals[SIGNAL_COUNT] = { 0 };
65
66 static void image_loader_init(GTypeInstance *instance, gpointer g_class);
67 static void image_loader_class_init(ImageLoaderClass *class);
68 static void image_loader_finalize(GObject *object);
69 static void image_loader_stop(ImageLoader *il);
70
71 GType image_loader_get_type(void)
72 {
73         static GType type = 0;
74         if (type == 0)
75                 {
76                 static const GTypeInfo info = {
77                         sizeof(ImageLoaderClass),
78                         NULL,   /* base_init */
79                         NULL,   /* base_finalize */
80                         (GClassInitFunc)image_loader_class_init, /* class_init */
81                         NULL,   /* class_finalize */
82                         NULL,   /* class_data */
83                         sizeof(ImageLoader),
84                         0,      /* n_preallocs */
85                         (GInstanceInitFunc)image_loader_init, /* instance_init */
86                         NULL    /* value_table */
87                         };
88                 type = g_type_register_static(G_TYPE_OBJECT, "ImageLoaderType", &info, 0);
89                 }
90         return type;
91 }
92
93 static void image_loader_init(GTypeInstance *instance, gpointer g_class)
94 {
95         ImageLoader *il = (ImageLoader *)instance;
96
97         il->pixbuf = NULL;
98         il->idle_id = 0;
99         il->idle_priority = G_PRIORITY_DEFAULT_IDLE;
100         il->done = FALSE;
101         il->loader = NULL;
102
103         il->bytes_read = 0;
104         il->bytes_total = 0;
105
106         il->idle_done_id = 0;
107
108         il->idle_read_loop_count = IMAGE_LOADER_IDLE_READ_LOOP_COUNT_DEFAULT;
109         il->read_buffer_size = IMAGE_LOADER_READ_BUFFER_SIZE_DEFAULT;
110         il->mapped_file = NULL;
111
112         il->requested_width = 0;
113         il->requested_height = 0;
114         il->actual_width = 0;
115         il->actual_height = 0;
116         il->shrunk = FALSE;
117
118         il->can_destroy = TRUE;
119
120 #ifdef HAVE_GTHREAD
121 #if GLIB_CHECK_VERSION(2,32,0)
122         il->data_mutex = g_new(GMutex, 1);
123         g_mutex_init(il->data_mutex);
124         il->can_destroy_cond = g_new(GCond, 1);
125         g_cond_init(il->can_destroy_cond);
126 #else
127         il->data_mutex = g_mutex_new();
128         il->can_destroy_cond = g_cond_new();
129 #endif
130 #endif
131         DEBUG_1("new image loader %p, bufsize=%" G_GSIZE_FORMAT " idle_loop=%u", il, il->read_buffer_size, il->idle_read_loop_count);
132 }
133
134 static void image_loader_class_init(ImageLoaderClass *class)
135 {
136         GObjectClass *gobject_class = G_OBJECT_CLASS (class);
137
138 //      gobject_class->set_property = image_loader_set_property;
139 //      gobject_class->get_property = image_loader_get_property;
140
141         gobject_class->finalize = image_loader_finalize;
142
143
144         signals[SIGNAL_AREA_READY] =
145                 g_signal_new("area_ready",
146                              G_OBJECT_CLASS_TYPE(gobject_class),
147                              G_SIGNAL_RUN_LAST,
148                              G_STRUCT_OFFSET(ImageLoaderClass, area_ready),
149                              NULL, NULL,
150                              gq_marshal_VOID__INT_INT_INT_INT,
151                              G_TYPE_NONE, 4,
152                              G_TYPE_INT,
153                              G_TYPE_INT,
154                              G_TYPE_INT,
155                              G_TYPE_INT);
156
157         signals[SIGNAL_ERROR] =
158                 g_signal_new("error",
159                              G_OBJECT_CLASS_TYPE(gobject_class),
160                              G_SIGNAL_RUN_LAST,
161                              G_STRUCT_OFFSET(ImageLoaderClass, error),
162                              NULL, NULL,
163                              g_cclosure_marshal_VOID__VOID,
164                              G_TYPE_NONE, 0);
165
166         signals[SIGNAL_DONE] =
167                 g_signal_new("done",
168                              G_OBJECT_CLASS_TYPE(gobject_class),
169                              G_SIGNAL_RUN_LAST,
170                              G_STRUCT_OFFSET(ImageLoaderClass, done),
171                              NULL, NULL,
172                              g_cclosure_marshal_VOID__VOID,
173                              G_TYPE_NONE, 0);
174
175         signals[SIGNAL_PERCENT] =
176                 g_signal_new("percent",
177                              G_OBJECT_CLASS_TYPE(gobject_class),
178                              G_SIGNAL_RUN_LAST,
179                              G_STRUCT_OFFSET(ImageLoaderClass, percent),
180                              NULL, NULL,
181                              g_cclosure_marshal_VOID__DOUBLE,
182                              G_TYPE_NONE, 1,
183                              G_TYPE_DOUBLE);
184
185         signals[SIGNAL_SIZE] =
186                 g_signal_new("size_prepared",
187                              G_OBJECT_CLASS_TYPE(gobject_class),
188                              G_SIGNAL_RUN_LAST,
189                              G_STRUCT_OFFSET(ImageLoaderClass, area_ready),
190                              NULL, NULL,
191                              gq_marshal_VOID__INT_INT,
192                              G_TYPE_NONE, 2,
193                              G_TYPE_INT,
194                              G_TYPE_INT);
195
196 }
197
198 static void image_loader_finalize(GObject *object)
199 {
200         ImageLoader *il = (ImageLoader *)object;
201
202         image_loader_stop(il);
203
204         if (il->error) DEBUG_1("%s", image_loader_get_error(il));
205
206         DEBUG_1("freeing image loader %p bytes_read=%" G_GSIZE_FORMAT, il, il->bytes_read);
207
208         if (il->idle_done_id)
209                 {
210                 g_source_remove(il->idle_done_id);
211                 il->idle_done_id = 0;
212                 }
213
214         while (g_source_remove_by_user_data(il))
215                 {
216                 DEBUG_2("pending signals detected");
217                 }
218
219         while (il->area_param_list)
220                 {
221                 DEBUG_1("pending area_ready signals detected");
222                 while (g_source_remove_by_user_data(il->area_param_list->data)) {}
223                 g_free(il->area_param_list->data);
224                 il->area_param_list = g_list_delete_link(il->area_param_list, il->area_param_list);
225                 }
226
227         while (il->area_param_delayed_list)
228                 {
229                 g_free(il->area_param_delayed_list->data);
230                 il->area_param_delayed_list = g_list_delete_link(il->area_param_delayed_list, il->area_param_delayed_list);
231                 }
232
233         if (il->pixbuf) g_object_unref(il->pixbuf);
234
235         if (il->error) g_error_free(il->error);
236
237         file_data_unref(il->fd);
238 #ifdef HAVE_GTHREAD
239 #if GLIB_CHECK_VERSION(2,32,0)
240         g_mutex_clear(il->data_mutex);
241         g_free(il->data_mutex);
242         g_cond_clear(il->can_destroy_cond);
243         g_free(il->can_destroy_cond);
244 #else
245         g_mutex_free(il->data_mutex);
246         g_cond_free(il->can_destroy_cond);
247 #endif
248 #endif
249 }
250
251 void image_loader_free(ImageLoader *il)
252 {
253         if (!il) return;
254         g_object_unref(G_OBJECT(il));
255 }
256
257
258 ImageLoader *image_loader_new(FileData *fd)
259 {
260         ImageLoader *il;
261
262         if (!fd) return NULL;
263
264         il = (ImageLoader *) g_object_new(TYPE_IMAGE_LOADER, NULL);
265
266         il->fd = file_data_ref(fd);
267
268         return il;
269 }
270
271 /**************************************************************************************/
272 /* send signals via idle calbacks - the callback are executed in the main thread */
273
274 typedef struct _ImageLoaderAreaParam ImageLoaderAreaParam;
275 struct _ImageLoaderAreaParam {
276         ImageLoader *il;
277         guint x;
278         guint y;
279         guint w;
280         guint h;
281 };
282
283
284 static gboolean image_loader_emit_area_ready_cb(gpointer data)
285 {
286         ImageLoaderAreaParam *par = data;
287         ImageLoader *il = par->il;
288         guint x, y, w, h;
289         g_mutex_lock(il->data_mutex);
290         il->area_param_list = g_list_remove(il->area_param_list, par);
291         x = par->x;
292         y = par->y;
293         w = par->w;
294         h = par->h;
295         g_free(par);
296         g_mutex_unlock(il->data_mutex);
297
298         g_signal_emit(il, signals[SIGNAL_AREA_READY], 0, x, y, w, h);
299
300         return FALSE;
301 }
302
303 static gboolean image_loader_emit_done_cb(gpointer data)
304 {
305         ImageLoader *il = data;
306         g_signal_emit(il, signals[SIGNAL_DONE], 0);
307         return FALSE;
308 }
309
310 static gboolean image_loader_emit_error_cb(gpointer data)
311 {
312         ImageLoader *il = data;
313         g_signal_emit(il, signals[SIGNAL_ERROR], 0);
314         return FALSE;
315 }
316
317 static gboolean image_loader_emit_percent_cb(gpointer data)
318 {
319         ImageLoader *il = data;
320         g_signal_emit(il, signals[SIGNAL_PERCENT], 0, image_loader_get_percent(il));
321         return FALSE;
322 }
323
324 static gboolean image_loader_emit_size_cb(gpointer data)
325 {
326         gint width, height;
327         ImageLoader *il = data;
328         g_mutex_lock(il->data_mutex);
329         width = il->actual_width;
330         height = il->actual_height;
331         g_mutex_unlock(il->data_mutex);
332         g_signal_emit(il, signals[SIGNAL_SIZE], 0, width, height);
333         return FALSE;
334 }
335
336
337 /* DONE and ERROR are emited only once, thus they can have normal priority
338    PERCENT and AREA_READY should be processed ASAP
339 */
340
341 static void image_loader_emit_done(ImageLoader *il)
342 {
343         g_idle_add_full(il->idle_priority, image_loader_emit_done_cb, il, NULL);
344 }
345
346 static void image_loader_emit_error(ImageLoader *il)
347 {
348         g_idle_add_full(il->idle_priority, image_loader_emit_error_cb, il, NULL);
349 }
350
351 static void image_loader_emit_percent(ImageLoader *il)
352 {
353         g_idle_add_full(G_PRIORITY_HIGH, image_loader_emit_percent_cb, il, NULL);
354 }
355
356 static void image_loader_emit_size(ImageLoader *il)
357 {
358         g_idle_add_full(G_PRIORITY_HIGH, image_loader_emit_size_cb, il, NULL);
359 }
360
361 static ImageLoaderAreaParam *image_loader_queue_area_ready(ImageLoader *il, GList **list, guint x, guint y, guint w, guint h)
362 {
363         if (*list)
364                 {
365                 ImageLoaderAreaParam *prev_par = (*list)->data;
366                 if (prev_par->x == x && prev_par->w == w &&
367                     prev_par->y + prev_par->h == y)
368                         {
369                         /* we can merge the notifications */
370                         prev_par->h += h;
371                         return NULL;
372                         }
373                 if (prev_par->x == x && prev_par->w == w &&
374                     y + h == prev_par->y)
375                         {
376                         /* we can merge the notifications */
377                         prev_par->h += h;
378                         prev_par->y = y;
379                         return NULL;
380                         }
381                 if (prev_par->y == y && prev_par->h == h &&
382                     prev_par->x + prev_par->w == x)
383                         {
384                         /* we can merge the notifications */
385                         prev_par->w += w;
386                         return NULL;
387                         }
388                 if (prev_par->y == y && prev_par->h == h &&
389                     x + w == prev_par->x)
390                         {
391                         /* we can merge the notifications */
392                         prev_par->w += w;
393                         prev_par->x = x;
394                         return NULL;
395                         }
396                 }
397
398         ImageLoaderAreaParam *par = g_new0(ImageLoaderAreaParam, 1);
399         par->il = il;
400         par->x = x;
401         par->y = y;
402         par->w = w;
403         par->h = h;
404
405         *list = g_list_prepend(*list, par);
406         return par;
407 }
408
409 /* this function expects that il->data_mutex is locked by caller */
410 static void image_loader_emit_area_ready(ImageLoader *il, guint x, guint y, guint w, guint h)
411 {
412         ImageLoaderAreaParam *par = image_loader_queue_area_ready(il, &il->area_param_list, x, y, w, h);
413
414         if (par)
415                 {
416                 g_idle_add_full(G_PRIORITY_HIGH, image_loader_emit_area_ready_cb, par, NULL);
417                 }
418 }
419
420 /**************************************************************************************/
421 /* the following functions may be executed in separate thread */
422
423 /* this function expects that il->data_mutex is locked by caller */
424 static void image_loader_queue_delayed_area_ready(ImageLoader *il, guint x, guint y, guint w, guint h)
425 {
426         image_loader_queue_area_ready(il, &il->area_param_delayed_list, x, y, w, h);
427 }
428
429
430
431 static gboolean image_loader_get_stopping(ImageLoader *il)
432 {
433         gboolean ret;
434         if (!il) return FALSE;
435
436         g_mutex_lock(il->data_mutex);
437         ret = il->stopping;
438         g_mutex_unlock(il->data_mutex);
439
440         return ret;
441 }
442
443
444 static void image_loader_sync_pixbuf(ImageLoader *il)
445 {
446         GdkPixbuf *pb;
447
448         g_mutex_lock(il->data_mutex);
449
450         if (!il->loader)
451                 {
452                 g_mutex_unlock(il->data_mutex);
453                 return;
454                 }
455
456         pb = il->backend.get_pixbuf(il->loader);
457
458         if (pb == il->pixbuf)
459                 {
460                 g_mutex_unlock(il->data_mutex);
461                 return;
462                 }
463
464         if (g_ascii_strcasecmp(".jps", il->fd->extension) == 0)
465                 {
466                 g_object_set_data(G_OBJECT(pb), "stereo_data", GINT_TO_POINTER(STEREO_PIXBUF_CROSS));
467                 }
468
469         if (il->pixbuf) g_object_unref(il->pixbuf);
470
471         il->pixbuf = pb;
472         if (il->pixbuf) g_object_ref(il->pixbuf);
473
474         g_mutex_unlock(il->data_mutex);
475 }
476
477 static void image_loader_area_updated_cb(gpointer loader,
478                                  guint x, guint y, guint w, guint h,
479                                  gpointer data)
480 {
481         ImageLoader *il = data;
482
483         if (!image_loader_get_pixbuf(il))
484                 {
485                 image_loader_sync_pixbuf(il);
486                 if (!image_loader_get_pixbuf(il))
487                         {
488                         log_printf("critical: area_ready signal with NULL pixbuf (out of mem?)\n");
489                         }
490                 }
491
492         g_mutex_lock(il->data_mutex);
493         if (il->delay_area_ready)
494                 image_loader_queue_delayed_area_ready(il, x, y, w, h);
495         else
496                 image_loader_emit_area_ready(il, x, y, w, h);
497
498         if (il->stopping) il->backend.abort(il->loader);
499
500         g_mutex_unlock(il->data_mutex);
501 }
502
503 static void image_loader_area_prepared_cb(gpointer loader, gpointer data)
504 {
505         ImageLoader *il = data;
506         GdkPixbuf *pb;
507         guchar *pix;
508         size_t h, rs;
509
510         /* a workaround for
511            http://bugzilla.gnome.org/show_bug.cgi?id=547669
512            http://bugzilla.gnome.org/show_bug.cgi?id=589334
513         */
514         gchar *format = il->backend.get_format_name(loader);
515         if (strcmp(format, "svg") == 0 ||
516             strcmp(format, "xpm") == 0)
517                 {
518                 g_free(format);
519                 return;
520                 }
521
522         g_free(format);
523
524         pb = il->backend.get_pixbuf(loader);
525
526         h = gdk_pixbuf_get_height(pb);
527         rs = gdk_pixbuf_get_rowstride(pb);
528         pix = gdk_pixbuf_get_pixels(pb);
529
530         memset(pix, 0, rs * h); /*this should be faster than pixbuf_fill */
531
532 }
533
534 static void image_loader_size_cb(gpointer loader,
535                                  gint width, gint height, gpointer data)
536 {
537         ImageLoader *il = data;
538         gchar **mime_types;
539         gboolean scale = FALSE;
540         gint n;
541
542         g_mutex_lock(il->data_mutex);
543         il->actual_width = width;
544         il->actual_height = height;
545         if (il->requested_width < 1 || il->requested_height < 1)
546                 {
547                 g_mutex_unlock(il->data_mutex);
548                 image_loader_emit_size(il);
549                 return;
550                 }
551         g_mutex_unlock(il->data_mutex);
552
553 #ifdef HAVE_FFMPEGTHUMBNAILER
554         if (il->fd->format_class == FORMAT_CLASS_VIDEO)
555                 scale = TRUE;
556 #endif
557         mime_types = il->backend.get_format_mime_types(loader);
558         n = 0;
559         while (mime_types[n] && !scale)
560                 {
561                 if (strstr(mime_types[n], "jpeg")) scale = TRUE;
562                 n++;
563                 }
564         g_strfreev(mime_types);
565
566         if (!scale)
567                 {
568                 image_loader_emit_size(il);
569                 return;
570                 }
571
572         g_mutex_lock(il->data_mutex);
573
574         gint nw, nh;
575         if (width > il->requested_width || height > il->requested_height)
576                 {
577
578                 if (((gdouble)il->requested_width / width) < ((gdouble)il->requested_height / height))
579                         {
580                         nw = il->requested_width;
581                         nh = (gdouble)nw / width * height;
582                         if (nh < 1) nh = 1;
583                         }
584                 else
585                         {
586                         nh = il->requested_height;
587                         nw = (gdouble)nh / height * width;
588                         if (nw < 1) nw = 1;
589                         }
590
591                 il->actual_width = nw;
592                 il->actual_height = nh;
593                 il->backend.set_size(loader, nw, nh);
594                 il->shrunk = TRUE;
595                 }
596
597         g_mutex_unlock(il->data_mutex);
598         image_loader_emit_size(il);
599 }
600
601 static void image_loader_stop_loader(ImageLoader *il)
602 {
603         if (!il) return;
604
605         if (il->loader)
606                 {
607                 /* some loaders do not have a pixbuf till close, order is important here */
608                 il->backend.close(il->loader, il->error ? NULL : &il->error); /* we are interested in the first error only */
609                 image_loader_sync_pixbuf(il);
610                 il->backend.free(il->loader);
611                 il->loader = NULL;
612                 }
613         g_mutex_lock(il->data_mutex);
614         il->done = TRUE;
615         g_mutex_unlock(il->data_mutex);
616 }
617
618 static void image_loader_setup_loader(ImageLoader *il)
619 {
620         gchar *format;
621
622         g_mutex_lock(il->data_mutex);
623 #ifdef HAVE_FFMPEGTHUMBNAILER
624         if (il->fd->format_class == FORMAT_CLASS_VIDEO)
625                 {
626                 DEBUG_1("Using custom ffmpegthumbnailer loader");
627                 image_loader_backend_set_ft(&il->backend);
628                 }
629         else
630 #endif
631 #ifdef HAVE_PDF
632         if (il->bytes_total >= 4 &&
633             (memcmp(il->mapped_file + 0, "%PDF", 4) == 0))
634                 {
635                 DEBUG_1("Using custom pdf loader");
636                 image_loader_backend_set_pdf(&il->backend);
637                 }
638         else
639 #endif
640 #ifdef HAVE_HEIF
641         if (il->bytes_total >= 12 &&
642                 ((memcmp(il->mapped_file + 4, "ftypheic", 8) == 0) ||
643                 (memcmp(il->mapped_file + 4, "ftypmsf1", 8) == 0) ||
644                 (memcmp(il->mapped_file + 4, "ftypmif1", 8) == 0)))
645                 {
646                 DEBUG_1("Using custom heif loader");
647                 image_loader_backend_set_heif(&il->backend);
648                 }
649         else
650 #endif
651 #ifdef HAVE_WEBP
652         if (il->bytes_total >= 12 &&
653                 (memcmp(il->mapped_file, "RIFF", 4) == 0) &&
654                 (memcmp(il->mapped_file + 8, "WEBP", 4) == 0))
655                 {
656                 DEBUG_1("Using custom webp loader");
657                 image_loader_backend_set_webp(&il->backend);
658                 }
659         else
660 #endif
661 #ifdef HAVE_DJVU
662         if (il->bytes_total >= 16 &&
663                 (memcmp(il->mapped_file, "AT&TFORM", 8) == 0) &&
664                 (memcmp(il->mapped_file + 12, "DJV", 3) == 0))
665                 {
666                 DEBUG_1("Using custom djvu loader");
667                 image_loader_backend_set_djvu(&il->backend);
668                 }
669         else
670 #endif
671 #ifdef HAVE_JPEG
672         if (il->bytes_total >= 2 && il->mapped_file[0] == 0xff && il->mapped_file[1] == 0xd8)
673                 {
674                 DEBUG_1("Using custom jpeg loader");
675                 image_loader_backend_set_jpeg(&il->backend);
676                 }
677         else
678         if (il->bytes_total >= 11 &&
679                 (memcmp(il->mapped_file + 4, "ftypcrx", 7) == 0) &&
680                 (memcmp(il->mapped_file + 64, "CanonCR3", 8) == 0))
681                 {
682                 DEBUG_1("Using custom cr3 loader");
683                 image_loader_backend_set_cr3(&il->backend);
684                 }
685         else
686 #endif
687 #ifdef HAVE_TIFF
688         if (il->bytes_total >= 10 &&
689             (memcmp(il->mapped_file, "MM\0*", 4) == 0 ||
690              memcmp(il->mapped_file, "MM\0+\0\x08\0\0", 8) == 0 ||
691              memcmp(il->mapped_file, "II+\0\x08\0\0\0", 8) == 0 ||
692              memcmp(il->mapped_file, "II*\0", 4) == 0))
693                 {
694                 DEBUG_1("Using custom tiff loader");
695                 image_loader_backend_set_tiff(&il->backend);
696                 }
697         else
698 #endif
699         if (il->bytes_total >= 3 && il->mapped_file[0] == 0x44 && il->mapped_file[1] == 0x44 && il->mapped_file[2] == 0x53)
700                 {
701                 DEBUG_1("Using dds loader");
702                 image_loader_backend_set_dds(&il->backend);
703                 }
704         else
705         if (il->bytes_total >= 6 &&
706                 (memcmp(il->mapped_file, "8BPS\0\x01", 6) == 0))
707                 {
708                 DEBUG_1("Using custom psd loader");
709                 image_loader_backend_set_psd(&il->backend);
710                 }
711         else
712 #ifdef HAVE_J2K
713         if (il->bytes_total >= 12 &&
714                 (memcmp(il->mapped_file, "\0\0\0\x0CjP\x20\x20\x0D\x0A\x87\x0A", 12) == 0))
715                 {
716                 DEBUG_1("Using custom j2k loader");
717                 image_loader_backend_set_j2k(&il->backend);
718                 }
719         else
720 #endif
721         if (il->fd->format_class == FORMAT_CLASS_COLLECTION)
722                 {
723                 DEBUG_1("Using custom collection loader");
724                 image_loader_backend_set_collection(&il->backend);
725                 }
726         else
727         if (g_strcmp0(strrchr(il->fd->path, '.'), ".svgz") == 0)
728                 {
729                 DEBUG_1("Using custom svgz loader");
730                 image_loader_backend_set_svgz(&il->backend);
731                 }
732         else
733                 image_loader_backend_set_default(&il->backend);
734
735         il->loader = il->backend.loader_new(image_loader_area_updated_cb, image_loader_size_cb, image_loader_area_prepared_cb, il);
736
737 #ifdef HAVE_TIFF
738         format = il->backend.get_format_name(il->loader);
739         if (g_strcmp0(format, "tiff") == 0)
740                 {
741                 il->backend.set_page_num(il->loader, il->fd->page_num);
742                 }
743         g_free(format);
744 #endif
745
746 #ifdef HAVE_PDF
747         format = il->backend.get_format_name(il->loader);
748         if (g_strcmp0(format, "pdf") == 0)
749                 {
750                 il->backend.set_page_num(il->loader, il->fd->page_num);
751                 }
752         g_free(format);
753 #endif
754
755 #ifdef HAVE_HEIF
756         format = il->backend.get_format_name(il->loader);
757         if (g_strcmp0(format, "heif") == 0)
758                 {
759                 il->backend.set_page_num(il->loader, il->fd->page_num);
760                 }
761         g_free(format);
762 #endif
763
764 #ifdef HAVE_DJVU
765         format = il->backend.get_format_name(il->loader);
766         if (g_strcmp0(format, "djvu") == 0)
767                 {
768                 il->backend.set_page_num(il->loader, il->fd->page_num);
769                 }
770         g_free(format);
771 #endif
772
773         g_mutex_unlock(il->data_mutex);
774 }
775
776
777 static void image_loader_done(ImageLoader *il)
778 {
779         image_loader_stop_loader(il);
780
781         image_loader_emit_done(il);
782 }
783
784 static void image_loader_error(ImageLoader *il)
785 {
786         image_loader_stop_loader(il);
787
788         DEBUG_1("pixbuf_loader reported load error for: %s", il->fd->path);
789
790         image_loader_emit_error(il);
791 }
792
793 static gboolean image_loader_continue(ImageLoader *il)
794 {
795         gint b;
796         gint c;
797
798         if (!il) return FALSE;
799
800         c = il->idle_read_loop_count ? il->idle_read_loop_count : 1;
801         while (c > 0 && !image_loader_get_stopping(il))
802                 {
803                 b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read);
804
805                 if (b == 0)
806                         {
807                         image_loader_done(il);
808                         return FALSE;
809                         }
810
811                 if (b < 0 || (b > 0 && !il->backend.write(il->loader, il->mapped_file + il->bytes_read, b, &il->error)))
812                         {
813                         image_loader_error(il);
814                         return FALSE;
815                         }
816
817                 il->bytes_read += b;
818
819                 c--;
820                 }
821
822         if (il->bytes_total > 0)
823                 {
824                 image_loader_emit_percent(il);
825                 }
826
827         return TRUE;
828 }
829
830 static gboolean image_loader_begin(ImageLoader *il)
831 {
832         gssize b;
833         gchar *format;
834
835         if (il->pixbuf) return FALSE;
836
837         b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read);
838         if (b < 1) return FALSE;
839
840         image_loader_setup_loader(il);
841
842         g_assert(il->bytes_read == 0);
843         if (il->backend.load) {
844                 b = il->bytes_total;
845                 if (!il->backend.load(il->loader, il->mapped_file, b, &il->error))
846                         {
847                         image_loader_stop_loader(il);
848                         return FALSE;
849                         }
850         }
851         else if (!il->backend.write(il->loader, il->mapped_file, b, &il->error))
852                 {
853                 image_loader_stop_loader(il);
854                 return FALSE;
855                 }
856
857 #ifdef HAVE_PDF
858         format = il->backend.get_format_name(il->loader);
859         if (g_strcmp0(format, "pdf") == 0)
860                 {
861                 gint i = il->backend.get_page_total(il->loader);
862                 file_data_set_page_total(il->fd, i);
863                 }
864         g_free(format);
865 #endif
866 #ifdef HAVE_HEIF
867         format = il->backend.get_format_name(il->loader);
868         if (g_strcmp0(format, "heif") == 0)
869                 {
870                 gint i = il->backend.get_page_total(il->loader);
871                 file_data_set_page_total(il->fd, i);
872                 }
873         g_free(format);
874 #endif
875 #ifdef HAVE_DJVU
876         format = il->backend.get_format_name(il->loader);
877         if (g_strcmp0(format, "djvu") == 0)
878                 {
879                 gint i = il->backend.get_page_total(il->loader);
880                 file_data_set_page_total(il->fd, i);
881                 }
882         g_free(format);
883 #endif
884 #ifdef HAVE_TIFF
885         format = il->backend.get_format_name(il->loader);
886         if (g_strcmp0(format, "tiff") == 0)
887                 {
888                 gint i = il->backend.get_page_total(il->loader);
889                 file_data_set_page_total(il->fd, i);
890                 }
891         g_free(format);
892 #endif
893
894         il->bytes_read += b;
895
896         /* read until size is known */
897         while (il->loader && !il->backend.get_pixbuf(il->loader) && b > 0 && !image_loader_get_stopping(il))
898                 {
899                 b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read);
900                 if (b < 0 || (b > 0 && !il->backend.write(il->loader, il->mapped_file + il->bytes_read, b, &il->error)))
901                         {
902                         image_loader_stop_loader(il);
903                         return FALSE;
904                         }
905                 il->bytes_read += b;
906                 }
907         if (!il->pixbuf) image_loader_sync_pixbuf(il);
908
909         if (il->bytes_read == il->bytes_total || b < 1)
910                 {
911                 /* done, handle (broken) loaders that do not have pixbuf till close */
912                 image_loader_stop_loader(il);
913
914                 if (!il->pixbuf) return FALSE;
915
916                 image_loader_done(il);
917                 return TRUE;
918                 }
919
920         if (!il->pixbuf)
921                 {
922                 image_loader_stop_loader(il);
923                 return FALSE;
924                 }
925
926         return TRUE;
927 }
928
929 /**************************************************************************************/
930 /* the following functions are always executed in the main thread */
931
932
933 static gboolean image_loader_setup_source(ImageLoader *il)
934 {
935         struct stat st;
936         gchar *pathl;
937
938         if (!il || il->loader || il->mapped_file) return FALSE;
939
940         il->mapped_file = NULL;
941
942         if (il->fd)
943                 {
944                 ExifData *exif = exif_read_fd(il->fd);
945
946                 if (options->thumbnails.use_exif)
947                         il->mapped_file = exif_get_preview(exif, (guint *)&il->bytes_total, il->requested_width, il->requested_height);
948                 else
949                         il->mapped_file = exif_get_preview(exif, (guint *)&il->bytes_total, 0, 0); /* get the largest available preview image or NULL for normal images*/
950
951                 if (il->mapped_file)
952                         {
953                         il->preview = TRUE;
954                         DEBUG_1("Usable reduced size (preview) image loaded from file %s", il->fd->path);
955                         }
956                 exif_free_fd(il->fd, exif);
957                 }
958
959
960         if (!il->mapped_file)
961                 {
962                 /* normal file */
963                 gint load_fd;
964
965                 pathl = path_from_utf8(il->fd->path);
966                 load_fd = open(pathl, O_RDONLY | O_NONBLOCK);
967                 g_free(pathl);
968                 if (load_fd == -1) return FALSE;
969
970                 if (fstat(load_fd, &st) == 0)
971                         {
972                         il->bytes_total = st.st_size;
973                         }
974                 else
975                         {
976                         close(load_fd);
977                         return FALSE;
978                         }
979
980                 il->mapped_file = mmap(0, il->bytes_total, PROT_READ|PROT_WRITE, MAP_PRIVATE, load_fd, 0);
981                 close(load_fd);
982                 if (il->mapped_file == MAP_FAILED)
983                         {
984                         il->mapped_file = 0;
985                         return FALSE;
986                         }
987                 il->preview = FALSE;
988                 }
989
990         return TRUE;
991 }
992
993 static void image_loader_stop_source(ImageLoader *il)
994 {
995         if (!il) return;
996
997         if (il->mapped_file)
998                 {
999                 if (il->preview)
1000                         {
1001                         exif_free_preview(il->mapped_file);
1002                         }
1003                 else
1004                         {
1005                         munmap(il->mapped_file, il->bytes_total);
1006                         }
1007                 il->mapped_file = NULL;
1008                 }
1009 }
1010
1011 static void image_loader_stop(ImageLoader *il)
1012 {
1013         if (!il) return;
1014
1015         if (il->idle_id)
1016                 {
1017                 g_source_remove(il->idle_id);
1018                 il->idle_id = 0;
1019                 }
1020
1021         if (il->thread)
1022                 {
1023                 /* stop loader in the other thread */
1024                 g_mutex_lock(il->data_mutex);
1025                 il->stopping = TRUE;
1026                 while (!il->can_destroy) g_cond_wait(il->can_destroy_cond, il->data_mutex);
1027                 g_mutex_unlock(il->data_mutex);
1028                 }
1029
1030         image_loader_stop_loader(il);
1031         image_loader_stop_source(il);
1032
1033 }
1034
1035 void image_loader_delay_area_ready(ImageLoader *il, gboolean enable)
1036 {
1037         g_mutex_lock(il->data_mutex);
1038         il->delay_area_ready = enable;
1039         if (!enable)
1040                 {
1041                 /* send delayed */
1042                 GList *list, *work;
1043                 list = g_list_reverse(il->area_param_delayed_list);
1044                 il->area_param_delayed_list = NULL;
1045                 g_mutex_unlock(il->data_mutex);
1046
1047                 work = list;
1048
1049                 while (work)
1050                         {
1051                         ImageLoaderAreaParam *par = work->data;
1052                         work = work->next;
1053
1054                         g_signal_emit(il, signals[SIGNAL_AREA_READY], 0, par->x, par->y, par->w, par->h);
1055                         g_free(par);
1056                         }
1057                 g_list_free(list);
1058                 }
1059         else
1060                 {
1061                 /* just unlock */
1062                 g_mutex_unlock(il->data_mutex);
1063                 }
1064 }
1065
1066
1067 /**************************************************************************************/
1068 /* execution via idle calls */
1069
1070 static gboolean image_loader_idle_cb(gpointer data)
1071 {
1072         gboolean ret = FALSE;
1073         ImageLoader *il = data;
1074
1075         if (il->idle_id)
1076                 {
1077                 ret = image_loader_continue(il);
1078                 }
1079
1080         if (!ret)
1081                 {
1082                 image_loader_stop_source(il);
1083                 }
1084
1085         return ret;
1086 }
1087
1088
1089 static gboolean image_loader_start_idle(ImageLoader *il)
1090 {
1091         gboolean ret;
1092
1093         if (!il) return FALSE;
1094
1095         if (!il->fd) return FALSE;
1096
1097         if (!image_loader_setup_source(il)) return FALSE;
1098
1099         ret = image_loader_begin(il);
1100
1101         if (ret && !il->done) il->idle_id = g_idle_add_full(il->idle_priority, image_loader_idle_cb, il, NULL);
1102         return ret;
1103 }
1104
1105 /**************************************************************************************/
1106 /* execution via thread */
1107
1108 #ifdef HAVE_GTHREAD
1109 static GThreadPool *image_loader_thread_pool = NULL;
1110
1111 static GCond *image_loader_prio_cond = NULL;
1112 static GMutex *image_loader_prio_mutex = NULL;
1113 static gint image_loader_prio_num = 0;
1114
1115
1116 static void image_loader_thread_enter_high(void)
1117 {
1118         g_mutex_lock(image_loader_prio_mutex);
1119         image_loader_prio_num++;
1120         g_mutex_unlock(image_loader_prio_mutex);
1121 }
1122
1123 static void image_loader_thread_leave_high(void)
1124 {
1125         g_mutex_lock(image_loader_prio_mutex);
1126         image_loader_prio_num--;
1127         if (image_loader_prio_num == 0) g_cond_broadcast(image_loader_prio_cond); /* wake up all low prio threads */
1128         g_mutex_unlock(image_loader_prio_mutex);
1129 }
1130
1131 static void image_loader_thread_wait_high(void)
1132 {
1133         g_mutex_lock(image_loader_prio_mutex);
1134         while (image_loader_prio_num)
1135                 {
1136                 g_cond_wait(image_loader_prio_cond, image_loader_prio_mutex);
1137                 }
1138
1139         g_mutex_unlock(image_loader_prio_mutex);
1140 }
1141
1142
1143 static void image_loader_thread_run(gpointer data, gpointer user_data)
1144 {
1145         ImageLoader *il = data;
1146         gboolean cont;
1147         gboolean err;
1148
1149         if (il->idle_priority > G_PRIORITY_DEFAULT_IDLE)
1150                 {
1151                 /* low prio, wait untill high prio tasks finishes */
1152                 image_loader_thread_wait_high();
1153                 }
1154         else
1155                 {
1156                 /* high prio */
1157                 image_loader_thread_enter_high();
1158                 }
1159
1160         err = !image_loader_begin(il);
1161
1162         if (err)
1163                 {
1164                 /*
1165                 loader failed, we have to send signal
1166                 (idle mode returns the image_loader_begin return value directly)
1167                 (success is always reported indirectly from image_loader_begin)
1168                 */
1169                 image_loader_emit_error(il);
1170                 }
1171
1172         cont = !err;
1173
1174         while (cont && !image_loader_get_is_done(il) && !image_loader_get_stopping(il))
1175                 {
1176                 if (il->idle_priority > G_PRIORITY_DEFAULT_IDLE)
1177                         {
1178                         /* low prio, wait untill high prio tasks finishes */
1179                         image_loader_thread_wait_high();
1180                         }
1181                 cont = image_loader_continue(il);
1182                 }
1183         image_loader_stop_loader(il);
1184
1185         if (il->idle_priority <= G_PRIORITY_DEFAULT_IDLE)
1186                 {
1187                 /* high prio */
1188                 image_loader_thread_leave_high();
1189                 }
1190
1191         g_mutex_lock(il->data_mutex);
1192         il->can_destroy = TRUE;
1193         g_cond_signal(il->can_destroy_cond);
1194         g_mutex_unlock(il->data_mutex);
1195
1196 }
1197
1198
1199 static gboolean image_loader_start_thread(ImageLoader *il)
1200 {
1201         if (!il) return FALSE;
1202
1203         if (!il->fd) return FALSE;
1204
1205         il->thread = TRUE;
1206
1207         if (!image_loader_setup_source(il)) return FALSE;
1208
1209         if (!image_loader_thread_pool)
1210                 {
1211                 image_loader_thread_pool = g_thread_pool_new(image_loader_thread_run, NULL, -1, FALSE, NULL);
1212 #if GLIB_CHECK_VERSION(2,32,0)
1213                 if (!image_loader_prio_cond) image_loader_prio_cond = g_new(GCond, 1);
1214                 g_cond_init(image_loader_prio_cond);
1215                 if (!image_loader_prio_mutex) image_loader_prio_mutex = g_new(GMutex, 1);
1216                 g_mutex_init(image_loader_prio_mutex);
1217 #else
1218                 image_loader_prio_cond = g_cond_new();
1219                 image_loader_prio_mutex = g_mutex_new();
1220 #endif
1221                 }
1222
1223         il->can_destroy = FALSE; /* ImageLoader can't be freed until image_loader_thread_run finishes */
1224
1225         g_thread_pool_push(image_loader_thread_pool, il, NULL);
1226         DEBUG_1("Thread pool num threads: %d", g_thread_pool_get_num_threads(image_loader_thread_pool));
1227
1228         return TRUE;
1229 }
1230 #endif /* HAVE_GTHREAD */
1231
1232
1233 /**************************************************************************************/
1234 /* public interface */
1235
1236
1237 gboolean image_loader_start(ImageLoader *il)
1238 {
1239         if (!il) return FALSE;
1240
1241         if (!il->fd) return FALSE;
1242
1243 #ifdef HAVE_GTHREAD
1244         return image_loader_start_thread(il);
1245 #else
1246         return image_loader_start_idle(il);
1247 #endif
1248 }
1249
1250
1251 /* don't forget to gdk_pixbuf_ref() it if you want to use it after image_loader_free() */
1252 GdkPixbuf *image_loader_get_pixbuf(ImageLoader *il)
1253 {
1254         GdkPixbuf *ret;
1255         if (!il) return NULL;
1256
1257         g_mutex_lock(il->data_mutex);
1258         ret = il->pixbuf;
1259         g_mutex_unlock(il->data_mutex);
1260         return ret;
1261 }
1262
1263 void image_loader_set_requested_size(ImageLoader *il, gint width, gint height)
1264 {
1265         if (!il) return;
1266
1267         g_mutex_lock(il->data_mutex);
1268         il->requested_width = width;
1269         il->requested_height = height;
1270         g_mutex_unlock(il->data_mutex);
1271 }
1272
1273 void image_loader_set_buffer_size(ImageLoader *il, guint count)
1274 {
1275         if (!il) return;
1276
1277         g_mutex_lock(il->data_mutex);
1278         il->idle_read_loop_count = count ? count : 1;
1279         g_mutex_unlock(il->data_mutex);
1280 }
1281
1282 void image_loader_set_priority(ImageLoader *il, gint priority)
1283 {
1284         if (!il) return;
1285
1286         if (il->thread) return; /* can't change prio if the thread already runs */
1287         il->idle_priority = priority;
1288 }
1289
1290
1291 gdouble image_loader_get_percent(ImageLoader *il)
1292 {
1293         gdouble ret;
1294         if (!il) return 0.0;
1295
1296         g_mutex_lock(il->data_mutex);
1297         if (il->bytes_total == 0)
1298                 {
1299                 ret = 0.0;
1300                 }
1301         else
1302                 {
1303                 ret = (gdouble)il->bytes_read / il->bytes_total;
1304                 }
1305         g_mutex_unlock(il->data_mutex);
1306         return ret;
1307 }
1308
1309 gboolean image_loader_get_is_done(ImageLoader *il)
1310 {
1311         gboolean ret;
1312         if (!il) return FALSE;
1313
1314         g_mutex_lock(il->data_mutex);
1315         ret = il->done;
1316         g_mutex_unlock(il->data_mutex);
1317
1318         return ret;
1319 }
1320
1321 FileData *image_loader_get_fd(ImageLoader *il)
1322 {
1323         FileData *ret;
1324         if (!il) return NULL;
1325
1326         g_mutex_lock(il->data_mutex);
1327         ret = il->fd;
1328         g_mutex_unlock(il->data_mutex);
1329
1330         return ret;
1331 }
1332
1333 gboolean image_loader_get_shrunk(ImageLoader *il)
1334 {
1335         gboolean ret;
1336         if (!il) return FALSE;
1337
1338         g_mutex_lock(il->data_mutex);
1339         ret = il->shrunk;
1340         g_mutex_unlock(il->data_mutex);
1341         return ret;
1342 }
1343
1344 const gchar *image_loader_get_error(ImageLoader *il)
1345 {
1346         const gchar *ret = NULL;
1347         if (!il) return NULL;
1348         g_mutex_lock(il->data_mutex);
1349         if (il->error) ret = il->error->message;
1350         g_mutex_unlock(il->data_mutex);
1351         return ret;
1352 }
1353
1354
1355 /* FIXME - this can be rather slow and blocks until the size is known */
1356 gboolean image_load_dimensions(FileData *fd, gint *width, gint *height)
1357 {
1358         ImageLoader *il;
1359         gboolean success;
1360
1361         il = image_loader_new(fd);
1362
1363         success = image_loader_start_idle(il);
1364
1365         if (success && il->pixbuf)
1366                 {
1367                 if (width) *width = gdk_pixbuf_get_width(il->pixbuf);
1368                 if (height) *height = gdk_pixbuf_get_height(il->pixbuf);;
1369                 }
1370         else
1371                 {
1372                 if (width) *width = -1;
1373                 if (height) *height = -1;
1374                 }
1375
1376         image_loader_free(il);
1377
1378         return success;
1379 }
1380 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */