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

« back to all changes in this revision

Viewing changes to plug-ins/winicon/icosave.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* The GIMP -- an image manipulation program
 
1
/* GIMP - The GNU Image Manipulation Program
2
2
 * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
3
3
 *
4
4
 * GIMP Plug-in for Windows Icon files.
22
22
#include "config.h"
23
23
 
24
24
#include <errno.h>
25
 
#include <stdio.h>
26
25
#include <string.h>
27
26
 
 
27
#include <glib/gstdio.h>
 
28
 
28
29
#include <libgimp/gimp.h>
29
30
#include <libgimp/gimpui.h>
30
31
 
 
32
#include <png.h>
 
33
 
31
34
/* #define ICO_DBG */
32
35
 
33
36
#include "main.h"
34
37
#include "icoload.h"
 
38
#include "icosave.h"
35
39
#include "icodialog.h"
36
40
 
37
41
#include "libgimp/stdplugins-intl.h"
38
42
 
39
43
 
40
 
static gint     ico_write_int8         (FILE *fp, guint8 *data, gint count);
41
 
static gint     ico_write_int16        (FILE *fp, guint16 *data, gint count);
42
 
static gint     ico_write_int32        (FILE *fp, guint32 *data, gint count);
43
 
 
44
 
static gint *   ico_show_icon_dialog   (gint32 image_ID, gint *num_icons);
 
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);
45
53
 
46
54
/* Helpers to set bits in a *cleared* data chunk */
47
 
static void     ico_set_bit_in_data    (guint8 *data, gint line_width,
48
 
                                        gint bit_num, gint bit_val);
49
 
static void     ico_set_nibble_in_data (guint8 *data, gint line_width,
50
 
                                        gint nibble_num, gint nibble_val);
51
 
static void     ico_set_byte_in_data   (guint8 *data, gint line_width,
52
 
                                        gint byte_num, gint byte_val);
 
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);
53
67
 
54
68
static gint     ico_get_layer_num_colors  (gint32    layer,
55
 
                                           gboolean *uses_alpha_levels);
 
69
                                           gboolean *uses_alpha_levels);
56
70
static void     ico_image_get_reduced_buf (guint32   layer,
57
 
                                           gint      bpp,
58
 
                                           gint     *num_colors,
59
 
                                           guchar  **cmap_out,
60
 
                                           guchar  **buf_out);
 
71
                                           gint      bpp,
 
72
                                           gint     *num_colors,
 
73
                                           guchar  **cmap_out,
 
74
                                           guchar  **buf_out);
61
75
 
62
76
 
63
77
static gint
142
156
}
143
157
 
144
158
 
145
 
static gint*
146
 
ico_show_icon_dialog (gint32  image_ID,
147
 
                      gint   *num_icons)
 
159
static void
 
160
ico_save_init (gint32 image_ID, IcoSaveInfo *info)
148
161
{
149
 
  GtkWidget *dialog, *hbox;
150
 
  GtkWidget *icon_menu;
151
 
  gint      *layers, *icon_depths = NULL;
152
 
  gint       num_layers, i, num_colors;
 
162
  gint      *layers;
 
163
  gint       i, num_colors;
153
164
  gboolean   uses_alpha_values;
154
 
  gchar      key[MAXLEN];
155
 
 
156
 
  *num_icons = 0;
157
 
 
158
 
  gimp_ui_init ("winicon", TRUE);
159
 
 
160
 
  layers = gimp_image_get_layers (image_ID, &num_layers);
161
 
  dialog = ico_specs_dialog_new (num_layers);
162
 
 
163
 
  for (i = 0; i < num_layers; i++)
164
 
    {
165
 
      /* if (gimp_layer_get_visible(layers[i])) */
166
 
      ico_specs_dialog_add_icon (dialog, layers[i], i);
167
 
    }
168
 
 
169
 
  /* Scale the thing to approximately fit its content, but not too large ... */
170
 
  gtk_window_set_default_size (GTK_WINDOW (dialog),
171
 
                               500,
172
 
                               120 + (num_layers > 4 ? 400 : num_layers * 100));
173
 
 
174
 
  icon_depths = g_object_get_data (G_OBJECT (dialog), "icon_depths");
 
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);
175
171
 
176
172
  /* Limit the color depths to values that don't cause any color loss --
177
173
     the user should pick these anyway, so we can save her some time.
178
174
     If the user wants to lose some colors, the settings can always be changed
179
175
     in the dialog: */
180
 
  for (i = 0; i < num_layers; i++)
 
176
  for (i = 0; i < info->num_icons; i++)
181
177
    {
182
178
      num_colors = ico_get_layer_num_colors (layers[i], &uses_alpha_values);
183
179
 
184
 
      g_snprintf (key, MAXLEN, "layer_%i_hbox", layers[i]);
185
 
      hbox = g_object_get_data (G_OBJECT (dialog), key);
186
 
      icon_menu = g_object_get_data (G_OBJECT (hbox), "icon_menu");
187
 
 
188
180
      if (!uses_alpha_values)
189
181
        {
190
182
          if (num_colors <= 2)
191
183
            {
192
184
              /* Let's suggest monochrome */
193
 
              icon_depths[i] = 1;
194
 
              icon_depths[num_layers + i] = 1;
195
 
              ico_specs_dialog_update_icon_preview (dialog, layers[i], 2);
196
 
              gtk_combo_box_set_active (GTK_COMBO_BOX (icon_menu), 0);
 
185
              info->default_depths [i] = 1;
197
186
            }
198
187
          else if (num_colors <= 16)
199
188
            {
200
189
              /* Let's suggest 4bpp */
201
 
              icon_depths[i] = 4;
202
 
              icon_depths[num_layers + i] = 4;
203
 
              ico_specs_dialog_update_icon_preview (dialog, layers[i], 4);
204
 
              gtk_combo_box_set_active (GTK_COMBO_BOX (icon_menu), 1);
 
190
              info->default_depths [i] = 4;
205
191
            }
206
192
          else if (num_colors <= 256)
207
193
            {
208
194
              /* Let's suggest 8bpp */
209
 
              icon_depths[i] = 8;
210
 
              icon_depths[num_layers + i] = 8;
211
 
              ico_specs_dialog_update_icon_preview (dialog, layers[i], 8);
212
 
              gtk_combo_box_set_active (GTK_COMBO_BOX (icon_menu), 2);
213
 
            }
214
 
        }
215
 
 
216
 
      /* Otherwise, or if real alpha levels are used, stick with 32bpp */
217
 
    }
