146
ico_show_icon_dialog (gint32 image_ID,
160
ico_save_init (gint32 image_ID, IcoSaveInfo *info)
149
GtkWidget *dialog, *hbox;
150
GtkWidget *icon_menu;
151
gint *layers, *icon_depths = NULL;
152
gint num_layers, i, num_colors;
153
164
gboolean uses_alpha_values;
158
gimp_ui_init ("winicon", TRUE);
160
layers = gimp_image_get_layers (image_ID, &num_layers);
161
dialog = ico_specs_dialog_new (num_layers);
163
for (i = 0; i < num_layers; i++)
165
/* if (gimp_layer_get_visible(layers[i])) */
166
ico_specs_dialog_add_icon (dialog, layers[i], i);
169
/* Scale the thing to approximately fit its content, but not too large ... */
170
gtk_window_set_default_size (GTK_WINDOW (dialog),
172
120 + (num_layers > 4 ? 400 : num_layers * 100));
174
icon_depths = g_object_get_data (G_OBJECT (dialog), "icon_depths");
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);
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++)
182
178
num_colors = ico_get_layer_num_colors (layers[i], &uses_alpha_values);
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");
188
180
if (!uses_alpha_values)
190
182
if (num_colors <= 2)
192
184
/* Let's suggest monochrome */
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;
198
187
else if (num_colors <= 16)
200
189
/* Let's suggest 4bpp */
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;
206
192
else if (num_colors <= 256)
208
194
/* Let's suggest 8bpp */
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);
216
/* Otherwise, or if real alpha levels are used, stick with 32bpp */
195
info->default_depths [i] = 8;
199
/* Let's suggest 24bpp */
200
info->default_depths [i] = 24;
205
/* Otherwise, or if real alpha levels are used, stick with 32bpp */
206
info->default_depths [i] = 32;
210
if (gimp_drawable_width (layers[i]) > 255
211
|| gimp_drawable_height (layers[i]) > 255 )
213
info->compress[i] = TRUE;
217
info->compress[i] = FALSE;
221
/* set with default values */
222
memcpy (info->depths, info->default_depths,
223
sizeof (gint) * info->num_icons);
229
ico_save_dialog (gint32 image_ID,
236
gimp_ui_init ("winicon", TRUE);
238
dialog = ico_dialog_new (info);
239
for (i = 0; i < info->num_icons; i++)
241
/* if (gimp_layer_get_visible(layers[i])) */
242
ico_dialog_add_icon (dialog, info->layers[i], i);
245
/* Scale the thing to approximately fit its content, but not too large ... */
246
gtk_window_set_default_size (GTK_WINDOW (dialog),
248
120 + (info->num_icons > 4 ?
249
500 : info->num_icons * 120));
221
251
gtk_widget_show (dialog);
223
if (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK)
224
*num_icons = num_layers;
252
response = gimp_dialog_run (GIMP_DIALOG (dialog));
228
253
gtk_widget_destroy (dialog);
234
static GimpPDBStatusType
235
ico_init (const gchar *filename,
239
memset (ico, 0, sizeof(MsIcon));
241
if (! (ico->fp = fopen (filename, "wb")))
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;
248
ico->filename = filename;
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);
255
return GIMP_PDB_SUCCESS;
260
ico_init_direntry (MsIconEntry *entry,
264
/* Was calloc'd, so initialized to 0. */
265
entry->width = gimp_drawable_width (layer);
266
entry->height = gimp_drawable_height (layer);
269
entry->num_colors = (1 << bpp);
271
entry->num_planes = 1;
274
D(("Initialized entry to w %i, h %i, bpp %i\n",
275
gimp_drawable_width (layer), entry->width, entry->bpp));
277
/* We'll set size and offset when writing things out */
254
if (response == GTK_RESPONSE_OK)
282
261
ico_set_bit_in_data (guint8 *data,
458
ico_init_data (MsIcon *ico,
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;
470
GHashTable *color_to_slot = NULL;
472
D(("Creating data structures for icon %i ------------------------\n", num_icon));
474
/* Shortcuts, for convenience */
475
entry = &ico->icon_dir[num_icon];
476
data = &ico->icon_data[num_icon];
478
/* Entries and data were calloc'd, so initialized to 0. */
480
data->header_size = 40;
481
data->width = gimp_drawable_width (layer);
482
data->height = 2 * gimp_drawable_height (layer);
486
num_colors = (1L << bpp);
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));
491
/* Reduce colors in copy of image */
492
ico_image_get_reduced_buf (layer, bpp, &num_colors_used, &palette, &buffer);
493
buffer32 = (guint32 *) buffer;
495
/* Set up colormap and andmap when necessary: */
498
/* Create a colormap */
499
data->palette = ico_create_palette (palette,
500
num_colors, num_colors_used,
502
data->palette_len = num_colors * 4;
504
color_to_slot = ico_create_color_to_palette_map (data->palette,
506
D((" created %i-slot colormap with %i colors, black at slot %i\n",
507
num_colors, num_colors_used, black_index));
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;
514
for (y = 0; y < entry->height; y++)
515
for (x = 0; x < entry->width; x++)
517
pixel = (guint8 *) &buffer32[y * entry->width + x];
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));
524
data->xor_map = ico_alloc_map(entry->width, entry->height, bpp, &xor_len);
525
data->xor_len = xor_len;
527
/* Now fill in the xor map */
531
for (y = 0; y < entry->height; y++)
532
for (x = 0; x < entry->width; x++)
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]);
538
if (ico_get_bit_from_data (data->and_map, entry->width,
539
(entry->height-y-1) * entry->width + x))
541
ico_set_bit_in_data (data->xor_map, entry->width,
542
(entry->height-y-1) * entry->width + x,
547
ico_set_bit_in_data (data->xor_map, entry->width,
548
(entry->height-y-1) * entry->width + x,
555
for (y = 0; y < entry->height; y++)
556
for (x = 0; x < entry->width; x++)
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]);
562
if (ico_get_bit_from_data (data->and_map, entry->width,
563
(entry->height-y-1) * entry->width + x))
565
ico_set_nibble_in_data (data->xor_map, entry->width,
566
(entry->height-y-1) * entry->width + x,
571
ico_set_nibble_in_data (data->xor_map, entry->width,
572
(entry->height-y-1) * entry->width + x,
579
for (y = 0; y < entry->height; y++)
580
for (x = 0; x < entry->width; x++)
582
pixel = (guint8 *) &buffer32[y * entry->width + x];
583
palette_index = ico_get_palette_index (color_to_slot,
588
if (ico_get_bit_from_data (data->and_map, entry->width,
589
(entry->height-y-1) * entry->width + x))
591
ico_set_byte_in_data (data->xor_map, entry->width,
592
(entry->height-y-1) * entry->width + x,
597
ico_set_byte_in_data (data->xor_map, entry->width,
598
(entry->height-y-1) * entry->width + x,
606
for (y = 0; y < entry->height; y++)
607
for (x = 0; x < entry->width; x++)
609
pixel = (guint8 *) &buffer32[y * entry->width + x];
611
((guint32 *) data->xor_map)[(entry->height-y-1) * entry->width + x] =
612
GUINT32_TO_LE ((pixel[0] << 16) |
619
D((" filled and_map of length %i, xor_map of length %i\n",
620
data->and_len, data->xor_len));
624
g_hash_table_foreach (color_to_slot, ico_free_hash_item, NULL);
625
g_hash_table_destroy (color_to_slot);
634
ico_setup (MsIcon *ico,
643
layers = gimp_image_get_layers (image, &num_icons);
645
/* Set up icon entries */
646
for (i = 0; i < num_icons; i++)
648
ico_init_direntry (&ico->icon_dir[i], layers[i], icon_depths[i]);
649
gimp_progress_update ((gdouble) i / (gdouble) num_icons * 0.3);
652
/* Set up data entries (the actual icons), and calculate each one's size */
653
for (i = 0; i < num_icons; i++)
655
ico_init_data (ico, i, layers[i], icon_depths[i]);
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;
663
gimp_progress_update (0.3 + (gdouble) i / (gdouble) num_icons * 0.3);
666
/* Finally, calculate offsets for each icon and store them in each entry */
667
offset = 3 * sizeof (guint16) + ico->icon_count * sizeof (MsIconEntry);
669
for (i = 0; i < num_icons; i++)
671
ico->icon_dir[i].offset = offset;
672
offset += ico->icon_dir[i].size;
674
gimp_progress_update (0.6 + (gdouble) i / (gdouble) num_icons * 0.3);
677
gimp_progress_update (1.0);
683
static GimpPDBStatusType
684
ico_save (MsIcon *ico)
690
ico->cp += ico_write_int16 (ico->fp, &ico->reserved, 3);
692
for (i = 0; i < ico->icon_count; i++)
694
entry = &ico->icon_dir[i];
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);
701
for (i = 0; i < ico->icon_count; i++)
703
data = &ico->icon_data[i];
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);
710
ico->cp += ico_write_int8 (ico->fp,
711
(guint8 *) data->palette, data->palette_len);
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);
717
return GIMP_PDB_SUCCESS;
721
ico_layers_too_big (gint32 image)
726
layers = gimp_image_get_layers (image, &num_layers);
728
for (i = 0; i < num_layers; i++)
730
if ((gimp_drawable_width (layers[i]) > 255) ||
731
(gimp_drawable_height (layers[i]) > 255))
743
437
ico_get_layer_num_colors (gint32 layer,
744
438
gboolean *uses_alpha_levels)
960
683
gimp_drawable_detach (drawable);
962
686
*buf_out = buffer;
690
ico_write_png (FILE *fp,
696
png_byte **row_pointers;
699
gint num_colors_used;
707
width = gimp_drawable_width (layer);
708
height = gimp_drawable_height (layer);
710
png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
714
info_ptr = png_create_info_struct (png_ptr);
717
png_destroy_write_struct (&png_ptr, NULL);
721
if (setjmp (png_jmpbuf (png_ptr)))
723
png_destroy_write_struct (&png_ptr, &info_ptr);
725
g_free (row_pointers);
733
ico_image_get_reduced_buf (layer, depth, &num_colors_used,
736
png_init_io (png_ptr, fp);
737
png_set_IHDR (png_ptr, info_ptr, width, height,
741
PNG_COMPRESSION_TYPE_DEFAULT,
742
PNG_FILTER_TYPE_DEFAULT);
743
png_write_info (png_ptr, info_ptr);
745
rowstride = ico_rowstride (width, 32);
746
row_pointers = g_new (png_byte*, height);
747
for (i = 0; i < height; i++)
749
row_pointers[i] = buffer + rowstride * i;
751
png_write_image (png_ptr, row_pointers);
755
png_write_end (png_ptr, info_ptr);
756
png_destroy_write_struct (&png_ptr, &info_ptr);
758
g_free (row_pointers);
765
ico_write_icon (FILE *fp,
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;
773
guchar *buffer = NULL, *pixel;
776
GHashTable *color_to_slot = NULL;
777
guchar *xor_map, *and_map;
779
guint32 *palette32 = NULL;
780
gint palette_len = 0;
782
D(("Creating data structures for icon %i ------------------------\n",
785
width = gimp_drawable_width (layer);
786
height = gimp_drawable_height (layer);
788
header.header_size = 40;
789
header.width = width;
790
header.height = 2 * height;
793
header.compression = 0;
794
header.image_size = 0;
797
header.used_clrs = 0;
798
header.important_clrs = 0;
800
num_colors = (1L << header.bpp);
802
D((" header size %i, w %i, h %i, planes %i, bpp %i\n",
803
header.header_size, header.width, header.height, header.planes,
806
/* Reduce colors in copy of image */
807
ico_image_get_reduced_buf (layer, header.bpp, &num_colors_used,
809
buffer32 = (guint32 *) buffer;
811
/* Set up colormap and andmap when necessary: */
814
/* Create a colormap */
815
palette32 = ico_create_palette (palette,
816
num_colors, num_colors_used,
818
palette_len = num_colors * 4;
820
color_to_slot = ico_create_color_to_palette_map (palette32,
822
D((" created %i-slot colormap with %i colors, black at slot %i\n",
823
num_colors, num_colors_used, black_index));
826
/* Create and_map. It's padded out to 32 bits per line: */
827
and_map = ico_alloc_map (width, height, 1, &and_len);
829
for (y = 0; y < height; y++)
830
for (x = 0; x < width; x++)
832
pixel = (guint8 *) &buffer32[y * width + x];
834
ico_set_bit_in_data (and_map, width,
835
(height - y -1) * width + x,
836
(pixel[3] > ICO_ALPHA_THRESHOLD ? 0 : 1));
839
xor_map = ico_alloc_map (width, height, header.bpp, &xor_len);
841
/* Now fill in the xor map */
845
for (y = 0; y < height; y++)
846
for (x = 0; x < width; x++)
848
pixel = (guint8 *) &buffer32[y * width + x];
849
palette_index = ico_get_palette_index (color_to_slot, pixel[0],
852
if (ico_get_bit_from_data (and_map, width,
853
(height - y - 1) * width + x))
855
ico_set_bit_in_data (xor_map, width,
856
(height - y -1) * width + x,
861
ico_set_bit_in_data (xor_map, width,
862
(height - y -1) * width + x,
869
for (y = 0; y < height; y++)
870
for (x = 0; x < width; x++)
872
pixel = (guint8 *) &buffer32[y * width + x];
873
palette_index = ico_get_palette_index(color_to_slot, pixel[0],
876
if (ico_get_bit_from_data (and_map, width,
877
(height - y - 1) * width + x))
879
ico_set_nibble_in_data (xor_map, width,
880
(height - y -1) * width + x,
885
ico_set_nibble_in_data (xor_map, width,
886
(height - y - 1) * width + x,
893
for (y = 0; y < height; y++)
894
for (x = 0; x < width; x++)
896
pixel = (guint8 *) &buffer32[y * width + x];
897
palette_index = ico_get_palette_index (color_to_slot,
902
if (ico_get_bit_from_data (and_map, width,
903
(height - y - 1) * width + x))
905
ico_set_byte_in_data (xor_map, width,
906
(height - y - 1) * width + x,
911
ico_set_byte_in_data (xor_map, width,
912
(height - y - 1) * width + x,
920
for (y = 0; y < height; y++)
922
guchar *row = xor_map + (xor_len * (height - y - 1) / height);
924
for (x = 0; x < width; x++)
926
pixel = (guint8 *) &buffer32[y * width + x];
938
for (y = 0; y < height; y++)
939
for (x = 0; x < width; x++)
941
pixel = (guint8 *) &buffer32[y * width + x];
943
((guint32 *) xor_map)[(height - y -1) * width + x] =
944
GUINT32_TO_LE ((pixel[0] << 16) |
951
D((" filled and_map of length %i, xor_map of length %i\n",
956
g_hash_table_foreach (color_to_slot, ico_free_hash_item, NULL);
957
g_hash_table_destroy (color_to_slot);
963
ico_write_int32 (fp, (guint32*) &header, 3);
964
ico_write_int16 (fp, &header.planes, 2);
965
ico_write_int32 (fp, &header.compression, 6);
968
ico_write_int8 (fp, (guint8 *) palette32, palette_len);
970
ico_write_int8 (fp, xor_map, xor_len);
971
ico_write_int8 (fp, and_map, and_len);
981
ico_save_info_free (IcoSaveInfo *info)
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));
965
990
GimpPDBStatusType
966
SaveICO (const gchar *filename,
991
ico_save_image (const gchar *filename,
971
gint *icon_depths = NULL;
973
GimpPDBStatusType exit_state;
1000
IcoFileHeader header;
1001
IcoFileEntry *entries;
975
1004
D(("*** Saving Microsoft icon file %s\n", filename));
977
if (ico_layers_too_big (image))
979
g_message (_("Windows icons cannot be higher or wider than 255 pixels."));
980
return GIMP_PDB_EXECUTION_ERROR;
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;
987
temp_buf = g_strdup_printf (_("Saving '%s'..."),
988
gimp_filename_to_utf8 (filename));
989
gimp_progress_init (temp_buf);
992
/* Okay, let's actually save the thing with the depths the
995
if ((exit_state = ico_init (filename, &ico, num_icons) != GIMP_PDB_SUCCESS))
998
D(("icon initialized ...\n"));
1000
ico_setup (&ico, image, icon_depths, num_icons);
1002
D(("icon data created ...\n"));
1004
exit_state = ico_save(&ico);
1006
D(("*** icon saved, exit status %i.\n\n", exit_state));
1009
g_free (icon_depths);
1006
ico_save_init (image, &info);
1008
if (run_mode == GIMP_RUN_INTERACTIVE)
1010
/* Allow user to override default values */
1011
if ( !ico_save_dialog (image, &info))
1012
return GIMP_PDB_CANCEL;
1015
gimp_progress_init_printf (_("Saving '%s'"),
1016
gimp_filename_to_utf8 (filename));
1018
if (! (fp = g_fopen (filename, "wb")))
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;
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) )
1032
ico_save_info_free (&info);
1034
return GIMP_PDB_EXECUTION_ERROR;
1037
entries = g_new0 (IcoFileEntry, info.num_icons);
1038
if (fwrite (entries, sizeof (IcoFileEntry), info.num_icons, fp) <= 0)
1040
ico_save_info_free (&info);
1042
return GIMP_PDB_EXECUTION_ERROR;
1045
for (i = 0; i < info.num_icons; i++)
1047
gimp_progress_update ((gdouble)i / (gdouble)info.num_icons);
1049
width = gimp_drawable_width (info.layers[i]);
1050
height = gimp_drawable_height (info.layers[i]);
1051
if (width <= 255 && height <= 255)
1053
entries[i].width = width;
1054
entries[i].height = height;
1058
entries[i].width = 0;
1059
entries[i].height = 0;
1061
if ( info.depths[i] <= 8 )
1062
entries[i].num_colors = 1 << info.depths[i];
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);
1070
if (info.compress[i])
1071
saved = ico_write_png (fp, info.layers[i], info.depths[i]);
1073
saved = ico_write_icon (fp, info.layers[i], info.depths[i]);
1077
ico_save_info_free (&info);
1079
return GIMP_PDB_EXECUTION_ERROR;
1082
entries[i].size = ftell (fp) - entries[i].offset;
1085
if (fseek (fp, sizeof(IcoFileHeader), SEEK_SET) < 0
1086
|| fwrite (entries, sizeof (IcoFileEntry), info.num_icons, fp) <= 0)
1088
ico_save_info_free (&info);
1090
return GIMP_PDB_EXECUTION_ERROR;
1093
gimp_progress_update (1.0);
1095
ico_save_info_free (&info);
1097
return GIMP_PDB_SUCCESS;