~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to plug-ins/file-ico/ico-save.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2008-10-06 13:30:41 UTC
  • mto: This revision was merged to the branch mainline in revision 35.
  • Revision ID: james.westby@ubuntu.com-20081006133041-3panbkcanaymfsmp
Tags: upstream-2.6.0
ImportĀ upstreamĀ versionĀ 2.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 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
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
20
 */
 
21
 
 
22
#include "config.h"
 
23
 
 
24
#include <errno.h>
 
25
#include <string.h>
 
26
 
 
27
#include <glib/gstdio.h>
 
28
 
 
29
#include <libgimp/gimp.h>
 
30
#include <libgimp/gimpui.h>
 
31
 
 
32
#include <png.h>
 
33
 
 
34
/* #define ICO_DBG */
 
35
 
 
36
#include "ico.h"
 
37
#include "ico-load.h"
 
38
#include "ico-save.h"
 
39
#include "ico-dialog.h"
 
40
 
 
41
#include "libgimp/stdplugins-intl.h"
 
42
 
 
43
 
 
44
static gint     ico_write_int8         (FILE   *fp,
 
45
                                        guint8 *data,
 
46
                                        gint    count);
 
47
static gint     ico_write_int16        (FILE *fp,
 
48
                                        guint16 *data,
 
49
                                        gint count);
 
50
static gint     ico_write_int32        (FILE    *fp,
 
51
                                        guint32 *data,
 
52
                                        gint     count);
 
53
 
 
54
/* Helpers to set bits in a *cleared* data chunk */
 
55
static void     ico_set_bit_in_data    (guint8 *data,
 
56
                                        gint    line_width,
 
57
                                        gint    bit_num,
 
58
                                        gint    bit_val);
 
59
static void     ico_set_nibble_in_data (guint8 *data,
 
60
                                        gint    line_width,
 
61
                                        gint    nibble_num,
 
62
                                        gint    nibble_val);
 
63
static void     ico_set_byte_in_data   (guint8 *data,
 
64
                                        gint    line_width,
 
65
                                        gint    byte_num,
 
66
                                        gint    byte_val);
 
67
 
 
68
static gint     ico_get_layer_num_colors  (gint32    layer,
 
69
                                           gboolean *uses_alpha_levels);
 
70
static void     ico_image_get_reduced_buf (guint32   layer,
 
71
                                           gint      bpp,
 
72
                                           gint     *num_colors,
 
73
                                           guchar  **cmap_out,
 
74
                                           guchar  **buf_out);
 
75
 
 
76
 
 
77
static gint
 
78
ico_write_int32 (FILE     *fp,
 
79
                 guint32  *data,
 
80
                 gint      count)
 
81
{
 
82
  gint total;
 
83
 
 
84
  total = count;
 
85
  if (count > 0)
 
86
    {
 
87
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
 
88
      gint i;
 
89
 
 
90
      for (i = 0; i < count; i++)
 
91
        data[i] = GUINT32_FROM_LE (data[i]);
 
92
#endif
 
93
 
 
94
      ico_write_int8 (fp, (guint8 *) data, count * 4);
 
95
 
 
96
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
 
97
      /* Put it back like we found it */
 
98
      for (i = 0; i < count; i++)
 
99
        data[i] = GUINT32_FROM_LE (data[i]);
 
100
#endif
 
101
    }
 
102
 
 
103
  return total * 4;
 
104
}
 
105
 
 
106
 
 
107
static gint
 
108
ico_write_int16 (FILE     *fp,
 
109
                 guint16  *data,
 
110
                 gint      count)
 
111
{
 
112
  gint total;
 
113
 
 
114
  total = count;
 
115
  if (count > 0)
 
116
    {
 
117
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
 
118
      gint i;
 
119
 
 
120
      for (i = 0; i < count; i++)
 
121
        data[i] = GUINT16_FROM_LE (data[i]);
 
122
#endif
 
123
 
 
124
      ico_write_int8 (fp, (guint8 *) data, count * 2);
 
125
 
 
126
#if (G_BYTE_ORDER == G_BIG_ENDIAN)
 
127
      /* Put it back like we found it */
 
128
      for (i = 0; i < count; i++)
 
129
        data[i] = GUINT16_FROM_LE (data[i]);
 
130
#endif
 
131
    }
 
132
 
 
133
  return total * 2;
 
134
}
 
135
 
 
136
 
 
137
static gint
 
138
ico_write_int8 (FILE     *fp,
 
139
                guint8   *data,
 
140
                gint      count)
 
141
{
 
142
  gint total;
 
143
  gint bytes;
 
144
 
 
145
  total = count;
 
146
  while (count > 0)
 
147
    {
 
148
      bytes = fwrite ((gchar *) data, sizeof (gchar), count, fp);
 
149
      if (bytes <= 0) /* something bad happened */
 
150
        break;
 
151
      count -= bytes;
 
152
      data += bytes;
 
153
    }
 
154
 
 
155
  return total;
 
156
}
 
157
 
 
158
 
 
159
static void
 
160
ico_save_init (gint32 image_ID, IcoSaveInfo *info)
 