218
 
 
219
 
  g_free (layers);
 
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 ("winicon", 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
                               120 + (info->num_icons > 4 ?
 
249
                                      500 : info->num_icons * 120));
220
250
 
221
251
  gtk_widget_show (dialog);
222
 
 
223
 
  if (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK)
224
 
    *num_icons = num_layers;
225
 
  else
226
 
    icon_depths = NULL;
227
 
 
 
252
  response = gimp_dialog_run (GIMP_DIALOG (dialog));
228
253
  gtk_widget_destroy (dialog);
229
 
 
230
 
  return icon_depths;
231
 
}
232
 
 
233
 
 
234
 
static GimpPDBStatusType
235
 
ico_init (const gchar *filename,
236
 
          MsIcon      *ico,
237
 
          gint         num_icons)
238
 
{
239
 
  memset (ico, 0, sizeof(MsIcon));
240
 
 
241
 
  if (! (ico->fp = fopen (filename, "wb")))
242
 
    {
243
 
      g_message (_("Could not open '%s' for writing: %s"),
244
 
                 gimp_filename_to_utf8 (filename), g_strerror (errno));
245
 
      return GIMP_PDB_EXECUTION_ERROR;
246
 
    }
247
 
 
248
 
  ico->filename      = filename;
249
 
  ico->reserved      = 0;
250
 
  ico->resource_type = 1;
251
 
  ico->icon_count    = num_icons;
252
 
  ico->icon_dir      = g_new0 (MsIconEntry, num_icons);
253
 
  ico->icon_data     = g_new0 (MsIconData, num_icons);
254
 
 
255
 
  return GIMP_PDB_SUCCESS;
256
 
}
257
 
 
258
 
 
259
 
static void
260
 
ico_init_direntry (MsIconEntry *entry,
261
 
                   gint32       layer,
262
 
                   gint         bpp)
263
 
{
264
 
  /* Was calloc'd, so initialized to 0. */
265
 
  entry->width  = gimp_drawable_width (layer);
266
 
  entry->height = gimp_drawable_height (layer);
267
 
 
268
 
  if (bpp < 8)
269
 
    entry->num_colors = (1 << bpp);
270
 
 
271
 
  entry->num_planes = 1;
272
 
  entry->bpp        = bpp;
273
 
 
274
 
  D(("Initialized entry to w %i, h %i, bpp %i\n",
275
 
     gimp_drawable_width (layer), entry->width, entry->bpp));
276
 
 
277
 
  /* We'll set size and offset when writing things out */
278
 
}
279
 
 
 
254
  if (response == GTK_RESPONSE_OK)
 
255
    return TRUE;
 
256
  else
 
257
    return FALSE;
 
258
}
280
259
 
281
260
static void
282
261
ico_set_bit_in_data (guint8 *data,
316
295
  offset = nibble_num % line_width;
317
296
  nibble_val = nibble_val & 0x0000000F;
318
297
 
319
 
  data[line * width8 * 4 + offset/2] |= (nibble_val << (4 * (1 - (offset % 2))));
 
298
  data[line * width8 * 4 + offset/2] |=
 
299
    (nibble_val << (4 * (1 - (offset % 2))));
320
300
}
321
301
 
322
302
 
342
322
}
343
323
 
344
324
 
345
 
 
346
325
/* Create a colormap from the given buffer data */
347
326
static guint32 *
348
327
ico_create_palette(guchar *cmap,
454
433
  return *slot;
455
434
}
456
435
 
457
 
static void
458
 
ico_init_data (MsIcon *ico,
459
 
               gint    num_icon,
460
 
               gint32  layer,
461
 
               gint    bpp)
462
 
