7 ico_push_error(int error) {
8 char error_buf[ICO_MAX_MESSAGE];
10 ico_error_message(error, error_buf, sizeof(error_buf));
11 i_push_error(error, error_buf);
16 read_one_icon(ico_reader_t *file, int index) {
21 image = ico_image_read(file, index, &error);
23 ico_push_error(error);
24 i_push_error(0, "error reading ICO/CUR image");
32 ico_color_t *inp = image->image_data;
34 if (!i_int_check_image_file_limits(image->width, image->height, 4, 1)) {
35 ico_image_release(image);
39 result = i_img_8_new(image->width, image->height, 4);
41 ico_image_release(image);
45 line_buf = mymalloc(image->width * sizeof(i_color));
47 for (y = 0; y < image->height; ++y) {
49 for (x = 0; x < image->width; ++x) {
50 outp->rgba.r = inp->r;
51 outp->rgba.g = inp->g;
52 outp->rgba.b = inp->b;
53 outp->rgba.a = inp->a;
57 i_plin(result, 0, image->width, y, line_buf);
65 unsigned char *image_data;
67 if (!i_int_check_image_file_limits(image->width, image->height, 3, 1)) {
68 ico_image_release(image);
72 result = i_img_pal_new(image->width, image->height, 3, 256);
74 ico_image_release(image);
78 /* fill in the palette */
79 for (pal_index = 0; pal_index < image->palette_size; ++pal_index) {
81 c.rgba.r = image->palette[pal_index].r;
82 c.rgba.g = image->palette[pal_index].g;
83 c.rgba.b = image->palette[pal_index].b;
84 c.rgba.a = 255; /* so as to not confuse some code */
86 if (i_addcolors(result, &c, 1) < 0) {
87 i_push_error(0, "could not add color to palette");
88 ico_image_release(image);
89 i_img_destroy(result);
94 /* fill in the image data */
95 image_data = image->image_data;
96 for (y = 0; y < image->height; ++y) {
97 i_ppal(result, 0, image->width, y, image_data);
98 image_data += image->width;
103 unsigned char *inp = image->mask_data;
107 /* fill in the mask tag */
108 /* space for " .\n", width + 1 chars per line and NUL */
109 mask = mymalloc(3 + (image->width + 1) * image->height + 1);
115 for (y = 0; y < image->height; ++y) {
116 for (x = 0; x < image->width; ++x) {
117 *outp++ = *inp++ ? '*' : '.';
119 if (y != image->height - 1) /* not on the last line */
124 if (ico_type(file) == ICON_ICON)
125 i_tags_set(&result->tags, "ico_mask", mask, (outp-mask)-1);
127 i_tags_set(&result->tags, "cur_mask", mask, (outp-mask)-1);
131 if (ico_type(file) == ICON_ICON) {
132 i_tags_setn(&result->tags, "ico_bits", image->bit_count);
133 i_tags_set(&result->tags, "i_format", "ico", 3);
136 i_tags_setn(&result->tags, "cur_bits", image->bit_count);
137 i_tags_set(&result->tags, "i_format", "cur", 3);
138 i_tags_setn(&result->tags, "cur_hotspotx", image->hotspot_x);
139 i_tags_setn(&result->tags, "cur_hotspoty", image->hotspot_y);
142 ico_image_release(image);
148 i_readico_single(io_glue *ig, int index) {
155 file = ico_reader_open(ig, &error);
157 ico_push_error(error);
158 i_push_error(0, "error opening ICO/CUR file");
162 /* the index is range checked by msicon.c - don't duplicate it here */
164 result = read_one_icon(file, index);
165 ico_reader_close(file);
171 i_readico_multi(io_glue *ig, int *count) {
179 file = ico_reader_open(ig, &error);
181 ico_push_error(error);
182 i_push_error(0, "error opening ICO/CUR file");
186 imgs = mymalloc(sizeof(i_img *) * ico_image_count(file));
189 for (index = 0; index < ico_image_count(file); ++index) {
190 i_img *im = read_one_icon(file, index);
194 imgs[(*count)++] = im;
197 ico_reader_close(file);
208 validate_image(i_img *im) {
209 if (im->xsize > 255 || im->ysize > 255) {
210 i_push_error(0, "image too large for ico file");
213 if (im->channels < 1 || im->channels > 4) {
214 /* this shouldn't happen, but check anyway */
215 i_push_error(0, "invalid channels");
223 translate_mask(i_img *im, unsigned char *out, const char *in) {
226 int len = strlen(in);
228 int newline; /* set to the first newline type we see */
229 int notnewline; /* set to whatever in ( "\n\r" newline isn't ) */
236 if (in[2] == '\n' || in[2] == '\r') {
238 notnewline = '\n' + '\r' - newline;
246 while (y < im->ysize && pos < len) {
248 while (x < im->xsize && pos < len) {
249 if (in[pos] == newline) {
250 /* don't process it, we look for it later */
253 else if (in[pos] == notnewline) {
254 ++pos; /* just drop it */
256 else if (in[pos] == one) {
261 else if (in[pos] == zero) {
266 else if (in[pos] == ' ' || in[pos] == '\t') {
267 /* just ignore whitespace */
274 while (x++ < im->xsize) {
277 while (pos < len && in[pos] != newline)
279 if (pos < len && in[pos] == newline)
280 ++pos; /* actually skip the newline */
284 while (y++ < im->ysize) {
285 for (x = 0; x < im->xsize; ++x)
293 derive_mask(i_img *im, ico_image_t *ico) {
295 if (im->channels == 1 || im->channels == 3) {
296 /* msicon.c's default mask is what we want */
297 myfree(ico->mask_data);
298 ico->mask_data = NULL;
301 int channel = im->channels - 1;
302 i_sample_t *linebuf = mymalloc(sizeof(i_sample_t) * im->xsize);
304 unsigned char *out = ico->mask_data;
306 for (y = 0; y < im->ysize; ++y) {
307 i_gsamp(im, 0, im->xsize, y, linebuf, &channel, 1);
308 for (x = 0; x < im->xsize; ++x) {
309 *out++ = linebuf[x] == 255 ? 0 : 1;
317 fill_image_base(i_img *im, ico_image_t *ico, const char *mask_name) {
320 ico->width = im->xsize;
321 ico->height = im->ysize;
322 ico->direct = im->type == i_direct_type;
328 unsigned char *linebuf = mymalloc(ico->width * 4);
329 ico->image_data = mymalloc(sizeof(ico_color_t) * ico->width * ico->height);
331 switch (im->channels) {
333 channels[0] = channels[1] = channels[2] = channels[3] = 0;
338 channels[0] = channels[1] = channels[2] = 0;
358 out = ico->image_data;
359 for (y = 0; y < im->ysize; ++y) {
360 i_gsamp(im, 0, im->xsize, y, linebuf, channels, 4);
362 for (x = 0; x < im->xsize; ++x) {
366 out->a = set_alpha ? 255 : *in;
379 i_palidx *linebuf = mymalloc(sizeof(i_palidx) * ico->width);
381 ico->image_data = mymalloc(sizeof(ico_color_t) * ico->width * ico->height);
383 out = ico->image_data;
384 for (y = 0; y < im->ysize; ++y) {
385 i_gpal(im, 0, im->xsize, y, linebuf);
387 for (x = 0; x < im->xsize; ++x) {
393 ico->palette_size = i_colorcount(im);
394 ico->palette = mymalloc(sizeof(ico_color_t) * ico->palette_size);
395 colors = mymalloc(sizeof(i_color) * ico->palette_size);
396 i_getcolors(im, 0, colors, ico->palette_size);
397 for (i = 0; i < ico->palette_size; ++i) {
398 if (im->channels == 1 || im->channels == 2) {
399 ico->palette[i].r = ico->palette[i].g =
400 ico->palette[i].b = colors[i].rgba.r;
403 ico->palette[i].r = colors[i].rgba.r;
404 ico->palette[i].g = colors[i].rgba.g;
405 ico->palette[i].b = colors[i].rgba.b;
415 ico->mask_data = mymalloc(im->xsize * im->ysize);
417 if (!i_tags_find(&im->tags, mask_name, 0, &mask_index)
418 || !im->tags.tags[mask_index].data
419 || !translate_mask(im, ico->mask_data,
420 im->tags.tags[mask_index].data)) {
421 derive_mask(im, ico);
427 unfill_image(ico_image_t *ico) {
428 myfree(ico->image_data);
430 myfree(ico->palette);
432 myfree(ico->mask_data);
436 fill_image_icon(i_img *im, ico_image_t *ico) {
437 fill_image_base(im, ico, "ico_mask");
438 ico->hotspot_x = ico->hotspot_y = 0;
442 i_writeico_wiol(i_io_glue_t *ig, i_img *im) {
448 if (!validate_image(im))
451 fill_image_icon(im, &ico);
453 if (!ico_write(ig, &ico, 1, ICON_ICON, &error)) {
454 ico_push_error(error);
461 if (i_io_close(ig) < 0) {
462 i_push_error(0, "error closing output");
470 i_writeico_multi_wiol(i_io_glue_t *ig, i_img **ims, int count) {
477 if (count > 0xFFFF) {
478 i_push_error(0, "too many images for ico files");
482 for (i = 0; i < count; ++i)
483 if (!validate_image(ims[i]))
486 icons = mymalloc(sizeof(ico_image_t) * count);
488 for (i = 0; i < count; ++i)
489 fill_image_icon(ims[i], icons + i);
491 if (!ico_write(ig, icons, count, ICON_ICON, &error)) {
492 ico_push_error(error);
493 for (i = 0; i < count; ++i)
494 unfill_image(icons + i);
499 for (i = 0; i < count; ++i)
500 unfill_image(icons + i);
503 if (i_io_close(ig) < 0) {
504 i_push_error(0, "error closing output");
512 fill_image_cursor(i_img *im, ico_image_t *ico) {
514 fill_image_base(im, ico, "ico_mask");
516 if (!i_tags_get_int(&im->tags, "cur_hotspotx", 0, &hotx))
518 if (!i_tags_get_int(&im->tags, "cur_hotspoty", 0, &hoty))
523 else if (hotx >= im->xsize)
524 hotx = im->xsize - 1;
528 else if (hoty >= im->ysize)
529 hoty = im->ysize - 1;
531 ico->hotspot_x = hotx;
532 ico->hotspot_y = hoty;
536 i_writecur_wiol(i_io_glue_t *ig, i_img *im) {
542 if (!validate_image(im))
545 fill_image_cursor(im, &ico);
547 if (!ico_write(ig, &ico, 1, ICON_CURSOR, &error)) {
548 ico_push_error(error);
555 if (i_io_close(ig) < 0) {
556 i_push_error(0, "error closing output");
564 i_writecur_multi_wiol(i_io_glue_t *ig, i_img **ims, int count) {
571 if (count > 0xFFFF) {
572 i_push_error(0, "too many images for ico files");
576 for (i = 0; i < count; ++i)
577 if (!validate_image(ims[i]))
580 icons = mymalloc(sizeof(ico_image_t) * count);
582 for (i = 0; i < count; ++i)
583 fill_image_cursor(ims[i], icons + i);
585 if (!ico_write(ig, icons, count, ICON_CURSOR, &error)) {
586 ico_push_error(error);
587 for (i = 0; i < count; ++i)
588 unfill_image(icons + i);
593 for (i = 0; i < count; ++i)
594 unfill_image(icons + i);
597 if (i_io_close(ig) < 0) {
598 i_push_error(0, "error closing output");