161
{
 
162
  gint      *layers;
 
163
  gint       i, num_colors;
 
164
  gboolean   uses_alpha_values;
 
165
 
 
166
  layers = gimp_image_get_layers (image_ID, &info->num_icons);
 
167
  info->layers = layers;
 
168
  info->depths = g_new (gint, info->num_icons);
 
169
  info->default_depths = g_new (gint, info->num_icons);
 
170
  info->compress = g_new (gboolean, info->num_icons);
 
171
 
 
172
  /* Limit the color depths to values that don't cause any color loss --
 
173
     the user should pick these anyway, so we can save her some time.
 
174
     If the user wants to lose some colors, the settings can always be changed
 
175
     in the dialog: */
 
176
  for (i = 0; i < info->num_icons; i++)
 
177
    {
 
178
      num_colors = ico_get_layer_num_colors (layers[i], &uses_alpha_values);
 
179
 
 
180
      if (!uses_alpha_values)
 
181
        {
 
182
          if (num_colors <= 2)
 
183
            {
 
184
              /* Let's suggest monochrome */
 
185
              info->default_depths [i] = 1;
 
186
            }
 
187
          else if (num_colors <= 16)
 
188
            {
 
189
              /* Let's suggest 4bpp */
 
190
              info->default_depths [i] = 4;
 
191
            }
 
192
          else if (num_colors <= 256)
 
193
            {
 
194
              /* Let's suggest 8bpp */
 
195
              info->default_depths [i] = 8;
 
196
            }
 
197
          else
 
198
            {
 
199
              /* Let's suggest 24bpp */
 
200
              info->default_depths [i] = 24;
 
201
            }
 
202
        }
 
203
      else
 
204
        {
 
205
          /* Otherwise, or if real alpha levels are used, stick with 32bpp */
 
206
          info->default_depths [i] = 32;
 
207
        }
 
208
 
 
209
      /* vista icons */
 
210
      if (gimp_drawable_width (layers[i]) > 255
 
211
          || gimp_drawable_height (layers[i]) > 255 )
 
212
        {
 
213
          info->compress[i] = TRUE;
 
214
        }
 
215
      else
 
216
        {
 
217
          info->compress[i] = FALSE;
 
218
        }
 
219
    }
 
220
 
 
221
  /* set with default values */
 
222
  memcpy (info->depths, info->default_depths,
 
223
          sizeof (gint) * info->num_icons);
 
224
}
 
225
 
 
226
 
 
227
 
 
228
static gboolean
 
229
ico_save_dialog (gint32          image_ID,
 
230
                 IcoSaveInfo    *info)
 
231
{
 
232
  GtkWidget *dialog;
 
233
  gint       i;
 
234
  gint       response;
 
235
 
 
236
  gimp_ui_init (PLUG_IN_BINARY, TRUE);
 
237
 
 
238
  dialog = ico_dialog_new (info);
 
239
  for (i = 0; i < info->num_icons; i++)
 
240
    {
 
241
      /* if (gimp_layer_get_visible(layers[i])) */
 
242
      ico_dialog_add_icon (dialog, info->layers[i], i);
 
243
    }
 
244
 
 
245
  /* Scale the thing to approximately fit its content, but not too large ... */
 
246
  gtk_window_set_default_size (GTK_WINDOW (dialog),
 
247
                               -1,
 
248
                               200 + (info->num_icons > 4 ?
 
249
                                      500 : info->num_icons * 120));
 
250
 
 
251
  gtk_widget_show (dialog);
 
252
 
 
253
  response = gimp_dialog_run (GIMP_DIALOG (dialog));
 
254
 
 
255
  gtk_widget_destroy (dialog);
 
256
 
 
257
  return (response == GTK_RESPONSE_OK);
 
258
}
 
259
 
 
260
static void
 
261
ico_set_bit_in_data (guint8 *data,
 
262
                     gint    line_width,
 
263
                     gint    bit_num,
 
264
                     gint    bit_val)
 
265
{
 
266
  gint line;
 
267
  gint width32;
 
268
  gint offset;
 
269
 
 
270
  /* width per line in multiples of 32 bits */
 
271
  width32 = (line_width % 32 == 0 ? line_width/32 : line_width/32 + 1);
 
272
 
 
273
  line = bit_num / line_width;
 
274
  offset = bit_num % line_width;
 
275
  bit_val = bit_val & 0x00000001;
 
276
 
 
277
  data[line * width32 * 4 + offset/8] |= (bit_val << (7 - (offset % 8)));
 
278
}
 
279
 
 
280
 
 
281
static void
 
282
ico_set_nibble_in_data (guint8 *data,
 
283
                        gint    line_width,
 
284
                        gint    nibble_num,
 
285
                        gint    nibble_val)
 
286
{
 
287
  gint line;
 
288
  gint width8;
 
289
  gint offset;
 
290
 
 
291
  /* width per line in multiples of 32 bits */
 
292
  width8 = (line_width % 8 == 0 ? line_width/8 : line_width/8 + 1);
 
293
 
 
294
  line = nibble_num / line_width;
 
295
  offset = nibble_num % line_width;
 
296
  nibble_val = nibble_val & 0x0000000F;
 
297
 
 
298
  data[line * width8 * 4 + offset/2] |=
 
299
    (nibble_val << (4 * (1 - (offset % 2))));
 
300
}
 
301
 
 
302
 
 
303
static void
 