{
463
 
  MsIconEntry    *entry;
464
 
  MsIconData     *data;
465
 
  gint            and_len, xor_len, palette_index, x, y;
466
 
  gint            num_colors = 0, num_colors_used = 0, black_index;
467
 
  guchar         *buffer = NULL, *pixel;
468
 
  guint32        *buffer32;
469
 
  guchar         *palette;
470
 
  GHashTable     *color_to_slot = NULL;
471
 
 
472
 
  D(("Creating data structures for icon %i ------------------------\n", num_icon));
473
 
 
474
 
  /* Shortcuts, for convenience */
475
 
  entry = &ico->icon_dir[num_icon];
476
 
  data  = &ico->icon_data[num_icon];
477
 
 
478
 
  /* Entries and data were calloc'd, so initialized to 0. */
479
 
 
480
 
  data->header_size = 40;
481
 
  data->width       = gimp_drawable_width (layer);
482
 
  data->height      = 2 * gimp_drawable_height (layer);
483
 
  data->planes      = 1;
484
 
  data->bpp         = bpp;
485
 
 
486
 
  num_colors = (1L << bpp);
487
 
 
488
 
  D(("  header size %i, w %i, h %i, planes %i, bpp %i\n",
489
 
     data->header_size, data->width, data->height, data->planes, data->bpp));
490
 
 
491
 
  /* Reduce colors in copy of image */
492
 
  ico_image_get_reduced_buf (layer, bpp, &num_colors_used, &palette, &buffer);
493
 
  buffer32 = (guint32 *) buffer;
494
 
 
495
 
  /* Set up colormap and andmap when necessary: */
496
 
  if (bpp <= 8)
497
 
    {
498
 
      /* Create a colormap */
499
 
      data->palette = ico_create_palette (palette,
500
 
                                          num_colors, num_colors_used,
501
 
                                          &black_index);
502
 
      data->palette_len = num_colors * 4;
503
 
 
504
 
      color_to_slot = ico_create_color_to_palette_map (data->palette,
505
 
                                                       num_colors_used);
506
 
      D(("  created %i-slot colormap with %i colors, black at slot %i\n",
507
 
         num_colors, num_colors_used, black_index));
508
 
    }
509
 
 
510
 
  /* Create and_map. It's padded out to 32 bits per line: */
511
 
  data->and_map = ico_alloc_map (entry->width, entry->height, 1, &and_len);
512
 
  data->and_len = and_len;
513
 
 
514
 
  for (y = 0; y < entry->height; y++)
515
 
    for (x = 0; x < entry->width; x++)
516
 
      {
517
 
        pixel = (guint8 *) &buffer32[y * entry->width + x];
518
 
 
519
 
        ico_set_bit_in_data (data->and_map, entry->width,
520
 
                             (entry->height-y-1) * entry->width + x,
521
 
                             (pixel[3] == 255 ? 0 : 1));
522
 
      }
523
 
 
524
 
  data->xor_map = ico_alloc_map(entry->width, entry->height, bpp, &xor_len);
525
 
  data->xor_len = xor_len;
526
 
 
527
 
  /* Now fill in the xor map */
528
 
  switch (bpp)
529
 
    {
530
 
    case 1:
531
 
      for (y = 0; y < entry->height; y++)
532
 
        for (x = 0; x < entry->width; x++)
533
 
          {
534
 
            pixel = (guint8 *) &buffer32[y * entry->width + x];
535
 
            palette_index = ico_get_palette_index (color_to_slot,
536
 
                                                   pixel[0], pixel[1], pixel[2]);
537
 
 
538
 
            if (ico_get_bit_from_data (data->and_map, entry->width,
539
 
                                       (entry->height-y-1) * entry->width + x))
540
 
              {
541
 
                ico_set_bit_in_data (data->xor_map, entry->width,
542
 
                                     (entry->height-y-1) * entry->width + x,
543
 
                                     black_index);
544
 
              }
545
 
            else
546
 
              {
547
 
                ico_set_bit_in_data (data->xor_map, entry->width,
548
 
                                     (entry->height-y-1) * entry->width + x,
549
 
                                     palette_index);
550
 
              }
551
 
          }
552
 
      break;
553
 
 
554
 
    case 4:
555
 
      for (y = 0; y < entry->height; y++)
556
 
        for (x = 0; x < entry->width; x++)
557
 
          {
558
 
            pixel = (guint8 *) &buffer32[y * entry->width + x];
559
 
            palette_index = ico_get_palette_index(color_to_slot,
560
 
                                                  pixel[0], pixel[1], pixel[2]);
561
 
 
562
 
            if (ico_get_bit_from_data (data->and_map, entry->width,
563
 
                                       (entry->height-y-1) * entry->width + x))
564
 
              {
565
 
                ico_set_nibble_in_data (data->xor_map, entry->width,
566
 
                                        (entry->height-y-1) * entry->width + x,
567
 
                                        black_index);
568
 
              }
569
 
            else
570
 
              {
571
 
                ico_set_nibble_in_data (data->xor_map, entry->width,
572
 
                                        (entry->height-y-1) * entry->width + x,
573
 
                                        palette_index);
574
 
              }
575
 
          }
576
 
      break;
577
 
 
578
 
    case 8:
579
 
      for (y = 0; y < entry->height; y++)
580
 
        for (x = 0; x < entry->width; x++)
581
 
          {
582
 
            pixel = (guint8 *) &buffer32[y * entry->width + x];
583
 
            palette_index = ico_get_palette_index (color_to_slot,
584
 
                                                   pixel[0],
585
 
                                                   pixel[1],
586
 
                                                   pixel[2]);
587
 
 
588
 
            if (ico_get_bit_from_data (data->and_map, entry->width,
589
 
                                       (entry->height-y-1) * entry->width + x))
590
 
              {
591
 
                ico_set_byte_in_data (data->xor_map, entry->width,
592
 
                                      (entry->height-y-1) * entry->width + x,
593
 
                                      black_index);
594
 
              }
595
 
            else
596
 
              {
597
 
                ico_set_byte_in_data (data->xor_map, entry->width,
598
 
                                      (entry->height-y-1) * entry->width + x,
599
 
                                      palette_index);
600
 
              }
601
 
 
602
 
          }
603
 
      break;
604
 
 
605
 
    default:
606
 
      for (y = 0; y < entry->height; y++)
607
 
        for (x = 0; x < entry->width; x++)
608
 
          {
609
 
            pixel = (guint8 *) &buffer32[y * entry->width + x];
610
 
 
611
 
            ((guint32 *) data->xor_map)[(entry->height-y-1) * entry->width + x] =
612
 
              GUINT32_TO_LE ((pixel[0] << 16) |
613
 
                             (pixel[1] << 8)  |
614
 
                             (pixel[2])       |
615
 
                             (pixel[3] << 24));
616
 
          }
617
 
    }
618
 
 
619
 
  D(("  filled and_map of length %i, xor_map of length %i\n",
620
 
     data->and_len, data->xor_len));
621
 
 
622
 
  if (color_to_slot)
623
 
    {
624
 
      g_hash_table_foreach (color_to_slot, ico_free_hash_item, NULL);
625
 
      g_hash_table_destroy (color_to_slot);
626
 
    }
627
 
 
628
 
  g_free(palette);
629
 
  g_free(buffer);
630
 
}
631
 
 
632
 
 
633
 
