nrg: Improved support for v2
[deark.git] / modules / icns.c
blob96b862379fb2c94db40636c193f9cd131d3c0af6
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // icns - Apple Icon Image format
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_icns);
11 static const u32 pal16[16] = {
12 0xffffff,0xfcf305,0xff6402,0xdd0806,0xf20884,0x4600a5,0x0000d4,0x02abea,
13 0x1fb714,0x006411,0x562c05,0x90713a,0xc0c0c0,0x808080,0x404040,0x000000
16 #define IMGTYPE_EMBEDDED_FILE 1
17 #define IMGTYPE_MASK 2
18 #define IMGTYPE_IMAGE 3
19 #define IMGTYPE_IMAGE_AND_MASK 4
21 struct image_type_info {
22 u32 code;
23 int width;
24 int height;
25 int bpp; // bits per pixel. 0 = unspecified
26 int image_type; // IMGTYPE_*
28 static const struct image_type_info image_type_info_arr[] = {
29 { 0x69636d23, 16, 12, 1, IMGTYPE_IMAGE_AND_MASK }, // icm#
30 { 0x69637323, 16, 16, 1, IMGTYPE_IMAGE_AND_MASK }, // ics#
31 { 0x49434e23, 32, 32, 1, IMGTYPE_IMAGE_AND_MASK }, // ICN#
32 { 0x69636823, 48, 48, 1, IMGTYPE_IMAGE_AND_MASK }, // ich#
34 { 0x49434f4e, 32, 32, 1, IMGTYPE_IMAGE }, // ICON
35 { 0x69636d34, 16, 12, 4, IMGTYPE_IMAGE }, // icm4
36 { 0x69637334, 16, 16, 4, IMGTYPE_IMAGE }, // ics4
37 { 0x69636c34, 32, 32, 4, IMGTYPE_IMAGE }, // icl4
38 { 0x69636834, 48, 48, 4, IMGTYPE_IMAGE }, // ich4
39 { 0x69636d38, 16, 12, 8, IMGTYPE_IMAGE }, // icm8
40 { 0x69637338, 16, 16, 8, IMGTYPE_IMAGE }, // ics8
41 { 0x69636c38, 32, 32, 8, IMGTYPE_IMAGE }, // icl8
42 { 0x69636838, 48, 48, 8, IMGTYPE_IMAGE }, // ich8
43 { 0x69733332, 16, 16, 24, IMGTYPE_IMAGE }, // is32
44 { 0x696c3332, 32, 32, 24, IMGTYPE_IMAGE }, // il32
45 { 0x69683332, 48, 48, 24, IMGTYPE_IMAGE }, // ih32
46 { 0x69743332, 128, 128, 24, IMGTYPE_IMAGE }, // it32
48 { 0x73386d6b, 16, 16, 8, IMGTYPE_MASK }, // s8mk
49 { 0x6c386d6b, 32, 32, 8, IMGTYPE_MASK }, // l8mk
50 { 0x68386d6b, 48, 48, 8, IMGTYPE_MASK }, // h8mk
51 { 0x74386d6b, 128, 128, 8, IMGTYPE_MASK }, // t8mk
53 { 0x69637034, 16, 16, 0, IMGTYPE_EMBEDDED_FILE }, // icp4
54 { 0x69637035, 32, 32, 0, IMGTYPE_EMBEDDED_FILE }, // icp5
55 { 0x69637036, 64, 64, 0, IMGTYPE_EMBEDDED_FILE }, // icp6
56 { 0x69633037, 128, 128, 0, IMGTYPE_EMBEDDED_FILE }, // ic07
57 { 0x69633038, 256, 256, 0, IMGTYPE_EMBEDDED_FILE }, // ic08
58 { 0x69633039, 512, 512, 0, IMGTYPE_EMBEDDED_FILE }, // ic09
59 { 0x69633130, 1024, 1024, 0, IMGTYPE_EMBEDDED_FILE }, // ic10
60 { 0x69633131, 32, 32, 0, IMGTYPE_EMBEDDED_FILE }, // ic11
61 { 0x69633132, 64, 64, 0, IMGTYPE_EMBEDDED_FILE }, // ic12
62 { 0x69633133, 256, 256, 0, IMGTYPE_EMBEDDED_FILE }, // ic13
63 { 0x69633134, 512, 512, 0, IMGTYPE_EMBEDDED_FILE }, // ic14
65 { 0x544f4320, 0, 0, 0, 0 }, // 'TOC '
66 { 0x69636e56, 0, 0, 0, 0 } // icnV
69 struct mask_wrapper {
70 de_bitmap *img;
73 struct page_ctx {
74 int image_num;
75 i64 image_pos;
76 i64 image_len;
77 struct mask_wrapper *mask_ref; // (pointer to a d->mask field; do not free)
78 i64 rowspan;
79 const struct image_type_info *type_info;
80 struct de_fourcc code4cc;
81 char filename_token[32];
84 #define MASKTYPEID_16_12_1 0
85 #define MASKTYPEID_16_16_1 1
86 #define MASKTYPEID_32_32_1 2
87 #define MASKTYPEID_48_48_1 3
88 #define MASKTYPEID_16_16_8 4
89 #define MASKTYPEID_32_32_8 5
90 #define MASKTYPEID_48_48_8 6
91 #define MASKTYPEID_128_128_8 7
92 #define NUM_MASKTYPES 8
94 typedef struct localctx_struct {
95 i64 file_size;
96 struct mask_wrapper mask[NUM_MASKTYPES];
97 } lctx;
99 static const u32 supplpal256[41] = {
100 0xee0000,0xdd0000,0xbb0000,0xaa0000,0x880000,
101 0x770000,0x550000,0x440000,0x220000,0x110000,
102 0x00ee00,0x00dd00,0x00bb00,0x00aa00,0x008800,
103 0x007700,0x005500,0x004400,0x002200,0x001100,
104 0x0000ee,0x0000dd,0x0000bb,0x0000aa,0x000088,
105 0x000077,0x000055,0x000044,0x000022,0x000011,
106 0xeeeeee,0xdddddd,0xbbbbbb,0xaaaaaa,0x888888,
107 0x777777,0x555555,0x444444,0x222222,0x111111,0x000000
110 static u32 getpal256(int k)
112 u8 r, g, b;
114 if(k<0 || k>255) return 0;
115 if(k<=214) {
116 // The first 215 palette entries follow a simple pattern.
117 r = (u8)((5-k/36)*0x33);
118 g = (5-(k%36)/6)*0x33;
119 b = (5-k%6)*0x33;
120 return DE_MAKE_RGB(r,g,b);
123 return supplpal256[k-215];
126 static void do_decode_1_4_8bit(deark *c, lctx *d, struct page_ctx *pg)
128 de_bitmap *img = NULL;
129 i64 i, j;
130 u8 b;
131 de_color fgcol;
132 int bypp;
134 bypp = (pg->type_info->bpp==1)?2:4;
135 img = de_bitmap_create(c, pg->type_info->width, pg->type_info->height, bypp);
137 for(j=0; j<pg->type_info->height; j++) {
138 for(i=0; i<pg->type_info->width; i++) {
139 b = de_get_bits_symbol(c->infile, pg->type_info->bpp, pg->image_pos + pg->rowspan*j, i);
140 if(pg->type_info->bpp==8) {
141 fgcol = getpal256((int)b);
143 else if(pg->type_info->bpp==4) {
144 fgcol = pal16[(unsigned int)b];
146 else {
147 fgcol = b ? DE_STOCKCOLOR_BLACK : DE_STOCKCOLOR_WHITE;
149 fgcol = DE_MAKE_OPAQUE(fgcol);
150 de_bitmap_setpixel_rgb(img, i, j, fgcol);
154 if(pg->mask_ref && pg->mask_ref->img) {
155 de_bitmap_apply_mask(img, pg->mask_ref->img, 0);
158 de_bitmap_write_to_file(img, pg->filename_token, 0);
159 de_bitmap_destroy(img);
162 static void do_uncompress_24(deark *c, lctx *d, struct page_ctx *pg, dbuf *unc_pixels,
163 i64 skip)
165 i64 pos;
166 u8 b;
167 i64 count;
168 u8 n;
170 pos = pg->image_pos;
171 if(skip) pos+=4;
173 while(1) {
174 if(pos >= pg->image_pos + pg->image_len) break;
176 b = de_getbyte(pos);
177 pos++;
178 if(b>=128) {
179 // Compressed run
180 count = (i64)b - 125;
181 n = de_getbyte(pos);
182 pos++;
183 dbuf_write_run(unc_pixels, n, count);
185 else {
186 // An uncompressed run
187 count = 1 + (i64)b;
188 dbuf_copy(c->infile, pos, count, unc_pixels);
189 pos += count;
194 static void do_decode_24bit(deark *c, lctx *d, struct page_ctx *pg)
196 dbuf *unc_pixels = NULL;
197 de_bitmap *img = NULL;
198 i64 i, j;
199 u8 cr, cg, cb;
200 i64 w, h;
201 i64 skip;
203 w = pg->type_info->width;
204 h = pg->type_info->height;
206 // TODO: Try to support uncompressed 24-bit images, assuming they exist.
208 // Apparently, some 'it32' icons begin with four extra 0x00 bytes.
209 // Skip over the first four bytes if they are 0x00.
210 // (I don't know the reason for these bytes, but this is the same
211 // logic libicns uses.)
212 skip = 0;
213 if(pg->code4cc.id==0x69743332) { // 'it32' (128x128)
214 if(!dbuf_memcmp(c->infile, pg->image_pos, "\0\0\0\0", 4)) {
215 skip = 4;
219 unc_pixels = dbuf_create_membuf(c, w*h*3, 1);
220 do_uncompress_24(c, d, pg, unc_pixels, skip);
222 img = de_bitmap_create(c, w, h, 4);
224 for(j=0; j<pg->type_info->height; j++) {
225 for(i=0; i<pg->type_info->width; i++) {
226 cr = dbuf_getbyte(unc_pixels, j*w + i);
227 cg = dbuf_getbyte(unc_pixels, (h+j)*w + i);
228 cb = dbuf_getbyte(unc_pixels, (2*h+j)*w + i);
229 de_bitmap_setpixel_rgb(img, i, j, DE_MAKE_RGB(cr,cg,cb));
233 if(pg->mask_ref && pg->mask_ref->img) {
234 de_bitmap_apply_mask(img, pg->mask_ref->img, 0);
237 de_bitmap_write_to_file(img, pg->filename_token, 0);
238 de_bitmap_destroy(img);
239 if(unc_pixels) dbuf_close(unc_pixels);
242 static void do_extract_png_or_jp2(deark *c, lctx *d, struct page_ctx *pg)
244 u8 buf[8];
245 de_finfo *fi = NULL;
247 de_dbg(c, "Trying to extract file at %d", (int)pg->image_pos);
249 // Detect the format
250 de_read(buf, pg->image_pos, sizeof(buf));
252 fi = de_finfo_create(c);
253 de_finfo_set_name_from_sz(c, fi, pg->filename_token, 0, DE_ENCODING_ASCII);
255 if(buf[4]=='j' && buf[5]=='P') {
256 dbuf_create_file_from_slice(c->infile, pg->image_pos, pg->image_len, "jp2", fi, 0);
258 else if(buf[0]==0x89 && buf[1]==0x50) {
259 dbuf_create_file_from_slice(c->infile, pg->image_pos, pg->image_len, "png", fi, 0);
261 else {
262 de_err(c, "(Image #%d) Unidentified file format", pg->image_num);
265 de_finfo_destroy(c, fi);
268 // Assumes image_type is IMAGE or IMAGE_AND_MASK.
269 static struct mask_wrapper *find_mask(deark *c, lctx *d, struct page_ctx *pg)
271 struct mask_wrapper *mw = NULL;
272 const struct image_type_info *t;
274 t = pg->type_info;
276 // As far as I can determine, icons with 8 or fewer bits/pixel always use the
277 // 1-bit mask. Note that 1-bit masks cannot appear by themselves, and always
278 // follow a 1-bit image. So if there is an 8- or 4-bit image, there must
279 // always be a 1-bit image of the same dimensions.
281 if(t->code==0x49434f4e) { // 'ICON'
282 // I'm assuming this format doesn't have a mask.
283 return NULL;
286 if(t->width==16 && t->height==12 && t->bpp<=8) {
287 mw = &d->mask[MASKTYPEID_16_12_1];
289 else if(t->width==16 && t->height==16 && t->bpp<=8) {
290 mw = &d->mask[MASKTYPEID_16_16_1];
292 else if(t->width==32 && t->bpp<=8) {
293 mw = &d->mask[MASKTYPEID_32_32_1];
295 else if(t->width==48 && t->bpp<=8) {
296 mw = &d->mask[MASKTYPEID_48_48_1];
298 else if(t->width==16 && t->bpp>=24) {
299 mw = &d->mask[MASKTYPEID_16_16_8];
301 else if(t->width==32 && t->bpp>=24) {
302 mw = &d->mask[MASKTYPEID_32_32_8];
304 else if(t->width==48 && t->bpp>=24) {
305 mw = &d->mask[MASKTYPEID_48_48_8];
307 else if(t->width==128 && t->bpp>=24) {
308 mw = &d->mask[MASKTYPEID_128_128_8];
311 if(mw && mw->img) return mw;
312 return NULL;
315 static void convert_image_gray8(dbuf *f, i64 fpos, i64 rowspan, de_bitmap *img)
317 i64 i, j;
319 for(j=0; j<img->height; j++) {
320 for(i=0; i<img->width; i++) {
321 u8 n;
323 n = dbuf_getbyte(f, fpos+j*rowspan+i);
324 de_bitmap_setpixel_gray(img, i, j, n);
329 static void do_read_mask(deark *c, lctx *d, struct page_ctx *pg, int masktype_id,
330 int depth, i64 w, i64 h)
332 de_bitmap *img;
333 i64 rowspan;
334 i64 mask_offset;
336 if(depth==1) {
337 rowspan = (w+7)/8;
338 mask_offset = rowspan*h;
340 else {
341 rowspan = w;
342 mask_offset = 0;
345 de_dbg(c, "mask(%d"DE_CHAR_TIMES"%d,%d) at %"I64_FMT"(+%d)", (int)w, (int)h, depth, pg->image_pos,
346 (int)mask_offset);
348 if(d->mask[masktype_id].img) {
349 de_bitmap_destroy(d->mask[masktype_id].img);
351 d->mask[masktype_id].img = de_bitmap_create(c, w, h, 1);
352 img = d->mask[masktype_id].img;
354 if(depth==1) {
355 de_convert_image_bilevel(c->infile, pg->image_pos+mask_offset, rowspan, img, 0);
357 else {
358 convert_image_gray8(c->infile, pg->image_pos+mask_offset, rowspan, img);
362 static void do_icon(deark *c, lctx *d, struct page_ctx *pg)
364 i64 expected_image_size;
365 int is_compressed;
367 if(!pg->type_info) return; // Shouldn't happen.
369 de_strlcpy(pg->filename_token, "", sizeof(pg->filename_token));
371 if(pg->type_info->image_type==IMGTYPE_MASK) {
372 de_dbg(c, "transparency mask");
373 return;
376 if(pg->type_info->image_type==IMGTYPE_EMBEDDED_FILE) {
377 de_snprintf(pg->filename_token, sizeof(pg->filename_token), "%dx%d",
378 (int)pg->type_info->width, (int)pg->type_info->height);
379 do_extract_png_or_jp2(c, d, pg);
380 return;
383 if(pg->type_info->image_type!=IMGTYPE_IMAGE &&
384 pg->type_info->image_type!=IMGTYPE_IMAGE_AND_MASK)
386 return;
389 // At this point we know it's a regular image (or an image+mask)
391 // Note - This pg->rowspan is arguably incorrect for 24-bit images, since
392 // rows aren't stored contiguously.
393 pg->rowspan = ((pg->type_info->bpp * pg->type_info->width)+7)/8;
395 expected_image_size = pg->rowspan * pg->type_info->height;
396 if(pg->type_info->image_type==IMGTYPE_IMAGE_AND_MASK) {
397 expected_image_size *= 2;
400 is_compressed = (pg->type_info->bpp==24) ? 1 : 0;
402 if(!is_compressed) {
403 if(pg->image_len < expected_image_size) {
404 de_err(c, "(Image #%d) Premature end of image (expected %d bytes, found %d)",
405 pg->image_num, (int)expected_image_size, (int)pg->image_len);
406 return;
408 if(pg->image_len > expected_image_size) {
409 de_warn(c, "(Image #%d) Extra image data found (expected %d bytes, found %d)",
410 pg->image_num, (int)expected_image_size, (int)pg->image_len);
414 pg->mask_ref = find_mask(c, d, pg);
416 de_snprintf(pg->filename_token, sizeof(pg->filename_token), "%dx%dx%d",
417 (int)pg->type_info->width, (int)pg->type_info->height, (int)pg->type_info->bpp);
419 de_dbg(c, "image dimensions: %d"DE_CHAR_TIMES"%d, bpp: %d",
420 pg->type_info->width, pg->type_info->height, pg->type_info->bpp);
422 if(pg->type_info->bpp==1 || pg->type_info->bpp==4 || pg->type_info->bpp==8) {
423 do_decode_1_4_8bit(c, d, pg);
424 return;
426 else if(pg->type_info->bpp==24) {
427 do_decode_24bit(c, d, pg);
428 return;
431 de_warn(c, "(Image #%d) Image type '%s' is not supported", pg->image_num, pg->code4cc.id_sanitized_sz);
434 static void de_run_icns_pass(deark *c, lctx *d, int pass)
436 i64 segment_pos;
437 struct page_ctx *pg = NULL;
438 int image_count;
440 segment_pos = 8;
441 image_count = 0;
443 while(1) {
444 i64 segment_len;
446 if(pg) { de_free(c, pg); pg=NULL; }
448 if(segment_pos+8 > d->file_size) break;
450 pg = de_malloc(c, sizeof(struct page_ctx));
451 pg->image_num = image_count;
453 dbuf_read_fourcc(c->infile, segment_pos, &pg->code4cc, 4, 0x0);
455 segment_len = de_getu32be(segment_pos+4);
457 pg->image_pos = segment_pos + 8;
458 pg->image_len = segment_len - 8;
460 if(pass==2) {
461 de_dbg(c, "image #%d, type '%s', at %d, size=%d", pg->image_num, pg->code4cc.id_dbgstr,
462 (int)pg->image_pos, (int)pg->image_len);
464 if(segment_len<8 || segment_pos+segment_len > d->file_size) {
465 if(pass==2) {
466 de_err(c, "Invalid length for segment '%s' (%u)", pg->code4cc.id_sanitized_sz,
467 (unsigned int)segment_len);
469 break;
472 if(pass==2) {
473 size_t i;
475 // Find this type code in the image_type_info array
476 pg->type_info = NULL;
477 for(i=0; i<DE_ARRAYCOUNT(image_type_info_arr); i++) {
478 if(image_type_info_arr[i].code==pg->code4cc.id) {
479 pg->type_info = &image_type_info_arr[i];
480 break;
483 if(!pg->type_info) {
484 de_warn(c, "(Image #%d) Unknown image type '%s'", pg->image_num, pg->code4cc.id_sanitized_sz);
488 if(pass==1) {
489 switch(pg->code4cc.id) {
490 case 0x69636d23: // icm# 16x12x1
491 do_read_mask(c, d, pg, MASKTYPEID_16_12_1, 1, 16, 12);
492 break;
493 case 0x69637323: // ics# 16x16x1
494 do_read_mask(c, d, pg, MASKTYPEID_16_16_1, 1, 16, 16);
495 break;
496 case 0x49434e23: // ICN# 32x32x1
497 do_read_mask(c, d, pg, MASKTYPEID_32_32_1, 1, 32, 32);
498 break;
499 case 0x69636823: // ich# 48x48x1
500 do_read_mask(c, d, pg, MASKTYPEID_48_48_1, 1, 48, 48);
501 break;
502 case 0x73386d6b: // s8mk 16x16x8
503 do_read_mask(c, d, pg, MASKTYPEID_16_16_8, 8, 16, 16);
504 break;
505 case 0x6c386d6b: // l8mk 32x32x8
506 do_read_mask(c, d, pg, MASKTYPEID_32_32_8, 8, 32, 32);
507 break;
508 case 0x68386d6b: // h8mk 48x48x8
509 do_read_mask(c, d, pg, MASKTYPEID_48_48_8, 8, 48, 48);
510 break;
511 case 0x74386d6b: // t8mk 128x128x8
512 do_read_mask(c, d, pg, MASKTYPEID_128_128_8, 8, 128, 128);
513 break;
516 else if(pass==2) {
517 de_dbg_indent(c, 1);
518 do_icon(c, d, pg);
519 de_dbg_indent(c, -1);
522 image_count++;
523 segment_pos += segment_len;
526 if(pg) de_free(c, pg);
529 static void de_run_icns(deark *c, de_module_params *mparams)
531 lctx *d = NULL;
533 d = de_malloc(c, sizeof(lctx));
535 d->file_size = de_getu32be(4);
536 de_dbg(c, "reported file size: %d", (int)d->file_size);
537 if(d->file_size > c->infile->len) d->file_size = c->infile->len;
539 de_dbg(c, "pass 1: reading masks");
540 de_dbg_indent(c, 1);
541 de_run_icns_pass(c, d, 1);
542 de_dbg_indent(c, -1);
543 de_dbg(c, "pass 2: decoding/extracting icons");
544 de_dbg_indent(c, 1);
545 de_run_icns_pass(c, d, 2);
546 de_dbg_indent(c, -1);
548 if(d) {
549 int i;
551 for(i=0; i<NUM_MASKTYPES; i++) {
552 if(d->mask[i].img) {
553 de_bitmap_destroy(d->mask[i].img);
554 d->mask[i].img = NULL;
557 de_free(c, d);
561 static int de_identify_icns(deark *c)
563 i64 fsize;
565 if(dbuf_memcmp(c->infile, 0, "icns", 4)) return 0;
567 fsize = de_getu32be(4);
568 if(fsize == c->infile->len) return 100;
569 return 20;
572 void de_module_icns(deark *c, struct deark_module_info *mi)
574 mi->id = "icns";
575 mi->desc = "Macintosh icon";
576 mi->run_fn = de_run_icns;
577 mi->identify_fn = de_identify_icns;