304
ico_set_byte_in_data (guint8 *data,
 
305
                      gint    line_width,
 
306
                      gint    byte_num,
 
307
                      gint    byte_val)
 
308
{
 
309
  gint line;
 
310
  gint width4;
 
311
  gint offset;
 
312
  gint byte;
 
313
 
 
314
  /* width per line in multiples of 32 bits */
 
315
  width4 = (line_width % 4 == 0 ? line_width/4 : line_width/4 + 1);
 
316
 
 
317
  line = byte_num / line_width;
 
318
  offset = byte_num % line_width;
 
319
  byte = byte_val & 0x000000FF;
 
320
 
 
321
  data[line * width4 * 4 + offset] = byte;
 
322
}
 
323
 
 
324
 
 
325
/* Create a colormap from the given buffer data */
 
326
static guint32 *
 
327
ico_create_palette (const guchar *cmap,
 
328
                    gint          num_colors,
 
329
                    gint          num_colors_used,
 
330
                    gint         *black_slot)
 
331
{
 
332
  guchar *palette;
 
333
  gint    i;
 
334
 
 
335
  g_return_val_if_fail (cmap != NULL || num_colors_used == 0, NULL);
 
336
  g_return_val_if_fail (num_colors_used <= num_colors, NULL);
 
337
 
 
338
  palette = g_new0 (guchar, num_colors * 4);
 
339
  *black_slot = -1;
 
340
 
 
341
  for (i = 0; i < num_colors_used; i++)
 
342
    {
 
343
      palette[i * 4 + 2] = cmap[i * 3];
 
344
      palette[i * 4 + 1] = cmap[i * 3 + 1];
 
345
      palette[i * 4]     = cmap[i * 3 + 2];
 
346
 
 
347
      if ((cmap[i*3]     == 0) &&
 
348
          (cmap[i*3 + 1] == 0) &&
 
349
          (cmap[i*3 + 2] == 0))
 
350
        {
 
351
          *black_slot = i;
 
352
        }
 
353
    }
 
354
 
 
355
  if (*black_slot == -1)
 
356
    {
 
357
      if (num_colors_used == num_colors)
 
358
        {
 
359
          D(("WARNING -- no room for black, this shouldn't happen.\n"));
 
360
          *black_slot = num_colors - 1;
 
361
 
 
362
          palette[(num_colors-1) * 4]     = 0;
 
363
          palette[(num_colors-1) * 4 + 1] = 0;
 
364
          palette[(num_colors-1) * 4 + 2] = 0;
 
365
        }
 
366
      else
 
367
        {
 
368
          *black_slot = num_colors_used;
 
369
        }
 
370
    }
 
371
 
 
372
  return (guint32 *) palette;
 
373
}
 
374
 
 
375
 
 
376
static GHashTable *
 
377
ico_create_color_to_palette_map (const guint32 *palette,
 
378
                                 gint           num_colors)
 
379
{
 
380
  GHashTable *hash;
 
381
  gint        i;
 
382
 
 
383
  hash = g_hash_table_new_full (g_int_hash, g_int_equal,
 
384
                                (GDestroyNotify) g_free,
 
385
                                (GDestroyNotify) g_free);
 
386
 
 
387
  for (i = 0; i < num_colors; i++)
 
388
    {
 
389
      const guint8 *pixel = (const guint8 *) &palette[i];
 
390
      gint         *color;
 
391
      gint         *slot;
 
392
 
 
393
      color = g_new (gint, 1);
 
394
      slot = g_new (gint, 1);
 
395
 
 
396
      *color = (pixel[2] << 16 | pixel[1] << 8 | pixel[0]);
 
397
      *slot = i;
 
398
 
 
399
      g_hash_table_insert (hash, color, slot);
 
400
    }
 
401
 
 
402
  return hash;
 
403
}
 
404
 
 
405
static gint
 
406
ico_get_palette_index (GHashTable *hash,
 
407
                       gint        red,
 
408
                       gint        green,
 
409
                       gint        blue)
 
410
{
 
411
  gint  color = 0;
 
412
  gint *slot;
 
413
 
 
414
  color = (red << 16 | green << 8 | blue);
 
415
  slot = g_hash_table_lookup (hash, &color);
 
416
 
 
417
  if (!slot)
 
418
    {
 
419
      return 0;
 
420
    }
 
421
 
 
422
  return *slot;
 
423
}
 
424
 
 
425
static gint
 
426
ico_get_layer_num_colors (gint32    layer,
 
427
                          gboolean *uses_alpha_levels)
 
428
{
 
429
  GimpPixelRgn    pixel_rgn;
 
430
  gint            w, h;
 
431
  gint            bpp;
 
432
  gint            num_colors = 0;
 
433
  guint           num_pixels;
 
434
  guchar         *buffer;
 
435
  guchar         *src;
 
436
  guint32        *colors;
 
437
  guint32        *c;
 
438
  GHashTable     *hash;
 
439
  GimpDrawable   *drawable = gimp_drawable_get (layer);
 
440
 
 
441
  w = gimp_drawable_width (layer);
 
442
  h = gimp_drawable_height (layer);
 
443
 
 
444
  num_pixels = w * h;
 
445
 
 
446
  bpp = gimp_drawable_bpp (layer);
 
447
 
 
448
  buffer = src = g_new (guchar, num_pixels * bpp);
 
449
 
 
450
  gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, w, h, FALSE, FALSE);
 