static void
634
 
ico_setup (MsIcon *ico,
635
 
           gint32  image,
636
 
           gint   *icon_depths,
637
 
           gint    num_icons)
638
 
{
639
 
  gint *layers;
640
 
  gint  i;
641
 
  gint  offset;
642
 
 
643
 
  layers = gimp_image_get_layers (image, &num_icons);
644
 
 
645
 
  /* Set up icon entries */
646
 
  for (i = 0; i < num_icons; i++)
647
 
    {
648
 
      ico_init_direntry (&ico->icon_dir[i], layers[i], icon_depths[i]);
649
 
      gimp_progress_update ((gdouble) i / (gdouble) num_icons * 0.3);
650
 
    }
651
 
 
652
 
  /* Set up data entries (the actual icons), and calculate each one's size */
653
 
  for (i = 0; i < num_icons; i++)
654
 
    {
655
 
      ico_init_data (ico, i, layers[i], icon_depths[i]);
656
 
 
657
 
      ico->icon_dir[i].size =
658
 
        ico->icon_data[i].header_size +
659
 
        ico->icon_data[i].palette_len +
660
 
        ico->icon_data[i].xor_len +
661
 
        ico->icon_data[i].and_len;
662
 
 
663
 
      gimp_progress_update (0.3 + (gdouble) i / (gdouble) num_icons * 0.3);
664
 
    }
665
 
 
666
 
  /* Finally, calculate offsets for each icon and store them in each entry */
667
 
  offset = 3 * sizeof (guint16) + ico->icon_count * sizeof (MsIconEntry);
668
 
 
669
 
  for (i = 0; i < num_icons; i++)
670
 
    {
671
 
      ico->icon_dir[i].offset = offset;
672
 
      offset += ico->icon_dir[i].size;
673
 
 
674
 
      gimp_progress_update (0.6 + (gdouble) i / (gdouble) num_icons * 0.3);
675
 
    }
676
 
 
677
 
  gimp_progress_update (1.0);
678
 
 
679
 
  g_free (layers);
680
 
}
681
 
 
682
 
 
683
 
static GimpPDBStatusType
684
 
ico_save (MsIcon *ico)
685
 
{
686
 
  MsIconEntry *entry;
687
 
  MsIconData *data;
688
 
  int i;
689
 
 
690
 
  ico->cp += ico_write_int16 (ico->fp, &ico->reserved, 3);
691
 
 
692
 
  for (i = 0; i < ico->icon_count; i++)
693
 
    {
694
 
      entry = &ico->icon_dir[i];
695
 
 
696
 
      ico->cp += ico_write_int8 (ico->fp, (guint8 *) entry, 4);
697
 
      ico->cp += ico_write_int16 (ico->fp, &entry->num_planes, 2);
698
 
      ico->cp += ico_write_int32 (ico->fp, &entry->size, 2);
699
 
    }
700
 
 
701
 
  for (i = 0; i < ico->icon_count; i++)
702
 
    {
703
 
      data  = &ico->icon_data[i];
704
 
 
705
 
      ico->cp += ico_write_int32 (ico->fp, (guint32 *) data, 3);
706
 
      ico->cp += ico_write_int16 (ico->fp, &data->planes, 2);
707
 
      ico->cp += ico_write_int32 (ico->fp, &data->compression, 6);
708
 
 
709
 
      if (data->palette)
710
 
        ico->cp += ico_write_int8 (ico->fp,
711
 
                                   (guint8 *) data->palette, data->palette_len);
712
 
 
713
 
      ico->cp += ico_write_int8 (ico->fp, data->xor_map, data->xor_len);
714
 
      ico->cp += ico_write_int8 (ico->fp, data->and_map, data->and_len);
715
 
    }
716
 
 
717
 
  return GIMP_PDB_SUCCESS;
718
 
}
719
 
 
720
 
static gboolean
721
 
ico_layers_too_big (gint32 image)
722
 
{
723
 
  gint *layers;
724
 
  gint  i, num_layers;
725
 
 
726
 
  layers = gimp_image_get_layers (image, &num_layers);
727
 
 
728
 
  for (i = 0; i < num_layers; i++)
729
 
    {
730
 
      if ((gimp_drawable_width (layers[i])  > 255) ||
731
 
          (gimp_drawable_height (layers[i]) > 255))
732
 
        {
733
 
          g_free (layers);
734
 
          return TRUE;
735
 
        }
736
 
    }
737
 
 
738
 
  g_free (layers);
739
 
  return FALSE;
740
 
}
741
 
 
742
436
static gint
743
437
ico_get_layer_num_colors (gint32    layer,
744
438
                          gboolean *uses_alpha_levels)
831
525
  return num_colors;
