2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16 * See the COPYING file for license information.
18 * Guillaume Chazarain <guichaz@yahoo.fr>
21 /***********************************
22 * Loading and unloading of images *
23 ***********************************/
25 #include <stdio.h> /* FILE, fopen(), fread(), fclose(), perror() */
26 #include <signal.h> /* signal(), SIG_DFL, SIGSEGV */
27 #include <string.h> /* strlen(), strrchr() */
32 #include "gliv-image.h"
34 #include "str_utils.h"
37 #include "files_list.h"
40 #include "decompression.h"
41 #include "thumbnails.h"
42 #include "rendering.h"
43 #include "tree_browser.h"
46 extern options_struct
*options
;
47 extern GlivImage
*current_image
;
49 /* Used to know at any time if we are loading an image. */
50 static gchar
*loading_filename
= NULL
;
53 * Used to be quiet when we try to load files
54 * not explicitly requested by the user.
56 static gint quiet
= 0;
58 void start_quiet(void)
68 const gchar
*currently_loading(void)
70 return loading_filename
;
73 static void segv_handler(gint sig
)
78 sig_str
= g_strsignal(sig
);
80 if (loading_filename
== NULL
)
81 g_printerr(_("%s not while loading an image\n"), sig_str
);
83 g_printerr(_("%s while loading %s\n"), sig_str
, loading_filename
);
88 /* Called when the first image is loaded. */
89 void install_segv_handler(void)
91 signal(SIGSEGV
, segv_handler
);
94 void fill_ident(GlivImage
* im
)
96 gchar
*alpha_str
= NULL
;
102 alpha_str
= g_strconcat(" (", _("alpha channel"), ")", NULL
);
104 alpha_str
= g_strdup("");
106 im_nr
= get_image_number(im
);
107 im
->ident
= g_strdup_printf("%s (%u/%u)%s",
109 filename_to_utf8(im
->node
->data
) : "",
110 im_nr
+ 1, get_list_length(), alpha_str
);
115 const gchar
*get_extension(const gchar
* filename
)
118 const gchar
*basename
;
120 basename
= strrchr(filename
, '/');
121 if (basename
== NULL
)
126 ext
= strrchr(basename
, '.');
134 #define LOADING_ERROR if (!quiet) g_printerr
136 static loader_t
get_decompressor(const gchar
* filename
, gint ext_len
)
138 const struct format
*res
;
140 /* We want the image extension between image_ext_start and image_ext_end. */
141 const gchar
*image_ext_end
= filename
+ strlen(filename
) - ext_len
- 1;
142 const gchar
*image_ext_start
= image_ext_end
- 1;
144 gint image_ext_length
= 0;
147 while (image_ext_start
> filename
&& *image_ext_start
!= '.') {
152 image_ext
= g_strndup(image_ext_start
+ 1, image_ext_length
);
153 res
= ext_to_loader(image_ext
, image_ext_length
);
158 LOADING_ERROR(_("%s: unknown decompressed extension\n"),
159 filename_to_utf8(filename
));
163 switch (res
->loader
) {
165 LOADING_ERROR(_("%s: image cannot be compressed twice\n"),
166 filename_to_utf8(filename
));
170 return LOADER_DECOMP_PIXBUF
;
172 case LOADER_DOT_GLIV
:
173 return LOADER_DECOMP_DOT_GLIV
;
180 loader_t
get_loader(const gchar
* filename
)
182 const struct format
*res
;
186 ext
= get_extension(filename
);
188 LOADING_ERROR(_("%s: unknown extension (none)\n"),
189 filename_to_utf8(filename
));
193 ext_len
= strlen(ext
);
194 res
= ext_to_loader(ext
, ext_len
);
197 LOADING_ERROR(_("%s: unknown extension\n"), filename_to_utf8(filename
));
201 if (res
->loader
== LOADER_DECOMP
)
202 return get_decompressor(filename
, ext_len
);
209 * We used to blacken image pixels with alpha == 0.
210 * These pixels are invisible but may alter the bilinear filtering.
211 * We have stopped doing it since the time lost is too big for the benefit.
213 static void clean_alpha(GdkPixbuf
* pixbuf
)
217 pixel
= gdk_pixbuf_get_pixels(pixbuf
);
218 end
= pixel
+ pixels_size(pixels_size
);
220 for (; pixel
< end
; pixel
+= 4) {
224 * This is not valid C since a cast cannot be a lvalue but...
226 *((guint32
*) pixel
) = 0;
231 void set_loading(const gchar
* filename
)
233 /* Used if there is a segfault. */
234 g_free(loading_filename
);
235 loading_filename
= g_strdup(filename
);
236 update_current_image_status(FALSE
);
238 if (filename
== NULL
)
240 * Do it, now that we are no more in
241 * the currently_loading() case
246 /* Wrapper: two args -> one arg. */
248 const gchar
*filename
;
252 static GdkPixbuf
*load_gdk_pixbuf(fname_error
* param
)
254 GdkPixbuf
*pixbuf
= NULL
;
257 loader
= get_loader(param
->filename
);
258 if (loader
== LOADER_DECOMP_PIXBUF
)
259 pixbuf
= load_compressed_pixbuf(param
->filename
, param
->error
);
265 pixbuf
= gdk_pixbuf_new_from_file(param
->filename
, param
->error
);
270 static GdkPixbuf
*load_gdk_pixbuf_threaded(const gchar
* filename
,
276 param
= g_new(fname_error
, 1);
277 param
->filename
= filename
;
278 param
->error
= (error
== NULL
) ? g_new(GError
*, 1) : error
;
280 *param
->error
= NULL
;
281 pixbuf
= do_threaded((GThreadFunc
) load_gdk_pixbuf
, param
);
283 if (pixbuf
== NULL
) {
286 * The caller won't handle the error, handle it here
288 if (*param
->error
!= NULL
)
289 DIALOG_MSG("%s", (*param
->error
)->message
);
291 DIALOG_MSG(_("Cannot load %s"), filename
);
294 add_thumbnail(filename
, pixbuf
);
300 gint
pixels_size(GdkPixbuf
* pixbuf
)
302 /* The last rowstride may not be full. */
303 gint w
= gdk_pixbuf_get_width(pixbuf
);
304 gint h
= gdk_pixbuf_get_height(pixbuf
);
305 gint rs
= gdk_pixbuf_get_rowstride(pixbuf
);
306 gint nb_chan
= gdk_pixbuf_get_n_channels(pixbuf
);
307 gint bps
= gdk_pixbuf_get_bits_per_sample(pixbuf
);
309 return ((h
- 1) * rs
+ w
* ((nb_chan
* bps
+ 7) / 8));
312 G_GNUC_PURE
static gint
nb_maps(gint dim
)
316 while (dim
> rt
->max_texture_size
) {
324 GlivImage
*make_gliv_image(GdkPixbuf
* pixbuf
)
328 im
= gliv_image_new();
332 im
->first_image
= (current_image
== NULL
);
334 im
->width
= gdk_pixbuf_get_width(pixbuf
);
335 im
->height
= gdk_pixbuf_get_height(pixbuf
);
336 im
->has_alpha
= gdk_pixbuf_get_has_alpha(pixbuf
);
338 if (options
->mipmap
) {
339 gint nb_w
= nb_maps(im
->width
);
340 gint nb_h
= nb_maps(im
->height
);
341 im
->nb_maps
= MIN(nb_w
, nb_h
);
345 im
->maps
= g_new(texture_map
, im
->nb_maps
);
346 im
->maps
[0].pixbuf
= pixbuf
;
357 GlivImage
*load_file(const gchar
* filename
, GError
** error
)
359 GdkPixbuf
*loaded_image
;
360 GlivImage
*im
= NULL
;
362 set_loading(filename_to_utf8(filename
));
364 loaded_image
= load_gdk_pixbuf_threaded(filename
, error
);
365 if (loaded_image
!= NULL
)
366 im
= make_gliv_image(loaded_image
);