451
  gimp_pixel_rgn_get_rect (&pixel_rgn, buffer, 0, 0, w, h);
 
452
 
 
453
  gimp_drawable_detach (drawable);
 
454
 
 
455
  hash = g_hash_table_new (g_int_hash, g_int_equal);
 
456
  *uses_alpha_levels = FALSE;
 
457
 
 
458
  colors = c = g_new (guint32, num_pixels);
 
459
 
 
460
  switch (bpp)
 
461
    {
 
462
    case 1:
 
463
      while (num_pixels--)
 
464
        {
 
465
          *c = *src;
 
466
          g_hash_table_insert (hash, c, c);
 
467
          src++;
 
468
          c++;
 
469
        }
 
470
      break;
 
471
 
 
472
    case 2:
 
473
      while (num_pixels--)
 
474
        {
 
475
          *c = (src[1] << 8) | src[0];
 
476
          if (src[1] != 0 && src[1] != 255)
 
477
            *uses_alpha_levels = TRUE;
 
478
          g_hash_table_insert (hash, c, c);
 
479
          src += 2;
 
480
          c++;
 
481
        }
 
482
      break;
 
483
 
 
484
    case 3:
 
485
      while (num_pixels--)
 
486
        {
 
487
          *c = (src[2] << 16) | (src[1] << 8) | src[0];
 
488
          g_hash_table_insert (hash, c, c);
 
489
          src += 3;
 
490
          c++;
 
491
        }
 
492
      break;
 
493
 
 
494
    case 4:
 
495
      while (num_pixels--)
 
496
        {
 
497
          *c = (src[3] << 24) | (src[2] << 16) | (src[1] << 8) | src[0];
 
498
          if (src[3] != 0 && src[3] != 255)
 
499
            *uses_alpha_levels = TRUE;
 
500
          g_hash_table_insert (hash, c, c);
 
501
          src += 4;
 
502
          c++;
 
503
        }
 
504
      break;
 
505
    }
 
506
 
 
507
  num_colors = g_hash_table_size (hash);
 
508
 
 
509
  g_hash_table_destroy (hash);
 
510
 
 
511
  g_free (colors);
 
512
  g_free (buffer);
 
513
 
 
514
  return num_colors;
 
515
}
 
516
 
 
517
gboolean
 
518
ico_cmap_contains_black (const guchar *cmap,
 
519
                         gint          num_colors)
 
520
{
 
521
  gint i;
 
522
 
 
523
  for (i = 0; i < num_colors; i++)
 
524
    {
 
525
      if ((cmap[3 * i    ] == 0) &&
 
526
          (cmap[3 * i + 1] == 0) &&
 
527
          (cmap[3 * i + 2] == 0))
 
528
        {
 
529
          return TRUE;
 
530
        }
 
531
    }
 
532
 
 
533
  return FALSE;
 
534
}
 
535
 
 
536
static void
 
537
ico_image_get_reduced_buf (guint32   layer,
 
538
                           gint      bpp,
 
539
                           gint     *num_colors,
 
540
                           guchar  **cmap_out,
 
541
                           guchar  **buf_out)
 