832
526
}
833
527
 
834
 
static gboolean
 
528
gboolean
835
529
ico_cmap_contains_black (guchar *cmap,
836
530
                         gint    num_colors)
837
531
{
862
556
  gint32          tmp_layer;
863
557
  gint            w, h;
864
558
  guchar         *buffer;
865
 
  guchar         *cmap;
 
559
  guchar         *cmap = NULL;
866
560
  GimpDrawable   *drawable = gimp_drawable_get (layer);
867
561
 
868
562
  w = gimp_drawable_width (layer);
869
563
  h = gimp_drawable_height (layer);
870
 
  *cmap_out = NULL;
 
564
 
871
565
  *num_colors = 0;
872
566
 
873
567
  buffer = g_new (guchar, w * h * 4);
874
568
 
875
 
  if (bpp <= 8 || drawable->bpp != 4)
 
569
  if (bpp <= 8 || bpp == 24 || drawable->bpp != 4)
876
570
    {
877
571
      gint32        image = gimp_drawable_get_image (layer);
878
572
      GimpDrawable *tmp;
923
617
               * We need to eliminate one more color to make room for black.
924
618
               */
925
619
 
926
 
              gimp_image_convert_rgb (tmp_image);
 
620
              if (gimp_drawable_is_indexed (layer))
 
621
                {
 
622
                  g_free (cmap);
 
623
                  cmap = gimp_image_get_colormap (image, num_colors);
 
624
                  gimp_image_set_colormap (tmp_image, cmap, *num_colors);
 
625
                }
 
626
              else if (gimp_drawable_is_gray (layer))
 
627
                {
 
628
                  gimp_image_convert_grayscale (tmp_image);
 
629
                }
 
630
              else
 
631
                {
 
632
                  gimp_image_convert_rgb (tmp_image);
 
633
                }
927
634
 
928
635
              tmp = gimp_drawable_get (tmp_layer);
929
636
              gimp_pixel_rgn_init (&dst_pixel_rgn,
931
638
              gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h);
932
639
              gimp_drawable_detach (tmp);
933
640
 
 
641
              if (!gimp_drawable_is_rgb (layer))
 
642
                gimp_image_convert_rgb (tmp_image);
 
643
 
934
644
              gimp_image_convert_indexed (tmp_image,
935
645
                                          GIMP_FS_DITHER, GIMP_MAKE_PALETTE,
936
 
                                          (1 << bpp) - 1, TRUE, FALSE, "dummy");
 
646
                                          (1<<bpp) - 1, TRUE, FALSE, "dummy");
937
647
              g_free (cmap);
938
648
              cmap = gimp_image_get_colormap (tmp_image, num_colors);
939
649
            }
940
650
 
941
 
          *cmap_out = g_memdup (cmap, *num_colors * 3);
942
651
          gimp_image_convert_rgb (tmp_image);
943
652
        }
 
653
      else if (bpp == 24)
 
654
        {
 
655
          GimpParam    *return_vals;
 
656
          gint          n_return_vals;
 
657
 
 
658
          return_vals =
 
659
            gimp_run_procedure ("plug-in-threshold-alpha", &n_return_vals,
 
660
                                GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
 
661
                                GIMP_PDB_IMAGE, tmp_image,
 
662
                                GIMP_PDB_DRAWABLE, tmp_layer,
 
663
                                GIMP_PDB_INT32, ICO_ALPHA_THRESHOLD,
 
664
                                GIMP_PDB_END);
 
665
          gimp_destroy_params (return_vals, n_return_vals);
 
666
        }
944
667
 
945
668
      gimp_layer_add_alpha (tmp_layer);
946
669
 
959
682
 
960
683
  gimp_drawable_detach (drawable);
961
684
 
 
685
  *cmap_out = cmap;
962
686
  *buf_out = buffer;
963
687
}
964
688
 
 
689
static gboolean
 
690
ico_write_png (FILE   *fp,
 
691
               gint32  layer,
 
692
               gint32  depth)
 
693
{
 
694
  png_structp png_ptr;
 
695
  png_infop   info_ptr;
 
696
  png_byte  **row_pointers;
 
697
  gint        i, rowstride;
 
698
  gint        width, height;
 
699
  gint        num_colors_used;
 
700
  guchar     *palette;
 
701
  guchar     *buffer;
 
702
 
 
703
  row_pointers = NULL;
 
704
  palette = NULL;
 
705
  buffer = NULL;
 
706
 
 
707
  width = gimp_drawable_width (layer);
 
708
  height = gimp_drawable_height (layer);
 
709
 
 
710
  png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
 
711
  if ( !png_ptr )
 
712
    return FALSE;
 
713
 
 
714
  info_ptr = png_create_info_struct (png_ptr);
 
715
  if ( !info_ptr )
 
716
    {
 
717
      png_destroy_write_struct (&png_ptr, NULL);
 
718
      return FALSE;
 
719
    }
 
720
 
 
721
  if (setjmp (png_jmpbuf (png_ptr)))
 
722
    {
 
723
      png_destroy_write_struct (&png_ptr, &info_ptr);
 
724
      if ( row_pointers )
 
725
        g_free (row_pointers);
 
726
      if (palette)
 
727
        g_free (palette);
 
728
      if (buffer)
 
729
        g_free (buffer);
 
730
      return FALSE;
 
731
    }
 
732
 
 
733
  ico_image_get_reduced_buf (layer, depth, &num_colors_used,
 
734
                             &palette, &buffer);
 
735
 
 
736
  png_init_io (png_ptr, fp);
 
737
  png_set_IHDR (png_ptr, info_ptr, width, height,
 
738
                8,
 
739
                PNG_COLOR_TYPE_RGBA,
 
740
                PNG_INTERLACE_NONE,
 
741
                PNG_COMPRESSION_TYPE_DEFAULT,
 
742
                PNG_FILTER_TYPE_DEFAULT);
 
743
  png_write_info (png_ptr, info_ptr);
 
744
 
 
745
  rowstride = ico_rowstride (width, 32);
 
746
  row_pointers = g_new (png_byte*, height);
 
747
  for (i = 0; i < height; i++)
 
748
    {
 
749
      row_pointers[i] = buffer + rowstride * i;
 
750
    }
 
751
  png_write_image (png_ptr, row_pointers);
 
752
 
 
753
  row_pointers = NULL;
 
754
 
 
755
  png_write_end (png_ptr, info_ptr);
 
756
  png_destroy_write_struct (&png_ptr, &info_ptr);
 
757
 
 
758
  g_free (row_pointers);
 
759
  g_free (palette);
 
760
  g_free (buffer);
 
761
  return TRUE;
 
762
}
 
