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
{
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
77 struct mask_wrapper
*mask_ref
; // (pointer to a d->mask field; do not free)
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
{
96 struct mask_wrapper mask
[NUM_MASKTYPES
];
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
)
114 if(k
<0 || k
>255) return 0;
116 // The first 215 palette entries follow a simple pattern.
117 r
= (u8
)((5-k
/36)*0x33);
118 g
= (5-(k
%36)/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
;
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
];
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
,
174 if(pos
>= pg
->image_pos
+ pg
->image_len
) break;
180 count
= (i64
)b
- 125;
183 dbuf_write_run(unc_pixels
, n
, count
);
186 // An uncompressed run
188 dbuf_copy(c
->infile
, pos
, count
, unc_pixels
);
194 static void do_decode_24bit(deark
*c
, lctx
*d
, struct page_ctx
*pg
)
196 dbuf
*unc_pixels
= NULL
;
197 de_bitmap
*img
= NULL
;
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.)
213 if(pg
->code4cc
.id
==0x69743332) { // 'it32' (128x128)
214 if(!dbuf_memcmp(c
->infile
, pg
->image_pos
, "\0\0\0\0", 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
)
247 de_dbg(c
, "Trying to extract file at %d", (int)pg
->image_pos
);
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);
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
;
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.
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
;
315 static void convert_image_gray8(dbuf
*f
, i64 fpos
, i64 rowspan
, de_bitmap
*img
)
319 for(j
=0; j
<img
->height
; j
++) {
320 for(i
=0; i
<img
->width
; i
++) {
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
)
338 mask_offset
= rowspan
*h
;
345 de_dbg(c
, "mask(%d"DE_CHAR_TIMES
"%d,%d) at %"I64_FMT
"(+%d)", (int)w
, (int)h
, depth
, pg
->image_pos
,
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
;
355 de_convert_image_bilevel(c
->infile
, pg
->image_pos
+mask_offset
, rowspan
, img
, 0);
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
;
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");
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
);
383 if(pg
->type_info
->image_type
!=IMGTYPE_IMAGE
&&
384 pg
->type_info
->image_type
!=IMGTYPE_IMAGE_AND_MASK
)
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;
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
);
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
);
426 else if(pg
->type_info
->bpp
==24) {
427 do_decode_24bit(c
, d
, pg
);
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
)
437 struct page_ctx
*pg
= NULL
;
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;
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
) {
466 de_err(c
, "Invalid length for segment '%s' (%u)", pg
->code4cc
.id_sanitized_sz
,
467 (unsigned int)segment_len
);
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
];
484 de_warn(c
, "(Image #%d) Unknown image type '%s'", pg
->image_num
, pg
->code4cc
.id_sanitized_sz
);
489 switch(pg
->code4cc
.id
) {
490 case 0x69636d23: // icm# 16x12x1
491 do_read_mask(c
, d
, pg
, MASKTYPEID_16_12_1
, 1, 16, 12);
493 case 0x69637323: // ics# 16x16x1
494 do_read_mask(c
, d
, pg
, MASKTYPEID_16_16_1
, 1, 16, 16);
496 case 0x49434e23: // ICN# 32x32x1
497 do_read_mask(c
, d
, pg
, MASKTYPEID_32_32_1
, 1, 32, 32);
499 case 0x69636823: // ich# 48x48x1
500 do_read_mask(c
, d
, pg
, MASKTYPEID_48_48_1
, 1, 48, 48);
502 case 0x73386d6b: // s8mk 16x16x8
503 do_read_mask(c
, d
, pg
, MASKTYPEID_16_16_8
, 8, 16, 16);
505 case 0x6c386d6b: // l8mk 32x32x8
506 do_read_mask(c
, d
, pg
, MASKTYPEID_32_32_8
, 8, 32, 32);
508 case 0x68386d6b: // h8mk 48x48x8
509 do_read_mask(c
, d
, pg
, MASKTYPEID_48_48_8
, 8, 48, 48);
511 case 0x74386d6b: // t8mk 128x128x8
512 do_read_mask(c
, d
, pg
, MASKTYPEID_128_128_8
, 8, 128, 128);
519 de_dbg_indent(c
, -1);
523 segment_pos
+= segment_len
;
526 if(pg
) de_free(c
, pg
);
529 static void de_run_icns(deark
*c
, de_module_params
*mparams
)
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");
541 de_run_icns_pass(c
, d
, 1);
542 de_dbg_indent(c
, -1);
543 de_dbg(c
, "pass 2: decoding/extracting icons");
545 de_run_icns_pass(c
, d
, 2);
546 de_dbg_indent(c
, -1);
551 for(i
=0; i
<NUM_MASKTYPES
; i
++) {
553 de_bitmap_destroy(d
->mask
[i
].img
);
554 d
->mask
[i
].img
= NULL
;
561 static int de_identify_icns(deark
*c
)
565 if(dbuf_memcmp(c
->infile
, 0, "icns", 4)) return 0;
567 fsize
= de_getu32be(4);
568 if(fsize
== c
->infile
->len
) return 100;
572 void de_module_icns(deark
*c
, struct deark_module_info
*mi
)
575 mi
->desc
= "Macintosh icon";
576 mi
->run_fn
= de_run_icns
;
577 mi
->identify_fn
= de_identify_icns
;