542
{
 
543
  GimpPixelRgn    src_pixel_rgn, dst_pixel_rgn;
 
544
  gint32          tmp_image;
 
545
  gint32          tmp_layer;
 
546
  gint            w, h;
 
547
  guchar         *buffer;
 
548
  guchar         *cmap = NULL;
 
549
  GimpDrawable   *drawable = gimp_drawable_get (layer);
 
550
 
 
551
  w = gimp_drawable_width (layer);
 
552
  h = gimp_drawable_height (layer);
 
553
 
 
554
  *num_colors = 0;
 
555
 
 
556
  buffer = g_new (guchar, w * h * 4);
 
557
 
 
558
  if (bpp <= 8 || bpp == 24 || drawable->bpp != 4)
 
559
    {
 
560
      gint32        image = gimp_drawable_get_image (layer);
 
561
      GimpDrawable *tmp;
 
562
 
 
563
      tmp_image = gimp_image_new (gimp_drawable_width (layer),
 
564
                                  gimp_drawable_height (layer),
 
565
                                  gimp_image_base_type (image));
 
566
      gimp_image_undo_disable (tmp_image);
 
567
 
 
568
      if (gimp_drawable_is_indexed (layer))
 
569
        {
 
570
          guchar *cmap;
 
571
          gint    num_colors;
 
572
 
 
573
          cmap = gimp_image_get_colormap (image, &num_colors);
 
574
          gimp_image_set_colormap (tmp_image, cmap, num_colors);
 
575
          g_free (cmap);
 
576
        }
 
577
 
 
578
      tmp_layer = gimp_layer_new (tmp_image, "tmp", w, h,
 
579
                                  gimp_drawable_type (layer),
 
580
                                  100, GIMP_NORMAL_MODE);
 
581
      gimp_image_add_layer (tmp_image, tmp_layer, 0);
 
582
 
 
583
      tmp = gimp_drawable_get (tmp_layer);
 
584
 
 
585
      gimp_pixel_rgn_init (&src_pixel_rgn, drawable, 0, 0, w, h, FALSE, FALSE);
 
586
      gimp_pixel_rgn_init (&dst_pixel_rgn, tmp,      0, 0, w, h, TRUE, FALSE);
 
587
      gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h);
 
588
      gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
 
589
      gimp_drawable_detach (tmp);
 
590
 
 
591
      if (! gimp_drawable_is_rgb (tmp_layer))
 
592
        gimp_image_convert_rgb (tmp_image);
 
593
 
 
594
      if (bpp <= 8)
 
595
        {
 
596
          gimp_image_convert_indexed (tmp_image,
 
597
                                      GIMP_FS_DITHER, GIMP_MAKE_PALETTE,
 
598
                                      1 << bpp, TRUE, FALSE, "dummy");
 
599
 
 
600
          cmap = gimp_image_get_colormap (tmp_image, num_colors);
 
601
 
 
602
          if (*num_colors == (1 << bpp) &&
 
603
              !ico_cmap_contains_black (cmap, *num_colors))
 
604
            {
 
605
              /* Windows icons with color maps need the color black.
 
606
               * We need to eliminate one more color to make room for black.
 
607
               */
 
608
 
 
609
              if (gimp_drawable_is_indexed (layer))
 
610
                {
 
611
                  g_free (cmap);
 
612
                  cmap = gimp_image_get_colormap (image, num_colors);
 
613
                  gimp_image_set_colormap (tmp_image, cmap, *num_colors);
 
614
                }
 
615
              else if (gimp_drawable_is_gray (layer))
 
616
                {
 
617
                  gimp_image_convert_grayscale (tmp_image);
 
618
                }
 
619
              else
 
620
                {
 
621
                  gimp_image_convert_rgb (tmp_image);
 
622
                }
 
623
 
 
624
              tmp = gimp_drawable_get (tmp_layer);
 
625
              gimp_pixel_rgn_init (&dst_pixel_rgn,
 
626
                                   tmp, 0, 0, w, h, TRUE, FALSE);
 
627
              gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
 
628
              gimp_drawable_detach (tmp);
 
629
 
 
630
              if (!gimp_drawable_is_rgb (layer))
 
631
                gimp_image_convert_rgb (tmp_image);
 
632
 
 
633
              gimp_image_convert_indexed (tmp_image,
 
634
                                          GIMP_FS_DITHER, GIMP_MAKE_PALETTE,
 
635
                                          (1<<bpp) - 1, TRUE, FALSE, "dummy");
 
636
              g_free (cmap);
 
637
              cmap = gimp_image_get_colormap (tmp_image, num_colors);
 
638
            }
 
639
 
 
640
          gimp_image_convert_rgb (tmp_image);
 
641
        }
 
642
      else if (bpp == 24)
 
643
        {
 
644
          GimpParam    *return_vals;
 
645
          gint          n_return_vals;
 
646
 
 
647
          return_vals =
 
648
            gimp_run_procedure ("plug-in-threshold-alpha", &n_return_vals,
 
649
                                GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
 
650
                                GIMP_PDB_IMAGE, tmp_image,
 
651
                                GIMP_PDB_DRAWABLE, tmp_layer,
 
652
                                GIMP_PDB_INT32, ICO_ALPHA_THRESHOLD,
 
653
                                GIMP_PDB_END);
 
654
          gimp_destroy_params (return_vals, n_return_vals);
 
655
        }
 
656
 
 
657
      gimp_layer_add_alpha (tmp_layer);
 
658
 
 
659
      tmp = gimp_drawable_get (tmp_layer);
 
660
      gimp_pixel_rgn_init (&src_pixel_rgn, tmp, 0, 0, w, h, FALSE, FALSE);
 
661
      gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h);
 
662
      gimp_drawable_detach (tmp);
 
663
 
 
664
      gimp_image_delete (tmp_image);
 
665
    }
 
666
  else
 
667
    {
 
668
      gimp_pixel_rgn_init (&src_pixel_rgn, drawable, 0, 0, w, h, FALSE, FALSE);
 
669
      gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h);
 
670
    }
 
671
 
 
672
  gimp_drawable_detach (drawable);
 
673
 
 
674
  *cmap_out = cmap;
 
675
  *buf_out = buffer;
 
676
}
 
677
 
 
678
static gboolean
 
679
ico_write_png (FILE   *fp,
 
680
               gint32  layer,
 
681
               gint32  depth)
 