763
 
 
764
static gboolean
 
765
ico_write_icon (FILE   *fp,
 
766
                gint32  layer,
 
767
                gint32  depth)
 
768
{
 
769
  IcoFileDataHeader  header;
 
770
  gint               and_len, xor_len, palette_index, x, y;
 
771
  gint               num_colors = 0, num_colors_used = 0, black_index = 0;
 
772
  gint               width, height;
 
773
  guchar            *buffer = NULL, *pixel;
 
774
  guint32           *buffer32;
 
775
  guchar            *palette;
 
776
  GHashTable        *color_to_slot = NULL;
 
777
  guchar            *xor_map, *and_map;
 
778
 
 
779
  guint32           *palette32 = NULL;
 
780
  gint               palette_len = 0;
 
781
 
 
782
  D(("Creating data structures for icon %i ------------------------\n",
 
783
     num_icon));
 
784
 
 
785
  width = gimp_drawable_width (layer);
 
786
  height = gimp_drawable_height (layer);
 
787
 
 
788
  header.header_size     = 40;
 
789
  header.width          = width;
 
790
  header.height         = 2 * height;
 
791
  header.planes         = 1;
 
792
  header.bpp            = depth;
 
793
  header.compression    = 0;
 
794
  header.image_size     = 0;
 
795
  header.x_res          = 0;
 
796
  header.y_res          = 0;
 
797
  header.used_clrs      = 0;
 
798
  header.important_clrs = 0;
 
799
 
 
800
  num_colors = (1L << header.bpp);
 
801
 
 
802
  D(("  header size %i, w %i, h %i, planes %i, bpp %i\n",
 
803
     header.header_size, header.width, header.height, header.planes,
 
804
     header.bpp));
 
805
 
 
806
  /* Reduce colors in copy of image */
 
807
  ico_image_get_reduced_buf (layer, header.bpp, &num_colors_used,
 
808
                             &palette, &buffer);
 
809
  buffer32 = (guint32 *) buffer;
 
810
 
 
811
  /* Set up colormap and andmap when necessary: */
 
812
  if (header.bpp <= 8)
 
813
    {
 
814
      /* Create a colormap */
 
815
      palette32 = ico_create_palette (palette,
 
816
                                      num_colors, num_colors_used,
 
817
                                      &black_index);
 
818
      palette_len = num_colors * 4;
 
819
 
 
820
      color_to_slot = ico_create_color_to_palette_map (palette32,
 
821
                                                       num_colors_used);
 
822
      D(("  created %i-slot colormap with %i colors, black at slot %i\n",
 
823
         num_colors, num_colors_used, black_index));
 
824
    }
 
825
 
 
826
  /* Create and_map. It's padded out to 32 bits per line: */
 
827
  and_map = ico_alloc_map (width, height, 1, &and_len);
 
828
 
 
829
  for (y = 0; y < height; y++)
 
830
    for (x = 0; x < width; x++)
 
831
      {
 
832
        pixel = (guint8 *) &buffer32[y * width + x];
 
833
 
 
834
        ico_set_bit_in_data (and_map, width,
 
835
                             (height - y -1) * width + x,
 
836
                             (pixel[3] > ICO_ALPHA_THRESHOLD ? 0 : 1));
 
837
      }
 
838
 
 
839
  xor_map = ico_alloc_map (width, height, header.bpp, &xor_len);
 
840
 
 
841
  /* Now fill in the xor map */
 
842
  switch (header.bpp)
 
843
    {
 
844
    case 1:
 
845
      for (y = 0; y < height; y++)
 
846
        for (x = 0; x < width; x++)
 
847
          {
 
848
            pixel = (guint8 *) &buffer32[y * width + x];
 
849
            palette_index = ico_get_palette_index (color_to_slot, pixel[0],
 
850
                                                   pixel[1], pixel[2]);
 
851
 
 
852
            if (ico_get_bit_from_data (and_map, width,
 
853
                                       (height - y - 1) * width + x))
 
854
              {
 
855
                ico_set_bit_in_data (xor_map, width,
 
856
                                     (height - y -1) * width + x,
 
857
                                     black_index);
 
858
              }
 
859
            else
 
860
              {
 
861
                ico_set_bit_in_data (xor_map, width,
 
862
                                     (height - y -1) * width + x,
 
863
                                     palette_index);
 
864
              }
 
865
          }
 
866
      break;
 
867
 
 
868
    case 4:
 
869
      for (y = 0; y < height; y++)
 
870
        for (x = 0; x < width; x++)
 
871
          {
 
872
            pixel = (guint8 *) &buffer32[y * width + x];
 
873
            palette_index = ico_get_palette_index(color_to_slot, pixel[0],
 
874
                                                  pixel[1], pixel[2]);
 
875
 
 
876
            if (ico_get_bit_from_data (and_map, width,
 
877
                                       (height - y - 1) * width + x))
 
878
              {
 
879
                ico_set_nibble_in_data (xor_map, width,
 
880
                                        (height - y -1) * width + x,
 
881
                                        black_index);
 
882
              }
 
883
            else
 
884
              {
 
885
                ico_set_nibble_in_data (xor_map, width,
 
886
                                        (height - y - 1) * width + x,
 
887
                                        palette_index);
 
888
              }
 
889
          }
 
890
      break;
 
891
 
 
892
    case 8:
 
893
      for (y = 0; y < height; y++)
 
894
        for (x = 0; x < width; x++)
 
895
          {
 
896
            pixel = (guint8 *) &buffer32[y * width + x];
 
897
            palette_index = ico_get_palette_index (color_to_slot,
 
898
                                                   pixel[0],
 
899
                                                   pixel[1],
 
900
                                                   pixel[2]);
 
901
 
 
902
            if (ico_get_bit_from_data (and_map, width,
 
903
                                       (height - y - 1) * width + x))
 
904
              {
 
905
                ico_set_byte_in_data (xor_map, width,
 
906
                                      (height - y - 1) * width + x,
 
907
                                      black_index);
 
908
              }
 
909
            else
 
910
              {
 
911
                ico_set_byte_in_data (xor_map, width,
 
912
                                      (height - y - 1) * width + x,
 
913
                                      palette_index);
 
914
              }
 
915
 
 
916
          }
 
917
      break;
 
918
 
 
919
    case 24:
 
920
      for (y = 0; y < height; y++)
 
921
        {
 
922
          guchar *row = xor_map + (xor_len * (height - y - 1) / height);
 
923
 
 
924
          for (x = 0; x < width; x++)
 
925
            {
 
926
              pixel = (guint8 *) &buffer32[y * width + x];
 
927
 
 
928
              row[0] = pixel[2];
 
929
              row[1] = pixel[1];
 
930
              row[2] = pixel[0];
 
931
 
 
932
              row += 3;
 
933
            }
 
934
        }
 
935
      break;
 
936
 
 
937
    default:
 
938
      for (y = 0; y < height; y++)
 
939
        for (x = 0; x < width; x++)
 
940
          {
 
941
            pixel = (guint8 *) &buffer32[y * width + x];
 
942
 
 
943
            ((guint32 *) xor_map)[(height - y -1) * width + x] =
 
944
              GUINT32_TO_LE ((pixel[0] << 16) |
 
945
                             (pixel[1] << 8)  |
 
946
                             (pixel[2])       |
 
947
                             (pixel[3] << 24));
 
948
          }
 
949
    }
 
950
 
 
951
  D(("  filled and_map of length %i, xor_map of length %i\n",
 
952
     and_len, xor_len));
 
953
 
 
954
  if (color_to_slot)
 
955
    {
 
956
      g_hash_table_foreach (color_to_slot, ico_free_hash_item, NULL);
 
957
      g_hash_table_destroy (color_to_slot);
 
958
    }
 
959
 
 
960
  g_free (palette);
 
961
  g_free (buffer);
 
962
 
 
963
  ico_write_int32 (fp, (guint32*) &header, 3);
 
964
  ico_write_int16 (fp, &header.planes, 2);
 
965
  ico_write_int32 (fp, &header.compression, 6);
 
966
 
 
967
  if (palette_len)
 
968
    ico_write_int8 (fp, (guint8 *) palette32, palette_len);
 
969
 
 
970
  ico_write_int8 (fp, xor_map, xor_len);
 
971
  ico_write_int8 (fp, and_map, and_len);
 
972
 
 
973
  g_free (palette32);
 
974
  g_free (xor_map);
 
975
  g_free (and_map);
 
976
 
 
977
  return TRUE;
 
978
}
 
