1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3 *
4 * GIMP Plug-in for Windows Icon files.
5 * Copyright (C) 2002 Christian Kreibich <christian@whoop.org>.
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 3 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
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <errno.h>
24 #include <string.h>
25
26 #include <glib/gstdio.h>
27
28 #include <libgimp/gimp.h>
29 #include <libgimp/gimpui.h>
30
31 #include <png.h>
32
33 /* #define ICO_DBG */
34
35 #include "ico.h"
36 #include "ico-load.h"
37
38 #include "libgimp/stdplugins-intl.h"
39
40
41 #define A_VAL(p) ((guchar *)(p))[3]
42 #define R_VAL(p) ((guchar *)(p))[2]
43 #define G_VAL(p) ((guchar *)(p))[1]
44 #define B_VAL(p) ((guchar *)(p))[0]
45
46 #define A_VAL_GIMP(p) ((guchar *)(p))[3]
47 #define R_VAL_GIMP(p) ((guchar *)(p))[0]
48 #define G_VAL_GIMP(p) ((guchar *)(p))[1]
49 #define B_VAL_GIMP(p) ((guchar *)(p))[2]
50
51
52 static gint ico_read_int8 (FILE *fp,
53 guint8 *data,
54 gint count);
55 static gint ico_read_int16 (FILE *fp,
56 guint16 *data,
57 gint count);
58 static gint ico_read_int32 (FILE *fp,
59 guint32 *data,
60 gint count);
61
62 static gint
ico_read_int32(FILE * fp,guint32 * data,gint count)63 ico_read_int32 (FILE *fp,
64 guint32 *data,
65 gint count)
66 {
67 gint i, total;
68
69 total = count;
70 if (count > 0)
71 {
72 ico_read_int8 (fp, (guint8 *) data, count * 4);
73 for (i = 0; i < count; i++)
74 data[i] = GUINT32_FROM_LE (data[i]);
75 }
76
77 return total * 4;
78 }
79
80
81 static gint
ico_read_int16(FILE * fp,guint16 * data,gint count)82 ico_read_int16 (FILE *fp,
83 guint16 *data,
84 gint count)
85 {
86 gint i, total;
87
88 total = count;
89 if (count > 0)
90 {
91 ico_read_int8 (fp, (guint8 *) data, count * 2);
92 for (i = 0; i < count; i++)
93 data[i] = GUINT16_FROM_LE (data[i]);
94 }
95
96 return total * 2;
97 }
98
99
100 static gint
ico_read_int8(FILE * fp,guint8 * data,gint count)101 ico_read_int8 (FILE *fp,
102 guint8 *data,
103 gint count)
104 {
105 gint total;
106 gint bytes;
107
108 total = count;
109 while (count > 0)
110 {
111 bytes = fread ((gchar *) data, sizeof (gchar), count, fp);
112 if (bytes <= 0) /* something bad happened */
113 break;
114
115 count -= bytes;
116 data += bytes;
117 }
118
119 return total;
120 }
121
122
123 static guint32
ico_read_init(FILE * fp)124 ico_read_init (FILE *fp)
125 {
126 IcoFileHeader header;
127
128 /* read and check file header */
129 if (! ico_read_int16 (fp, &header.reserved, 1) ||
130 ! ico_read_int16 (fp, &header.resource_type, 1) ||
131 ! ico_read_int16 (fp, &header.icon_count, 1) ||
132 header.reserved != 0 ||
133 header.resource_type != 1)
134 {
135 return 0;
136 }
137
138 return header.icon_count;
139 }
140
141
142 static gboolean
ico_read_size(FILE * fp,IcoLoadInfo * info)143 ico_read_size (FILE *fp,
144 IcoLoadInfo *info)
145 {
146 png_structp png_ptr;
147 png_infop info_ptr;
148 png_uint_32 w, h;
149 gint32 bpp;
150 gint32 color_type;
151 guint32 magic;
152
153 if (fseek (fp, info->offset, SEEK_SET) < 0)
154 return FALSE;
155
156 ico_read_int32 (fp, &magic, 1);
157
158 if (magic == ICO_PNG_MAGIC)
159 {
160 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL,
161 NULL);
162 if (! png_ptr)
163 return FALSE;
164
165 info_ptr = png_create_info_struct (png_ptr);
166 if (! info_ptr)
167 {
168 png_destroy_read_struct (&png_ptr, NULL, NULL);
169 return FALSE;
170 }
171
172 if (setjmp (png_jmpbuf (png_ptr)))
173 {
174 png_destroy_read_struct (&png_ptr, NULL, NULL);
175 return FALSE;
176 }
177 png_init_io (png_ptr, fp);
178 png_set_sig_bytes (png_ptr, 4);
179 png_read_info (png_ptr, info_ptr);
180 png_get_IHDR (png_ptr, info_ptr, &w, &h, &bpp, &color_type,
181 NULL, NULL, NULL);
182 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
183 info->width = w;
184 info->height = h;
185 D(("ico_read_size: PNG: %ix%i\n", info->width, info->height));
186 return TRUE;
187 }
188 else if (magic == 40)
189 {
190 if (ico_read_int32 (fp, &info->width, 1) &&
191 ico_read_int32 (fp, &info->height, 1))
192 {
193 info->height /= 2;
194 D(("ico_read_size: ICO: %ix%i\n", info->width, info->height));
195 return TRUE;
196 }
197 else
198 {
199 info->width = 0;
200 info->height = 0;
201 return FALSE;
202 }
203 }
204 return FALSE;
205 }
206
207 static IcoLoadInfo*
ico_read_info(FILE * fp,gint icon_count,GError ** error)208 ico_read_info (FILE *fp,
209 gint icon_count,
210 GError **error)
211 {
212 gint i;
213 IcoFileEntry *entries;
214 IcoLoadInfo *info;
215
216 /* read icon entries */
217 entries = g_new (IcoFileEntry, icon_count);
218 if (fread (entries, sizeof (IcoFileEntry), icon_count, fp) <= 0)
219 {
220 g_set_error (error, G_FILE_ERROR, 0,
221 _("Could not read '%lu' bytes"),
222 sizeof (IcoFileEntry));
223 g_free (entries);
224 return NULL;
225 }
226
227 info = g_new (IcoLoadInfo, icon_count);
228 for (i = 0; i < icon_count; i++)
229 {
230 info[i].width = entries[i].width;
231 info[i].height = entries[i].height;
232 info[i].bpp = GUINT16_FROM_LE (entries[i].bpp);
233 info[i].size = GUINT32_FROM_LE (entries[i].size);
234 info[i].offset = GUINT32_FROM_LE (entries[i].offset);
235
236 if (info[i].width == 0 || info[i].height == 0)
237 {
238 ico_read_size (fp, info + i);
239 }
240
241 D(("ico_read_info: %ix%i (%i bits, size: %i, offset: %i)\n",
242 info[i].width, info[i].height, info[i].bpp,
243 info[i].size, info[i].offset));
244
245 if (info[i].width == 0 || info[i].height == 0)
246 {
247 g_set_error (error, G_FILE_ERROR, 0,
248 _("Icon #%d has zero width or height"), i);
249 g_free (info);
250 g_free (entries);
251 return NULL;
252 }
253 }
254
255 g_free (entries);
256
257 return info;
258 }
259
260 static gboolean
ico_read_png(FILE * fp,guint32 header,guchar * buf,gint maxsize,gint * width,gint * height)261 ico_read_png (FILE *fp,
262 guint32 header,
263 guchar *buf,
264 gint maxsize,
265 gint *width,
266 gint *height)
267 {
268 png_structp png_ptr;
269 png_infop info;
270 png_uint_32 w;
271 png_uint_32 h;
272 gint32 bit_depth;
273 gint32 color_type;
274 guint32 **rows;
275 gint i;
276
277 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
278 if (! png_ptr)
279 return FALSE;
280 info = png_create_info_struct (png_ptr);
281 if (! info)
282 {
283 png_destroy_read_struct (&png_ptr, NULL, NULL);
284 return FALSE;
285 }
286
287 if (setjmp (png_jmpbuf (png_ptr)))
288 {
289 png_destroy_read_struct (&png_ptr, &info, NULL);
290 return FALSE;
291 }
292
293 png_init_io (png_ptr, fp);
294 png_set_sig_bytes (png_ptr, 4);
295 png_read_info (png_ptr, info);
296 png_get_IHDR (png_ptr, info, &w, &h, &bit_depth, &color_type,
297 NULL, NULL, NULL);
298 if (w*h*4 > maxsize)
299 {
300 png_destroy_read_struct (&png_ptr, &info, NULL);
301 return FALSE;
302 }
303 D(("ico_read_png: %ix%i, %i bits, %i type\n", (gint)w, (gint)h,
304 bit_depth, color_type));
305 switch (color_type)
306 {
307 case PNG_COLOR_TYPE_GRAY:
308 png_set_expand_gray_1_2_4_to_8 (png_ptr);
309 if (bit_depth == 16)
310 png_set_strip_16 (png_ptr);
311 png_set_gray_to_rgb (png_ptr);
312 png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
313 break;
314 case PNG_COLOR_TYPE_GRAY_ALPHA:
315 png_set_expand_gray_1_2_4_to_8 (png_ptr);
316 if (bit_depth == 16)
317 png_set_strip_16 (png_ptr);
318 png_set_gray_to_rgb (png_ptr);
319 break;
320 case PNG_COLOR_TYPE_PALETTE:
321 png_set_palette_to_rgb (png_ptr);
322 if (png_get_valid (png_ptr, info, PNG_INFO_tRNS))
323 png_set_tRNS_to_alpha (png_ptr);
324 else
325 png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
326 break;
327 case PNG_COLOR_TYPE_RGB:
328 if (bit_depth == 16)
329 png_set_strip_16 (png_ptr);
330 png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
331 break;
332 case PNG_COLOR_TYPE_RGB_ALPHA:
333 if (bit_depth == 16)
334 png_set_strip_16 (png_ptr);
335 break;
336 }
337
338 *width = w;
339 *height = h;
340 rows = g_new (guint32*, h);
341 rows[0] = (guint32*) buf;
342 for (i = 1; i < h; i++)
343 rows[i] = rows[i-1] + w;
344 png_read_image (png_ptr, (png_bytepp) rows);
345 png_destroy_read_struct (&png_ptr, &info, NULL);
346 g_free (rows);
347 return TRUE;
348 }
349
350 gint
ico_get_bit_from_data(const guint8 * data,gint line_width,gint bit)351 ico_get_bit_from_data (const guint8 *data,
352 gint line_width,
353 gint bit)
354 {
355 gint line;
356 gint width32;
357 gint offset;
358 gint result;
359
360 /* width per line in multiples of 32 bits */
361 width32 = (line_width % 32 == 0 ? line_width/32 : line_width/32 + 1);
362 line = bit / line_width;
363 offset = bit % line_width;
364
365 result = (data[line * width32 * 4 + offset/8] & (1 << (7 - (offset % 8))));
366
367 return (result ? 1 : 0);
368 }
369
370
371 gint
ico_get_nibble_from_data(const guint8 * data,gint line_width,gint nibble)372 ico_get_nibble_from_data (const guint8 *data,
373 gint line_width,
374 gint nibble)
375 {
376 gint line;
377 gint width32;
378 gint offset;
379 gint result;
380
381 /* width per line in multiples of 32 bits */
382 width32 = (line_width % 8 == 0 ? line_width/8 : line_width/8 + 1);
383 line = nibble / line_width;
384 offset = nibble % line_width;
385
386 result =
387 (data[line * width32 * 4 + offset/2] & (0x0F << (4 * (1 - offset % 2))));
388
389 if (offset % 2 == 0)
390 result = result >> 4;
391
392 return result;
393 }
394
395 gint
ico_get_byte_from_data(const guint8 * data,gint line_width,gint byte)396 ico_get_byte_from_data (const guint8 *data,
397 gint line_width,
398 gint byte)
399 {
400 gint line;
401 gint width32;
402 gint offset;
403
404 /* width per line in multiples of 32 bits */
405 width32 = (line_width % 4 == 0 ? line_width / 4 : line_width / 4 + 1);
406 line = byte / line_width;
407 offset = byte % line_width;
408
409 return data[line * width32 * 4 + offset];
410 }
411
412 static gboolean
ico_read_icon(FILE * fp,guint32 header_size,guchar * buf,gint maxsize,gint * width,gint * height)413 ico_read_icon (FILE *fp,
414 guint32 header_size,
415 guchar *buf,
416 gint maxsize,
417 gint *width,
418 gint *height)
419 {
420 IcoFileDataHeader data;
421 gint length;
422 gint x, y, w, h;
423 guchar *xor_map, *and_map;
424 guint32 *palette;
425 guint32 *dest_vec;
426 guchar *row;
427 gint rowstride;
428
429 palette = NULL;
430
431 data.header_size = header_size;
432 ico_read_int32 (fp, &data.width, 1);
433 ico_read_int32 (fp, &data.height, 1);
434 ico_read_int16 (fp, &data.planes, 1);
435 ico_read_int16 (fp, &data.bpp, 1);
436 ico_read_int32 (fp, &data.compression, 1);
437 ico_read_int32 (fp, &data.image_size, 1);
438 ico_read_int32 (fp, &data.x_res, 1);
439 ico_read_int32 (fp, &data.y_res, 1);
440 ico_read_int32 (fp, &data.used_clrs, 1);
441 ico_read_int32 (fp, &data.important_clrs, 1);
442
443 D((" header size %i, "
444 "w %i, h %i, planes %i, size %i, bpp %i, used %i, imp %i.\n",
445 data.header_size, data.width, data.height,
446 data.planes, data.image_size, data.bpp,
447 data.used_clrs, data.important_clrs));
448
449 if (data.planes != 1 ||
450 data.compression != 0)
451 {
452 D(("skipping image: invalid header\n"));
453 return FALSE;
454 }
455
456 if (data.bpp != 1 &&
457 data.bpp != 4 &&
458 data.bpp != 8 &&
459 data.bpp != 24 &&
460 data.bpp != 32)
461 {
462 D(("skipping image: invalid depth: %i\n", data.bpp));
463 return FALSE;
464 }
465
466 if (data.width * data.height * 2 > maxsize)
467 {
468 D(("skipping image: too large\n"));
469 return FALSE;
470 }
471
472 w = data.width;
473 h = data.height / 2;
474
475 if (data.bpp <= 8)
476 {
477 if (data.used_clrs == 0)
478 data.used_clrs = (1 << data.bpp);
479
480 D((" allocating a %i-slot palette for %i bpp.\n",
481 data.used_clrs, data.bpp));
482
483 palette = g_new0 (guint32, data.used_clrs);
484 ico_read_int8 (fp, (guint8 *) palette, data.used_clrs * 4);
485 }
486
487 xor_map = ico_alloc_map (w, h, data.bpp, &length);
488 ico_read_int8 (fp, xor_map, length);
489 D((" length of xor_map: %i\n", length));
490
491 /* Read in and_map. It's padded out to 32 bits per line: */
492 and_map = ico_alloc_map (w, h, 1, &length);
493 ico_read_int8 (fp, and_map, length);
494 D((" length of and_map: %i\n", length));
495
496 dest_vec = (guint32 *) buf;
497 switch (data.bpp)
498 {
499 case 1:
500 for (y = 0; y < h; y++)
501 for (x = 0; x < w; x++)
502 {
503 guint32 color = palette[ico_get_bit_from_data (xor_map,
504 w, y * w + x)];
505 guint32 *dest = dest_vec + (h - 1 - y) * w + x;
506
507 R_VAL_GIMP (dest) = R_VAL (&color);
508 G_VAL_GIMP (dest) = G_VAL (&color);
509 B_VAL_GIMP (dest) = B_VAL (&color);
510
511 if (ico_get_bit_from_data (and_map, w, y * w + x))
512 A_VAL_GIMP (dest) = 0;
513 else
514 A_VAL_GIMP (dest) = 255;
515 }
516 break;
517
518 case 4:
519 for (y = 0; y < h; y++)
520 for (x = 0; x < w; x++)
521 {
522 guint32 color = palette[ico_get_nibble_from_data (xor_map,
523 w, y * w + x)];
524 guint32 *dest = dest_vec + (h - 1 - y) * w + x;
525
526 R_VAL_GIMP (dest) = R_VAL (&color);
527 G_VAL_GIMP (dest) = G_VAL (&color);
528 B_VAL_GIMP (dest) = B_VAL (&color);
529
530 if (ico_get_bit_from_data (and_map, w, y * w + x))
531 A_VAL_GIMP (dest) = 0;
532 else
533 A_VAL_GIMP (dest) = 255;
534 }
535 break;
536
537 case 8:
538 for (y = 0; y < h; y++)
539 for (x = 0; x < w; x++)
540 {
541 guint32 color = palette[ico_get_byte_from_data (xor_map,
542 w, y * w + x)];
543 guint32 *dest = dest_vec + (h - 1 - y) * w + x;
544
545 R_VAL_GIMP (dest) = R_VAL (&color);
546 G_VAL_GIMP (dest) = G_VAL (&color);
547 B_VAL_GIMP (dest) = B_VAL (&color);
548
549 if (ico_get_bit_from_data (and_map, w, y * w + x))
550 A_VAL_GIMP (dest) = 0;
551 else
552 A_VAL_GIMP (dest) = 255;
553 }
554 break;
555
556 default:
557 {
558 gint bytespp = data.bpp / 8;
559
560 rowstride = ico_rowstride (w, data.bpp);
561
562 for (y = 0; y < h; y++)
563 {
564 row = xor_map + rowstride * y;
565
566 for (x = 0; x < w; x++)
567 {
568 guint32 *dest = dest_vec + (h - 1 - y) * w + x;
569
570 B_VAL_GIMP (dest) = row[0];
571 G_VAL_GIMP (dest) = row[1];
572 R_VAL_GIMP (dest) = row[2];
573
574 if (data.bpp < 32)
575 {
576 if (ico_get_bit_from_data (and_map, w, y * w + x))
577 A_VAL_GIMP (dest) = 0;
578 else
579 A_VAL_GIMP (dest) = 255;
580 }
581 else
582 {
583 A_VAL_GIMP (dest) = row[3];
584 }
585
586 row += bytespp;
587 }
588 }
589 }
590 }
591 if (palette)
592 g_free (palette);
593 g_free (xor_map);
594 g_free (and_map);
595 *width = w;
596 *height = h;
597 return TRUE;
598 }
599
600 static gint32
ico_load_layer(FILE * fp,gint32 image,gint32 icon_num,guchar * buf,gint maxsize,IcoLoadInfo * info)601 ico_load_layer (FILE *fp,
602 gint32 image,
603 gint32 icon_num,
604 guchar *buf,
605 gint maxsize,
606 IcoLoadInfo *info)
607 {
608 gint width, height;
609 gint32 layer;
610 guint32 first_bytes;
611 GeglBuffer *buffer;
612 gchar name[ICO_MAXBUF];
613
614 if (fseek (fp, info->offset, SEEK_SET) < 0 ||
615 ! ico_read_int32 (fp, &first_bytes, 1))
616 return -1;
617
618 if (first_bytes == ICO_PNG_MAGIC)
619 {
620 if (!ico_read_png (fp, first_bytes, buf, maxsize, &width, &height))
621 return -1;
622 }
623 else if (first_bytes == 40)
624 {
625 if (!ico_read_icon (fp, first_bytes, buf, maxsize, &width, &height))
626 return -1;
627 }
628 else
629 {
630 return -1;
631 }
632
633 /* read successfully. add to image */
634 g_snprintf (name, sizeof (name), _("Icon #%i"), icon_num+1);
635 layer = gimp_layer_new (image, name, width, height,
636 GIMP_RGBA_IMAGE,
637 100,
638 gimp_image_get_default_new_layer_mode (image));
639 gimp_image_insert_layer (image, layer, -1, icon_num);
640
641 buffer = gimp_drawable_get_buffer (layer);
642
643 gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
644 NULL, buf, GEGL_AUTO_ROWSTRIDE);
645
646 g_object_unref (buffer);
647
648 return layer;
649 }
650
651
652 gint32
ico_load_image(const gchar * filename,GError ** error)653 ico_load_image (const gchar *filename,
654 GError **error)
655 {
656 FILE *fp;
657 IcoLoadInfo *info;
658 gint max_width, max_height;
659 gint i;
660 gint32 image;
661 guchar *buf;
662 guint icon_count;
663 gint maxsize;
664
665 gimp_progress_init_printf (_("Opening '%s'"),
666 gimp_filename_to_utf8 (filename));
667
668 fp = g_fopen (filename, "rb");
669 if (! fp)
670 {
671 g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
672 _("Could not open '%s' for reading: %s"),
673 gimp_filename_to_utf8 (filename), g_strerror (errno));
674 return -1;
675 }
676
677 icon_count = ico_read_init (fp);
678 if (!icon_count)
679 {
680 fclose (fp);
681 return -1;
682 }
683
684 info = ico_read_info (fp, icon_count, error);
685 if (! info)
686 {
687 fclose (fp);
688 return -1;
689 }
690
691 /* find width and height of image */
692 max_width = 0;
693 max_height = 0;
694 for (i = 0; i < icon_count; i++)
695 {
696 if (info[i].width > max_width)
697 max_width = info[i].width;
698 if (info[i].height > max_height)
699 max_height = info[i].height;
700 }
701 if (max_width <= 0 || max_height <= 0)
702 {
703 g_free (info);
704 fclose (fp);
705 return -1;
706 }
707 D(("image size: %ix%i\n", max_width, max_height));
708
709 image = gimp_image_new (max_width, max_height, GIMP_RGB);
710 gimp_image_set_filename (image, filename);
711
712 maxsize = max_width * max_height * 4;
713 buf = g_new (guchar, max_width * max_height * 4);
714 for (i = 0; i < icon_count; i++)
715 {
716 ico_load_layer (fp, image, i, buf, maxsize, info+i);
717 }
718 g_free (buf);
719 g_free (info);
720 fclose (fp);
721
722 gimp_progress_update (1.0);
723
724 return image;
725 }
726
727 gint32
ico_load_thumbnail_image(const gchar * filename,gint * width,gint * height,GError ** error)728 ico_load_thumbnail_image (const gchar *filename,
729 gint *width,
730 gint *height,
731 GError **error)
732 {
733 FILE *fp;
734 IcoLoadInfo *info;
735 gint32 image;
736 gint w = 0;
737 gint h = 0;
738 gint bpp = 0;
739 gint match = 0;
740 gint i, icon_count;
741 guchar *buf;
742
743 gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
744 gimp_filename_to_utf8 (filename));
745
746 fp = g_fopen (filename, "rb");
747 if (! fp)
748 {
749 g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
750 _("Could not open '%s' for reading: %s"),
751 gimp_filename_to_utf8 (filename), g_strerror (errno));
752 return -1;
753 }
754
755 icon_count = ico_read_init (fp);
756 if (! icon_count)
757 {
758 fclose (fp);
759 return -1;
760 }
761
762 D(("*** %s: Microsoft icon file, containing %i icon(s)\n",
763 filename, icon_count));
764
765 info = ico_read_info (fp, icon_count, error);
766 if (! info)
767 {
768 fclose (fp);
769 return -1;
770 }
771
772 /* Do a quick scan of the icons in the file to find the best match */
773 for (i = 0; i < icon_count; i++)
774 {
775 if ((info[i].width > w && w < *width) ||
776 (info[i].height > h && h < *height))
777 {
778 w = info[i].width;
779 h = info[i].height;
780 bpp = info[i].bpp;
781
782 match = i;
783 }
784 else if (w == info[i].width &&
785 h == info[i].height &&
786 info[i].bpp > bpp)
787 {
788 /* better quality */
789 bpp = info[i].bpp;
790 match = i;
791 }
792 }
793
794 if (w <= 0 || h <= 0)
795 return -1;
796
797 image = gimp_image_new (w, h, GIMP_RGB);
798 buf = g_new (guchar, w*h*4);
799 ico_load_layer (fp, image, match, buf, w*h*4, info+match);
800 g_free (buf);
801
802 *width = w;
803 *height = h;
804
805 D(("*** thumbnail successfully loaded.\n\n"));
806
807 gimp_progress_update (1.0);
808
809 g_free (info);
810 fclose (fp);
811
812 return image;
813 }
814