682
{
 
683
  png_structp png_ptr;
 
684
  png_infop   info_ptr;
 
685
  png_byte  **row_pointers;
 
686
  gint        i, rowstride;
 
687
  gint        width, height;
 
688
  gint        num_colors_used;
 
689
  guchar     *palette;
 
690
  guchar     *buffer;
 
691
 
 
692
  row_pointers = NULL;
 
693
  palette = NULL;
 
694
  buffer = NULL;
 
695
 
 
696
  width = gimp_drawable_width (layer);
 
697
  height = gimp_drawable_height (layer);
 
698
 
 
699
  png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
700
  if ( !png_ptr )
 
701
    return FALSE;
 
702
 
 
703
  info_ptr = png_create_info_struct (png_ptr);
 
704
  if ( !info_ptr )
 
705
    {
 
706
      png_destroy_write_struct (&png_ptr, NULL);
 
707
      return FALSE;
 
708
    }
 
709
 
 
710
  if (setjmp (png_jmpbuf (png_ptr)))
 
711
    {
 
712
      png_destroy_write_struct (&png_ptr, &info_ptr);
 
713
      if ( row_pointers )
 
714
        g_free (row_pointers);
 
715
      if (palette)
 
716
        g_free (palette);
 
717
      if (buffer)
 
718
        g_free (buffer);
 
719
      return FALSE;
 
720
    }
 
721
 
 
722
  ico_image_get_reduced_buf (layer, depth, &num_colors_used,
 
723
                             &palette, &buffer);
 
724
 
 
725
  png_init_io (png_ptr, fp);
 
726
  png_set_IHDR (png_ptr, info_ptr, width, height,
 
727
                8,
 
728
                PNG_COLOR_TYPE_RGBA,
 
729
                PNG_INTERLACE_NONE,
 
730
                PNG_COMPRESSION_TYPE_DEFAULT,
 
731
                PNG_FILTER_TYPE_DEFAULT);
 
732
  png_write_info (png_ptr, info_ptr);
 
733
 
 
734
  rowstride = ico_rowstride (width, 32);
 
735
  row_pointers = g_new (png_byte*, height);
 
736
  for (i = 0; i < height; i++)
 
737
    {
 
738
      row_pointers[i] = buffer + rowstride * i;
 
739
    }
 
740
  png_write_image (png_ptr, row_pointers);
 
741
 
 
742
  row_pointers = NULL;
 
743
 
 
744
  png_write_end (png_ptr, info_ptr);
 
745
  png_destroy_write_struct (&png_ptr, &info_ptr);
 
746
 
 
747
  g_free (row_pointers);
 
748
  g_free (palette);
 
749
  g_free (buffer);
 
750
  return TRUE;
 
751
}
 
752
 
 
753
static gboolean
 
754
ico_write_icon (FILE   *fp,
 
755
                gint32  layer,
 
756
                gint32  depth)
 