979
 
 
980
static void
 
981
ico_save_info_free (IcoSaveInfo  *info)
 
982
{
 
983
  g_free (info->depths);
 
984
  g_free (info->default_depths);
 
985
  g_free (info->compress);
 
986
  g_free (info->layers);
 
987
  memset (info, 0, sizeof (IcoSaveInfo));
 
988
}
 
989
 
965
990
GimpPDBStatusType
966
 
SaveICO (const gchar *filename,
967
 
         gint32       image)
 
991
ico_save_image (const gchar *filename,
 
992
                gint32       image,
 
993
                gint32       run_mode)
968
994
{
969
 
  MsIcon             ico;
970
 
  gchar             *temp_buf;
971
 
  gint              *icon_depths = NULL;
972
 
  gint               num_icons;
973
 
  GimpPDBStatusType  exit_state;
 
995
  FILE *fp;
 
996
 
 
997
  gint i;
 
998
  gint width, height;
 
999
  IcoSaveInfo      info;
 
1000
  IcoFileHeader    header;
 
1001
  IcoFileEntry    *entries;
 
1002
  gboolean          saved;
974
1003
 
975
1004
  D(("*** Saving Microsoft icon file %s\n", filename));
976
1005
 
977
 
  if (ico_layers_too_big (image))
978
 
    {
979
 
      g_message (_("Windows icons cannot be higher or wider than 255 pixels."));
980
 
      return GIMP_PDB_EXECUTION_ERROR;
981
 
    }
982
 
 
983
 
  /* First, set up the icon specs dialog and show it: */
984
 
  if ((icon_depths = ico_show_icon_dialog (image, &num_icons)) == NULL)
985
 
    return GIMP_PDB_CANCEL;
986
 
 
987
 
  temp_buf = g_strdup_printf (_("Saving '%s'..."),
988
 
                              gimp_filename_to_utf8 (filename));
989
 
  gimp_progress_init (temp_buf);
990
 
  g_free (temp_buf);
991
 
 
992
 
  /* Okay, let's actually save the thing with the depths the
993
 
     user specified. */
994
 
 
995
 
  if ((exit_state = ico_init (filename, &ico, num_icons) != GIMP_PDB_SUCCESS))
996
 
    return exit_state;
997
 
 
998
 
  D(("icon initialized ...\n"));
999
 
 
1000
 
  ico_setup (&ico, image, icon_depths, num_icons);
1001
 
 
1002
 
  D(("icon data created ...\n"));
1003
 
 
1004
 
  exit_state = ico_save(&ico);
1005
 
 
1006
 
  D(("*** icon saved, exit status %i.\n\n", exit_state));
1007
 
 
1008
 
  ico_cleanup (&ico);
1009
 
  g_free (icon_depths);
1010
 
 
1011
 
  return exit_state;
 
1006
  ico_save_init (image, &info);
 
1007
 
 
1008
  if (run_mode == GIMP_RUN_INTERACTIVE)
 
1009
    {
 
1010
      /* Allow user to override default values */
 
1011
      if ( !ico_save_dialog (image, &info))
 
1012
        return GIMP_PDB_CANCEL;
 
1013
    }
 
1014
 
 
1015
  gimp_progress_init_printf (_("Saving '%s'"),
 
1016
                             gimp_filename_to_utf8 (filename));
 
1017
 
 
1018
  if (! (fp = g_fopen (filename, "wb")))
 
1019
    {
 
1020
      g_message (_("Could not open '%s' for writing: %s"),
 
1021
                 gimp_filename_to_utf8 (filename), g_strerror (errno));
 
1022
      return GIMP_PDB_EXECUTION_ERROR;
 
1023
    }
 
1024
 
 
1025
  header.reserved = 0;
 
1026
  header.resource_type = 1;
 
1027
  header.icon_count = info.num_icons;
 
1028
  if ( !ico_write_int16 (fp, &header.reserved, 1)
 
1029
       || !ico_write_int16 (fp, &header.resource_type, 1)
 
1030
       || !ico_write_int16 (fp, &header.icon_count, 1) )
 
1031
    {
 
1032
      ico_save_info_free (&info);
 
1033
      fclose (fp);
 
1034
      return GIMP_PDB_EXECUTION_ERROR;
 
1035
    }
 
1036
 
 
1037
  entries = g_new0 (IcoFileEntry, info.num_icons);
 
1038
  if (fwrite (entries, sizeof (IcoFileEntry), info.num_icons, fp) <= 0)
 
1039
    {
 
1040
      ico_save_info_free (&info);
 
1041
      fclose (fp);
 
1042
      return GIMP_PDB_EXECUTION_ERROR;
 
1043
    }
 
1044
 
 
1045
  for (i = 0; i < info.num_icons; i++)
 
1046
    {
 
1047
      gimp_progress_update ((gdouble)i / (gdouble)info.num_icons);
 
1048
 
 
1049
      width = gimp_drawable_width (info.layers[i]);
 
1050
      height = gimp_drawable_height (info.layers[i]);
 
1051
      if (width <= 255 && height <= 255)
 
1052
        {
 
1053
          entries[i].width = width;
 
1054
          entries[i].height = height;
 
1055
        }
 
1056
      else
 
1057
        {
 
1058
          entries[i].width = 0;
 
1059
          entries[i].height = 0;
 
1060
        }
 
1061
      if ( info.depths[i] <= 8 )
 
1062
        entries[i].num_colors = 1 << info.depths[i];
 
1063
      else
 
1064
        entries[i].num_colors = 0;
 
1065
      entries[i].reserved = 0;
 
1066
      entries[i].planes = 1;
 
1067
      entries[i].bpp = info.depths[i];
 
1068
      entries[i].offset = ftell (fp);
 
1069
 
 
1070
      if (info.compress[i])
 
1071
        saved = ico_write_png (fp, info.layers[i], info.depths[i]);
 
1072
      else
 
1073
        saved = ico_write_icon (fp, info.layers[i], info.depths[i]);
 
1074
 
 
1075
      if (!saved)
 
1076
        {
 
1077
          ico_save_info_free (&info);
 
1078
          fclose (fp);
 
1079
          return GIMP_PDB_EXECUTION_ERROR;
 
1080
        }
 
1081
 
 
1082
      entries[i].size = ftell (fp) - entries[i].offset;
 
1083
    }
 
1084
 
 
1085
  if (fseek (fp, sizeof(IcoFileHeader), SEEK_SET) < 0
 
1086
      || fwrite (entries, sizeof (IcoFileEntry), info.num_icons, fp) <= 0)
 
1087
    {
 
1088
      ico_save_info_free (&info);
 
1089
      fclose (fp);
 
1090
      return GIMP_PDB_EXECUTION_ERROR;
 
1091
    }
 
1092
 
 
1093
  gimp_progress_update (1.0);
 
1094
 
 
1095
  ico_save_info_free (&info);
 
1096
  fclose (fp);
 
1097
  return GIMP_PDB_SUCCESS;
1012
1098
}