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 de_color g_stdpal16
[16] = {
12 0xffffffffU
,0xfffcf305U
,0xffff6402U
,0xffdd0806U
,0xfff20884U
,0xff4600a5U
,0xff0000d4U
,0xff02abeaU
,
13 0xff1fb714U
,0xff006411U
,0xff562c05U
,0xff90713aU
,0xffc0c0c0U
,0xff808080U
,0xff404040U
,0xff000000U
16 #define IMGTYPE_EMBEDDED_FILE 1 // JP2 or PNG
17 #define IMGTYPE_MASK 2
18 #define IMGTYPE_IMAGE 3
19 #define IMGTYPE_IMAGE_AND_MASK 4
20 #define IMGTYPE_ARGB_ETC 5 // ARGB or JP2 or PNG
31 struct image_type_info
{
35 int bpp
; // bits per pixel. 0 = unspecified
36 int image_type
; // IMGTYPE_*
38 static const struct image_type_info image_type_info_arr
[] = {
39 { 0x69636d23, 16, 12, 1, IMGTYPE_IMAGE_AND_MASK
}, // icm#
40 { 0x69637323, 16, 16, 1, IMGTYPE_IMAGE_AND_MASK
}, // ics#
41 { 0x49434e23, 32, 32, 1, IMGTYPE_IMAGE_AND_MASK
}, // ICN#
42 { 0x69636823, 48, 48, 1, IMGTYPE_IMAGE_AND_MASK
}, // ich#
44 { 0x49434f4e, 32, 32, 1, IMGTYPE_IMAGE
}, // ICON
45 { 0x69636d34, 16, 12, 4, IMGTYPE_IMAGE
}, // icm4
46 { 0x69637334, 16, 16, 4, IMGTYPE_IMAGE
}, // ics4
47 { 0x69636c34, 32, 32, 4, IMGTYPE_IMAGE
}, // icl4
48 { 0x69636834, 48, 48, 4, IMGTYPE_IMAGE
}, // ich4
49 { 0x69636d38, 16, 12, 8, IMGTYPE_IMAGE
}, // icm8
50 { 0x69637338, 16, 16, 8, IMGTYPE_IMAGE
}, // ics8
51 { 0x69636c38, 32, 32, 8, IMGTYPE_IMAGE
}, // icl8
52 { 0x69636838, 48, 48, 8, IMGTYPE_IMAGE
}, // ich8
53 { 0x69733332, 16, 16, 24, IMGTYPE_IMAGE
}, // is32
54 { 0x696c3332, 32, 32, 24, IMGTYPE_IMAGE
}, // il32
55 { 0x69683332, 48, 48, 24, IMGTYPE_IMAGE
}, // ih32
56 { 0x69743332, 128, 128, 24, IMGTYPE_IMAGE
}, // it32
58 { 0x73386d6b, 16, 16, 8, IMGTYPE_MASK
}, // s8mk
59 { 0x6c386d6b, 32, 32, 8, IMGTYPE_MASK
}, // l8mk
60 { 0x68386d6b, 48, 48, 8, IMGTYPE_MASK
}, // h8mk
61 { 0x74386d6b, 128, 128, 8, IMGTYPE_MASK
}, // t8mk
63 { 0x69637034, 16, 16, 0, IMGTYPE_EMBEDDED_FILE
}, // icp4
64 { 0x69637035, 32, 32, 0, IMGTYPE_EMBEDDED_FILE
}, // icp5
65 { 0x69637036, 64, 64, 0, IMGTYPE_EMBEDDED_FILE
}, // icp6
66 { 0x69633037, 128, 128, 0, IMGTYPE_EMBEDDED_FILE
}, // ic07
67 { 0x69633038, 256, 256, 0, IMGTYPE_EMBEDDED_FILE
}, // ic08
68 { 0x69633039, 512, 512, 0, IMGTYPE_EMBEDDED_FILE
}, // ic09
69 { 0x69633130, 1024, 1024, 0, IMGTYPE_EMBEDDED_FILE
}, // ic10
70 { 0x69633131, 32, 32, 0, IMGTYPE_EMBEDDED_FILE
}, // ic11
71 { 0x69633132, 64, 64, 0, IMGTYPE_EMBEDDED_FILE
}, // ic12
72 { 0x69633133, 256, 256, 0, IMGTYPE_EMBEDDED_FILE
}, // ic13
73 { 0x69633134, 512, 512, 0, IMGTYPE_EMBEDDED_FILE
}, // ic14
74 { 0x73623234, 24, 24, 0, IMGTYPE_EMBEDDED_FILE
}, // sb24
75 { 0x69637342, 36, 36, 0, IMGTYPE_EMBEDDED_FILE
}, // icsB
76 { 0x53423234, 48, 48, 0, IMGTYPE_EMBEDDED_FILE
}, // SB24
78 { 0x69633034, 16, 16, 0, IMGTYPE_ARGB_ETC
}, // ic04
79 { 0x69633035, 32, 32, 0, IMGTYPE_ARGB_ETC
}, // ic05
80 { 0x69637362, 18, 18, 0, IMGTYPE_ARGB_ETC
}, // icsb
82 { 0x544f4320, 0, 0, 0, 0 }, // 'TOC '
83 { 0x69636e56, 0, 0, 0, 0 } // icnV
99 struct mask_wrapper
*mask_ref
; // (pointer to a d->mask field; do not free)
101 const struct image_type_info
*type_info
;
102 struct de_fourcc code4cc
;
103 enum content_enum content_type
; // Used when code4cc is insufficient
104 char filename_token
[32];
108 #define MASKTYPEID_16_12_1 0
109 #define MASKTYPEID_16_16_1 1
110 #define MASKTYPEID_32_32_1 2
111 #define MASKTYPEID_48_48_1 3
112 #define MASKTYPEID_16_16_8 4
113 #define MASKTYPEID_32_32_8 5
114 #define MASKTYPEID_48_48_8 6
115 #define MASKTYPEID_128_128_8 7
116 #define NUM_MASKTYPES 8
118 typedef struct localctx_struct
{
124 struct mask_wrapper mask
[NUM_MASKTYPES
];
126 de_color stdpal256
[256];
129 static const de_color supplpal256
[41] = {
130 0xffee0000U
,0xffdd0000U
,0xffbb0000U
,0xffaa0000U
,0xff880000U
,
131 0xff770000U
,0xff550000U
,0xff440000U
,0xff220000U
,0xff110000U
,
132 0xff00ee00U
,0xff00dd00U
,0xff00bb00U
,0xff00aa00U
,0xff008800U
,
133 0xff007700U
,0xff005500U
,0xff004400U
,0xff002200U
,0xff001100U
,
134 0xff0000eeU
,0xff0000ddU
,0xff0000bbU
,0xff0000aaU
,0xff000088U
,
135 0xff000077U
,0xff000055U
,0xff000044U
,0xff000022U
,0xff000011U
,
136 0xffeeeeeeU
,0xffddddddU
,0xffbbbbbbU
,0xffaaaaaaU
,0xff888888U
,
137 0xff777777U
,0xff555555U
,0xff444444U
,0xff222222U
,0xff111111U
,0xff000000U
140 static de_color
getpal256(int k
)
144 if(k
<0 || k
>255) return 0;
146 // The first 215 palette entries follow a simple pattern.
147 r
= (u8
)((5-k
/36)*0x33);
148 g
= (5-(k
%36)/6)*0x33;
150 return DE_MAKE_RGB(r
,g
,b
);
153 return supplpal256
[k
-215];
156 static void populate_stdpal256(lctx
*d
)
160 if(d
->have_stdpal256
) return;
161 d
->have_stdpal256
= 1;
163 for(k
=0; k
<256; k
++) {
164 d
->stdpal256
[k
] = getpal256(k
);
168 static void do_decode_1_4_8bit(deark
*c
, lctx
*d
, struct page_ctx
*pg
)
170 de_bitmap
*img
= NULL
;
173 bypp
= (pg
->type_info
->bpp
==1)?2:4;
174 img
= de_bitmap_create(c
, pg
->type_info
->width
, pg
->type_info
->height
, bypp
);
176 if(pg
->type_info
->bpp
==8) {
177 populate_stdpal256(d
);
178 de_memcpy(pg
->pal
, d
->stdpal256
, sizeof(d
->stdpal256
));
180 else if(pg
->type_info
->bpp
==4) {
181 de_memcpy(pg
->pal
, g_stdpal16
, sizeof(g_stdpal16
));
184 pg
->pal
[0] = DE_STOCKCOLOR_WHITE
;
185 pg
->pal
[1] = DE_STOCKCOLOR_BLACK
;
188 de_convert_image_paletted(c
->infile
, pg
->image_pos
, pg
->type_info
->bpp
, pg
->rowspan
,
191 if(pg
->mask_ref
&& pg
->mask_ref
->img
) {
192 de_bitmap_apply_mask(img
, pg
->mask_ref
->img
, 0);
195 de_bitmap_write_to_file(img
, pg
->filename_token
, DE_CREATEFLAG_OPT_IMAGE
);
196 de_bitmap_destroy(img
);
199 static void do_uncompress_24(deark
*c
, lctx
*d
, struct page_ctx
*pg
, dbuf
*unc_pixels
,
211 if(pos
>= pg
->image_pos
+ pg
->image_len
) break;
217 count
= (i64
)b
- 125;
220 dbuf_write_run(unc_pixels
, n
, count
);
223 // An uncompressed run
225 dbuf_copy(c
->infile
, pos
, count
, unc_pixels
);
231 static void read_image_plane(deark
*c
, lctx
*d
,
232 dbuf
*unc_pixels
, i64 plane
, de_bitmap
*img
, i64 samplenum
)
244 v
= dbuf_getbyte(unc_pixels
, (plane
*h
+j
)*w
+ i
);
245 de_bitmap_setsample(img
, i
, j
, samplenum
, v
);
250 static void do_decode_24bit(deark
*c
, lctx
*d
, struct page_ctx
*pg
)
252 dbuf
*unc_pixels
= NULL
;
253 de_bitmap
*img
= NULL
;
257 w
= pg
->type_info
->width
;
258 h
= pg
->type_info
->height
;
260 // TODO: Try to support uncompressed 24-bit images, assuming they exist.
262 // Apparently, some 'it32' icons begin with four extra 0x00 bytes.
263 // Skip over the first four bytes if they are 0x00.
264 // (I don't know the reason for these bytes, but this is the same
265 // logic libicns uses.)
267 if(pg
->code4cc
.id
==0x69743332) { // 'it32' (128x128)
268 if(!dbuf_memcmp(c
->infile
, pg
->image_pos
, "\0\0\0\0", 4)) {
273 unc_pixels
= dbuf_create_membuf(c
, w
*h
*3, 1);
274 do_uncompress_24(c
, d
, pg
, unc_pixels
, skip
);
276 img
= de_bitmap_create(c
, w
, h
, 4);
278 de_bitmap_rect(img
, 0, 0, w
, h
, DE_STOCKCOLOR_BLACK
, 0);
279 read_image_plane(c
, d
, unc_pixels
, 0, img
, 0);
280 read_image_plane(c
, d
, unc_pixels
, 1, img
, 1);
281 read_image_plane(c
, d
, unc_pixels
, 2, img
, 2);
283 if(pg
->mask_ref
&& pg
->mask_ref
->img
) {
284 de_bitmap_apply_mask(img
, pg
->mask_ref
->img
, 0);
287 de_bitmap_write_to_file(img
, pg
->filename_token
, DE_CREATEFLAG_OPT_IMAGE
);
288 de_bitmap_destroy(img
);
289 if(unc_pixels
) dbuf_close(unc_pixels
);
292 // Sets pg->content_type
293 static void identify_content(deark
*c
, lctx
*d
, struct page_ctx
*pg
)
297 if(pg
->content_type
!=CONTENT_UNSET
) return;
299 // Read the first few bytes
300 de_read(buf
, pg
->image_pos
, sizeof(buf
));
302 if(buf
[4]=='j' && buf
[5]=='P') {
303 pg
->content_type
= CONTENT_JP2
;
305 else if(buf
[0]==0xff && buf
[1]==0x4f && buf
[2]==0xff && buf
[3]==0x51) {
306 pg
->content_type
= CONTENT_J2C
;
308 else if(buf
[0]==0x89 && buf
[1]==0x50) {
309 pg
->content_type
= CONTENT_PNG
;
311 else if(buf
[0]=='A' && buf
[1]=='R' && buf
[2]=='G' && buf
[3]=='B') {
312 pg
->content_type
= CONTENT_ARGB
;
315 pg
->content_type
= CONTENT_UNKNOWN
;
319 // Call this only after the PNG or JP2 format has been identified.
320 static void do_extract_png_or_jp2(deark
*c
, lctx
*d
, struct page_ctx
*pg
)
325 if(pg
->content_type
==CONTENT_JP2
) {
328 else if(pg
->content_type
==CONTENT_J2C
) {
331 else if(pg
->content_type
==CONTENT_PNG
) {
338 fi
= de_finfo_create(c
);
340 de_snprintf(pg
->filename_token
, sizeof(pg
->filename_token
), "%dx%d",
341 (int)pg
->type_info
->width
, (int)pg
->type_info
->height
);
342 de_finfo_set_name_from_sz(c
, fi
, pg
->filename_token
, 0, DE_ENCODING_ASCII
);
344 dbuf_create_file_from_slice(c
->infile
, pg
->image_pos
, pg
->image_len
, ext
, fi
, 0);
347 de_finfo_destroy(c
, fi
);
350 static void do_argb(deark
*c
, lctx
*d
, struct page_ctx
*pg
)
352 dbuf
*unc_pixels
= NULL
;
353 de_bitmap
*img
= NULL
;
356 w
= pg
->type_info
->width
;
357 h
= pg
->type_info
->height
;
359 unc_pixels
= dbuf_create_membuf(c
, w
*h
*4, 1);
360 do_uncompress_24(c
, d
, pg
, unc_pixels
, 4);
362 img
= de_bitmap_create(c
, w
, h
, 4);
364 read_image_plane(c
, d
, unc_pixels
, 0, img
, 3);
365 read_image_plane(c
, d
, unc_pixels
, 1, img
, 0);
366 read_image_plane(c
, d
, unc_pixels
, 2, img
, 1);
367 read_image_plane(c
, d
, unc_pixels
, 3, img
, 2);
369 de_snprintf(pg
->filename_token
, sizeof(pg
->filename_token
), "%dx%dx32",
372 de_bitmap_write_to_file(img
, pg
->filename_token
, DE_CREATEFLAG_OPT_IMAGE
);
373 de_bitmap_destroy(img
);
374 if(unc_pixels
) dbuf_close(unc_pixels
);
377 static void do_argb_png_or_jp2(deark
*c
, lctx
*d
, struct page_ctx
*pg
)
379 identify_content(c
, d
, pg
);
381 if(pg
->type_info
->image_type
==IMGTYPE_ARGB_ETC
&& pg
->content_type
==CONTENT_ARGB
) {
386 de_dbg(c
, "Trying to extract file at %"I64_FMT
, pg
->image_pos
);
388 if(pg
->content_type
==CONTENT_JP2
|| pg
->content_type
==CONTENT_J2C
||
389 pg
->content_type
==CONTENT_PNG
)
391 do_extract_png_or_jp2(c
, d
, pg
);
395 de_err(c
, "(Image #%d) Unidentified file format", pg
->image_num
);
398 // Assumes image_type is IMAGE or IMAGE_AND_MASK.
399 static struct mask_wrapper
*find_mask(deark
*c
, lctx
*d
, struct page_ctx
*pg
)
401 struct mask_wrapper
*mw
= NULL
;
402 struct mask_wrapper
*mw1
= NULL
;
403 struct mask_wrapper
*mw8
= NULL
;
404 const struct image_type_info
*t
;
410 // TODO: What is the correct way to match masks to images?
412 if(t
->code
==0x49434f4e) { // 'ICON'
413 // I'm assuming this format doesn't have a mask.
417 if(t
->width
==16 && t
->height
==12 && t
->bpp
<=8) {
418 mw1
= &d
->mask
[MASKTYPEID_16_12_1
];
421 if(t
->width
==16 && t
->height
==16) {
422 mw1
= &d
->mask
[MASKTYPEID_16_16_1
];
423 mw8
= &d
->mask
[MASKTYPEID_16_16_8
];
427 mw1
= &d
->mask
[MASKTYPEID_32_32_1
];
428 mw8
= &d
->mask
[MASKTYPEID_32_32_8
];
432 mw1
= &d
->mask
[MASKTYPEID_48_48_1
];
433 mw8
= &d
->mask
[MASKTYPEID_48_48_8
];
437 mw8
= &d
->mask
[MASKTYPEID_128_128_8
];
459 if(mw1
&& mw1
->img
) mw
= mw1
;
463 if(mw8
&& mw8
->img
) mw
= mw8
;
467 found_mask
= (mw
&& mw
->img
);
468 if(!found_mask
) goto notfound
;
470 if(t
->image_type
==IMGTYPE_IMAGE_AND_MASK
&& mw
==mw1
) {
471 // Sanity check. This could fail if there are multiple icons of
473 if(pg
->segment_pos
!= mw
->segment_pos
) {
479 de_dbg(c
, "[using mask at %"I64_FMT
"]", mw
->segment_pos
);
483 de_dbg(c
, "[no mask found for icon at %"I64_FMT
"]", pg
->segment_pos
);
487 static void convert_image_gray8(dbuf
*f
, i64 fpos
, i64 rowspan
, de_bitmap
*img
)
491 for(j
=0; j
<img
->height
; j
++) {
492 for(i
=0; i
<img
->width
; i
++) {
495 n
= dbuf_getbyte(f
, fpos
+j
*rowspan
+i
);
496 de_bitmap_setpixel_gray(img
, i
, j
, n
);
501 static void do_read_mask(deark
*c
, lctx
*d
, struct page_ctx
*pg
, int masktype_id
,
502 int depth
, i64 w
, i64 h
)
507 int saved_indent_level
;
509 de_dbg_indent_save(c
, &saved_indent_level
);
513 mask_offset
= rowspan
*h
;
520 de_dbg(c
, "mask(%d"DE_CHAR_TIMES
"%d,%d) segment at %"I64_FMT
", mask at %"I64_FMT
"+%"I64_FMT
,
521 (int)w
, (int)h
, depth
, pg
->segment_pos
, pg
->image_pos
, mask_offset
);
524 if(d
->mask
[masktype_id
].img
) {
525 de_dbg(c
, "duplicate mask type %u", (UI
)masktype_id
);
526 de_bitmap_destroy(d
->mask
[masktype_id
].img
);
528 d
->mask
[masktype_id
].img
= de_bitmap_create(c
, w
, h
, 1);
529 d
->mask
[masktype_id
].segment_pos
= pg
->segment_pos
;
530 img
= d
->mask
[masktype_id
].img
;
533 de_convert_image_bilevel(c
->infile
, pg
->image_pos
+mask_offset
, rowspan
, img
, 0);
536 convert_image_gray8(c
->infile
, pg
->image_pos
+mask_offset
, rowspan
, img
);
539 de_dbg_indent_restore(c
, saved_indent_level
);
542 static void do_icon(deark
*c
, lctx
*d
, struct page_ctx
*pg
)
544 i64 expected_image_size
;
547 if(!pg
->type_info
) return; // Shouldn't happen.
549 de_strlcpy(pg
->filename_token
, "", sizeof(pg
->filename_token
));
551 if(pg
->type_info
->image_type
==IMGTYPE_MASK
) {
552 de_dbg(c
, "[transparency mask]");
556 if(pg
->type_info
->image_type
==IMGTYPE_EMBEDDED_FILE
||
557 pg
->type_info
->image_type
==IMGTYPE_ARGB_ETC
)
559 do_argb_png_or_jp2(c
, d
, pg
);
563 if(pg
->type_info
->image_type
!=IMGTYPE_IMAGE
&&
564 pg
->type_info
->image_type
!=IMGTYPE_IMAGE_AND_MASK
)
569 // At this point we know it's a regular image (or an image+mask)
571 // Note - This pg->rowspan is arguably incorrect for 24-bit images, since
572 // rows aren't stored contiguously.
573 pg
->rowspan
= ((pg
->type_info
->bpp
* pg
->type_info
->width
)+7)/8;
575 expected_image_size
= pg
->rowspan
* pg
->type_info
->height
;
576 if(pg
->type_info
->image_type
==IMGTYPE_IMAGE_AND_MASK
) {
577 expected_image_size
*= 2;
580 is_compressed
= (pg
->type_info
->bpp
==24) ? 1 : 0;
583 if(pg
->image_len
< expected_image_size
) {
584 de_err(c
, "(Image #%d) Premature end of image (expected %d bytes, found %d)",
585 pg
->image_num
, (int)expected_image_size
, (int)pg
->image_len
);
588 if(pg
->image_len
> expected_image_size
) {
589 de_warn(c
, "(Image #%d) Extra image data found (expected %d bytes, found %d)",
590 pg
->image_num
, (int)expected_image_size
, (int)pg
->image_len
);
594 pg
->mask_ref
= find_mask(c
, d
, pg
);
596 de_snprintf(pg
->filename_token
, sizeof(pg
->filename_token
), "%dx%dx%d",
597 (int)pg
->type_info
->width
, (int)pg
->type_info
->height
, (int)pg
->type_info
->bpp
);
599 de_dbg(c
, "image dimensions: %d"DE_CHAR_TIMES
"%d, bpp: %d",
600 pg
->type_info
->width
, pg
->type_info
->height
, pg
->type_info
->bpp
);
602 if(pg
->type_info
->bpp
==1 || pg
->type_info
->bpp
==4 || pg
->type_info
->bpp
==8) {
603 do_decode_1_4_8bit(c
, d
, pg
);
606 else if(pg
->type_info
->bpp
==24) {
607 do_decode_24bit(c
, d
, pg
);
611 de_warn(c
, "(Image #%d) Image type '%s' is not supported", pg
->image_num
, pg
->code4cc
.id_sanitized_sz
);
614 static void de_run_icns_pass(deark
*c
, lctx
*d
, int pass
)
617 struct page_ctx
*pg
= NULL
;
619 int saved_indent_level
;
621 de_dbg_indent_save(c
, &saved_indent_level
);
628 if(pg
) { de_free(c
, pg
); pg
=NULL
; }
630 if(segment_pos
+8 > d
->file_size
) break;
632 pg
= de_malloc(c
, sizeof(struct page_ctx
));
633 pg
->segment_pos
= segment_pos
;
634 pg
->image_num
= image_count
;
636 dbuf_read_fourcc(c
->infile
, segment_pos
, &pg
->code4cc
, 4, 0x0);
638 segment_len
= de_getu32be(segment_pos
+4);
640 pg
->image_pos
= segment_pos
+ 8;
641 pg
->image_len
= segment_len
- 8;
644 de_dbg(c
, "image #%d, type '%s', segment at %"I64_FMT
", image at %"I64_FMT
", size=%"I64_FMT
,
645 pg
->image_num
, pg
->code4cc
.id_dbgstr
,
646 pg
->segment_pos
, pg
->image_pos
, pg
->image_len
);
650 if(segment_len
<8 || segment_pos
+segment_len
> d
->file_size
) {
652 de_err(c
, "Invalid length for segment '%s' (%u)", pg
->code4cc
.id_sanitized_sz
,
653 (unsigned int)segment_len
);
660 de_dbg(c
, "[empty icon]");
668 // Find this type code in the image_type_info array
669 pg
->type_info
= NULL
;
670 for(i
=0; i
<DE_ARRAYCOUNT(image_type_info_arr
); i
++) {
671 if(image_type_info_arr
[i
].code
==pg
->code4cc
.id
) {
672 pg
->type_info
= &image_type_info_arr
[i
];
677 de_warn(c
, "(Image #%d) Unknown image type '%s'", pg
->image_num
, pg
->code4cc
.id_sanitized_sz
);
682 de_dbg_indent(c
, -1);
683 switch(pg
->code4cc
.id
) {
684 case 0x69636d23: // icm# 16x12x1
685 do_read_mask(c
, d
, pg
, MASKTYPEID_16_12_1
, 1, 16, 12);
687 case 0x69637323: // ics# 16x16x1
688 do_read_mask(c
, d
, pg
, MASKTYPEID_16_16_1
, 1, 16, 16);
690 case 0x49434e23: // ICN# 32x32x1
691 do_read_mask(c
, d
, pg
, MASKTYPEID_32_32_1
, 1, 32, 32);
693 case 0x69636823: // ich# 48x48x1
694 do_read_mask(c
, d
, pg
, MASKTYPEID_48_48_1
, 1, 48, 48);
696 case 0x73386d6b: // s8mk 16x16x8
697 do_read_mask(c
, d
, pg
, MASKTYPEID_16_16_8
, 8, 16, 16);
699 case 0x6c386d6b: // l8mk 32x32x8
700 do_read_mask(c
, d
, pg
, MASKTYPEID_32_32_8
, 8, 32, 32);
702 case 0x68386d6b: // h8mk 48x48x8
703 do_read_mask(c
, d
, pg
, MASKTYPEID_48_48_8
, 8, 48, 48);
705 case 0x74386d6b: // t8mk 128x128x8
706 do_read_mask(c
, d
, pg
, MASKTYPEID_128_128_8
, 8, 128, 128);
717 segment_pos
+= segment_len
;
718 de_dbg_indent(c
, -1);
721 if(pg
) de_free(c
, pg
);
722 de_dbg_indent_restore(c
, saved_indent_level
);
725 static void extract_masks(deark
*c
, lctx
*d
)
730 de_dbg(c
, "extracting masks");
731 for(i
=0; i
<NUM_MASKTYPES
; i
++) {
733 de_snprintf(tokenbuf
, sizeof(tokenbuf
), "mask%ux%ux%u",
734 d
->mask
[i
].width
, d
->mask
[i
].height
, (UI
)d
->mask
[i
].nbits
);
735 de_bitmap_write_to_file(d
->mask
[i
].img
, tokenbuf
, DE_CREATEFLAG_OPT_IMAGE
);
740 // FIXME? The way we handle mask type attributes is awkward.
741 // This function was added just for the "getmasks" feature.
742 static void init_masktype_info(lctx
*d
)
750 static const struct mti_struct mti
[NUM_MASKTYPES
] = {
751 { MASKTYPEID_16_12_1
, 1, 16, 12 },
752 { MASKTYPEID_16_16_1
, 1, 16, 16 },
753 { MASKTYPEID_32_32_1
, 1, 32, 32 },
754 { MASKTYPEID_48_48_1
, 1, 48, 48 },
755 { MASKTYPEID_16_16_8
, 8, 16, 16 },
756 { MASKTYPEID_32_32_8
, 8, 32, 32 },
757 { MASKTYPEID_48_48_8
, 8, 48, 48 },
758 { MASKTYPEID_128_128_8
, 8, 128, 128 }
761 for(i
=0; i
<DE_ARRAYCOUNT(mti
); i
++) {
762 d
->mask
[mti
[i
].masktype
].nbits
= mti
[i
].nbits
;
763 d
->mask
[mti
[i
].masktype
].width
= mti
[i
].width
;
764 d
->mask
[mti
[i
].masktype
].height
= mti
[i
].height
;
768 static void de_run_icns(deark
*c
, de_module_params
*mparams
)
773 d
= de_malloc(c
, sizeof(lctx
));
774 init_masktype_info(d
);
776 // (If these options are undocumented, it's because they're still in
777 // development/testing.)
778 // 81 = Use 8-bit mask if present, otherwise 1-bit mask
779 // 18 = Use 1-bit mask if present, otherwise 8-bit mask
780 // 8 = Use 8-bit mask only
781 // 1 = Use 1-bit mask only
782 // 0 = No transparency
784 // TODO: Maybe set opt_mask1 = 81
785 d
->opt_mask1
= 1; // Setting for (most) 1bpp icons
786 d
->opt_mask8
= 81; // Setting for 4 and 8bpp icons
787 d
->opt_mask24
= 81; // Setting for 24bpp icons
788 s
= de_get_ext_option(c
, "icns:mask1");
790 d
->opt_mask1
= (u8
)de_atoi(s
);
792 s
= de_get_ext_option(c
, "icns:mask8");
794 d
->opt_mask8
= (u8
)de_atoi(s
);
796 s
= de_get_ext_option(c
, "icns:mask24");
798 d
->opt_mask24
= (u8
)de_atoi(s
);
801 d
->opt_getmasks
= de_get_ext_option_bool(c
, "icns:getmasks", 0);
803 d
->file_size
= de_getu32be(4);
804 de_dbg(c
, "reported file size: %d", (int)d
->file_size
);
805 if(d
->file_size
> c
->infile
->len
) d
->file_size
= c
->infile
->len
;
807 de_dbg(c
, "pass 1: reading masks");
809 de_run_icns_pass(c
, d
, 1);
810 de_dbg_indent(c
, -1);
812 if(d
->opt_getmasks
) {
817 de_dbg(c
, "pass 2: decoding/extracting icons");
819 de_run_icns_pass(c
, d
, 2);
820 de_dbg_indent(c
, -1);
826 for(i
=0; i
<NUM_MASKTYPES
; i
++) {
828 if(!d
->mask
[i
].used_flag
&& !d
->opt_getmasks
) {
829 de_dbg(c
, "[mask at %"I64_FMT
" was not used]", d
->mask
[i
].segment_pos
);
831 de_bitmap_destroy(d
->mask
[i
].img
);
832 d
->mask
[i
].img
= NULL
;
839 static int de_identify_icns(deark
*c
)
843 if(dbuf_memcmp(c
->infile
, 0, "icns", 4)) return 0;
845 fsize
= de_getu32be(4);
846 if(fsize
== c
->infile
->len
) return 100;
850 static void de_help_icns(deark
*c
)
852 de_msg(c
, "-opt icns:getmasks : Only extract the transparency masks");
855 void de_module_icns(deark
*c
, struct deark_module_info
*mi
)
858 mi
->desc
= "Macintosh icon";
859 mi
->run_fn
= de_run_icns
;
860 mi
->identify_fn
= de_identify_icns
;
861 mi
->help_fn
= de_help_icns
;