757
{
 
758
  IcoFileDataHeader  header;
 
759
  gint               and_len, xor_len, palette_index, x, y;
 
760
  gint               num_colors = 0, num_colors_used = 0, black_index = 0;
 
761
  gint               width, height;
 
762
  guchar            *buffer = NULL, *pixel;
 
763
  guint32           *buffer32;
 
764
  guchar            *palette;
 
765
  GHashTable        *color_to_slot = NULL;
 
766
  guchar            *xor_map, *and_map;
 
767
 
 
768
  guint32           *palette32 = NULL;
 
769
  gint               palette_len = 0;
 
770
 
 
771
  D(("Creating data structures for icon %i ------------------------\n",
 
772
     num_icon));
 
773
 
 
774
  width = gimp_drawable_width (layer);
 
775
  height = gimp_drawable_height (layer);
 
776
 
 
777
  header.header_size     = 40;
 
778
  header.width          = width;
 
779
  header.height         = 2 * height;
 
780
  header.planes         = 1;
 
781
  header.bpp            = depth;
 
782
  header.compression    = 0;
 
783
  header.image_size     = 0;
 
784
  header.x_res          = 0;
 
785
  header.y_res          = 0;
 
786
  header.used_clrs      = 0;
 
787
  header.important_clrs = 0;
 
788
 
 
789
  num_colors = (1L << header.bpp);
 
790
 
 
791
  D(("  header size %i, w %i, h %i, planes %i, bpp %i\n",
 
792
     header.header_size, header.width, header.height, header.planes,
 
793
     header.bpp));
 
794
 
 
795
  /* Reduce colors in copy of image */
 
796
  ico_image_get_reduced_buf (layer, header.bpp, &num_colors_used,
 
797
                             &palette, &buffer);
 
798
  buffer32 = (guint32 *) buffer;
 
799
 
 
800
  /* Set up colormap and and_map when necessary: */
 
801
  if (header.bpp <= 8)
 
802
    {
 
803
      /* Create a colormap */
 
804
      palette32 = ico_create_palette (palette,
 
805
                                      num_colors, num_colors_used,
 
806
                                      &black_index);
 
807
      palette_len = num_colors * 4;
 
808
 
 
809
      color_to_slot = ico_create_color_to_palette_map (palette32,
 
810
                                                       num_colors_used);
 
811
      D(("  created %i-slot colormap with %i colors, black at slot %i\n",
 
812
         num_colors, num_colors_used, black_index));
 
813
    }
 
814
 
 
815
  /* Create and_map. It's padded out to 32 bits per line: */
 
816
  and_map = ico_alloc_map (width, height, 1, &and_len);
 
817
 
 
818
  for (y = 0; y < height; y++)
 
819
    for (x = 0; x < width; x++)
 
820
      {
 
821
        pixel = (guint8 *) &buffer32[y * width + x];
 
822
 
 
823
        ico_set_bit_in_data (and_map, width,
 
824
                             (height - y -1) * width + x,
 
825
                             (pixel[3] > ICO_ALPHA_THRESHOLD ? 0 : 1));
 
826
      }
 
827
 
 
828
  xor_map = ico_alloc_map (width, height, header.bpp, &xor_len);
 
829
 
 
830
  /* Now fill in the xor map */
 
831
  switch (header.bpp)
 
832
    {
 
833
    case 1:
 
834
      for (y = 0; y < height; y++)
 
835
        for (x = 0; x < width; x++)
 
836
          {
 
837
            pixel = (guint8 *) &buffer32[y * width + x];
 
838
            palette_index = ico_get_palette_index (color_to_slot, pixel[0],
 
839
                                                   pixel[1], pixel[2]);
 
840
 
 
841
            if (ico_get_bit_from_data (and_map, width,
 
842
                                       (height - y - 1) * width + x))
 
843
              {
 
844
                ico_set_bit_in_data (xor_map, width,
 
845
                                     (height - y -1) * width + x,
 
846
                                     black_index);
 
847
              }
 
848
            else
 
849
              {
 
850
                ico_set_bit_in_data (xor_map, width,
 
851
                                     (height - y -1) * width + x,
 
852
                                     palette_index);
 
853
              }
 
854
          }
 
855
      break;
 
856
 
 
857
    case 4:
 
858
      for (y = 0; y < height; y++)
 
859
        for (x = 0; x < width; x++)
 
860
          {
 
861
            pixel = (guint8 *) &buffer32[y * width + x];
 
862
            palette_index = ico_get_palette_index(color_to_slot, pixel[0],
 
863
                                                  pixel[1], pixel[2]);
 
864
 
 
865
            if (ico_get_bit_from_data (and_map, width,
 
866
                                       (height - y - 1) * width + x))
 
867
              {
 
868
                ico_set_nibble_in_data (xor_map, width,
 
869
                                        (height - y -1) * width + x,
 
870
                                        black_index);
 
871
              }
 
872
            else
 
873
              {
 
874
                ico_set_nibble_in_data (xor_map, width,
 
875
                                        (height - y - 1) * width + x,
 
876
                                        palette_index);
 
877
              }
 
878
          }
 
879
      break;
 
880
 
 
881
    case 8:
 
882
      for (y = 0; y < height; y++)
 
883
        for (x = 0; x < width; x++)
 
884
          {
 
885
            pixel = (guint8 *) &buffer32[y * width + x];
 
886
            palette_index = ico_get_palette_index (color_to_slot,
 
887
                                                   pixel[0],
 
888
                                                   pixel[1],
 
889
                                                   pixel[2]);
 
890
 
 
891
            if (ico_get_bit_from_data (and_map, width,
 
892
                                       (height - y - 1) * width + x))
 
893
              {
 
894
                ico_set_byte_in_data (xor_map, width,
 
895
                                      (height - y - 1) * width + x,
 
896
                                      black_index);
 
897
              }
 
898
            else
 
899
              {
 
900
                ico_set_byte_in_data (xor_map, width,
 
901
                                      (height - y - 1) * width + x,
 
902
                                      palette_index);
 
903
              }
 
904
 
 
905
          }
 
906
      break;
 
907
 
 
908
    case 24:
 
909
      for (y = 0; y < height; y++)
 
910
        {
 
911
          guchar *row = xor_map + (xor_len * (height - y - 1) / height);
 
912
 
 
913
          for (x = 0; x < width; x++)
 
914
            {
 
915
              pixel = (guint8 *) &buffer32[y * width + x];
 
916
 
 
917
              row[0] = pixel[2];
 
918
              row[1] = pixel[1];
 
919
              row[2] = pixel[0];
 
920
 
 
921
              row += 3;
 
922
            }
 
923
        }
 
924
      break;
 
925
 
 
926
    default:
 
927
      for (y = 0; y < height; y++)
 
928
        for (x = 0; x < width; x++)
 
929
          {
 
930
            pixel = (guint8 *) &buffer32[y * width + x];
 
931
 
 
932
            ((guint32 *) xor_map)[(height - y -1) * width + x] =
 
933
              GUINT32_TO_LE ((pixel[0] << 16) |
 
934
                             (pixel[1] << 8)  |
 
935
                             (pixel[2])       |
 
936
                             (pixel[3] << 24));
 
937
          }
 
938
    }
 
939
 
 
940
  D(("  filled and_map of length %i, xor_map of length %i\n",
 
941
     and_len, xor_len));
 
942
 
 
943
  if (color_to_slot)
 
944
    g_hash_table_destroy (color_to_slot);
 
945
 
 
946
  g_free (palette);
 
947
  g_free (buffer);
 
948
 
 
949
  ico_write_int32 (fp, (guint32*) &header, 3);
 
950
  ico_write_int16 (fp, &header.planes, 2);
 
951
  ico_write_int32 (fp, &header.compression, 6);
 
952
 
 
953
  if (palette_len)
 
954
    ico_write_int8 (fp, (guint8 *) palette32, palette_len);
 
955
 
 
956
  ico_write_int8 (fp, xor_map, xor_len);
 
957
  ico_write_int8 (fp, and_map, and_len);
 
958
 
 
959
  g_free (palette32);
 
960
  g_free (xor_map);
 
961
  g_free (and_map);
 
962
 
 
963
  return TRUE;
 
964
}
 
965
 
 
966
static void
 
967
ico_save_info_free (IcoSaveInfo  *info)
 
968
{
 
969
  g_free (info->depths);
 
970
  g_free (info->default_depths);
 
971
  g_free (info->compress);
 
972
  g_free (info->layers);
 
973
  memset (info, 0, sizeof (IcoSaveInfo));
 
974
}
 
975
 
 
976
GimpPDBStatusType
 
