1 // This file is part of Deark.
2 // Copyright (C) 2016-2020 Jason Summers
3 // See the file COPYING for terms of use.
5 // IFF-ILBM and related image formats
6 // IFF-ANIM animation format
8 #include <deark-config.h>
9 #include <deark-private.h>
10 #include <deark-fmtutil.h>
11 DE_DECLARE_MODULE(de_module_ilbm
);
12 DE_DECLARE_MODULE(de_module_anim
);
13 DE_DECLARE_MODULE(de_module_deep
);
15 #define ANIM_MAX_FRAMES 10000
17 #define CODE_8SVX 0x38535658U
18 #define CODE_ABIT 0x41424954U
19 #define CODE_ACBM 0x4143424dU
20 #define CODE_ANHD 0x414e4844U
21 #define CODE_ANIM 0x414e494dU
22 #define CODE_ANSQ 0x414e5351U
23 #define CODE_BEAM 0x4245414dU
24 #define CODE_BMHD 0x424d4844U
25 #define CODE_BODY 0x424f4459U
26 #define CODE_CAMG 0x43414d47U
27 #define CODE_CCRT 0x43435254U
28 #define CODE_CLUT 0x434c5554U
29 #define CODE_CMAP 0x434d4150U
30 #define CODE_CRNG 0x43524e47U
31 #define CODE_CTBL 0x4354424cU
32 #define CODE_DLTA 0x444c5441U
33 #define CODE_DPAN 0x4450414eU
34 #define CODE_DPI 0x44504920U
35 #define CODE_DRNG 0x44524e47U
36 #define CODE_FORM 0x464f524dU
37 #define CODE_GRAB 0x47524142U
38 #define CODE_ILBM 0x494c424dU
39 #define CODE_PBM 0x50424d20U
40 #define CODE_PCHG 0x50434847U
41 #define CODE_RGB8 0x52474238U
42 #define CODE_RGBN 0x5247424eU
43 #define CODE_SBDY 0x53424459U
44 #define CODE_SHAM 0x5348414dU
45 #define CODE_TINY 0x54494e59U
46 #define CODE_VDAT 0x56444154U
47 #define CODE_XS24 0x58533234U
51 #define MASKINGTYPE_NONE 0
52 #define MASKINGTYPE_1BITMASK 1
53 #define MASKINGTYPE_COLORKEY 2
54 #define MASKINGTYPE_LASSO 3
57 COLORTYPE_DEFAULT
= 0,
61 // Parameters for a single image, derived from a combination of the global
62 // state and the image context.
66 i64 planes_total
; // Different from planes_fg if MASKINGTYPE_1BITMASK.
69 u8 use_colorkey_transparency
;
71 i64 x_aspect
, y_aspect
;
72 i64 bits_per_row_per_plane
;
73 i64 bytes_per_row_per_plane
;
74 i64 frame_buffer_rowspan
;
75 i64 frame_buffer_size
;
76 enum colortype_enum colortype
;
78 u8 is_pbm
; // frame buffer is PBM pixel format
79 u8 is_rgb24
; // frame buffer is RGB24 pixel format
85 int done_flag
; // Have we processed the image (BODY/DLTA/etc. chunk)?
86 int change_flag
; // Is this frame different from the previous one?
93 typedef struct localctx_ilbm
{
96 char formtype_sanitized_sz
[8];
97 i64 main_chunk_endpos
;
98 int FORM_level
; // nesting level of the frames' FORM chunks
100 int num_frames_started
;
101 int num_frames_finished
;
102 int debug_frame_buffer
;
103 #define TRANS_REMOVE 0
104 #define TRANS_RESPECT 1
111 u8 opt_anim_includedups
;
114 u8 cmap_changed_flag
;
115 u8 bmhd_changed_flag
;
116 u8 camg_changed_flag
;
118 u8 ham_flag
; // "hold and modify"
121 u8 ehb_flag
; // "extra halfbrite"
122 u8 uses_color_cycling
;
123 u8 color_cycling_warned
;
131 u8 uses_anim4_5_xor_mode
;
132 u8 uses_anim_long_data
;
133 u8 multipalette_warned
;
134 u8 extra_content_warned
;
143 UI transparent_color
;
144 i64 x_aspect
, y_aspect
;
146 i64 thumb_width
, thumb_height
;
148 int hotspot_x
, hotspot_y
;
150 struct frame_ctx
*frctx
; // Non-NULL means we're inside a frame
151 struct frame_ctx
*oldfrctx
[2];
152 i64 pal_ncolors
; // Number of colors we read from the file
153 int pal_is_grayscale
;
154 u32 pal_raw
[256]; // Palette as read from the file
155 u32 pal
[256]; // Palette that we will use
156 u8 delta_ops_used
[256];
159 static const char *anim_get_op_name(u8 op
)
161 const char *name
= NULL
;
164 case 0: name
="direct"; break;
165 case ANIM_OP_XOR
: name
="XOR"; break;
166 case 2: name
="long delta"; break;
167 case 3: name
="short delta"; break;
168 case 4: name
="short/long delta"; break;
169 case 5: name
="byte vert. delta"; break;
170 case 7: name
="short/long vert. delta, separated"; break;
171 case 8: name
="short/long vert. delta, contiguous"; break;
172 case 74: name
="ANIM-J (Eric Graham)"; break;
173 case 100: name
="ANIM32"; break;
174 case 101: name
="ANIM16"; break;
175 case 108: name
="ANIM-l (Eric Graham)"; break;
177 return name
?name
:"?";
180 static const char *get_maskingtype_name(u8 n
)
182 const char *name
= NULL
;
185 case MASKINGTYPE_NONE
: name
= "no transparency"; break;
186 case MASKINGTYPE_1BITMASK
: name
= "1-bit transparency mask"; break;
187 case MASKINGTYPE_COLORKEY
: name
= "color-key transparency"; break;
188 case MASKINGTYPE_LASSO
: name
= "lasso"; break;
190 return name
?name
:"?";
193 static const char *get_cmprtype_name(lctx
*d
, u8 n
)
195 const char *name
= NULL
;
197 if(d
->formtype
==CODE_ACBM
) return "n/a";
200 case 0: name
= "uncompressed"; break;
201 case 1: name
= "PackBits"; break;
202 case 2: name
= "VDAT"; break;
204 if(d
->formtype
==CODE_RGBN
|| d
->formtype
==CODE_RGB8
) {
209 return name
?name
:"?";
212 static void on_color_cycling_enabled(deark
*c
, lctx
*d
)
214 d
->uses_color_cycling
= 1;
215 if(d
->color_cycling_warned
) return;
216 de_warn(c
, "This image uses color cycling animation, which is not supported.");
217 d
->color_cycling_warned
= 1;
220 static void on_multipalette_enabled(deark
*c
, lctx
*d
)
222 if(!d
->opt_allowsham
) {
225 if(d
->multipalette_warned
) return;
226 if(d
->opt_allowsham
) {
227 de_warn(c
, "This is a multi-palette image, which is not correctly supported.");
230 de_err(c
, "Multi-palette ILBM images are not supported. "
231 "(\"-opt ilbm:allowspecial\" to decode anyway)");
235 static struct frame_ctx
*create_frame(deark
*c
, lctx
*d
)
237 struct frame_ctx
*frctx
;
238 frctx
= de_malloc(c
, sizeof(struct frame_ctx
));
242 static void destroy_frame(deark
*c
, lctx
*d
, struct frame_ctx
*frctx
)
245 dbuf_close(frctx
->frame_buffer
);
249 static void do_cmap(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
254 d
->cmap_changed_flag
= 1;
256 de_dbg(c
, "number of palette colors: %d", (int)ncolors
);
257 if(ncolors
>256) ncolors
=256;
259 de_read_palette_rgb(c
->infile
, pos
, ncolors
, 3, d
->pal_raw
, 256, 0);
260 if(ncolors
> d
->pal_ncolors
) {
261 d
->pal_ncolors
= ncolors
;
265 static int do_bmhd(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
269 const char *masking_name
;
271 d
->bmhd_changed_flag
= 1;
273 de_err(c
, "Bad BMHD chunk");
278 d
->width
= de_getu16be_p(&pos
);
279 d
->height
= de_getu16be_p(&pos
);
280 de_dbg_dimensions(c
, d
->width
, d
->height
);
283 d
->planes_raw
= (i64
)de_getbyte_p(&pos
);
284 de_dbg(c
, "planes: %d", (int)d
->planes_raw
);
285 d
->masking_code
= de_getbyte_p(&pos
);
286 masking_name
= get_maskingtype_name(d
->masking_code
);
288 d
->compression
= de_getbyte_p(&pos
);
289 de_dbg(c
, "compression: %d (%s)", (int)d
->compression
, get_cmprtype_name(d
, d
->compression
));
292 d
->transparent_color
= (UI
)de_getu16be_p(&pos
);
293 de_dbg(c
, "masking: %d (%s)", (int)d
->masking_code
, masking_name
);
294 if(d
->masking_code
==MASKINGTYPE_COLORKEY
|| d
->masking_code
==MASKINGTYPE_LASSO
) {
296 de_dbg(c
, "color key: %u", d
->transparent_color
);
297 de_dbg_indent(c
, -1);
300 d
->x_aspect
= (i64
)de_getbyte_p(&pos
);
301 d
->y_aspect
= (i64
)de_getbyte_p(&pos
);
302 de_dbg(c
, "aspect ratio: %d, %d", (int)d
->x_aspect
, (int)d
->y_aspect
);
309 static i64
delta3_calc_elem_pos(i64 elemnum
, i64 elemsize
, i64 elems_per_row
, i64 plane_offset
,
310 i64 frame_buffer_rowspan
)
314 row
= elemnum
/ elems_per_row
;
315 col
= elemnum
% elems_per_row
;
316 return row
* frame_buffer_rowspan
+ plane_offset
+ elemsize
* col
;
319 // Note - It should be easy to modify this to work for DLTA#2 compression as well
320 // (need a sample file).
321 static void decompress_plane_delta_op3(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
322 struct frame_ctx
*frctx
, i64 plane
, i64 pos1
, i64 maxlen
)
324 i64 endpos
= pos1
+maxlen
;
334 de_dbg2(c
, "delta3 plane at %"I64_FMT
", maxlen=%"I64_FMT
, pos1
, maxlen
);
336 elems_per_row
= (ibi
->bytes_per_row_per_plane
+ (elemsize
-1) ) / elemsize
;
337 if(elems_per_row
<1) goto done
;
338 elems_total
= elems_per_row
* ibi
->height
;
339 plane_offset
= plane
* ibi
->bytes_per_row_per_plane
;
345 if(elemnum
>= elems_total
) break;
346 if(pos
+2 >= endpos
) goto done
;
347 code
= de_geti16be_p(&pos
);
349 if(code
== -1) { // Stop.
352 else if(code
>= 0) { // Skip some number of elements, then write one element.
353 frctx
->change_flag
= 1;
356 de_read(elembuf
, pos
, elemsize
);
358 dstpos
= delta3_calc_elem_pos(elemnum
, elemsize
, elems_per_row
, plane_offset
,
359 ibi
->frame_buffer_rowspan
);
360 dbuf_write_at(frctx
->frame_buffer
, dstpos
, elembuf
, elemsize
);
362 else { // Skip some number of elements, then write multiple elements.
368 count
= de_getu16be_p(&pos
);
370 frctx
->change_flag
= 1;
372 for(k
=0; k
<count
; k
++) {
373 de_read(elembuf
, pos
, elemsize
);
376 dstpos
= delta3_calc_elem_pos(elemnum
, elemsize
, elems_per_row
, plane_offset
,
377 ibi
->frame_buffer_rowspan
);
378 dbuf_write_at(frctx
->frame_buffer
, dstpos
, elembuf
, elemsize
);
387 // "Short Delta" mode
388 // Decompress into frctx->frame_buffer
389 static void decompress_delta_op3(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
390 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
394 i64 planedata_offs
[8];
396 de_dbg(c
, "[delta3 data]");
399 planedata_offs
[i
] = de_getu32be_p(&pos
);
400 if(i
<ibi
->planes_total
) {
401 de_dbg2(c
, "plane[%d] offs: %"I64_FMT
, (int)i
, planedata_offs
[i
]);
402 if(planedata_offs
[i
]>0) {
403 decompress_plane_delta_op3(c
, d
, ibi
, frctx
, i
,
404 pos1
+planedata_offs
[i
], len
-planedata_offs
[i
]);
410 static i64
get_elem_as_int_p(dbuf
*f
, i64
*ppos
, i64 elem_size
)
413 return (i64
)dbuf_getbyte_p(f
, ppos
);
416 return dbuf_getu16be_p(f
, ppos
);
418 return dbuf_getu32be_p(f
, ppos
);
421 // This routine decompresses most frame types used in DLTA#5, #7, and #8.
422 // For #7, the codestream and datastream are stored separately, and have different
424 // For #5 and #8, datapos1 is not used.
425 static void decompress_plane_vdelta(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
426 struct frame_ctx
*frctx
, i64 plane_idx
,
427 dbuf
*inf
, i64 codepos1
, i64 datapos1
, i64 endpos
,
428 i64 code_size
, i64 dataelem_size
, int separate_data_stream
, u8 xor_mode
)
430 i64 pos
= codepos1
; // If !separate_data_stream, this is for code and data
431 i64 datapos
= datapos1
;
434 i64 dststride
= ibi
->frame_buffer_rowspan
;
436 u8 last_col_quirk
= 0;
437 int baddata_flag
= 0;
439 if(separate_data_stream
) {
440 de_dbg2(c
, "vdelta(%d,%d) plane %d at (%"I64_FMT
",%"I64_FMT
")", (int)code_size
,
441 (int)dataelem_size
, (int)plane_idx
, codepos1
, datapos1
);
444 de_dbg2(c
, "vdelta(%d) plane at (%"I64_FMT
")", (int)code_size
, codepos1
);
446 if(code_size
!=1 && code_size
!=2 && code_size
!=4) goto done
;
447 if(dataelem_size
!=1 && dataelem_size
!=2 && dataelem_size
!=4) goto done
;
448 if(xor_mode
&& dataelem_size
!=1) goto done
;
451 unc_threshold
= 0x80;
453 else if(code_size
==2) {
454 unc_threshold
= 0x8000;
457 unc_threshold
= 0x80000000U
;
460 if(dataelem_size
==1) {
461 num_columns
= (ibi
->width
+7)/8;
463 else if(dataelem_size
==2) {
464 num_columns
= (ibi
->width
+15)/16;
467 num_columns
= (ibi
->width
+31)/32;
470 if(frctx
->op
==8 && dataelem_size
==4) {
471 i64 num_columns_if_size2
;
473 num_columns_if_size2
= (ibi
->width
+15)/16;
474 if(num_columns
*2 != num_columns_if_size2
) {
475 // A dumb quirk of ANIM-8: The last column may use "word" mode,
476 // even when when all other columns use "long" mode.
481 for(col
=0; col
<num_columns
; col
++) {
484 i64 elem_bytes_to_write
;
486 i64 col_start_dstpos
;
487 i64 dataelem_size_thiscol
;
488 i64 code_size_thiscol
;
489 UI unc_threshold_thiscol
;
492 if(c
->debug_level
>=3) {
493 de_dbg3(c
, "col %u at %"I64_FMT
, (UI
)col
, pos
);
496 is_last_col
= (col
+1 == num_columns
);
497 code_size_thiscol
= code_size
;
498 dataelem_size_thiscol
= dataelem_size
;
499 unc_threshold_thiscol
= unc_threshold
;
500 if(is_last_col
&& last_col_quirk
) {
501 code_size_thiscol
= 2;
502 dataelem_size_thiscol
= 2;
503 unc_threshold_thiscol
= 0x8000;
511 // Defend against writing beyond the right edge of this plane
512 if(is_last_col
&& (dataelem_size_thiscol
==4) && (ibi
->bytes_per_row_per_plane
%4)) {
513 elem_bytes_to_write
= 2;
516 elem_bytes_to_write
= dataelem_size_thiscol
;
519 col_start_dstpos
= plane_idx
* ibi
->bytes_per_row_per_plane
+ dataelem_size
*col
;
521 opcount
= get_elem_as_int_p(inf
, &pos
, code_size_thiscol
);
522 if(c
->debug_level
>=3) {
523 de_dbg3(c
, "col %d op count: %"I64_FMT
, (int)col
, opcount
);
526 for(opidx
=0; opidx
<opcount
; opidx
++) {
537 op
= (UI
)get_elem_as_int_p(inf
, &pos
, code_size_thiscol
);
540 count
= get_elem_as_int_p(inf
, &pos
, code_size_thiscol
);
541 if(ypos
+count
> ibi
->height
) {
542 // TODO: Should we tolerate this, and set count = 0?
548 frctx
->change_flag
= 1;
551 if(separate_data_stream
) {
552 if(datapos
>=endpos
) {
556 dbuf_read(inf
, valbuf
, datapos
, dataelem_size_thiscol
);
557 datapos
+= dataelem_size_thiscol
;
560 dbuf_read(inf
, valbuf
, pos
, dataelem_size_thiscol
);
561 pos
+= dataelem_size_thiscol
;
564 for(k
=0; k
<count
; k
++) {
565 dstpos
= col_start_dstpos
+ ypos
*dststride
;
569 val
= valbuf
[0] ^ dbuf_getbyte(frctx
->frame_buffer
, dstpos
);
570 dbuf_writebyte_at(frctx
->frame_buffer
, dstpos
, val
);
573 dbuf_write_at(frctx
->frame_buffer
, dstpos
, valbuf
, elem_bytes_to_write
);
578 else if(op
< unc_threshold_thiscol
) { // skip
581 else { // uncompressed run
582 count
= (i64
)(op
- unc_threshold_thiscol
);
583 if(ypos
+count
> ibi
->height
) {
589 frctx
->change_flag
= 1;
592 for(k
=0; k
<count
; k
++) {
593 if(separate_data_stream
) {
594 if(datapos
>=endpos
) {
598 dbuf_read(inf
, valbuf
, datapos
, dataelem_size_thiscol
);
599 datapos
+= dataelem_size_thiscol
;
602 dbuf_read(inf
, valbuf
, pos
, dataelem_size_thiscol
);
603 pos
+= dataelem_size_thiscol
;
606 dstpos
= col_start_dstpos
+ ypos
*dststride
;
608 valbuf
[0] ^= dbuf_getbyte(frctx
->frame_buffer
, dstpos
);
610 dbuf_write_at(frctx
->frame_buffer
, dstpos
, valbuf
, elem_bytes_to_write
);
618 if(baddata_flag
&& !d
->errflag
) {
619 de_err(c
, "Delta decompression failed");
624 // Decompress into frctx->frame_buffer
625 static void decompress_delta_op5(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
626 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
628 i64 planedata_offs
[16];
631 int saved_indent_level
;
632 u8 delta4_5_xor_mode
= 0;
634 de_dbg_indent_save(c
, &saved_indent_level
);
635 if(!frctx
->frame_buffer
) goto done
;
637 de_dbg(c
, "[delta5 data]");
639 // Note that we ignore the 0x8 bit ("RLC - run length coded").
640 // I don't know what this option is for. *All* ANIM4/5 frames use run length
641 // coding, but they almost never have have this bit set.
642 // The rare files that do set this bit don't seem to be any different from
644 if((frctx
->bits
& 0xfffffff5U
) != 0) {
645 de_err(c
, "Unsupported ANHD options");
650 if(frctx
->bits
& 0x2) {
651 delta4_5_xor_mode
= 1;
654 for(i
=0; i
<16; i
++) {
655 if(d
->errflag
) goto done
;
656 planedata_offs
[i
] = de_getu32be_p(&pos
);
657 if(i
<ibi
->planes_total
) {
658 de_dbg2(c
, "plane[%d] offs: %"I64_FMT
, i
, planedata_offs
[i
]);
659 if(planedata_offs
[i
]>0) {
660 decompress_plane_vdelta(c
, d
, ibi
, frctx
, i
, c
->infile
,
661 pos1
+planedata_offs
[i
], 0, pos1
+len
, 1, 1,
662 0, delta4_5_xor_mode
);
668 de_dbg_indent_restore(c
, saved_indent_level
);
671 // Decompress into frctx->frame_buffer
672 static void decompress_delta_op7(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
673 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
675 i64 opcodelist_offs
[8];
676 i64 datalist_offs
[8];
679 int saved_indent_level
;
683 de_dbg_indent_save(c
, &saved_indent_level
);
684 if(!frctx
->frame_buffer
) goto done
;
686 de_dbg(c
, "[delta7 data]");
688 if(frctx
->bits
& 0xfffffffeU
) {
689 de_err(c
, "Unsupported ANHD options");
693 if(frctx
->bits
& 0x00000001) {
700 // We'll have to interleave lots of short reads between two different segments of
701 // the file, with no way to know how big either segment is.
702 // I see no good way to process this DLTA#7 format, except by first reading the
703 // entire chunk into memory.
704 if(len
> DE_MAX_SANE_OBJECT_SIZE
) {
708 inf
= dbuf_create_membuf(c
, len
, 0);
709 dbuf_copy(c
->infile
, pos1
, len
, inf
);
713 opcodelist_offs
[i
] = dbuf_getu32be_p(inf
, &infpos
);
717 datalist_offs
[i
] = dbuf_getu32be_p(inf
, &infpos
);
721 if(d
->errflag
) goto done
;
722 if(i
<ibi
->planes_total
) {
723 de_dbg2(c
, "opcode_list[%d] offs: %"I64_FMT
, i
, opcodelist_offs
[i
]);
724 de_dbg2(c
, "data_list[%d] offs: %"I64_FMT
, i
, datalist_offs
[i
]);
725 if(opcodelist_offs
[i
]>0) {
726 decompress_plane_vdelta(c
, d
, ibi
, frctx
, i
, inf
,
727 opcodelist_offs
[i
], datalist_offs
[i
], len
,
728 1, dataelem_size
, 1, 0);
735 de_dbg_indent_restore(c
, saved_indent_level
);
738 static void decompress_delta_op8(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
739 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
741 i64 planedata_offs
[16];
745 int saved_indent_level
;
747 de_dbg_indent_save(c
, &saved_indent_level
);
748 if(!frctx
->frame_buffer
) goto done
;
750 de_dbg(c
, "[delta8 data]");
752 if(frctx
->bits
& 0xfffffffeU
) {
753 de_err(c
, "Unsupported ANHD options");
757 if(frctx
->bits
& 0x00000001) {
764 for(i
=0; i
<16; i
++) {
765 if(d
->errflag
) goto done
;
766 planedata_offs
[i
] = de_getu32be_p(&pos
);
767 if(i
<ibi
->planes_total
) {
768 de_dbg2(c
, "plane[%d] offs: %"I64_FMT
, i
, planedata_offs
[i
]);
769 if(planedata_offs
[i
]>0) {
770 decompress_plane_vdelta(c
, d
, ibi
, frctx
, i
, c
->infile
,
771 pos1
+planedata_offs
[i
], 0, pos1
+len
, elem_size
, elem_size
, 0, 0);
777 de_dbg_indent_restore(c
, saved_indent_level
);
781 struct imgbody_info
*ibi
;
782 struct frame_ctx
*frctx
;
789 i64 nrows
; // block height in rows
790 i64 nbytes
; // block width in bytes per plane
793 static void do_delta74_blocks(deark
*c
, struct d74state
*d74s
)
795 i64 blkidx
, rowidx
, planeidx
, byteidx
;
796 i64 d74_bytes_per_row_per_plane
;
798 // Reportedly, the 'offset' field assumes a potentially-different measuring
799 // system than one would expect.
800 d74_bytes_per_row_per_plane
= (d74s
->ibi
->width
+ 7)/8;
802 for(blkidx
=0; blkidx
<d74s
->nblocks
; blkidx
++) {
804 i64 block_srcpos
= d74s
->pos
;
807 if(d74s
->pos
+2 >= d74s
->endpos
) goto done
;
808 offset
= de_getu16be_p(&d74s
->pos
);
810 block_dstpos
= (offset
/ d74_bytes_per_row_per_plane
) * d74s
->ibi
->frame_buffer_rowspan
+
811 (offset
% d74_bytes_per_row_per_plane
);
813 for(rowidx
=0; rowidx
<d74s
->nrows
; rowidx
++) {
814 for(planeidx
=0; planeidx
<d74s
->ibi
->planes_total
; planeidx
++) {
817 // Calculate the offset in our frame buffer.
818 dstpos
= block_dstpos
+ (rowidx
* d74s
->ibi
->frame_buffer_rowspan
) +
819 planeidx
* d74s
->ibi
->bytes_per_row_per_plane
;
821 for(byteidx
=0; byteidx
<d74s
->nbytes
; byteidx
++) {
824 val
= de_getbyte_p(&d74s
->pos
);
825 if(d74s
->op
) val
^= dbuf_getbyte(d74s
->frctx
->frame_buffer
, dstpos
);
826 dbuf_writebyte_at(d74s
->frctx
->frame_buffer
, dstpos
, val
);
832 if((d74s
->pos
- block_srcpos
) & 0x1) {
833 d74s
->pos
++; // padding byte
841 static void decompress_delta_op74(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
842 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
844 struct d74state d74s
;
846 de_zeromem(&d74s
, sizeof(struct d74state
));
850 d74s
.endpos
= pos1
+len
;
852 if(!d
->delta_ops_used
[74]) { // If this is the first DLTA#7 chunk...
853 if(ibi
->width
< 320) {
854 // The XAnim code says this is a special case, but I haven't found any
855 // sample files. (TODO)
856 de_warn(c
, "ANIM-J with width < 320 might not be supported correctly");
863 if(d74s
.pos
+2 >= d74s
.endpos
) goto done
;
864 code
= (UI
)de_getu16be_p(&d74s
.pos
);
866 frctx
->change_flag
= 1;
867 d74s
.op
= (UI
)de_getu16be_p(&d74s
.pos
);
868 d74s
.nrows
= de_getu16be_p(&d74s
.pos
);
870 d74s
.nblocks
= de_getu16be_p(&d74s
.pos
);
871 do_delta74_blocks(c
, &d74s
);
874 frctx
->change_flag
= 1;
875 d74s
.op
= (UI
)de_getu16be_p(&d74s
.pos
);
876 d74s
.nrows
= de_getu16be_p(&d74s
.pos
);
877 d74s
.nbytes
= de_getu16be_p(&d74s
.pos
);
878 d74s
.nblocks
= de_getu16be_p(&d74s
.pos
);
879 do_delta74_blocks(c
, &d74s
);
885 de_warn(c
, "Bad or unsupported ANIM-J compression code: %u", code
);
895 // Similar to op3, but different in enough ways that it probably isn't worth
896 // combining into one function.
897 static void decompress_plane_delta_op108(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
898 struct frame_ctx
*frctx
, i64 plane_idx
, dbuf
*inf
, i64 codepos1
, i64 datapos1
,
901 i64 codepos
= codepos1
;
902 i64 datapos
= datapos1
;
903 const i64 code_size
= 2;
904 const i64 dataelem_size
= 2;
908 int baddata_flag
= 0;
910 de_dbg2(c
, "delta108 plane %d at (%"I64_FMT
",%"I64_FMT
")", (int)plane_idx
,
913 elems_per_row
= (ibi
->bytes_per_row_per_plane
+ (dataelem_size
-1) ) / dataelem_size
;
914 if(elems_per_row
<1) goto done
;
915 plane_offset
= plane_idx
* ibi
->bytes_per_row_per_plane
;
923 if(codepos
+code_size
> endpos
) goto done
;
924 elemnum
= dbuf_getu16be_p(inf
, &codepos
);
926 if(elemnum
== 0xffff) { // Stop.
930 ypos
= elemnum
/ elems_per_row
;
931 xpos
= elemnum
% elems_per_row
;
932 dstpos
= plane_offset
+ ypos
* ibi
->frame_buffer_rowspan
+ dataelem_size
*xpos
;
934 if(codepos
+code_size
> endpos
) goto done
;
935 count_code
= dbuf_geti16be_p(inf
, &codepos
);
937 if(count_code
< 0) { // an uncompressed run
938 i64 count
= -count_code
;
941 frctx
->change_flag
= 1;
943 if(datapos
+ dataelem_size
> endpos
) {
947 dbuf_read(inf
, elembuf
, datapos
, dataelem_size
);
948 datapos
+= dataelem_size
;
950 for(k
=0; k
<count
; k
++) {
951 if(ypos
>= ibi
->height
) {
956 dbuf_write_at(frctx
->frame_buffer
, dstpos
, elembuf
, dataelem_size
);
958 dstpos
+= ibi
->frame_buffer_rowspan
;
962 i64 count
= count_code
;
965 if(count
> 0) frctx
->change_flag
= 1;
967 for(k
=0; k
<count
; k
++) {
968 if(ypos
>= ibi
->height
) {
972 if(datapos
+ dataelem_size
> endpos
) {
976 dbuf_read(inf
, elembuf
, datapos
, dataelem_size
);
977 datapos
+= dataelem_size
;
979 dbuf_write_at(frctx
->frame_buffer
, dstpos
, elembuf
, dataelem_size
);
981 dstpos
+= ibi
->frame_buffer_rowspan
;
987 if(baddata_flag
&& !d
->errflag
) {
988 de_err(c
, "Delta decompression failed");
993 static void decompress_delta_op108(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
994 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
996 i64 opcodelist_offs
[8];
997 i64 datalist_offs
[8];
1000 int saved_indent_level
;
1003 de_dbg_indent_save(c
, &saved_indent_level
);
1004 if(!frctx
->frame_buffer
) goto done
;
1006 de_dbg(c
, "[delta108 data]");
1008 // Read the entire chunk into memory, so that the random-access reads will be
1010 if(len
> DE_MAX_SANE_OBJECT_SIZE
) {
1014 inf
= dbuf_create_membuf(c
, len
, 0);
1015 dbuf_copy(c
->infile
, pos1
, len
, inf
);
1018 for(i
=0; i
<8; i
++) {
1019 datalist_offs
[i
] = dbuf_getu32be_p(inf
, &infpos
);
1022 for(i
=0; i
<8; i
++) {
1023 opcodelist_offs
[i
] = dbuf_getu32be_p(inf
, &infpos
);
1026 for(i
=0; i
<8; i
++) {
1027 if(d
->errflag
) goto done
;
1028 if(i
<ibi
->planes_total
) {
1029 de_dbg2(c
, "opcode_list[%d] offs: %"I64_FMT
, i
, opcodelist_offs
[i
]);
1030 de_dbg2(c
, "data_list[%d] offs: %"I64_FMT
, i
, datalist_offs
[i
]);
1031 if(opcodelist_offs
[i
]>0) {
1032 decompress_plane_delta_op108(c
, d
, ibi
, frctx
, i
, inf
,
1033 2*opcodelist_offs
[i
], 2*datalist_offs
[i
], len
);
1040 de_dbg_indent_restore(c
, saved_indent_level
);
1043 static void pal_fixup4(deark
*c
, lctx
*d
)
1048 for(k
=0; k
<d
->pal_ncolors
; k
++) {
1049 cr
= DE_COLOR_R(d
->pal
[k
]);
1050 cg
= DE_COLOR_G(d
->pal
[k
]);
1051 cb
= DE_COLOR_B(d
->pal
[k
]);
1055 d
->pal
[k
] = DE_MAKE_RGB(cr
, cg
, cb
);
1059 static void pal_fixup6(deark
*c
, lctx
*d
)
1064 for(k
=0; k
<d
->pal_ncolors
; k
++) {
1065 cr
= DE_COLOR_R(d
->pal
[k
]);
1066 cg
= DE_COLOR_G(d
->pal
[k
]);
1067 cb
= DE_COLOR_B(d
->pal
[k
]);
1068 cr
= (cr
&0xfc)|(cr
>>6);
1069 cg
= (cg
&0xfc)|(cg
>>6);
1070 cb
= (cb
&0xfc)|(cb
>>6);
1071 d
->pal
[k
] = DE_MAKE_RGB(cr
, cg
, cb
);
1075 // It's clear that some ILBM images have palette colors with only 4 bits of
1076 // precision (the low bits often being set to 0), while others have 8, or
1077 // something in between.
1078 // What's not clear is how to tell them apart.
1080 // * HAM6 images always have 4.
1081 // * HAM8 images always have 6.
1082 // * For anything else, assume 4 if the low 4 bits are all 0.
1084 // TODO: It may be safe to assume that 8-plane images always have 8, but
1085 // more research is needed.
1086 static void fixup_palette(deark
*c
, lctx
*d
)
1091 if(d
->pal_ncolors
<1) return;
1092 if(d
->formtype
==CODE_RGBN
|| d
->formtype
==CODE_RGB8
) return;
1103 for(k
=0; k
<d
->pal_ncolors
; k
++) {
1104 cr
= DE_COLOR_R(d
->pal
[k
]);
1105 cg
= DE_COLOR_G(d
->pal
[k
]);
1106 cb
= DE_COLOR_B(d
->pal
[k
]);
1107 if((cr
&0x0f) != 0) return;
1108 if((cg
&0x0f) != 0) return;
1109 if((cb
&0x0f) != 0) return;
1111 de_dbg(c
, "Palette seems to have 4 bits of precision. Rescaling palette.");
1115 // Called when we encounter a BODY or DLTA or TINY chunk
1116 static void do_before_image_chunk(deark
*c
, lctx
*d
)
1118 if(d
->bmhd_changed_flag
|| d
->camg_changed_flag
) {
1120 if(d
->planes_raw
==6 || d
->planes_raw
==5) {
1123 else if(d
->planes_raw
==8 || d
->planes_raw
==7) {
1127 de_warn(c
, "Invalid bit depth (%d) for HAM image.", (int)d
->planes_raw
);
1131 if(!d
->found_cmap
&& d
->planes_raw
<=8) {
1132 de_make_grayscale_palette(d
->pal
, (i64
)1<<(UI
)d
->planes_raw
, 0);
1135 if(d
->planes_raw
==6 && d
->pal_ncolors
==32 && !d
->ehb_flag
&& !d
->ham_flag
) {
1136 de_warn(c
, "Assuming this is an EHB image");
1141 if(d
->cmap_changed_flag
) {
1142 de_memcpy(d
->pal
, d
->pal_raw
, (size_t)d
->pal_ncolors
* sizeof(d
->pal_raw
[0]));
1145 if(d
->cmap_changed_flag
&& d
->ehb_flag
&& d
->planes_raw
==6) {
1148 // TODO: Should we still do this if the palette already has 64 colors
1149 // (as it often does)?
1150 for(k
=0; k
<32; k
++) {
1153 cr
= DE_COLOR_R(d
->pal
[k
]);
1154 cg
= DE_COLOR_G(d
->pal
[k
]);
1155 cb
= DE_COLOR_B(d
->pal
[k
]);
1156 d
->pal
[k
+32] = DE_MAKE_RGB(cr
/2, cg
/2, cb
/2);
1160 if(d
->fixpal_setting
&& d
->cmap_changed_flag
) {
1161 fixup_palette(c
, d
);
1164 if(d
->cmap_changed_flag
) {
1165 d
->pal_is_grayscale
= de_is_grayscale_palette(d
->pal
, 256);
1168 d
->cmap_changed_flag
= 0;
1169 d
->bmhd_changed_flag
= 0;
1170 d
->camg_changed_flag
= 0;
1173 static int init_imgbody_info(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
, int is_thumb
)
1177 ibi
->is_thumb
= is_thumb
;
1179 // Unlike ACBM, it would be messy and slow to convert PBM to the standard ILBM
1180 // frame buffer format (and back). So we support a special frame buffer format
1182 ibi
->is_pbm
= (d
->formtype
==CODE_PBM
);
1183 // We also have a special nonplanar RGB24 format (is_rgb24).
1185 if(d
->formtype
==CODE_RGBN
|| d
->formtype
==CODE_RGB8
) {
1187 if(((d
->formtype
==CODE_RGBN
&& d
->planes_raw
==13) ||
1188 (d
->formtype
==CODE_RGB8
&& d
->planes_raw
==25)) &&
1189 (d
->compression
==3 || d
->compression
==4) &&
1190 d
->masking_code
==MASKINGTYPE_NONE
)
1195 de_err(c
, "Unsupported RGBN/RGB8 format");
1201 ibi
->width
= d
->thumb_width
;
1202 ibi
->height
= d
->thumb_height
;
1205 ibi
->width
= d
->width
;
1206 ibi
->height
= d
->height
;
1209 // Quick & dirty support for -padpix.
1210 // TODO: Some of these conditions could be removed, with care.
1211 if(c
->padpix
&& (d
->width
%16) && !is_thumb
&& !d
->is_anim
&& d
->formtype
==CODE_ILBM
&&
1214 ibi
->width
= de_pad_to_n(ibi
->width
, 16);
1217 ibi
->compression
= d
->compression
;
1219 ibi
->masking_code
= d
->masking_code
;
1220 // Based on what little data I have, it seems that TINY images do not have
1221 // a transparency mask, even if the main image does.
1222 if(is_thumb
&& ibi
->masking_code
==MASKINGTYPE_1BITMASK
) {
1223 ibi
->masking_code
= MASKINGTYPE_NONE
;
1226 if(d
->planes_raw
==24) {
1227 ibi
->colortype
= COLORTYPE_RGB24
;
1230 ibi
->colortype
= COLORTYPE_DEFAULT
;
1233 if(ibi
->is_pbm
|| ibi
->is_rgb24
) {
1235 ibi
->planes_total
= 1;
1238 ibi
->planes_fg
= d
->planes_raw
;
1239 ibi
->planes_total
= d
->planes_raw
;
1240 if(ibi
->masking_code
==MASKINGTYPE_1BITMASK
) {
1241 ibi
->planes_total
++;
1244 ibi
->transparent_color
= d
->transparent_color
;
1245 ibi
->x_aspect
= d
->x_aspect
;
1246 ibi
->y_aspect
= d
->y_aspect
;
1249 if(d
->planes_raw
!=8 || d
->masking_code
==MASKINGTYPE_1BITMASK
) {
1250 de_err(c
, "Not a supported PBM format");
1256 ibi
->bytes_per_row_per_plane
= ibi
->width
;
1257 if(ibi
->bytes_per_row_per_plane
%2) {
1258 ibi
->bytes_per_row_per_plane
++;
1260 ibi
->bits_per_row_per_plane
= ibi
->bytes_per_row_per_plane
* 8;
1261 // Note: The PBM row size might be adjusted later, after decompression.
1263 else if(ibi
->is_rgb24
) {
1264 ibi
->bytes_per_row_per_plane
= ibi
->width
*3;
1265 ibi
->bits_per_row_per_plane
= ibi
->bytes_per_row_per_plane
* 8;
1268 ibi
->bits_per_row_per_plane
= de_pad_to_n(ibi
->width
, 16);
1269 ibi
->bytes_per_row_per_plane
= ibi
->bits_per_row_per_plane
/8;
1271 ibi
->frame_buffer_rowspan
= ibi
->bytes_per_row_per_plane
* ibi
->planes_total
;
1272 ibi
->frame_buffer_size
= ibi
->frame_buffer_rowspan
* ibi
->height
;
1274 if(ibi
->masking_code
==MASKINGTYPE_NONE
) {
1277 else if(ibi
->masking_code
==MASKINGTYPE_COLORKEY
) {
1278 if(ibi
->planes_fg
<=8 && !d
->ham_flag
) {
1279 ibi
->use_colorkey_transparency
= 1;
1282 else if(ibi
->masking_code
==MASKINGTYPE_1BITMASK
) {
1286 de_warn(c
, "This type of transparency is not supported");
1289 if(ibi
->use_colorkey_transparency
&& ibi
->transparent_color
<=255) {
1290 d
->pal
[ibi
->transparent_color
] = DE_SET_ALPHA(d
->pal
[ibi
->transparent_color
], 0);
1293 if(ibi
->colortype
==COLORTYPE_RGB24
) {
1296 else if(ibi
->planes_fg
<1 || ibi
->planes_fg
>8) {
1297 de_err(c
, "Bad or unsupported number of planes: %d", (int)ibi
->planes_fg
);
1306 static void write_frame(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
, struct frame_ctx
*frctx
);
1308 static void do_dlta(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
1310 struct frame_ctx
*frctx
= d
->frctx
;
1311 struct frame_ctx
*reference_frctx
= NULL
;
1312 struct imgbody_info
*ibi
= NULL
;
1313 int saved_indent_level
;
1315 de_dbg_indent_save(c
, &saved_indent_level
);
1317 if(d
->errflag
) goto done
;
1318 if(!d
->found_bmhd
) goto done
;
1319 if(!frctx
) goto done
;
1320 if(frctx
->done_flag
) goto done
;
1321 frctx
->done_flag
= 1;
1323 // TODO: Should the imgbody_info be saved somewhere, or recalculated for every frame?
1324 ibi
= de_malloc(c
, sizeof(struct imgbody_info
));
1326 do_before_image_chunk(c
, d
);
1328 if(!init_imgbody_info(c
, d
, ibi
, 0)) {
1333 // Find the reference frame (if it exists).
1334 // It is the highest numbered oldfrctx[] item whose index is at most
1335 // frctx->interleave-1, and which is non-NULL.
1336 if(frctx
->interleave
>=2) {
1337 reference_frctx
= d
->oldfrctx
[1];
1338 if(!reference_frctx
) {
1339 reference_frctx
= d
->oldfrctx
[0];
1343 reference_frctx
= d
->oldfrctx
[0];
1346 // Allocate buffer for this frame
1347 if(!frctx
->frame_buffer
) {
1348 frctx
->frame_buffer
= dbuf_create_membuf(c
, ibi
->frame_buffer_size
, 0x1);
1351 // Start by copying the reference frame to this frame. The decompress function
1352 // will then modify this frame.
1353 if(reference_frctx
&& reference_frctx
->frame_buffer
) {
1354 dbuf_copy(reference_frctx
->frame_buffer
, 0, reference_frctx
->frame_buffer
->len
,
1355 frctx
->frame_buffer
);
1360 decompress_delta_op3(c
, d
, ibi
, frctx
, pos1
, len
);
1363 decompress_delta_op5(c
, d
, ibi
, frctx
, pos1
, len
);
1366 decompress_delta_op7(c
, d
, ibi
, frctx
, pos1
, len
);
1369 decompress_delta_op8(c
, d
, ibi
, frctx
, pos1
, len
);
1372 decompress_delta_op74(c
, d
, ibi
, frctx
, pos1
, len
);
1375 decompress_delta_op108(c
, d
, ibi
, frctx
, pos1
, len
);
1378 de_err(c
, "Unsupported DLTA operation: %d", (int)frctx
->op
);
1381 if(d
->errflag
) goto done
;
1383 if(frctx
->change_flag
|| d
->opt_anim_includedups
) {
1384 write_frame(c
, d
, ibi
, frctx
);
1387 de_dbg(c
, "[suppressing duplicate frame]");
1391 // For the summary line, and so we can know when encountering an op for the
1394 d
->delta_ops_used
[(size_t)frctx
->op
] = 1;
1398 de_dbg_indent_restore(c
, saved_indent_level
);
1401 static int decompress_method0(deark
*c
, lctx
*d
, i64 pos
, i64 len
, dbuf
*unc_pixels
,
1406 amt_to_copy
= de_min_int(len
, expected_len
);
1407 dbuf_copy(c
->infile
, pos
, amt_to_copy
, unc_pixels
);
1411 static int decompress_rgbn8(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
1412 i64 pos1
, i64 len
, dbuf
*unc_pixels
)
1416 i64 endpos
= pos1
+len
;
1418 i64 npixels_expected
;
1419 u8 is_rgb8
= (d
->formtype
==CODE_RGB8
);
1421 npixels_expected
= ibi
->width
* ibi
->height
;
1429 if(npixels
>= npixels_expected
) {
1439 n
= (u32
)de_getu32be_p(&pos
);
1440 cbuf
[0] = (u8
)(n
>>24);
1441 cbuf
[1] = (u8
)((n
&0x00ff0000U
)>>16);
1442 cbuf
[2] = (u8
)((n
&0x0000ff00U
)>>8);
1443 // TODO?: There's also a "genlock" bit that's sort of a transparency mask.
1444 count
= (i64
)(n
& 0x7f);
1447 n
= (u32
)de_getu16be_p(&pos
);
1448 cbuf
[0] = (u8
)(n
>>12);
1449 cbuf
[1] = (u8
)((n
&0x0f00)>>8);
1450 cbuf
[2] = (u8
)((n
&0x00f0)>>4);
1451 for(i
=0; i
<3; i
++) {
1454 count
= (i64
)(n
& 0x07);
1460 c2raw
= de_getbyte_p(&pos
);
1465 count
= de_getu16be_p(&pos
);
1469 for(i
=0; i
<count
; i
++) {
1470 dbuf_write(unc_pixels
, cbuf
, 3);
1477 de_err(c
, "RGBN/RGB8 decompression failed");
1482 static int decompress_ilbm_packbits(deark
*c
, dbuf
*inf
, i64 pos
, i64 len
,
1483 dbuf
*unc_pixels
, i64 expected_len
, UI nbytes_per_unit
)
1486 struct de_dfilter_in_params dcmpri
;
1487 struct de_dfilter_out_params dcmpro
;
1488 struct de_dfilter_results dres
;
1489 struct de_packbits_params pbparams
;
1491 de_zeromem(&pbparams
, sizeof(struct de_packbits_params
));
1492 pbparams
.nbytes_per_unit
= nbytes_per_unit
;
1493 de_dfilter_init_objects(c
, &dcmpri
, &dcmpro
, &dres
);
1497 dcmpro
.f
= unc_pixels
;
1498 dcmpro
.len_known
= 1;
1499 dcmpro
.expected_len
= expected_len
;
1501 fmtutil_decompress_packbits_ex(c
, &dcmpri
, &dcmpro
, &dres
, &pbparams
);
1502 dbuf_flush(dcmpro
.f
);
1504 de_err(c
, "Decompression failed: %s", dres
.errmsg
);
1507 de_dbg(c
, "decompressed %"I64_FMT
" to %"I64_FMT
" bytes", len
, unc_pixels
->len
);
1515 struct imgbody_info
*ibi
;
1517 i64 vdat_chunk_count
; // (the plane number)
1522 static void vdat_write_element(deark
*c
, struct vdat_ctx
*vdctx
, const u8
*elembuf
)
1526 dstpos
= vdctx
->ibi
->bytes_per_row_per_plane
* vdctx
->vdat_chunk_count
;
1527 dstpos
+= 2*vdctx
->cur_col
;
1528 dstpos
+= vdctx
->ypos
* vdctx
->ibi
->frame_buffer_rowspan
;
1530 dbuf_write_at(vdctx
->unc_pixels
, dstpos
, elembuf
, 2);
1532 if(vdctx
->ypos
>= vdctx
->ibi
->height
) {
1538 static void do_vdat_chunk(deark
*c
, struct vdat_ctx
*vdctx
, i64 pos1
, i64 len
)
1554 cmd_cnt
= de_getu16be(pos
); // command count + 2
1557 de_dbg(c
, "number of command bytes: %d", (int)cmd_cnt
);
1558 if(cmd_cnt
<1) goto done
;
1560 cmds
= de_mallocarray(c
, cmd_cnt
, sizeof(u8
));
1563 de_read(cmds
, pos
, cmd_cnt
);
1567 for(i
=0; i
<cmd_cnt
; i
++) {
1575 count
= de_getu16be(pos
);
1577 for(k
=0; k
<count
; k
++) {
1578 de_read(elembuf
, pos
, 2);
1580 vdat_write_element(c
, vdctx
, elembuf
);
1583 else if(cmd
==0x01) {
1584 count
= de_getu16be(pos
);
1586 de_read(elembuf
, pos
, 2);
1588 for(k
=0; k
<count
; k
++) {
1589 vdat_write_element(c
, vdctx
, elembuf
);
1592 else if(cmd
>=0x80) {
1593 count
= (128-(i64
)(cmd
&0x7f));
1594 for(k
=0; k
<count
; k
++) {
1595 de_read(elembuf
, pos
, 2);
1597 vdat_write_element(c
, vdctx
, elembuf
);
1600 else { // cmd is from 0x02 to 0x7f
1601 de_read(elembuf
, pos
, 2);
1604 for(k
=0; k
<count
; k
++) {
1605 vdat_write_element(c
, vdctx
, elembuf
);
1614 static int my_vdat_chunk_handler(struct de_iffctx
*ictx
)
1617 struct vdat_ctx
*vdctx
= (struct vdat_ctx
*)ictx
->userdata
;
1619 if(ictx
->chunkctx
->chunk4cc
.id
!= CODE_VDAT
) {
1624 if(vdctx
->vdat_chunk_count
>= vdctx
->ibi
->planes_total
) goto done
;
1625 do_vdat_chunk(c
, vdctx
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
1628 if(ictx
->chunkctx
->chunk4cc
.id
== CODE_VDAT
) {
1629 vdctx
->vdat_chunk_count
++;
1634 static int decompress_method2(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
1635 i64 pos
, i64 len
, dbuf
*unc_pixels
, i64 expected_len
)
1637 struct vdat_ctx vdctx
;
1638 struct de_iffctx
*ictx_vdat
= NULL
;
1640 // For sanity, we'll use a separate IFF decoder for the contents of this BODY chunk.
1641 de_zeromem(&vdctx
, sizeof(struct vdat_ctx
));
1644 vdctx
.unc_pixels
= unc_pixels
;
1646 ictx_vdat
= fmtutil_create_iff_decoder(c
);
1647 ictx_vdat
->userdata
= (void*)&vdctx
;
1648 ictx_vdat
->handle_chunk_fn
= my_vdat_chunk_handler
;
1649 ictx_vdat
->f
= c
->infile
;
1650 fmtutil_read_iff_format(ictx_vdat
, pos
, len
);
1652 fmtutil_destroy_iff_decoder(ictx_vdat
);
1656 // Convert ACBM ABIT image to standard ILBM frame buffer format.
1657 static int convert_abit(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
1658 i64 pos
, i64 len
, dbuf
*frame_buffer
)
1663 planespan
= ibi
->height
* ibi
->bytes_per_row_per_plane
;
1665 for(plane
=0; plane
<ibi
->planes_total
; plane
++) {
1666 for(j
=0; j
<ibi
->height
; j
++) {
1667 dbuf_copy_at(c
->infile
, pos
+ plane
*planespan
+ j
*ibi
->bytes_per_row_per_plane
,
1668 ibi
->bytes_per_row_per_plane
, frame_buffer
,
1669 j
*ibi
->frame_buffer_rowspan
+ plane
*ibi
->bytes_per_row_per_plane
);
1675 // Detect and warn about HAM-E, which we don't support.
1676 static void detect_hame(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
1677 struct frame_ctx
*frctx
)
1683 static const u8 sig
[15] = { 0xa, 0x2, 0xf, 0x5, 0x8, 0x4, 0xd, 0xc,
1684 0x6, 0xd, 0xb, 0x0, 0x7, 0xf, 0x1 };
1686 if(d
->is_hame
) return;
1687 if(d
->ham_flag
) return;
1688 if(!d
->found_cmap
) return;
1689 if(ibi
->width
<640) return;
1690 if(ibi
->planes_fg
!=4 || ibi
->planes_total
!=4) return;
1691 if(ibi
->is_thumb
) return;
1692 if(frctx
->formtype
!=CODE_ILBM
&& frctx
->formtype
!=CODE_ACBM
) return;
1693 if(!frctx
|| !frctx
->frame_buffer
) return;
1695 // Note: This is quite possibly not the right way to detect HAM-E.
1696 // RECOIL does it by looking up the palette color of each pixel, and using
1697 // certain bits in the palette entry. In all the HAM-E images I have, the
1698 // palette is constructed so as to make that process a no-op.
1700 // Need to examine the values of the first 16 pixels, so need the first 2
1701 // bytes of each of the 4 planes of row 0.
1702 for(plane
=0; plane
<4; plane
++) {
1703 firstword
[plane
] = (UI
)dbuf_getu16be(frctx
->frame_buffer
,
1704 plane
* ibi
->bytes_per_row_per_plane
);
1707 for(k
=0; k
<16; k
++) {
1709 for(plane
=0; plane
<4; plane
++) {
1710 if(firstword
[plane
] & (1U<<(15-(UI
)k
))) {
1711 pixelval
[k
] |= 1U<<(UI
)plane
;
1716 if(de_memcmp(pixelval
, sig
, 15)) return;
1717 if(pixelval
[15]!=0x4 && pixelval
[15]!=0x8) return;
1719 if(d
->opt_allowhame
) {
1720 de_warn(c
, "This is probably a HAM-E image, which is not supported correctly.");
1723 de_err(c
, "HAM-E images are not supported. "
1724 "(\"-opt ilbm:allowspecial\" to decode anyway)");
1731 static int is_dctv_sig_at(dbuf
*f
, i64 pos
)
1735 static const u8 sig
[31] = {
1736 0x49, 0x87, 0x28, 0xde, 0x11, 0x0b, 0xef, 0xd2, 0x0c, 0x8e, 0x8b, 0x35, 0x5b, 0x75, 0xec, 0xb8,
1737 0x29, 0x6b, 0x03, 0xf9, 0x2b, 0xb4, 0x34, 0xee, 0x67, 0x1e, 0x7c, 0x4f, 0x53, 0x63, 0x15 };
1739 x
= dbuf_getbyte(f
, pos
);
1740 if(x
!= sig
[0]) return 0;
1741 if(dbuf_memcmp(f
, pos
, sig
, 31)) return 0;
1745 // Detect and warn about DCTV, which we don't support.
1746 static void detect_dctv(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
1747 struct frame_ctx
*frctx
)
1752 // As far as I can tell, in DCTV images, the last plane of the first row is
1754 // <00> <31-byte signature> <00 fill> <31-byte signature> <00>
1755 // (Sometimes, the last plane of the *second* row is the same.)
1756 // (But I have a 2-plane image in which it's the *first* plane of the first
1757 // two rows that are special. TODO: Figure this out.)
1760 // * Is DCTV possible if there are fewer than 64 bytes per row per plane (i.e. width < 512)?
1761 // * Can a DCTV image have transparency?
1762 // * If a DCTV image has a thumbnail image, what format does the thumbnail use?
1764 if(d
->is_dctv
) return;
1765 if(!frctx
|| !frctx
->frame_buffer
) return;
1766 if(ibi
->is_thumb
) return;
1767 if(frctx
->formtype
!=CODE_ILBM
&& frctx
->formtype
!=CODE_ACBM
) return;
1768 if(ibi
->bytes_per_row_per_plane
<64) return;
1770 // Test end of last plane of first row
1771 pos
= d
->planes_raw
* ibi
->bytes_per_row_per_plane
- 32;
1772 result
= is_dctv_sig_at(frctx
->frame_buffer
, pos
);
1775 // Test end of first plane of first row
1776 pos
= ibi
->bytes_per_row_per_plane
- 32;
1777 result
= is_dctv_sig_at(frctx
->frame_buffer
, pos
);
1782 if(d
->opt_allowdctv
) {
1783 de_warn(c
, "This is probably a DCTV image, which is not supported correctly.");
1786 de_err(c
, "DCTV images are not supported. "
1787 "(\"-opt ilbm:allowspecial\" to decode anyway)");
1795 static int do_image_chunk_internal(deark
*c
, lctx
*d
, struct frame_ctx
*frctx
, i64 pos1
, i64 len
, int is_thumb
)
1797 struct imgbody_info
*ibi
= NULL
;
1801 if(d
->errflag
) goto done
;
1802 if(!d
->found_bmhd
) goto done
;
1803 if(!frctx
) goto done
;
1804 if(frctx
->done_flag
) goto done
;
1805 frctx
->done_flag
= 1;
1807 ibi
= de_malloc(c
, sizeof(struct imgbody_info
));
1809 do_before_image_chunk(c
, d
);
1811 if(!init_imgbody_info(c
, d
, ibi
, is_thumb
)) {
1815 if(!frctx
->frame_buffer
) {
1816 frctx
->frame_buffer
= dbuf_create_membuf(c
, ibi
->frame_buffer_size
, 0x1);
1819 if(d
->formtype
==CODE_ACBM
) {
1820 // Note: I don't think ABIT images are ever compressed.
1821 if(!convert_abit(c
, d
, ibi
, pos1
, len
, frctx
->frame_buffer
)) goto done
;
1823 else if(d
->formtype
==CODE_RGBN
|| d
->formtype
==CODE_RGB8
) {
1824 if(!decompress_rgbn8(c
, d
, ibi
, pos1
, len
, frctx
->frame_buffer
)) goto done
;
1826 else if(ibi
->compression
==0) {
1827 if(!decompress_method0(c
, d
, pos1
, len
, frctx
->frame_buffer
, ibi
->frame_buffer_size
)) goto done
;
1829 else if(ibi
->compression
==1) {
1830 dbuf_enable_wbuffer(frctx
->frame_buffer
);
1831 ret
= decompress_ilbm_packbits(c
, c
->infile
, pos1
, len
,
1832 frctx
->frame_buffer
, ibi
->frame_buffer_size
, 1);
1833 dbuf_disable_wbuffer(frctx
->frame_buffer
);
1836 else if(ibi
->compression
==2) {
1837 if(!decompress_method2(c
, d
, ibi
, pos1
, len
, frctx
->frame_buffer
, ibi
->frame_buffer_size
)) goto done
;
1840 de_err(c
, "Unsupported compression method: %d", (int)ibi
->compression
);
1844 if(ibi
->is_pbm
&& (frctx
->frame_buffer
->len
!= ibi
->frame_buffer_size
) && (ibi
->width
%2)) {
1845 if(frctx
->frame_buffer
->len
== ibi
->width
*ibi
->height
) {
1846 // Hack: I have some PBM images (e.g. BBM thumbnails) that aren't row-padded.
1847 de_dbg(c
, "[assuming rows are not 16-bit padded]");
1848 ibi
->bytes_per_row_per_plane
= ibi
->width
;
1849 ibi
->bits_per_row_per_plane
= ibi
->bytes_per_row_per_plane
* 8;
1850 ibi
->frame_buffer_rowspan
= ibi
->bytes_per_row_per_plane
* ibi
->planes_total
;
1851 ibi
->frame_buffer_size
= ibi
->frame_buffer_rowspan
* ibi
->height
;
1855 if(frctx
->frame_buffer
->len
!= ibi
->frame_buffer_size
) {
1856 de_warn(c
, "Expected %"I64_FMT
" decompressed bytes, got %"I64_FMT
, ibi
->frame_buffer_size
,
1857 frctx
->frame_buffer
->len
);
1860 detect_dctv(c
, d
, ibi
, frctx
);
1861 detect_hame(c
, d
, ibi
, frctx
);
1863 write_frame(c
, d
, ibi
, frctx
);
1872 static void do_body_or_abit(deark
*c
, lctx
*d
, struct de_iffctx
*ictx
, i64 pos1
, i64 len
)
1874 if(!de_good_image_dimensions(c
, d
->width
, d
->height
)) {
1878 if(!do_image_chunk_internal(c
, d
, d
->frctx
, pos1
, len
, 0)) {
1886 static void do_tiny(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
1888 struct frame_ctx
*frctx
= NULL
;
1891 if(len
<=4) goto done
;
1893 d
->thumb_width
= de_getu16be_p(&pos
);
1894 d
->thumb_height
= de_getu16be_p(&pos
);
1895 de_dbg(c
, "thumbnail image, dimensions: %d"DE_CHAR_TIMES
"%d", (int)d
->thumb_width
, (int)d
->thumb_height
);
1896 if(!de_good_image_dimensions_noerr(c
, d
->thumb_width
, d
->thumb_height
)) {
1897 de_warn(c
, "Bad thumbnail image dimensions");
1901 frctx
= create_frame(c
, d
);
1902 (void)do_image_chunk_internal(c
, d
, frctx
, pos
, pos1
+len
-pos
, 1);
1905 destroy_frame(c
, d
, frctx
);
1908 // A few ILBM files with extension ".iff24" have this chunk, as
1909 // do some DEEP files.
1910 static void do_xs24(deark
*c
, dbuf
*f
, i64 pos1
, i64 len
)
1914 de_bitmap
*img
= NULL
;
1916 w
= de_getu16be_p(&pos
);
1918 h
= de_getu16be_p(&pos
);
1919 de_dbg(c
, "24-bit thumbnail image, dimensions: %u"DE_CHAR_TIMES
"%u", (UI
)w
, (UI
)h
);
1920 if(!de_good_image_dimensions_noerr(c
, w
, h
)) goto done
;
1921 if(rowspan
*h
+6 != len
) goto done
;
1922 pos
+= 2; // unknown field
1924 img
= de_bitmap_create(c
, w
, h
, 3);
1925 de_convert_image_rgb(f
, pos
, rowspan
, 3, img
, 0);
1926 de_bitmap_write_to_file(img
, "thumb", DE_CREATEFLAG_IS_AUX
|DE_CREATEFLAG_OPT_IMAGE
);
1928 de_bitmap_destroy(img
);
1931 static void get_bits_descr(deark
*c
, lctx
*d
, struct frame_ctx
*frctx
, de_ucstring
*s
)
1933 UI bits
= frctx
->bits
;
1935 if(frctx
->op
==4 || frctx
->op
==5 || frctx
->op
==7 || frctx
->op
==8) {
1937 ucstring_append_flags_item(s
, "long data");
1939 d
->uses_anim_long_data
= 1;
1942 if(frctx
->op
==4 || frctx
->op
==5) {
1944 ucstring_append_flags_item(s
, "XOR");
1946 d
->uses_anim4_5_xor_mode
= 1;
1949 ucstring_append_flags_item(s
, "one info list");
1953 ucstring_append_flags_item(s
, "RLC");
1957 ucstring_append_flags_item(s
, "vertical");
1961 ucstring_append_flags_item(s
, "long info offsets");
1967 ucstring_append_flags_itemf(s
, "0x%08x", bits
);
1971 static void do_anim_anhd(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
1975 de_ucstring
*bits_descr
= NULL
;
1976 struct frame_ctx
*frctx
= d
->frctx
;
1981 frctx
->op
= de_getbyte(pos
++);
1982 de_dbg(c
, "operation: %d (%s)", (int)frctx
->op
, anim_get_op_name(frctx
->op
));
1984 if(frctx
->op
==ANIM_OP_XOR
) {
1994 pos
+= 4; // abstime
1996 tmp
= de_getu32be_p(&pos
); // reltime
1997 de_dbg(c
, "reltime: %.5f sec", ((double)tmp
)/60.0);
1999 ileave_raw
= de_getbyte_p(&pos
);
2000 de_dbg(c
, "interleave: %d", (int)ileave_raw
);
2002 frctx
->interleave
= 2;
2005 frctx
->interleave
= (UI
)ileave_raw
;
2007 if(frctx
->interleave
>2 && !d
->errflag
) {
2008 de_err(c
, "Unsupported interleave");
2014 frctx
->bits
= (UI
)de_getu32be_p(&pos
);
2015 bits_descr
= ucstring_create(c
);
2016 get_bits_descr(c
, d
, frctx
, bits_descr
);
2017 de_dbg(c
, "bits: 0x%08x (%s)", frctx
->bits
, ucstring_getpsz_d(bits_descr
));
2019 ucstring_destroy(bits_descr
);
2022 static void do_camg(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
2026 d
->camg_changed_flag
= 1;
2033 d
->camg_mode
= (UI
)de_getu32be(pos
);
2034 de_dbg(c
, "CAMG mode: 0x%x", d
->camg_mode
);
2036 if(d
->camg_mode
& 0x0800)
2038 if(d
->camg_mode
& 0x0080)
2041 if(d
->formtype
==CODE_RGBN
|| d
->formtype
==CODE_RGB8
) {
2046 de_dbg_indent(c
, 1);
2047 de_dbg(c
, "HAM: %d", (int)d
->ham_flag
);
2048 de_dbg(c
, "EHB: %d", (int)d
->ehb_flag
);
2049 de_dbg_indent(c
, -1);
2052 static void do_dpi(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
2055 d
->x_dpi
= de_getu16be(pos
);
2056 d
->y_dpi
= de_getu16be(pos
+2);
2057 de_dbg(c
, "dpi: %d"DE_CHAR_TIMES
"%d", (int)d
->x_dpi
, (int)d
->y_dpi
);
2060 static void do_grab(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
2064 d
->hotspot_x
= (int)de_getu16be(pos
);
2065 d
->hotspot_y
= (int)de_getu16be(pos
+2);
2066 de_dbg(c
, "hotspot: (%d, %d)", d
->hotspot_x
, d
->hotspot_y
);
2069 static void do_dpan(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
2073 if(!d
->is_anim
) return;
2075 nframes
= de_getu16be(pos
+2);
2076 de_dbg(c
, "number of frames: %d", (int)nframes
);
2079 static void do_crng(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
2084 tmp1
= (UI
)de_getu16be(pos1
+2);
2085 tmp2
= (UI
)de_getu16be(pos1
+4);
2086 de_dbg(c
, "CRNG flags: 0x%04x", tmp2
);
2088 de_dbg(c
, "rate: %.2f fps", (double)(((double)tmp1
)*(60.0/16384.0)));
2089 on_color_cycling_enabled(c
, d
);
2093 static void do_drng(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
2097 tmp2
= (UI
)de_getu16be(pos1
+4);
2098 de_dbg(c
, "DRNG flags: 0x%04x", tmp2
);
2100 on_color_cycling_enabled(c
, d
);
2104 // Graphicraft Color Cycling Range and Timing
2105 static void do_ccrt(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
2109 tmp1
= de_geti16be(pos1
);
2110 de_dbg(c
, "cycling direction: %d", (int)tmp1
);
2112 d
->uses_color_cycling
= 1;
2116 // Frame sequencing chunk used in ANIM-J
2117 static void do_ansq(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
2122 // TODO: Figure out how critical this ANSQ info is.
2123 // If deltas are supposed to be applied out of sequence, we could at least
2126 num_items
= len
/ 4;
2127 de_dbg(c
, "number of frames in sequence: %d", (int)num_items
);
2128 if(c
->debug_level
<2) return;
2129 de_dbg_indent(c
, 1);
2130 for(i
=0; i
<num_items
&& i
<2000; i
++) {
2133 frnum
= de_getu16be(pos1
+i
*4);
2134 dur
= de_getu16be(pos1
+i
*4+2);
2135 de_dbg2(c
, "item[%d]: frame=%d, dur=%d", (int)i
, (int)frnum
, (int)dur
);
2137 de_dbg_indent(c
, -1);
2140 static void render_pixel_row_ham6(deark
*c
, lctx
*d
, i64 rownum
, const u32
*rowbuf
,
2141 UI rowbuf_size
, de_bitmap
*img
)
2146 // At the beginning of each row, the color accumulators are
2147 // initialized to palette entry 0.
2148 cr
= DE_COLOR_R(d
->pal
[0]);
2149 cg
= DE_COLOR_G(d
->pal
[0]);
2150 cb
= DE_COLOR_B(d
->pal
[0]);
2152 for(i
=0; i
<rowbuf_size
; i
++) {
2154 u8 val
= rowbuf
[i
] & 0xff;
2156 switch((val
>>4)&0x3) {
2157 case 0x1: // Modify blue value
2160 case 0x2: // Modify red value
2163 case 0x3: // Modify green value
2166 default: // 0: Use colormap value
2167 clr
= d
->pal
[(UI
)val
];
2168 cr
= DE_COLOR_R(clr
);
2169 cg
= DE_COLOR_G(clr
);
2170 cb
= DE_COLOR_B(clr
);
2174 de_bitmap_setpixel_rgb(img
, (i64
)i
, rownum
, DE_MAKE_RGB(cr
, cg
, cb
));
2178 static void render_pixel_row_ham8(deark
*c
, lctx
*d
, i64 rownum
, const u32
*rowbuf
,
2179 UI rowbuf_size
, de_bitmap
*img
)
2184 // At the beginning of each row, the color accumulators are
2185 // initialized to palette entry 0.
2186 cr
= DE_COLOR_R(d
->pal
[0]);
2187 cg
= DE_COLOR_G(d
->pal
[0]);
2188 cb
= DE_COLOR_B(d
->pal
[0]);
2190 for(i
=0; i
<rowbuf_size
; i
++) {
2192 u8 val
= rowbuf
[i
] & 0xff;
2194 switch((val
>>6)&0x3) {
2196 cb
= ((val
&0x3f)<<2)|((val
&0x3f)>>4);
2199 cr
= ((val
&0x3f)<<2)|((val
&0x3f)>>4);
2202 cg
= ((val
&0x3f)<<2)|((val
&0x3f)>>4);
2205 clr
= d
->pal
[(UI
)val
];
2206 cr
= DE_COLOR_R(clr
);
2207 cg
= DE_COLOR_G(clr
);
2208 cb
= DE_COLOR_B(clr
);
2212 de_bitmap_setpixel_rgb(img
, (i64
)i
, rownum
, DE_MAKE_RGB(cr
, cg
, cb
));
2216 static void render_pixel_row_normal(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
2217 i64 rownum
, const u32
*rowbuf
, UI rowbuf_size
, de_bitmap
*img
)
2221 for(k
=0; k
<rowbuf_size
; k
++) {
2222 de_bitmap_setpixel_rgb(img
, (i64
)k
, rownum
, d
->pal
[(UI
)rowbuf
[k
] & 0xff]);
2226 static void render_pixel_row_rgb24(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
2227 i64 rownum
, const u32
*rowbuf
, UI rowbuf_size
, de_bitmap
*img
)
2231 for(k
=0; k
<rowbuf_size
; k
++) {
2234 r
= (rowbuf
[k
] & 0x0000ff);
2235 g
= (rowbuf
[k
] & 0x00ff00)>>8;
2236 b
= (rowbuf
[k
] & 0xff0000)>>16;
2237 de_bitmap_setpixel_rgb(img
, (i64
)k
, rownum
, DE_MAKE_RGB(r
, g
, b
));
2241 static void set_finfo_data(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
, de_finfo
*fi
)
2247 de_finfo_set_name_from_sz(c
, fi
, "thumb", 0, DE_ENCODING_LATIN1
);
2250 if(d
->x_aspect
>0 && d
->y_aspect
>0) {
2253 if(!ibi
->is_thumb
&& d
->x_dpi
>0 && d
->y_dpi
>0) {
2258 fi
->density
.code
= DE_DENSITY_DPI
;
2259 fi
->density
.xdens
= (double)d
->x_dpi
;
2260 fi
->density
.ydens
= (double)d
->y_dpi
;
2262 else if(has_aspect
) {
2263 fi
->density
.code
= DE_DENSITY_UNK_UNITS
;
2264 fi
->density
.ydens
= (double)d
->x_aspect
;
2265 fi
->density
.xdens
= (double)d
->y_aspect
;
2268 if(!ibi
->is_thumb
&& d
->has_hotspot
) {
2269 fi
->has_hotspot
= 1;
2270 fi
->hotspot_x
= d
->hotspot_x
;
2271 fi
->hotspot_y
= d
->hotspot_y
;
2275 // Generate the final image and write it to a file.
2276 static void write_frame(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
, struct frame_ctx
*frctx
)
2278 de_bitmap
*img
= NULL
;
2280 u32
*rowbuf
= NULL
; // The current row of pixel (palette or RGB) values
2281 u8
*rowbuf_trns
= NULL
; // The current row's 1-bit transparency mask values
2284 de_finfo
*fi
= NULL
;
2289 if(d
->errflag
) goto done
;
2290 if(!frctx
) goto done
;
2291 if(!frctx
->frame_buffer
) {
2295 if(ibi
->colortype
==COLORTYPE_RGB24
) {
2296 if(ibi
->planes_fg
!=24) goto done
;
2298 else if(ibi
->planes_fg
<1 || ibi
->planes_fg
>8) {
2302 if(d
->debug_frame_buffer
) {
2305 fi_fb
= de_finfo_create(c
);
2306 de_finfo_set_name_from_sz(c
, fi_fb
, "fb", 0, DE_ENCODING_LATIN1
);
2307 de_convert_and_write_image_bilevel(frctx
->frame_buffer
, 0,
2308 ibi
->bits_per_row_per_plane
* ibi
->planes_total
,
2309 ibi
->height
, ibi
->frame_buffer_rowspan
, 0, fi_fb
, 0);
2310 de_finfo_destroy(c
, fi_fb
);
2313 rowbuf_size
= (UI
)ibi
->width
;
2314 rowbuf
= de_mallocarray(c
, rowbuf_size
, sizeof(rowbuf
[0]));
2315 rowbuf_trns
= de_mallocarray(c
, rowbuf_size
, sizeof(rowbuf_trns
[0]));
2320 else if(d
->found_cmap
&& d
->pal_is_grayscale
&& d
->planes_raw
<=8 && !d
->is_ham6
&& !d
->is_ham8
) {
2327 if(ibi
->use_colorkey_transparency
|| ibi
->masking_code
==MASKINGTYPE_1BITMASK
) {
2331 img
= de_bitmap_create(c
, ibi
->width
, ibi
->height
, bypp
);
2334 de_convert_image_paletted(frctx
->frame_buffer
, 0, 8, ibi
->frame_buffer_rowspan
,
2338 else if(ibi
->is_rgb24
) {
2339 de_convert_image_rgb(frctx
->frame_buffer
, 0, ibi
->bytes_per_row_per_plane
, 3,
2344 for(j
=0; j
<ibi
->height
; j
++) {
2349 // Process 8 pixels at a time
2350 for(z
=0; z
<ibi
->bytes_per_row_per_plane
; z
++) {
2351 de_zeromem(pixelval
, sizeof(pixelval
));
2352 de_zeromem(pixeltrnsval
, sizeof(pixeltrnsval
));
2354 // Read the zth byte in each plane
2355 for(plane
=0; plane
<ibi
->planes_total
; plane
++) {
2358 b
= dbuf_getbyte(frctx
->frame_buffer
,
2359 j
*ibi
->frame_buffer_rowspan
+
2360 plane
*ibi
->bytes_per_row_per_plane
+ z
);
2362 for(k
=0; k
<8; k
++) {
2363 if(b
& (1U<<(7-k
))) {
2364 if(plane
< ibi
->planes_fg
) {
2365 pixelval
[k
] |= 1U<<(UI
)plane
;
2368 // The only way this can happen is if this plane is a
2369 // 1-bit transparency mask.
2370 pixeltrnsval
[k
] = 1;
2376 for(k
=0; k
<8; k
++) {
2380 if(idx
< rowbuf_size
) {
2381 rowbuf
[idx
] = pixelval
[k
];
2382 rowbuf_trns
[idx
] = pixeltrnsval
[k
];
2387 if(ibi
->colortype
==COLORTYPE_RGB24
) {
2388 render_pixel_row_rgb24(c
, d
, ibi
, j
, rowbuf
, rowbuf_size
, img
);
2390 else if(d
->is_ham6
) {
2391 render_pixel_row_ham6(c
, d
, j
, rowbuf
, rowbuf_size
, img
);
2393 else if(d
->is_ham8
) {
2394 render_pixel_row_ham8(c
, d
, j
, rowbuf
, rowbuf_size
, img
);
2397 render_pixel_row_normal(c
, d
, ibi
, j
, rowbuf
, rowbuf_size
, img
);
2400 // Handle 1-bit transparency masks here, for all color types.
2401 if(ibi
->masking_code
==MASKINGTYPE_1BITMASK
) {
2404 for(i
=0; i
<rowbuf_size
; i
++) {
2407 if(rowbuf_trns
[i
]==0) {
2408 clr
= de_bitmap_getpixel(img
, i
, j
);
2409 clr
= DE_SET_ALPHA(clr
, 0);
2410 de_bitmap_setpixel_rgba(img
, i
, j
, clr
);
2417 if(d
->trans_setting
==TRANS_AUTO
) {
2418 if(ibi
->masking_code
==MASKINGTYPE_1BITMASK
) {
2419 de_bitmap_optimize_alpha(img
, 0x2|0x4);
2422 else if(d
->trans_setting
==TRANS_REMOVE
) {
2423 de_bitmap_remove_alpha(img
);
2426 fi
= de_finfo_create(c
);
2427 set_finfo_data(c
, d
, ibi
, fi
);
2429 createflags
|= DE_CREATEFLAG_IS_AUX
;
2432 // TODO: Enable this for ANIM?
2433 createflags
|= DE_CREATEFLAG_OPT_IMAGE
;
2436 de_bitmap_write_to_file_finfo(img
, fi
, createflags
);
2439 de_bitmap_destroy(img
);
2440 de_finfo_destroy(c
, fi
);
2442 de_free(c
, rowbuf_trns
);
2445 static void on_frame_begin(deark
*c
, lctx
*d
, u32 formtype
)
2447 if(d
->frctx
) return;
2448 d
->num_frames_started
++;
2449 d
->frctx
= create_frame(c
, d
);
2450 d
->frctx
->formtype
= formtype
;
2451 d
->frctx
->frame_idx
= d
->num_frames_finished
;
2452 if(d
->is_anim
) de_dbg(c
, "[frame #%d begin]", d
->frctx
->frame_idx
);
2455 static void on_frame_end(deark
*c
, lctx
*d
)
2457 if(!d
->frctx
) return;
2459 if(d
->is_anim
) de_dbg(c
, "[frame #%d end]", d
->frctx
->frame_idx
);
2461 destroy_frame(c
, d
, d
->oldfrctx
[1]); // Destroy the frame that's aged out
2462 d
->oldfrctx
[1] = d
->oldfrctx
[0]; // Make room for the new frame
2463 d
->oldfrctx
[0] = d
->frctx
; // Save the new frame
2465 d
->num_frames_finished
++;
2468 static int my_iff_chunk_handler(struct de_iffctx
*ictx
)
2472 lctx
*d
= (lctx
*)ictx
->userdata
;
2474 if(d
->num_frames_finished
>= ANIM_MAX_FRAMES
) {
2479 // Chunks that we support even if they are not in FORM:ILBM, FORM:PBM, etc. chunk.
2481 switch(ictx
->chunkctx
->chunk4cc
.id
) {
2483 if(ictx
->level
==0) {
2484 // Remember this for later
2485 d
->main_chunk_endpos
= ictx
->chunkctx
->dpos
+ ictx
->chunkctx
->dlen
;
2487 if(ictx
->level
>d
->FORM_level
) break;
2488 ictx
->is_std_container
= 1;
2492 // Chunks that we process only inside a FORM:ILBM, etc. chunk.
2494 if(!d
->frctx
) goto done
;
2496 switch(ictx
->chunkctx
->chunk4cc
.id
) {
2499 if(!do_bmhd(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
)) {
2506 do_anim_anhd(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2511 do_cmap(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2516 do_camg(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2523 do_body_or_abit(c
, d
, ictx
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2528 if(ictx
->curr_container_contentstype4cc
.id
!= CODE_ILBM
) {
2532 do_dlta(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2536 do_tiny(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2540 do_xs24(c
, ictx
->f
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2545 do_dpi(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2549 do_grab(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2553 do_dpan(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2557 do_crng(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2561 do_drng(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2565 do_ccrt(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2570 on_multipalette_enabled(c
, d
);
2574 on_multipalette_enabled(c
, d
);
2578 on_multipalette_enabled(c
, d
);
2582 on_multipalette_enabled(c
, d
);
2588 do_ansq(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2592 if(d
->is_anim
&& !d
->found_audio
) {
2593 de_info(c
, "Note: This file includes AnimFX-style audio, which is "
2601 return (quitflag
) ? 0 : 1;
2604 static int my_preprocess_iff_chunk_fn(struct de_iffctx
*ictx
)
2606 lctx
*d
= (lctx
*)ictx
->userdata
;
2607 const char *name
= NULL
;
2609 // frctx will be set if we're in an "image" container, such as FORM:ILBM.
2610 // It is possible, e.g., for an ANIM file to contain FORM:8SVX containers
2611 // which contain BODY chunks that are not "image data".
2613 switch(ictx
->chunkctx
->chunk4cc
.id
) {
2614 case CODE_ANHD
: name
="animation header"; break;
2615 case CODE_BMHD
: name
="bitmap header"; break;
2616 case CODE_BODY
: name
="image data"; break;
2617 case CODE_CAMG
: name
="Amiga viewport mode"; break;
2618 case CODE_CMAP
: name
="color map"; break;
2619 case CODE_CRNG
: name
="color register range info"; break;
2620 case CODE_DLTA
: name
="delta-compressed data"; break;
2621 case CODE_DPI
: name
="dots/inch"; break;
2622 case CODE_DRNG
: name
="color cycle"; break;
2623 case CODE_GRAB
: name
="hotspot"; break;
2624 case CODE_TINY
: name
="thumbnail"; break;
2629 ictx
->chunkctx
->chunk_name
= name
;
2634 static int my_on_std_container_start_fn(struct de_iffctx
*ictx
)
2637 lctx
*d
= (lctx
*)ictx
->userdata
;
2639 if(ictx
->level
==d
->FORM_level
) {
2643 if((ictx
->curr_container_contentstype4cc
.id
== CODE_ILBM
) ||
2644 (ictx
->curr_container_contentstype4cc
.id
== CODE_PBM
) ||
2645 (ictx
->curr_container_contentstype4cc
.id
== CODE_ACBM
) ||
2646 (ictx
->curr_container_contentstype4cc
.id
== CODE_RGBN
) ||
2647 (ictx
->curr_container_contentstype4cc
.id
== CODE_RGB8
))
2649 on_frame_begin(c
, d
, ictx
->curr_container_contentstype4cc
.id
);
2653 if(ictx
->curr_container_contentstype4cc
.id
== CODE_8SVX
) {
2656 if(!d
->extra_content_warned
) {
2657 de_warn(c
, "File includes unsupported content of type '%s'",
2658 ictx
->curr_container_contentstype4cc
.id_sanitized_sz
);
2659 d
->extra_content_warned
= 1;
2663 de_err(c
, "Unsupported ILBM-like format");
2671 static void look_for_RAST(deark
*c
, lctx
*d
, i64 pos
)
2673 if(d
->found_rast
) return;
2674 if(!dbuf_memcmp(c
->infile
, pos
, "RAST", 4)) {
2679 static void do_eof_stuff(deark
*c
, lctx
*d
)
2681 i64 endpos
, endpos_padded
;
2684 endpos
= d
->main_chunk_endpos
;
2685 if(endpos
<1) return;
2686 endpos_padded
= de_pad_to_2(endpos
);
2687 extra_bytes
= c
->infile
->len
- endpos_padded
;
2688 if(extra_bytes
<1) return;
2689 de_dbg(c
, "[found %"I64_FMT
" extra bytes at end of file, starting at %"I64_FMT
"]",
2690 extra_bytes
, endpos_padded
);
2692 look_for_RAST(c
, d
, endpos
);
2693 if(endpos_padded
!=endpos
) {
2694 look_for_RAST(c
, d
, endpos_padded
);
2697 de_warn(c
, "Possible RAST data found, which is not supported. "
2698 "Image might not be decoded correctly.");
2702 static int my_on_container_end_fn(struct de_iffctx
*ictx
)
2704 if(ictx
->level
==0) {
2705 // Stop after the first top-level chunk (the FORM chunk).
2711 static void summary_append(de_ucstring
*s
, const char *fmt
, ...)
2712 de_gnuc_attribute ((format (printf
, 2, 3)));
2714 static void summary_append(de_ucstring
*s
, const char *fmt
, ...)
2718 ucstring_append_char(s
, ' ');
2720 ucstring_vprintf(s
, DE_ENCODING_LATIN1
, fmt
, ap
);
2724 // Print a summary line indicating the main characteristics of this file.
2725 static void print_summary(deark
*c
, lctx
*d
)
2727 de_ucstring
*s
= NULL
;
2730 if(c
->debug_level
<1) goto done
;
2731 if(!d
->found_bmhd
) goto done
;
2733 s
= ucstring_create(c
);
2735 summary_append(s
,"%s", d
->formtype_sanitized_sz
);
2736 summary_append(s
, "planes=%d", (int)d
->planes_raw
);
2737 if(d
->masking_code
!=0) summary_append(s
, "masking=%d", (int)d
->masking_code
);
2738 summary_append(s
, "cmpr=%d", (int)d
->compression
);
2739 for(k
=0; k
<256; k
++) {
2740 if(d
->delta_ops_used
[k
]) {
2741 summary_append(s
, "delta%u", (UI
)k
);
2744 if(d
->uses_anim_long_data
) summary_append(s
, "long_data");
2745 if(d
->uses_anim4_5_xor_mode
) summary_append(s
, "xor_mode");
2747 if(d
->ham_flag
) summary_append(s
, "HAM");
2748 if(d
->ehb_flag
) summary_append(s
, "EHB");
2749 if(d
->is_sham
) summary_append(s
, "SHAM");
2750 if(d
->is_pchg
) summary_append(s
, "PCHG");
2751 if(d
->is_ctbl
) summary_append(s
, "CTBL");
2752 if(d
->is_beam
) summary_append(s
, "BEAM");
2753 if(d
->is_hame
) summary_append(s
, "HAM-E");
2754 if(d
->is_dctv
) summary_append(s
, "DCTV");
2755 if(d
->found_rast
) summary_append(s
, "RAST");
2756 if(d
->uses_color_cycling
) summary_append(s
, "color-cycling");
2757 if(d
->found_clut
) summary_append(s
, "CLUT");
2758 if(d
->found_audio
) summary_append(s
, "audio");
2759 if(!d
->found_cmap
) summary_append(s
, "no-CMAP");
2761 de_dbg(c
, "summary:%s", ucstring_getpsz(s
));
2764 ucstring_destroy(s
);
2767 static void strip_trailing_space_sz(char *sz
)
2772 if(n
>1 && sz
[n
-1]==0x20) {
2777 static void de_run_ilbm_or_anim(deark
*c
, de_module_params
*mparams
)
2783 const char *opt_trans_str
;
2785 struct de_iffctx
*ictx
= NULL
;
2786 struct de_fourcc formtype_4cc
;
2788 d
= de_malloc(c
, sizeof(lctx
));
2789 opt_fixpal
= (u8
)de_get_ext_option_bool(c
, "ilbm:fixpal", 0xff);
2791 opt_trans_str
= de_get_ext_option(c
, "ilbm:trans");
2793 if(!opt_trans_str
) {
2794 if(de_get_ext_option(c
, "ilbm:notrans")) { // Deprecated option
2799 if(de_get_ext_option_bool(c
, "ilbm:allowspecial", 0)) {
2800 d
->opt_allowsham
= 1;
2801 d
->opt_allowdctv
= 1;
2802 d
->opt_allowhame
= 1;
2804 // allowsham is deprecated
2805 opt
= de_get_ext_option_bool(c
, "ilbm:allowsham", -1);
2806 if(opt
==0) d
->opt_allowsham
= 0;
2807 else if(opt
>0) d
->opt_allowsham
= 1;
2809 id
= (u32
)de_getu32be(0);
2811 de_err(c
, "Not an IFF file");
2815 dbuf_read_fourcc(c
->infile
, 8, &formtype_4cc
, 4, 0);
2816 d
->formtype
= formtype_4cc
.id
;
2817 de_strlcpy(d
->formtype_sanitized_sz
, formtype_4cc
.id_sanitized_sz
, sizeof(d
->formtype_sanitized_sz
));
2819 // A quick hack, so we have "PBM" instead of "PBM ".
2820 // TODO: Maybe dbuf_read_fourcc should do this, or have an option to.
2821 strip_trailing_space_sz(d
->formtype_sanitized_sz
);
2823 switch(d
->formtype
) {
2834 de_err(c
, "Not a supported ILBM-like format (%s)", d
->formtype_sanitized_sz
);
2837 de_declare_fmtf(c
, "IFF-%s", d
->formtype_sanitized_sz
);
2840 d
->opt_anim_includedups
= (u8
)de_get_ext_option_bool(c
, "anim:includedups", 0);
2843 if(opt_fixpal
==0xff) {
2844 // Fixpal option defaults to No for ANIM format, othersize Yes.
2845 // (The concern with ANIM is that we don't want frame 1's colors
2846 // to fail to match frame 2's colors.)
2847 d
->fixpal_setting
= (d
->is_anim
? 0 : 1);
2850 d
->fixpal_setting
= opt_fixpal
;
2853 // Default for d->trans_setting
2855 // I don't think AUTO makes sense for ANIM.
2856 d
->trans_setting
= TRANS_RESPECT
;
2859 d
->trans_setting
= TRANS_AUTO
;
2863 if(!de_strcmp(opt_trans_str
, "auto")) {
2864 d
->trans_setting
= TRANS_AUTO
;
2866 else if(!de_strcmp(opt_trans_str
, "")) {
2867 d
->trans_setting
= TRANS_RESPECT
;
2872 opt_trans_n
= de_atoi(opt_trans_str
);
2873 if(opt_trans_n
==0) {
2874 d
->trans_setting
= TRANS_REMOVE
;
2876 else if(opt_trans_n
>0) {
2877 d
->trans_setting
= TRANS_RESPECT
;
2881 else if(opt_notrans
) {
2882 d
->trans_setting
= TRANS_REMOVE
;
2885 d
->FORM_level
= d
->is_anim
? 1 : 0;
2887 ictx
= fmtutil_create_iff_decoder(c
);
2888 ictx
->has_standard_iff_chunks
= 1;
2889 ictx
->userdata
= (void*)d
;
2890 ictx
->input_encoding
= de_get_input_encoding(c
, NULL
, DE_ENCODING_ASCII
);
2891 ictx
->handle_chunk_fn
= my_iff_chunk_handler
;
2892 ictx
->preprocess_chunk_fn
= my_preprocess_iff_chunk_fn
;
2893 ictx
->on_std_container_start_fn
= my_on_std_container_start_fn
;
2894 ictx
->on_container_end_fn
= my_on_container_end_fn
;
2895 ictx
->f
= c
->infile
;
2896 fmtutil_read_iff_format(ictx
, 0, c
->infile
->len
);
2902 print_summary(c
, d
);
2905 fmtutil_destroy_iff_decoder(ictx
);
2907 destroy_frame(c
, d
, d
->frctx
);
2908 destroy_frame(c
, d
, d
->oldfrctx
[0]);
2909 destroy_frame(c
, d
, d
->oldfrctx
[1]);
2914 static void de_run_ilbm(deark
*c
, de_module_params
*mparams
)
2916 de_run_ilbm_or_anim(c
, mparams
);
2919 static void de_run_anim(deark
*c
, de_module_params
*mparams
)
2921 de_run_ilbm_or_anim(c
, mparams
);
2924 static int de_identify_ilbm(deark
*c
)
2928 id
= (u32
)de_getu32be(0);
2929 if(id
!=CODE_FORM
) return 0;
2930 id
= (u32
)de_getu32be(8);
2942 static int de_identify_anim(deark
*c
)
2946 id
= (u32
)de_getu32be(0);
2947 if(id
!=CODE_FORM
) return 0;
2948 id
= (u32
)de_getu32be(8);
2949 if(id
==CODE_ANIM
) return 100;
2953 static void do_help_ilbm_anim(deark
*c
, int is_anim
)
2955 de_msg(c
, "-opt ilbm:trans=<0|1|auto> : Always remove (0) or respect (1) "
2957 de_msg(c
, "-opt ilbm:fixpal=<0|1> : Don't/Do try to fix palettes that are "
2958 "slightly too dark");
2959 de_msg(c
, "-opt ilbm:allowspecial : Suppress an error on some images");
2961 de_msg(c
, "-opt anim:includedups : Do not suppress duplicate frames");
2965 static void de_help_ilbm(deark
*c
)
2967 do_help_ilbm_anim(c
, 0);
2970 static void de_help_anim(deark
*c
)
2972 do_help_ilbm_anim(c
, 1);
2975 void de_module_ilbm(deark
*c
, struct deark_module_info
*mi
)
2978 mi
->desc
= "IFF-ILBM and related image formats";
2979 mi
->run_fn
= de_run_ilbm
;
2980 mi
->identify_fn
= de_identify_ilbm
;
2981 mi
->help_fn
= de_help_ilbm
;
2984 void de_module_anim(deark
*c
, struct deark_module_info
*mi
)
2987 mi
->desc
= "IFF-ANIM animation";
2988 mi
->run_fn
= de_run_anim
;
2989 mi
->identify_fn
= de_identify_anim
;
2990 mi
->help_fn
= de_help_anim
;
2995 #define CODE_DBOD 0x44424f44U
2996 #define CODE_DEEP 0x44454550U
2997 #define CODE_DGBL 0x4447424cU
2998 #define CODE_DLOC 0x444c4f43U
2999 #define CODE_DPEL 0x4450454cU
3000 #define CODE_MPIC 0x4d504943U
3001 #define CODE_TVDC 0x54564443U
3002 #define CODE_TVPP 0x54565050U
3004 #define DEEP_MAX_COMPONENTS 8
3009 u8 trans_setting
; // TRANS_*
3015 i64 x_aspect
, y_aspect
;
3016 i64 expected_image_size
;
3019 u8 have_alpha_hint
; // Preliminary, set while reading DPEL
3021 UI cmp_nbits
[DEEP_MAX_COMPONENTS
];
3022 UI cmp_type
[DEEP_MAX_COMPONENTS
];
3023 UI sample_map
[DEEP_MAX_COMPONENTS
];
3027 static void do_deep_DGBL(deark
*c
, struct deep_ctx
*d
, struct de_iffctx
*ictx
)
3029 i64 pos
= ictx
->chunkctx
->dpos
;
3031 d
->dspw
= dbuf_getu16be_p(ictx
->f
, &pos
);
3032 d
->dsph
= dbuf_getu16be_p(ictx
->f
, &pos
);
3033 de_dbg(c
, "display size: %"I64_FMT DE_CHAR_TIMES
"%"I64_FMT
, d
->dspw
, d
->dsph
);
3034 if(!d
->found_DLOC
) {
3036 d
->height
= d
->dsph
;
3038 d
->cmpr_meth
= (UI
)dbuf_getu16be_p(ictx
->f
, &pos
);
3039 de_dbg(c
, "cmpr meth: %u", d
->cmpr_meth
);
3040 d
->x_aspect
= (i64
)dbuf_getbyte_p(ictx
->f
, &pos
);
3041 d
->y_aspect
= (i64
)dbuf_getbyte_p(ictx
->f
, &pos
);
3042 de_dbg(c
, "aspect ratio: %d, %d", (int)d
->x_aspect
, (int)d
->y_aspect
);
3045 static void do_deep_DLOC(deark
*c
, struct deep_ctx
*d
, struct de_iffctx
*ictx
)
3047 i64 pos
= ictx
->chunkctx
->dpos
;
3048 i64 pixpos_x
, pixpos_y
;
3051 d
->width
= dbuf_getu16be_p(ictx
->f
, &pos
);
3052 d
->height
= dbuf_getu16be_p(ictx
->f
, &pos
);
3053 de_dbg_dimensions(c
, d
->width
, d
->height
);
3054 pixpos_x
= dbuf_geti16be_p(ictx
->f
, &pos
);
3055 pixpos_y
= dbuf_geti16be_p(ictx
->f
, &pos
);
3056 de_dbg(c
, "position: %"I64_FMT
", %"I64_FMT
, pixpos_x
, pixpos_y
);
3059 static void do_deep_DPEL(deark
*c
, struct deep_ctx
*d
, struct de_iffctx
*ictx
)
3061 i64 pos
= ictx
->chunkctx
->dpos
;
3062 i64 endpos
= ictx
->chunkctx
->dpos
+ ictx
->chunkctx
->dlen
;
3066 d
->num_components
= (UI
)dbuf_getu32be_p(ictx
->f
, &pos
);
3067 de_dbg(c
, "num cmpts: %u", (UI
)d
->num_components
);
3068 if(d
->num_components
>DEEP_MAX_COMPONENTS
) {
3069 d
->num_components
= 0;
3072 for(i
=0; i
<d
->num_components
; i
++) {
3073 if(pos
+4 > endpos
) break;
3074 d
->cmp_type
[i
] = (UI
)dbuf_getu16be_p(ictx
->f
, &pos
);
3075 if(d
->cmp_type
[i
]==4 || d
->cmp_type
[i
]==17) {
3076 d
->have_alpha_hint
= 1;
3078 d
->cmp_nbits
[i
] = (UI
)dbuf_getu16be_p(ictx
->f
, &pos
);
3079 de_dbg(c
, "cmpt[%u]: type=%u depth=%u", i
, d
->cmp_type
[i
], d
->cmp_nbits
[i
]);
3085 // Sets d->sample_map[], d->have_alpha...
3086 // If unsupported image type, reports an error and returns 0.
3087 static int deep_make_sample_map(deark
*c
, struct deep_ctx
*d
)
3090 u8 flags
[5] = {0,0,0,0,0};
3093 de_zeromem(d
->sample_map
, sizeof(d
->sample_map
));
3095 d
->is_assoc_alpha
= 0;
3097 if(d
->num_components
<3 || d
->num_components
>DEEP_MAX_COMPONENTS
) {
3101 for(k
=0; k
<(UI
)d
->num_components
; k
++) {
3102 switch(d
->cmp_type
[k
]) {
3104 d
->sample_map
[k
] = 0;
3107 d
->sample_map
[k
] = 1;
3110 d
->sample_map
[k
] = 2;
3113 d
->sample_map
[k
] = 3;
3115 d
->is_assoc_alpha
= 0;
3117 case 17: // Undocumented type 17 used in Video Toaster "Brushes" files.
3118 d
->sample_map
[k
] = 3;
3120 d
->is_assoc_alpha
= 1;
3123 d
->sample_map
[k
] = 4;
3126 flags
[d
->sample_map
[k
]] = 1;
3129 if(!flags
[0] || !flags
[1] || !flags
[2]) { // Need R, G, B
3132 if(flags
[4]) { // Found an unsupported sample type
3133 de_warn(c
, "Image type not fully supported");
3139 de_err(c
, "Unsupported image type");
3144 static void deep_decode_image_unc(deark
*c
, struct deep_ctx
*d
,
3145 dbuf
*f
, i64 pos1
, i64 len
)
3150 UI dst_samples_per_pixel
;
3151 de_bitmap
*img
= NULL
;
3152 de_finfo
*fi
= NULL
;
3153 u8 s
[5] = {0,0,0,0,0};
3155 fi
= de_finfo_create(c
);
3156 if(d
->x_aspect
&& d
->y_aspect
) {
3157 fi
->density
.code
= DE_DENSITY_UNK_UNITS
;
3158 fi
->density
.ydens
= (double)d
->x_aspect
;
3159 fi
->density
.xdens
= (double)d
->y_aspect
;
3162 dst_samples_per_pixel
= d
->have_alpha
? 4 : 3;
3163 img
= de_bitmap_create(c
, d
->width
, d
->height
, dst_samples_per_pixel
);
3165 for(j
=0; j
<d
->height
; j
++) {
3166 for(i
=0; i
<d
->width
; i
++) {
3169 if(pos
> pos1
+len
) {
3170 de_warn(c
, "Premature end of image");
3174 for(k
=0; k
<(UI
)d
->num_components
; k
++) {
3175 s
[d
->sample_map
[k
]] = dbuf_getbyte_p(f
, &pos
);
3178 clr
= DE_MAKE_RGBA(s
[0], s
[1], s
[2], s
[3]);
3179 if(d
->is_assoc_alpha
) {
3180 clr
= de_unpremultiply_alpha_clr(clr
);
3184 clr
= DE_MAKE_RGB(s
[0], s
[1], s
[2]);
3186 de_bitmap_setpixel_rgba(img
, i
, j
, clr
);
3191 if(d
->trans_setting
==TRANS_AUTO
) {
3192 de_bitmap_optimize_alpha(img
, (0x4|0x02));
3194 else if(d
->trans_setting
==TRANS_REMOVE
) {
3195 de_bitmap_remove_alpha(img
);
3197 de_bitmap_write_to_file_finfo(img
, fi
, DE_CREATEFLAG_OPT_IMAGE
);
3199 de_bitmap_destroy(img
);
3200 de_finfo_destroy(c
, fi
);
3203 static int decompress_deep_5(deark
*c
, struct deep_ctx
*d
, dbuf
*inf
,
3204 i64 pos1
, i64 len
, dbuf
*unc_pixels
)
3209 i64 curr_component
= 0;
3212 struct de_bitreader bitrd
;
3214 de_zeromem(&bitrd
, sizeof(struct de_bitreader
));
3216 bitrd
.curpos
= pos1
;
3217 bitrd
.endpos
= pos1
+len
;
3218 bitrd
.bbll
.is_lsb
= 0;
3219 dbuf_disable_wbuffer(unc_pixels
);
3221 if(!d
->found_TVDC
) {
3222 de_err(c
, "Missing TVDC chunk");
3232 n
= (UI
)de_bitreader_getbits(&bitrd
, 4);
3233 if(bitrd
.eof_flag
) goto done
;
3235 if(d
->tvdc_data
[n
*2+1]!=0 || d
->tvdc_data
[n
*2]!=0) {
3236 v
+= (u8
)(d
->tvdc_data
[n
*2+1]);
3240 n
= (UI
)de_bitreader_getbits(&bitrd
, 4);
3244 for(k
=0; k
<count
; k
++) {
3245 dbuf_writebyte_at(unc_pixels
, output_pos
, v
);
3246 output_pos
+= d
->num_components
;
3248 if(xpos
>= d
->width
) break;
3251 if(xpos
>= d
->width
) {
3252 de_bitreader_skip_to_byte_boundary(&bitrd
);
3256 if(curr_component
>= d
->num_components
) {
3258 if(ypos
>= d
->height
) goto done
;
3261 output_pos
= ypos
*(d
->width
* d
->num_components
) + curr_component
;
3269 static void deep_decompress_and_decode_image(deark
*c
, struct deep_ctx
*d
,
3270 dbuf
*f
, i64 pos1
, i64 len
)
3273 dbuf
*unc_pixels
= NULL
;
3275 unc_pixels
= dbuf_create_membuf(c
, d
->expected_image_size
, 0x1);
3276 if(d
->cmpr_meth
!=5) {
3277 dbuf_enable_wbuffer(unc_pixels
);
3279 if(d
->cmpr_meth
==5) {
3280 ret
= decompress_deep_5(c
, d
, f
, pos1
, len
, unc_pixels
);
3283 ret
= decompress_ilbm_packbits(c
, f
, pos1
, len
, unc_pixels
, d
->expected_image_size
,
3284 (UI
)d
->num_components
);
3286 dbuf_flush(unc_pixels
);
3289 deep_decode_image_unc(c
, d
, unc_pixels
, 0, unc_pixels
->len
);
3291 dbuf_close(unc_pixels
);
3294 static void do_deep_DBOD(deark
*c
, struct deep_ctx
*d
, struct de_iffctx
*ictx
)
3296 if(d
->cmpr_meth
!=0 && d
->cmpr_meth
!=1 && d
->cmpr_meth
!=5) {
3297 de_err(c
, "Unsupported compression type: %u", d
->cmpr_meth
);
3301 if(!deep_make_sample_map(c
, d
)) goto done
;
3303 if(!de_good_image_dimensions(c
, d
->width
, d
->height
)) {
3307 d
->expected_image_size
= d
->width
* d
->height
* d
->num_components
;
3309 if(d
->cmpr_meth
==0) {
3310 deep_decode_image_unc(c
, d
, ictx
->f
, ictx
->chunkctx
->dpos
,
3311 ictx
->chunkctx
->dlen
);
3314 deep_decompress_and_decode_image(c
, d
, ictx
->f
, ictx
->chunkctx
->dpos
,
3315 ictx
->chunkctx
->dlen
);
3322 static void convert_image_rgba(dbuf
*f
, i64 fpos
,
3331 for(j
=0; j
<img
->height
; j
++) {
3332 for(i
=0; i
<img
->width
; i
++) {
3333 dbuf_read(f
, buf
, pos
, 4);
3335 clr
= DE_MAKE_RGBA(buf
[0], buf
[1], buf
[2], buf
[3]);
3336 de_bitmap_setpixel_rgba(img
, i
, j
, clr
);
3341 static void do_deep_mpic(deark
*c
, struct deep_ctx
*d
, dbuf
*f
, i64 pos1
, i64 len
)
3347 de_bitmap
*img
= NULL
;
3349 w
= de_getu16be_p(&pos
);
3351 h
= de_getu16be_p(&pos
);
3352 de_dbg(c
, "32-bit thumbnail image, dimensions: %u"DE_CHAR_TIMES
"%u", (UI
)w
, (UI
)h
);
3354 // I have no documentation for MPIC.
3355 // I'm guessing that it's always RGBA or RGBx, and doesn't depend on DPEL.
3356 // I have some images where DBOD has 3 components, and MPIC has 4 components.
3357 // So I'm guessing that MPIC is *not* defined to be "the same format as DBOD".
3359 // Not sure what these fields are. First one might be sample count.
3360 n
= (UI
)de_getu32be_p(&pos
);
3361 if(n
!= 0x00040002) goto done
;
3363 if(pos
+ rowspan
*h
> pos1
+len
) goto done
;
3365 img
= de_bitmap_create(c
, w
, h
, 4);
3366 convert_image_rgba(f
, pos
, img
);
3368 // If the main image doesn't have an alpha channel, we assume the MPIC
3369 // thumbnail doesn't have transparency.
3370 if(d
->trans_setting
==TRANS_REMOVE
|| (d
->found_DPEL
&& d
->have_alpha_hint
==0)) {
3371 de_bitmap_remove_alpha(img
);
3373 else if(d
->trans_setting
==TRANS_AUTO
) {
3374 de_bitmap_optimize_alpha(img
, 0x1);
3377 de_bitmap_write_to_file(img
, "thumb", DE_CREATEFLAG_IS_AUX
|DE_CREATEFLAG_OPT_IMAGE
);
3382 de_warn(c
, "Unsupported MPIC thumbnail");
3384 de_bitmap_destroy(img
);
3388 static int my_deep_chunk_handler(struct de_iffctx
*ictx
)
3391 struct deep_ctx
*d
= (struct deep_ctx
*)ictx
->userdata
;
3393 switch(ictx
->chunkctx
->chunk4cc
.id
) {
3395 ictx
->is_std_container
= 1;
3399 if(ictx
->level
!= 1) goto done
;
3401 switch(ictx
->chunkctx
->chunk4cc
.id
) {
3403 do_deep_DGBL(c
, d
, ictx
);
3407 do_deep_DLOC(c
, d
, ictx
);
3411 do_deep_DPEL(c
, d
, ictx
);
3415 do_deep_DBOD(c
, d
, ictx
);
3421 dbuf_read(ictx
->f
, d
->tvdc_data
, ictx
->chunkctx
->dpos
, sizeof(d
->tvdc_data
));
3422 // Don't set ictx->handled, since we don't emit dbg info.
3425 do_deep_mpic(c
, d
, ictx
->f
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
3429 do_xs24(c
, ictx
->f
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
3438 static void de_run_deep(deark
*c
, de_module_params
*mparams
)
3440 struct deep_ctx
*d
= NULL
;
3441 struct de_iffctx
*ictx
= NULL
;
3442 const char *opt_trans_str
;
3444 d
= de_malloc(c
, sizeof(struct deep_ctx
));
3446 d
->trans_setting
= TRANS_AUTO
; // default
3447 opt_trans_str
= de_get_ext_option(c
, "deep:trans");
3449 if(!de_strcmp(opt_trans_str
, "auto")) {
3450 d
->trans_setting
= TRANS_AUTO
;
3452 else if(!de_strcmp(opt_trans_str
, "")) {
3453 d
->trans_setting
= TRANS_RESPECT
;
3458 opt_trans_n
= de_atoi(opt_trans_str
);
3459 if(opt_trans_n
==0) {
3460 d
->trans_setting
= TRANS_REMOVE
;
3462 else if(opt_trans_n
>0) {
3463 d
->trans_setting
= TRANS_RESPECT
;
3468 de_declare_fmt(c
, "IFF-DEEP");
3470 ictx
= fmtutil_create_iff_decoder(c
);
3471 ictx
->has_standard_iff_chunks
= 1;
3472 ictx
->alignment
= 2;
3473 ictx
->userdata
= (void*)d
;
3474 ictx
->handle_chunk_fn
= my_deep_chunk_handler
;
3475 ictx
->f
= c
->infile
;
3477 fmtutil_read_iff_format(ictx
, 0, c
->infile
->len
);
3478 de_dbg(c
, "image count: %d", d
->DBOD_count
);
3480 fmtutil_destroy_iff_decoder(ictx
);
3486 static int de_identify_deep(deark
*c
)
3490 if((UI
)de_getu32be(0)!=CODE_FORM
) return 0;
3491 n
= (UI
)de_getu32be(8);
3492 if(n
==CODE_DEEP
|| n
==CODE_TVPP
) return 100;
3496 static void de_help_deep(deark
*c
)
3498 de_msg(c
, "-opt deep:trans=<0|1|auto> : Always remove (0) or respect (1) "
3502 void de_module_deep(deark
*c
, struct deark_module_info
*mi
)
3505 mi
->desc
= "IFF-DEEP";
3506 mi
->run_fn
= de_run_deep
;
3507 mi
->identify_fn
= de_identify_deep
;
3508 mi
->help_fn
= de_help_deep
;