977
ico_save_image (const gchar  *filename,
 
978
                gint32        image,
 
979
                gint32        run_mode,
 
980
                GError      **error)
 
981
{
 
982
  FILE *fp;
 
983
 
 
984
  gint i;
 
985
  gint width, height;
 
986
  IcoSaveInfo      info;
 
987
  IcoFileHeader    header;
 
988
  IcoFileEntry    *entries;
 
989
  gboolean          saved;
 
990
 
 
991
  D(("*** Saving Microsoft icon file %s\n", filename));
 
992
 
 
993
  ico_save_init (image, &info);
 
994
 
 
995
  if (run_mode == GIMP_RUN_INTERACTIVE)
 
996
    {
 
997
      /* Allow user to override default values */
 
998
      if ( !ico_save_dialog (image, &info))
 
999
        return GIMP_PDB_CANCEL;
 
1000
    }
 
1001
 
 
1002
  gimp_progress_init_printf (_("Saving '%s'"),
 
1003
                             gimp_filename_to_utf8 (filename));
 
1004
 
 
1005
  if (! (fp = g_fopen (filename, "wb")))
 
1006
    {
 
1007
      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
 
1008
                   _("Could not open '%s' for writing: %s"),
 
1009
                   gimp_filename_to_utf8 (filename), g_strerror (errno));
 
1010
      return GIMP_PDB_EXECUTION_ERROR;
 
1011
    }
 
1012
 
 
1013
  header.reserved = 0;
 
1014
  header.resource_type = 1;
 
1015
  header.icon_count = info.num_icons;
 
1016
  if ( !ico_write_int16 (fp, &header.reserved, 1)
 
1017
       || !ico_write_int16 (fp, &header.resource_type, 1)
 
1018
       || !ico_write_int16 (fp, &header.icon_count, 1) )
 
1019
    {
 
1020
      ico_save_info_free (&info);
 
1021
      fclose (fp);
 
1022
      return GIMP_PDB_EXECUTION_ERROR;
 
1023
    }
 
1024
 
 
1025
  entries = g_new0 (IcoFileEntry, info.num_icons);
 
1026
  if (fwrite (entries, sizeof (IcoFileEntry), info.num_icons, fp) <= 0)
 
1027
    {
 
1028
      ico_save_info_free (&info);
 
1029
      fclose (fp);
 
1030
      return GIMP_PDB_EXECUTION_ERROR;
 
1031
    }
 
1032
 
 
1033
  for (i = 0; i < info.num_icons; i++)
 
1034
    {
 
1035
      gimp_progress_update ((gdouble)i / (gdouble)info.num_icons);
 
1036
 
 
1037
      width = gimp_drawable_width (info.layers[i]);
 
1038
      height = gimp_drawable_height (info.layers[i]);
 
1039
      if (width <= 255 && height <= 255)
 
1040
        {
 
1041
          entries[i].width = width;
 
1042
          entries[i].height = height;
 
1043
        }
 
1044
      else
 
1045
        {
 
1046
          entries[i].width = 0;
 
1047
          entries[i].height = 0;
 
1048
        }
 
1049
      if ( info.depths[i] <= 8 )
 
1050
        entries[i].num_colors = 1 << info.depths[i];
 
1051
      else
 
1052
        entries[i].num_colors = 0;
 
1053
      entries[i].reserved = 0;
 
1054
      entries[i].planes = 1;
 
1055
      entries[i].bpp = info.depths[i];
 
1056
      entries[i].offset = ftell (fp);
 
1057
 
 
1058
      if (info.compress[i])
 
1059
        saved = ico_write_png (fp, info.layers[i], info.depths[i]);
 
1060
      else
 
1061
        saved = ico_write_icon (fp, info.layers[i], info.depths[i]);
 
1062
 
 
1063
      if (!saved)
 
1064
        {
 
1065
          ico_save_info_free (&info);
 
1066
          fclose (fp);
 
1067
          return GIMP_PDB_EXECUTION_ERROR;
 
1068
        }
 
1069
 
 
1070
      entries[i].size = ftell (fp) - entries[i].offset;
 
1071
    }
 
1072
 
 
1073
  for (i = 0; i < info.num_icons; i++)
 
1074
    {
 
1075
      entries[i].planes = GUINT16_TO_LE (entries[i].planes);
 
1076
      entries[i].bpp    = GUINT16_TO_LE (entries[i].bpp);
 
1077
      entries[i].size   = GUINT32_TO_LE (entries[i].size);
 
1078
      entries[i].offset = GUINT32_TO_LE (entries[i].offset);
 
1079
    }
 
1080
 
 
1081
  if (fseek (fp, sizeof(IcoFileHeader), SEEK_SET) < 0
 
1082
      || fwrite (entries, sizeof (IcoFileEntry), info.num_icons, fp) <= 0)
 
1083
    {
 
1084
      ico_save_info_free (&info);
 
1085
      fclose (fp);
 
1086
      return GIMP_PDB_EXECUTION_ERROR;
 
1087
    }
 
1088
 
 
1089
  gimp_progress_update (1.0);
 
1090
 
 
1091
  ico_save_info_free (&info);
 
1092
  fclose (fp);
 
1093
 
 
1094
  return GIMP_PDB_SUCCESS;
 
1095
}