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
);
14 #define ANIM_MAX_FRAMES 10000
16 #define CODE_8SVX 0x38535658U
17 #define CODE_ABIT 0x41424954U
18 #define CODE_ACBM 0x4143424dU
19 #define CODE_ANHD 0x414e4844U
20 #define CODE_ANIM 0x414e494dU
21 #define CODE_ANSQ 0x414e5351U
22 #define CODE_BEAM 0x4245414dU
23 #define CODE_BMHD 0x424d4844U
24 #define CODE_BODY 0x424f4459U
25 #define CODE_CAMG 0x43414d47U
26 #define CODE_CCRT 0x43435254U
27 #define CODE_CLUT 0x434c5554U
28 #define CODE_CMAP 0x434d4150U
29 #define CODE_CRNG 0x43524e47U
30 #define CODE_CTBL 0x4354424cU
31 #define CODE_DLTA 0x444c5441U
32 #define CODE_DPAN 0x4450414eU
33 #define CODE_DPI 0x44504920U
34 #define CODE_DRNG 0x44524e47U
35 #define CODE_FORM 0x464f524dU
36 #define CODE_GRAB 0x47524142U
37 #define CODE_ILBM 0x494c424dU
38 #define CODE_PBM 0x50424d20U
39 #define CODE_PCHG 0x50434847U
40 #define CODE_SBDY 0x53424459U
41 #define CODE_SHAM 0x5348414dU
42 #define CODE_TINY 0x54494e59U
43 #define CODE_VDAT 0x56444154U
47 #define MASKINGTYPE_NONE 0
48 #define MASKINGTYPE_1BITMASK 1
49 #define MASKINGTYPE_COLORKEY 2
50 #define MASKINGTYPE_LASSO 3
53 COLORTYPE_DEFAULT
= 0,
57 // Parameters for a single image, derived from a combination of the global
58 // state and the image context.
62 i64 planes_total
; // Different from planes_fg if MASKINGTYPE_1BITMASK.
65 u8 use_colorkey_transparency
;
67 i64 x_aspect
, y_aspect
;
68 i64 bits_per_row_per_plane
;
69 i64 bytes_per_row_per_plane
;
70 i64 frame_buffer_rowspan
;
71 i64 frame_buffer_size
;
72 enum colortype_enum colortype
;
74 int is_pbm
; // frame buffer is PBM pixel format
80 int done_flag
; // Have we processed the image (BODY/DLTA/etc. chunk)?
81 int change_flag
; // Is this frame different from the previous one?
88 typedef struct localctx_struct
{
91 i64 main_chunk_endpos
;
92 int FORM_level
; // nesting level of the frames' FORM chunks
94 int num_frames_started
;
95 int num_frames_finished
;
96 int debug_frame_buffer
;
100 u8 opt_anim_includedups
;
103 u8 cmap_changed_flag
;
104 u8 bmhd_changed_flag
;
106 u8 ham_flag
; // "hold and modify"
109 u8 ehb_flag
; // "extra halfbrite"
110 u8 uses_color_cycling
;
111 u8 color_cycling_warned
;
119 u8 uses_anim4_5_xor_mode
;
120 u8 uses_anim_long_data
;
121 u8 multipalette_warned
;
122 u8 extra_content_warned
;
131 UI transparent_color
;
132 i64 x_aspect
, y_aspect
;
134 i64 thumb_width
, thumb_height
;
136 int hotspot_x
, hotspot_y
;
138 struct frame_ctx
*frctx
; // Non-NULL means we're inside a frame
139 struct frame_ctx
*oldfrctx
[2];
140 i64 pal_ncolors
; // Number of colors we read from the file
141 int pal_is_grayscale
;
142 u32 pal_raw
[256]; // Palette as read from the file
143 u32 pal
[256]; // Palette that we will use
144 u8 delta_ops_used
[256];
147 static const char *anim_get_op_name(u8 op
)
149 const char *name
= NULL
;
152 case 0: name
="direct"; break;
153 case ANIM_OP_XOR
: name
="XOR"; break;
154 case 2: name
="long delta"; break;
155 case 3: name
="short delta"; break;
156 case 4: name
="short/long delta"; break;
157 case 5: name
="byte vert. delta"; break;
158 case 7: name
="short/long vert. delta, separated"; break;
159 case 8: name
="short/long vert. delta, contiguous"; break;
160 case 74: name
="ANIM-J (Eric Graham)"; break;
161 case 100: name
="ANIM32"; break;
162 case 101: name
="ANIM16"; break;
163 case 108: name
="ANIM-l (Eric Graham)"; break;
165 return name
?name
:"?";
168 static const char *get_maskingtype_name(u8 n
)
170 const char *name
= NULL
;
173 case MASKINGTYPE_NONE
: name
= "no transparency"; break;
174 case MASKINGTYPE_1BITMASK
: name
= "1-bit transparency mask"; break;
175 case MASKINGTYPE_COLORKEY
: name
= "color-key transparency"; break;
176 case MASKINGTYPE_LASSO
: name
= "lasso"; break;
178 return name
?name
:"?";
181 static const char *get_cmprtype_name(lctx
*d
, u8 n
)
183 const char *name
= NULL
;
185 if(d
->formtype
==CODE_ACBM
) return "n/a";
188 case 0: name
= "uncompressed"; break;
189 case 1: name
= "PackBits"; break;
190 case 2: name
= "VDAT"; break;
192 return name
?name
:"?";
195 static void on_color_cycling_enabled(deark
*c
, lctx
*d
)
197 d
->uses_color_cycling
= 1;
198 if(d
->color_cycling_warned
) return;
199 de_warn(c
, "This image uses color cycling animation, which is not supported.");
200 d
->color_cycling_warned
= 1;
203 static void on_multipalette_enabled(deark
*c
, lctx
*d
)
205 if(!d
->opt_allowsham
) {
208 if(d
->multipalette_warned
) return;
209 if(d
->opt_allowsham
) {
210 de_warn(c
, "This is a multi-palette image, which is not correctly supported.");
213 de_err(c
, "Multi-palette ILBM images are not supported. "
214 "(\"-opt ilbm:allowsham\" to decode anyway)");
218 static struct frame_ctx
*create_frame(deark
*c
, lctx
*d
)
220 struct frame_ctx
*frctx
;
221 frctx
= de_malloc(c
, sizeof(struct frame_ctx
));
225 static void destroy_frame(deark
*c
, lctx
*d
, struct frame_ctx
*frctx
)
228 dbuf_close(frctx
->frame_buffer
);
232 static void do_cmap(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
237 d
->cmap_changed_flag
= 1;
239 de_dbg(c
, "number of palette colors: %d", (int)ncolors
);
240 if(ncolors
>256) ncolors
=256;
242 de_read_palette_rgb(c
->infile
, pos
, ncolors
, 3, d
->pal_raw
, 256, 0);
243 if(ncolors
> d
->pal_ncolors
) {
244 d
->pal_ncolors
= ncolors
;
248 static int do_bmhd(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
252 const char *masking_name
;
254 d
->bmhd_changed_flag
= 1;
256 de_err(c
, "Bad BMHD chunk");
261 d
->width
= de_getu16be_p(&pos
);
262 d
->height
= de_getu16be_p(&pos
);
263 de_dbg_dimensions(c
, d
->width
, d
->height
);
266 d
->planes_raw
= (i64
)de_getbyte_p(&pos
);
267 de_dbg(c
, "planes: %d", (int)d
->planes_raw
);
268 d
->masking_code
= de_getbyte_p(&pos
);
269 masking_name
= get_maskingtype_name(d
->masking_code
);
271 d
->compression
= de_getbyte_p(&pos
);
272 de_dbg(c
, "compression: %d (%s)", (int)d
->compression
, get_cmprtype_name(d
, d
->compression
));
275 d
->transparent_color
= (UI
)de_getu16be_p(&pos
);
276 de_dbg(c
, "masking: %d (%s)", (int)d
->masking_code
, masking_name
);
277 if(d
->masking_code
==MASKINGTYPE_COLORKEY
|| d
->masking_code
==MASKINGTYPE_LASSO
) {
279 de_dbg(c
, "color key: %u", d
->transparent_color
);
280 de_dbg_indent(c
, -1);
283 d
->x_aspect
= (i64
)de_getbyte_p(&pos
);
284 d
->y_aspect
= (i64
)de_getbyte_p(&pos
);
285 de_dbg(c
, "aspect ratio: %d, %d", (int)d
->x_aspect
, (int)d
->y_aspect
);
292 static i64
delta3_calc_elem_pos(i64 elemnum
, i64 elemsize
, i64 elems_per_row
, i64 plane_offset
,
293 i64 frame_buffer_rowspan
)
297 row
= elemnum
/ elems_per_row
;
298 col
= elemnum
% elems_per_row
;
299 return row
* frame_buffer_rowspan
+ plane_offset
+ elemsize
* col
;
302 // Note - It should be easy to modify this to work for DLTA#2 compression as well
303 // (need a sample file).
304 static void decompress_plane_delta_op3(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
305 struct frame_ctx
*frctx
, i64 plane
, i64 pos1
, i64 maxlen
)
307 i64 endpos
= pos1
+maxlen
;
317 de_dbg2(c
, "delta3 plane at %"I64_FMT
", maxlen=%"I64_FMT
, pos1
, maxlen
);
319 elems_per_row
= (ibi
->bytes_per_row_per_plane
+ (elemsize
-1) ) / elemsize
;
320 if(elems_per_row
<1) goto done
;
321 elems_total
= elems_per_row
* ibi
->height
;
322 plane_offset
= plane
* ibi
->bytes_per_row_per_plane
;
328 if(elemnum
>= elems_total
) break;
329 if(pos
+2 >= endpos
) goto done
;
330 code
= de_geti16be_p(&pos
);
332 if(code
== -1) { // Stop.
335 else if(code
>= 0) { // Skip some number of elements, then write one element.
336 frctx
->change_flag
= 1;
339 de_read(elembuf
, pos
, elemsize
);
341 dstpos
= delta3_calc_elem_pos(elemnum
, elemsize
, elems_per_row
, plane_offset
,
342 ibi
->frame_buffer_rowspan
);
343 dbuf_write_at(frctx
->frame_buffer
, dstpos
, elembuf
, elemsize
);
345 else { // Skip some number of elements, then write multiple elements.
351 count
= de_getu16be_p(&pos
);
353 frctx
->change_flag
= 1;
355 for(k
=0; k
<count
; k
++) {
356 de_read(elembuf
, pos
, elemsize
);
359 dstpos
= delta3_calc_elem_pos(elemnum
, elemsize
, elems_per_row
, plane_offset
,
360 ibi
->frame_buffer_rowspan
);
361 dbuf_write_at(frctx
->frame_buffer
, dstpos
, elembuf
, elemsize
);
370 // "Short Delta" mode
371 // Decompress into frctx->frame_buffer
372 static void decompress_delta_op3(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
373 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
377 i64 planedata_offs
[8];
379 de_dbg(c
, "[delta3 data]");
382 planedata_offs
[i
] = de_getu32be_p(&pos
);
383 if(i
<ibi
->planes_total
) {
384 de_dbg2(c
, "plane[%d] offs: %"I64_FMT
, (int)i
, planedata_offs
[i
]);
385 if(planedata_offs
[i
]>0) {
386 decompress_plane_delta_op3(c
, d
, ibi
, frctx
, i
,
387 pos1
+planedata_offs
[i
], len
-planedata_offs
[i
]);
393 static i64
get_elem_as_int_p(dbuf
*f
, i64
*ppos
, i64 elem_size
)
396 return (i64
)dbuf_getbyte_p(f
, ppos
);
399 return dbuf_getu16be_p(f
, ppos
);
401 return dbuf_getu32be_p(f
, ppos
);
404 // This routine decompresses most frame types used in DLTA#5, #7, and #8.
405 // For #7, the codestream and datastream are stored separately, and have different
407 // For #5 and #8, datapos1 is not used.
408 static void decompress_plane_vdelta(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
409 struct frame_ctx
*frctx
, i64 plane_idx
,
410 dbuf
*inf
, i64 codepos1
, i64 datapos1
, i64 endpos
,
411 i64 code_size
, i64 dataelem_size
, int separate_data_stream
, u8 xor_mode
)
413 i64 pos
= codepos1
; // If !separate_data_stream, this is for code and data
414 i64 datapos
= datapos1
;
417 i64 dststride
= ibi
->frame_buffer_rowspan
;
419 int baddata_flag
= 0;
421 if(separate_data_stream
) {
422 de_dbg2(c
, "vdelta(%d,%d) plane %d at (%"I64_FMT
",%"I64_FMT
")", (int)code_size
,
423 (int)dataelem_size
, (int)plane_idx
, codepos1
, datapos1
);
426 de_dbg2(c
, "vdelta(%d) plane at (%"I64_FMT
")", (int)code_size
, codepos1
);
428 if(code_size
!=1 && code_size
!=2 && code_size
!=4) goto done
;
429 if(dataelem_size
!=1 && dataelem_size
!=2 && dataelem_size
!=4) goto done
;
430 if(xor_mode
&& dataelem_size
!=1) goto done
;
433 unc_threshold
= 0x80;
435 else if(code_size
==2) {
436 unc_threshold
= 0x8000;
439 unc_threshold
= 0x80000000U
;
442 if(dataelem_size
==1) {
443 num_columns
= (ibi
->width
+7)/8;
445 else if(dataelem_size
==2) {
446 num_columns
= (ibi
->width
+15)/16;
449 num_columns
= (ibi
->width
+31)/32;
452 for(col
=0; col
<num_columns
; col
++) {
455 i64 elem_bytes_to_write
;
457 i64 col_start_dstpos
;
464 // Defend against writing beyond the right edge of this plane
465 if((dataelem_size
==4) && (col
+1 == num_columns
) && (ibi
->bytes_per_row_per_plane
%4)) {
466 elem_bytes_to_write
= 2;
469 elem_bytes_to_write
= dataelem_size
;
472 col_start_dstpos
= plane_idx
* ibi
->bytes_per_row_per_plane
+ dataelem_size
*col
;
474 opcount
= get_elem_as_int_p(inf
, &pos
, code_size
);
475 if(c
->debug_level
>=3) {
476 de_dbg3(c
, "col %d op count: %"I64_FMT
, (int)col
, opcount
);
479 for(opidx
=0; opidx
<opcount
; opidx
++) {
490 op
= (UI
)get_elem_as_int_p(inf
, &pos
, code_size
);
493 count
= get_elem_as_int_p(inf
, &pos
, code_size
);
494 if(ypos
+count
> ibi
->height
) {
500 frctx
->change_flag
= 1;
503 if(separate_data_stream
) {
504 if(datapos
>=endpos
) {
508 dbuf_read(inf
, valbuf
, datapos
, dataelem_size
);
509 datapos
+= dataelem_size
;
512 dbuf_read(inf
, valbuf
, pos
, dataelem_size
);
513 pos
+= dataelem_size
;
516 for(k
=0; k
<count
; k
++) {
517 dstpos
= col_start_dstpos
+ ypos
*dststride
;
521 val
= valbuf
[0] ^ dbuf_getbyte(frctx
->frame_buffer
, dstpos
);
522 dbuf_writebyte_at(frctx
->frame_buffer
, dstpos
, val
);
525 dbuf_write_at(frctx
->frame_buffer
, dstpos
, valbuf
, elem_bytes_to_write
);
530 else if(op
< unc_threshold
) { // skip
533 else { // uncompressed run
534 count
= (i64
)(op
- unc_threshold
);
535 if(ypos
+count
> ibi
->height
) {
541 frctx
->change_flag
= 1;
544 for(k
=0; k
<count
; k
++) {
545 if(separate_data_stream
) {
546 if(datapos
>=endpos
) {
550 dbuf_read(inf
, valbuf
, datapos
, dataelem_size
);
551 datapos
+= dataelem_size
;
554 dbuf_read(inf
, valbuf
, pos
, dataelem_size
);
555 pos
+= dataelem_size
;
558 dstpos
= col_start_dstpos
+ ypos
*dststride
;
560 valbuf
[0] ^= dbuf_getbyte(frctx
->frame_buffer
, dstpos
);
562 dbuf_write_at(frctx
->frame_buffer
, dstpos
, valbuf
, elem_bytes_to_write
);
570 if(baddata_flag
&& !d
->errflag
) {
571 de_err(c
, "Delta decompression failed");
576 // Decompress into frctx->frame_buffer
577 static void decompress_delta_op5(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
578 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
580 i64 planedata_offs
[16];
583 int saved_indent_level
;
584 u8 delta4_5_xor_mode
= 0;
586 de_dbg_indent_save(c
, &saved_indent_level
);
587 if(!frctx
->frame_buffer
) goto done
;
589 de_dbg(c
, "[delta5 data]");
591 // Note that we ignore the 0x8 bit ("RLC - run length coded").
592 // I don't know what this option is for. *All* ANIM4/5 frames use run length
593 // coding, but they almost never have have this bit set.
594 // The rare files that do set this bit don't seem to be any different from
596 if((frctx
->bits
& 0xfffffff5U
) != 0) {
597 de_err(c
, "Unsupported ANHD options");
602 if(frctx
->bits
& 0x2) {
603 delta4_5_xor_mode
= 1;
606 for(i
=0; i
<16; i
++) {
607 if(d
->errflag
) goto done
;
608 planedata_offs
[i
] = de_getu32be_p(&pos
);
609 if(i
<ibi
->planes_total
) {
610 de_dbg2(c
, "plane[%d] offs: %"I64_FMT
, i
, planedata_offs
[i
]);
611 if(planedata_offs
[i
]>0) {
612 decompress_plane_vdelta(c
, d
, ibi
, frctx
, i
, c
->infile
,
613 pos1
+planedata_offs
[i
], 0, pos1
+len
, 1, 1,
614 0, delta4_5_xor_mode
);
620 de_dbg_indent_restore(c
, saved_indent_level
);
623 // Decompress into frctx->frame_buffer
624 static void decompress_delta_op7(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
625 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
627 i64 opcodelist_offs
[8];
628 i64 datalist_offs
[8];
631 int saved_indent_level
;
635 de_dbg_indent_save(c
, &saved_indent_level
);
636 if(!frctx
->frame_buffer
) goto done
;
638 de_dbg(c
, "[delta7 data]");
640 if(frctx
->bits
& 0xfffffffeU
) {
641 de_err(c
, "Unsupported ANHD options");
645 if(frctx
->bits
& 0x00000001) {
652 // We'll have to interleave lots of short reads between two different segments of
653 // the file, with no way to know how big either segment is.
654 // I see no good way to process this DLTA#7 format, except by first reading the
655 // entire chunk into memory.
656 if(len
> DE_MAX_SANE_OBJECT_SIZE
) {
660 inf
= dbuf_create_membuf(c
, len
, 0);
661 dbuf_copy(c
->infile
, pos1
, len
, inf
);
665 opcodelist_offs
[i
] = dbuf_getu32be_p(inf
, &infpos
);
669 datalist_offs
[i
] = dbuf_getu32be_p(inf
, &infpos
);
673 if(d
->errflag
) goto done
;
674 if(i
<ibi
->planes_total
) {
675 de_dbg2(c
, "opcode_list[%d] offs: %"I64_FMT
, i
, opcodelist_offs
[i
]);
676 de_dbg2(c
, "data_list[%d] offs: %"I64_FMT
, i
, datalist_offs
[i
]);
677 if(opcodelist_offs
[i
]>0) {
678 decompress_plane_vdelta(c
, d
, ibi
, frctx
, i
, inf
,
679 opcodelist_offs
[i
], datalist_offs
[i
], len
,
680 1, dataelem_size
, 1, 0);
687 de_dbg_indent_restore(c
, saved_indent_level
);
690 static void decompress_delta_op8(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
691 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
693 i64 planedata_offs
[16];
697 int saved_indent_level
;
699 de_dbg_indent_save(c
, &saved_indent_level
);
700 if(!frctx
->frame_buffer
) goto done
;
702 de_dbg(c
, "[delta8 data]");
704 if(frctx
->bits
& 0xfffffffeU
) {
705 de_err(c
, "Unsupported ANHD options");
709 if(frctx
->bits
& 0x00000001) {
716 for(i
=0; i
<16; i
++) {
717 if(d
->errflag
) goto done
;
718 planedata_offs
[i
] = de_getu32be_p(&pos
);
719 if(i
<ibi
->planes_total
) {
720 de_dbg2(c
, "plane[%d] offs: %"I64_FMT
, i
, planedata_offs
[i
]);
721 if(planedata_offs
[i
]>0) {
722 decompress_plane_vdelta(c
, d
, ibi
, frctx
, i
, c
->infile
,
723 pos1
+planedata_offs
[i
], 0, pos1
+len
, elem_size
, elem_size
, 0, 0);
729 de_dbg_indent_restore(c
, saved_indent_level
);
733 struct imgbody_info
*ibi
;
734 struct frame_ctx
*frctx
;
741 i64 nrows
; // block height in rows
742 i64 nbytes
; // block width in bytes per plane
745 static void do_delta74_blocks(deark
*c
, struct d74state
*d74s
)
747 i64 blkidx
, rowidx
, planeidx
, byteidx
;
748 i64 d74_bytes_per_row_per_plane
;
750 // Reportedly, the 'offset' field assumes a potentially-different measuring
751 // system than one would expect.
752 d74_bytes_per_row_per_plane
= (d74s
->ibi
->width
+ 7)/8;
754 for(blkidx
=0; blkidx
<d74s
->nblocks
; blkidx
++) {
756 i64 block_srcpos
= d74s
->pos
;
759 if(d74s
->pos
+2 >= d74s
->endpos
) goto done
;
760 offset
= de_getu16be_p(&d74s
->pos
);
762 block_dstpos
= (offset
/ d74_bytes_per_row_per_plane
) * d74s
->ibi
->frame_buffer_rowspan
+
763 (offset
% d74_bytes_per_row_per_plane
);
765 for(rowidx
=0; rowidx
<d74s
->nrows
; rowidx
++) {
766 for(planeidx
=0; planeidx
<d74s
->ibi
->planes_total
; planeidx
++) {
769 // Calculate the offset in our frame buffer.
770 dstpos
= block_dstpos
+ (rowidx
* d74s
->ibi
->frame_buffer_rowspan
) +
771 planeidx
* d74s
->ibi
->bytes_per_row_per_plane
;
773 for(byteidx
=0; byteidx
<d74s
->nbytes
; byteidx
++) {
776 val
= de_getbyte_p(&d74s
->pos
);
777 if(d74s
->op
) val
^= dbuf_getbyte(d74s
->frctx
->frame_buffer
, dstpos
);
778 dbuf_writebyte_at(d74s
->frctx
->frame_buffer
, dstpos
, val
);
784 if((d74s
->pos
- block_srcpos
) & 0x1) {
785 d74s
->pos
++; // padding byte
793 static void decompress_delta_op74(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
794 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
796 struct d74state d74s
;
798 de_zeromem(&d74s
, sizeof(struct d74state
));
802 d74s
.endpos
= pos1
+len
;
804 if(!d
->delta_ops_used
[74]) { // If this is the first DLTA#7 chunk...
805 if(ibi
->width
< 320) {
806 // The XAnim code says this is a special case, but I haven't found any
807 // sample files. (TODO)
808 de_warn(c
, "ANIM-J with width < 320 might not be supported correctly");
815 if(d74s
.pos
+2 >= d74s
.endpos
) goto done
;
816 code
= (UI
)de_getu16be_p(&d74s
.pos
);
818 frctx
->change_flag
= 1;
819 d74s
.op
= (UI
)de_getu16be_p(&d74s
.pos
);
820 d74s
.nrows
= de_getu16be_p(&d74s
.pos
);
822 d74s
.nblocks
= de_getu16be_p(&d74s
.pos
);
823 do_delta74_blocks(c
, &d74s
);
826 frctx
->change_flag
= 1;
827 d74s
.op
= (UI
)de_getu16be_p(&d74s
.pos
);
828 d74s
.nrows
= de_getu16be_p(&d74s
.pos
);
829 d74s
.nbytes
= de_getu16be_p(&d74s
.pos
);
830 d74s
.nblocks
= de_getu16be_p(&d74s
.pos
);
831 do_delta74_blocks(c
, &d74s
);
837 de_warn(c
, "Bad or unsupported ANIM-J compression code (%u)", code
);
847 // Similar to op3, but different in enough ways that it probably isn't worth
848 // combining into one function.
849 static void decompress_plane_delta_op108(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
850 struct frame_ctx
*frctx
, i64 plane_idx
, dbuf
*inf
, i64 codepos1
, i64 datapos1
,
853 i64 codepos
= codepos1
;
854 i64 datapos
= datapos1
;
855 const i64 code_size
= 2;
856 const i64 dataelem_size
= 2;
860 int baddata_flag
= 0;
862 de_dbg2(c
, "delta108 plane %d at (%"I64_FMT
",%"I64_FMT
")", (int)plane_idx
,
865 elems_per_row
= (ibi
->bytes_per_row_per_plane
+ (dataelem_size
-1) ) / dataelem_size
;
866 if(elems_per_row
<1) goto done
;
867 plane_offset
= plane_idx
* ibi
->bytes_per_row_per_plane
;
875 if(codepos
+code_size
> endpos
) goto done
;
876 elemnum
= dbuf_getu16be_p(inf
, &codepos
);
878 if(elemnum
== 0xffff) { // Stop.
882 ypos
= elemnum
/ elems_per_row
;
883 xpos
= elemnum
% elems_per_row
;
884 dstpos
= plane_offset
+ ypos
* ibi
->frame_buffer_rowspan
+ dataelem_size
*xpos
;
886 if(codepos
+code_size
> endpos
) goto done
;
887 count_code
= dbuf_geti16be_p(inf
, &codepos
);
889 if(count_code
< 0) { // an uncompressed run
890 i64 count
= -count_code
;
893 frctx
->change_flag
= 1;
895 if(datapos
+ dataelem_size
> endpos
) {
899 dbuf_read(inf
, elembuf
, datapos
, dataelem_size
);
900 datapos
+= dataelem_size
;
902 for(k
=0; k
<count
; k
++) {
903 if(ypos
>= ibi
->height
) {
908 dbuf_write_at(frctx
->frame_buffer
, dstpos
, elembuf
, dataelem_size
);
910 dstpos
+= ibi
->frame_buffer_rowspan
;
914 i64 count
= count_code
;
917 if(count
> 0) frctx
->change_flag
= 1;
919 for(k
=0; k
<count
; k
++) {
920 if(ypos
>= ibi
->height
) {
924 if(datapos
+ dataelem_size
> endpos
) {
928 dbuf_read(inf
, elembuf
, datapos
, dataelem_size
);
929 datapos
+= dataelem_size
;
931 dbuf_write_at(frctx
->frame_buffer
, dstpos
, elembuf
, dataelem_size
);
933 dstpos
+= ibi
->frame_buffer_rowspan
;
939 if(baddata_flag
&& !d
->errflag
) {
940 de_err(c
, "Delta decompression failed");
945 static void decompress_delta_op108(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
946 struct frame_ctx
*frctx
, i64 pos1
, i64 len
)
948 i64 opcodelist_offs
[8];
949 i64 datalist_offs
[8];
952 int saved_indent_level
;
955 de_dbg_indent_save(c
, &saved_indent_level
);
956 if(!frctx
->frame_buffer
) goto done
;
958 de_dbg(c
, "[delta108 data]");
960 // Read the entire chunk into memory, so that the random-access reads will be
962 if(len
> DE_MAX_SANE_OBJECT_SIZE
) {
966 inf
= dbuf_create_membuf(c
, len
, 0);
967 dbuf_copy(c
->infile
, pos1
, len
, inf
);
971 datalist_offs
[i
] = dbuf_getu32be_p(inf
, &infpos
);
975 opcodelist_offs
[i
] = dbuf_getu32be_p(inf
, &infpos
);
979 if(d
->errflag
) goto done
;
980 if(i
<ibi
->planes_total
) {
981 de_dbg2(c
, "opcode_list[%d] offs: %"I64_FMT
, i
, opcodelist_offs
[i
]);
982 de_dbg2(c
, "data_list[%d] offs: %"I64_FMT
, i
, datalist_offs
[i
]);
983 if(opcodelist_offs
[i
]>0) {
984 decompress_plane_delta_op108(c
, d
, ibi
, frctx
, i
, inf
,
985 2*opcodelist_offs
[i
], 2*datalist_offs
[i
], len
);
992 de_dbg_indent_restore(c
, saved_indent_level
);
995 static void pal_fixup4(deark
*c
, lctx
*d
)
1000 for(k
=0; k
<d
->pal_ncolors
; k
++) {
1001 cr
= DE_COLOR_R(d
->pal
[k
]);
1002 cg
= DE_COLOR_G(d
->pal
[k
]);
1003 cb
= DE_COLOR_B(d
->pal
[k
]);
1007 d
->pal
[k
] = DE_MAKE_RGB(cr
, cg
, cb
);
1011 static void pal_fixup6(deark
*c
, lctx
*d
)
1016 for(k
=0; k
<d
->pal_ncolors
; k
++) {
1017 cr
= DE_COLOR_R(d
->pal
[k
]);
1018 cg
= DE_COLOR_G(d
->pal
[k
]);
1019 cb
= DE_COLOR_B(d
->pal
[k
]);
1020 cr
= (cr
&0xfc)|(cr
>>6);
1021 cg
= (cg
&0xfc)|(cg
>>6);
1022 cb
= (cb
&0xfc)|(cb
>>6);
1023 d
->pal
[k
] = DE_MAKE_RGB(cr
, cg
, cb
);
1027 // It's clear that some ILBM images have palette colors with only 4 bits of
1028 // precision (the low bits often being set to 0), while others have 8, or
1029 // something in between.
1030 // What's not clear is how to tell them apart.
1032 // * HAM6 images always have 4.
1033 // * HAM8 images always have 6.
1034 // * For anything else, assume 4 if the low 4 bits are all 0.
1036 // TODO: It may be safe to assume that 8-plane images always have 8, but
1037 // more research is needed.
1038 static void fixup_palette(deark
*c
, lctx
*d
)
1043 if(d
->pal_ncolors
<1) return;
1054 for(k
=0; k
<d
->pal_ncolors
; k
++) {
1055 cr
= DE_COLOR_R(d
->pal
[k
]);
1056 cg
= DE_COLOR_G(d
->pal
[k
]);
1057 cb
= DE_COLOR_B(d
->pal
[k
]);
1058 if((cr
&0x0f) != 0) return;
1059 if((cg
&0x0f) != 0) return;
1060 if((cb
&0x0f) != 0) return;
1062 de_dbg(c
, "Palette seems to have 4 bits of precision. Rescaling palette.");
1066 // Called when we encounter a BODY or DLTA or TINY chunk
1067 static void do_before_image_chunk(deark
*c
, lctx
*d
)
1069 if(d
->bmhd_changed_flag
) {
1070 if(!d
->found_cmap
&& d
->planes_raw
<=8) {
1071 de_make_grayscale_palette(d
->pal
, (i64
)1<<(UI
)d
->planes_raw
, 0);
1074 if(d
->planes_raw
==6 && d
->pal_ncolors
==32 && !d
->ehb_flag
&& !d
->ham_flag
) {
1075 de_warn(c
, "Assuming this is an EHB image");
1080 if(d
->cmap_changed_flag
) {
1081 de_memcpy(d
->pal
, d
->pal_raw
, (size_t)d
->pal_ncolors
* sizeof(d
->pal_raw
[0]));
1084 if(d
->cmap_changed_flag
&& d
->ehb_flag
&& d
->planes_raw
==6) {
1087 // TODO: Should we still do this if the palette already has 64 colors
1088 // (as it often does)?
1089 for(k
=0; k
<32; k
++) {
1092 cr
= DE_COLOR_R(d
->pal
[k
]);
1093 cg
= DE_COLOR_G(d
->pal
[k
]);
1094 cb
= DE_COLOR_B(d
->pal
[k
]);
1095 d
->pal
[k
+32] = DE_MAKE_RGB(cr
/2, cg
/2, cb
/2);
1100 if(d
->opt_fixpal
&& !d
->is_anim
&& d
->cmap_changed_flag
) {
1101 fixup_palette(c
, d
);
1104 if(d
->cmap_changed_flag
) {
1105 d
->pal_is_grayscale
= de_is_grayscale_palette(d
->pal
, 256);
1108 d
->cmap_changed_flag
= 0;
1109 d
->bmhd_changed_flag
= 0;
1112 static int init_imgbody_info(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
, int is_thumb
)
1116 ibi
->is_thumb
= is_thumb
;
1118 // Unlike ACBM, it would be messy and slow to convert PBM to the standard ILBM
1119 // frame buffer format (and back). So we support a special frame buffer format
1121 ibi
->is_pbm
= (d
->formtype
==CODE_PBM
);
1124 ibi
->width
= d
->thumb_width
;
1125 ibi
->height
= d
->thumb_height
;
1128 ibi
->width
= d
->width
;
1129 ibi
->height
= d
->height
;
1132 // Quick & dirty support for -padpix.
1133 // TODO: Some of these conditions could be removed, with care.
1134 if(c
->padpix
&& (d
->width
%16) && !is_thumb
&& !d
->is_anim
&& d
->formtype
==CODE_ILBM
&&
1137 ibi
->width
= de_pad_to_n(ibi
->width
, 16);
1140 ibi
->compression
= d
->compression
;
1142 ibi
->masking_code
= d
->masking_code
;
1143 // Based on what little data I have, it seems that TINY images do not have
1144 // a transparency mask, even if the main image does.
1145 if(is_thumb
&& ibi
->masking_code
==MASKINGTYPE_1BITMASK
) {
1146 ibi
->masking_code
= MASKINGTYPE_NONE
;
1149 if(d
->planes_raw
==24) {
1150 ibi
->colortype
= COLORTYPE_RGB24
;
1153 ibi
->colortype
= COLORTYPE_DEFAULT
;
1158 ibi
->planes_total
= 1;
1161 ibi
->planes_fg
= d
->planes_raw
;
1162 ibi
->planes_total
= d
->planes_raw
;
1163 if(ibi
->masking_code
==MASKINGTYPE_1BITMASK
) {
1164 ibi
->planes_total
++;
1167 ibi
->transparent_color
= d
->transparent_color
;
1168 ibi
->x_aspect
= d
->x_aspect
;
1169 ibi
->y_aspect
= d
->y_aspect
;
1172 if(d
->planes_raw
!=8 || d
->masking_code
==MASKINGTYPE_1BITMASK
) {
1173 de_err(c
, "Not a supported PBM format");
1179 ibi
->bytes_per_row_per_plane
= ibi
->width
;
1180 if(ibi
->bytes_per_row_per_plane
%2) {
1181 ibi
->bytes_per_row_per_plane
++;
1183 ibi
->bits_per_row_per_plane
= ibi
->bytes_per_row_per_plane
* 8;
1184 // Note: The PBM row size might be adjusted later, after decompression.
1187 ibi
->bits_per_row_per_plane
= de_pad_to_n(ibi
->width
, 16);
1188 ibi
->bytes_per_row_per_plane
= ibi
->bits_per_row_per_plane
/8;
1190 ibi
->frame_buffer_rowspan
= ibi
->bytes_per_row_per_plane
* ibi
->planes_total
;
1191 ibi
->frame_buffer_size
= ibi
->frame_buffer_rowspan
* ibi
->height
;
1193 if(ibi
->masking_code
==MASKINGTYPE_NONE
) {
1196 else if(ibi
->masking_code
==MASKINGTYPE_COLORKEY
) {
1197 if(!d
->opt_notrans
&& ibi
->planes_fg
<=8 && !d
->ham_flag
) {
1198 ibi
->use_colorkey_transparency
= 1;
1201 else if(ibi
->masking_code
==MASKINGTYPE_1BITMASK
) {
1205 de_warn(c
, "This type of transparency is not supported");
1208 if(ibi
->use_colorkey_transparency
&& ibi
->transparent_color
<=255) {
1209 d
->pal
[ibi
->transparent_color
] = DE_SET_ALPHA(d
->pal
[ibi
->transparent_color
], 0);
1212 if(ibi
->colortype
==COLORTYPE_RGB24
) {
1215 else if(ibi
->planes_fg
<1 || ibi
->planes_fg
>8) {
1216 de_err(c
, "Bad or unsupported number of planes (%d)", (int)ibi
->planes_fg
);
1225 static void write_frame(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
, struct frame_ctx
*frctx
);
1227 static void do_dlta(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
1229 struct frame_ctx
*frctx
= d
->frctx
;
1230 struct frame_ctx
*reference_frctx
= NULL
;
1231 struct imgbody_info
*ibi
= NULL
;
1232 int saved_indent_level
;
1234 de_dbg_indent_save(c
, &saved_indent_level
);
1236 if(d
->errflag
) goto done
;
1237 if(!d
->found_bmhd
) goto done
;
1238 if(!frctx
) goto done
;
1239 if(frctx
->done_flag
) goto done
;
1240 frctx
->done_flag
= 1;
1242 // TODO: Should the imgbody_info be saved somewhere, or recalculated for every frame?
1243 ibi
= de_malloc(c
, sizeof(struct imgbody_info
));
1245 do_before_image_chunk(c
, d
);
1247 if(!init_imgbody_info(c
, d
, ibi
, 0)) {
1252 // Find the reference frame (if it exists).
1253 // It is the highest numbered oldfrctx[] item whose index is at most
1254 // frctx->interleave-1, and which is non-NULL.
1255 if(frctx
->interleave
>=2) {
1256 reference_frctx
= d
->oldfrctx
[1];
1257 if(!reference_frctx
) {
1258 reference_frctx
= d
->oldfrctx
[0];
1262 reference_frctx
= d
->oldfrctx
[0];
1265 // Allocate buffer for this frame
1266 if(!frctx
->frame_buffer
) {
1267 frctx
->frame_buffer
= dbuf_create_membuf(c
, ibi
->frame_buffer_size
, 0x1);
1270 // Start by copying the reference frame to this frame. The decompress function
1271 // will then modify this frame.
1272 if(reference_frctx
&& reference_frctx
->frame_buffer
) {
1273 dbuf_copy(reference_frctx
->frame_buffer
, 0, reference_frctx
->frame_buffer
->len
,
1274 frctx
->frame_buffer
);
1279 decompress_delta_op3(c
, d
, ibi
, frctx
, pos1
, len
);
1282 decompress_delta_op5(c
, d
, ibi
, frctx
, pos1
, len
);
1285 decompress_delta_op7(c
, d
, ibi
, frctx
, pos1
, len
);
1288 decompress_delta_op8(c
, d
, ibi
, frctx
, pos1
, len
);
1291 decompress_delta_op74(c
, d
, ibi
, frctx
, pos1
, len
);
1294 decompress_delta_op108(c
, d
, ibi
, frctx
, pos1
, len
);
1297 de_err(c
, "Unsupported DLTA operation: %d", (int)frctx
->op
);
1300 if(d
->errflag
) goto done
;
1302 if(frctx
->change_flag
|| d
->opt_anim_includedups
) {
1303 write_frame(c
, d
, ibi
, frctx
);
1306 de_dbg(c
, "[suppressing duplicate frame]");
1310 // For the summary line, and so we can know when encountering an op for the
1313 d
->delta_ops_used
[(size_t)frctx
->op
] = 1;
1317 de_dbg_indent_restore(c
, saved_indent_level
);
1320 static int decompress_method0(deark
*c
, lctx
*d
, i64 pos
, i64 len
, dbuf
*unc_pixels
,
1325 amt_to_copy
= de_min_int(len
, expected_len
);
1326 dbuf_copy(c
->infile
, pos
, amt_to_copy
, unc_pixels
);
1330 static int decompress_method1(deark
*c
, lctx
*d
, i64 pos
, i64 len
, dbuf
*unc_pixels
,
1334 struct de_dfilter_in_params dcmpri
;
1335 struct de_dfilter_out_params dcmpro
;
1336 struct de_dfilter_results dres
;
1338 de_dfilter_init_objects(c
, &dcmpri
, &dcmpro
, &dres
);
1339 dcmpri
.f
= c
->infile
;
1342 dcmpro
.f
= unc_pixels
;
1343 dcmpro
.len_known
= 1;
1344 dcmpro
.expected_len
= expected_len
;
1346 fmtutil_decompress_packbits_ex(c
, &dcmpri
, &dcmpro
, &dres
, NULL
);
1348 de_err(c
, "Decompression failed: %s", dres
.errmsg
);
1351 de_dbg(c
, "decompressed %"I64_FMT
" to %"I64_FMT
" bytes", len
, unc_pixels
->len
);
1359 struct imgbody_info
*ibi
;
1361 i64 vdat_chunk_count
; // (the plane number)
1366 static void vdat_write_element(deark
*c
, struct vdat_ctx
*vdctx
, const u8
*elembuf
)
1370 dstpos
= vdctx
->ibi
->bytes_per_row_per_plane
* vdctx
->vdat_chunk_count
;
1371 dstpos
+= 2*vdctx
->cur_col
;
1372 dstpos
+= vdctx
->ypos
* vdctx
->ibi
->frame_buffer_rowspan
;
1374 dbuf_write_at(vdctx
->unc_pixels
, dstpos
, elembuf
, 2);
1376 if(vdctx
->ypos
>= vdctx
->ibi
->height
) {
1382 static void do_vdat_chunk(deark
*c
, struct vdat_ctx
*vdctx
, i64 pos1
, i64 len
)
1398 cmd_cnt
= de_getu16be(pos
); // command count + 2
1401 de_dbg(c
, "number of command bytes: %d", (int)cmd_cnt
);
1402 if(cmd_cnt
<1) goto done
;
1404 cmds
= de_mallocarray(c
, cmd_cnt
, sizeof(u8
));
1407 de_read(cmds
, pos
, cmd_cnt
);
1411 for(i
=0; i
<cmd_cnt
; i
++) {
1419 count
= de_getu16be(pos
);
1421 for(k
=0; k
<count
; k
++) {
1422 de_read(elembuf
, pos
, 2);
1424 vdat_write_element(c
, vdctx
, elembuf
);
1427 else if(cmd
==0x01) {
1428 count
= de_getu16be(pos
);
1430 de_read(elembuf
, pos
, 2);
1432 for(k
=0; k
<count
; k
++) {
1433 vdat_write_element(c
, vdctx
, elembuf
);
1436 else if(cmd
>=0x80) {
1437 count
= (128-(i64
)(cmd
&0x7f));
1438 for(k
=0; k
<count
; k
++) {
1439 de_read(elembuf
, pos
, 2);
1441 vdat_write_element(c
, vdctx
, elembuf
);
1444 else { // cmd is from 0x02 to 0x7f
1445 de_read(elembuf
, pos
, 2);
1448 for(k
=0; k
<count
; k
++) {
1449 vdat_write_element(c
, vdctx
, elembuf
);
1458 static int my_vdat_chunk_handler(struct de_iffctx
*ictx
)
1461 struct vdat_ctx
*vdctx
= (struct vdat_ctx
*)ictx
->userdata
;
1463 if(ictx
->chunkctx
->chunk4cc
.id
!= CODE_VDAT
) {
1468 if(vdctx
->vdat_chunk_count
>= vdctx
->ibi
->planes_total
) goto done
;
1469 do_vdat_chunk(c
, vdctx
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
1472 if(ictx
->chunkctx
->chunk4cc
.id
== CODE_VDAT
) {
1473 vdctx
->vdat_chunk_count
++;
1478 static int decompress_method2(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
1479 i64 pos
, i64 len
, dbuf
*unc_pixels
, i64 expected_len
)
1481 struct vdat_ctx vdctx
;
1482 struct de_iffctx
*ictx_vdat
= NULL
;
1484 // For sanity, we'll use a separate IFF decoder for the contents of this BODY chunk.
1485 de_zeromem(&vdctx
, sizeof(struct vdat_ctx
));
1488 vdctx
.unc_pixels
= unc_pixels
;
1490 ictx_vdat
= fmtutil_create_iff_decoder(c
);
1491 ictx_vdat
->userdata
= (void*)&vdctx
;
1492 ictx_vdat
->handle_chunk_fn
= my_vdat_chunk_handler
;
1493 ictx_vdat
->f
= c
->infile
;
1494 fmtutil_read_iff_format(ictx_vdat
, pos
, len
);
1496 fmtutil_destroy_iff_decoder(ictx_vdat
);
1500 // Convert ACBM ABIT image to standard ILBM frame buffer format.
1501 static int convert_abit(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
1502 i64 pos
, i64 len
, dbuf
*frame_buffer
)
1507 planespan
= ibi
->height
* ibi
->bytes_per_row_per_plane
;
1509 for(plane
=0; plane
<ibi
->planes_total
; plane
++) {
1510 for(j
=0; j
<ibi
->height
; j
++) {
1511 dbuf_copy_at(c
->infile
, pos
+ plane
*planespan
+ j
*ibi
->bytes_per_row_per_plane
,
1512 ibi
->bytes_per_row_per_plane
, frame_buffer
,
1513 j
*ibi
->frame_buffer_rowspan
+ plane
*ibi
->bytes_per_row_per_plane
);
1519 // Detect and warn about HAM-E, which we don't support.
1520 static void detect_hame(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
1521 struct frame_ctx
*frctx
)
1527 static const u8 sig
[15] = { 0xa, 0x2, 0xf, 0x5, 0x8, 0x4, 0xd, 0xc,
1528 0x6, 0xd, 0xb, 0x0, 0x7, 0xf, 0x1 };
1530 if(d
->is_hame
) return;
1531 if(d
->ham_flag
) return;
1532 if(!d
->found_cmap
) return;
1533 if(ibi
->width
<640) return;
1534 if(ibi
->planes_fg
!=4 || ibi
->planes_total
!=4) return;
1535 if(ibi
->is_thumb
) return;
1536 if(frctx
->formtype
!=CODE_ILBM
&& frctx
->formtype
!=CODE_ACBM
) return;
1537 if(!frctx
|| !frctx
->frame_buffer
) return;
1539 // Note: This is quite possibly not the right way to detect HAM-E.
1540 // RECOIL does it by looking up the palette color of each pixel, and using
1541 // certain bits in the palette entry. In all the HAM-E images I have, the
1542 // palette is constructed so as to make that process a no-op.
1544 // Need to examine the values of the first 16 pixels, so need the first 2
1545 // bytes of each of the 4 planes of row 0.
1546 for(plane
=0; plane
<4; plane
++) {
1547 firstword
[plane
] = (UI
)dbuf_getu16be(frctx
->frame_buffer
,
1548 plane
* ibi
->bytes_per_row_per_plane
);
1551 for(k
=0; k
<16; k
++) {
1553 for(plane
=0; plane
<4; plane
++) {
1554 if(firstword
[plane
] & (1U<<(15-(UI
)k
))) {
1555 pixelval
[k
] |= 1U<<(UI
)plane
;
1560 if(de_memcmp(pixelval
, sig
, 15)) return;
1561 if(pixelval
[15]!=0x4 && pixelval
[15]!=0x8) return;
1562 de_warn(c
, "This is probably a HAM-E image, which is not supported correctly.");
1566 // Detect and warn about DCTV, which we don't support.
1567 static void detect_dctv(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
1568 struct frame_ctx
*frctx
)
1570 static const u8 sig
[31] = {
1571 0x49, 0x87, 0x28, 0xde, 0x11, 0x0b, 0xef, 0xd2, 0x0c, 0x8e, 0x8b, 0x35, 0x5b, 0x75, 0xec, 0xb8,
1572 0x29, 0x6b, 0x03, 0xf9, 0x2b, 0xb4, 0x34, 0xee, 0x67, 0x1e, 0x7c, 0x4f, 0x53, 0x63, 0x15 };
1575 // As far as I can tell, in DCTV images, the last plane of the first row is
1577 // <00> <31-byte signature> <00 fill> <31-byte signature> <00>
1578 // (Sometimes, the last plane of the *second* row is the same.)
1580 // * Is DCTV possible if there are fewer than 64 bytes per row per plane (i.e. width < 512)?
1581 // * Can a DCTV image have transparency?
1582 // * If a DCTV image has a thumbnail image, what format does the thumbnail use?
1584 if(d
->is_dctv
) return;
1585 if(!frctx
|| !frctx
->frame_buffer
) return;
1586 if(ibi
->is_thumb
) return;
1587 if(frctx
->formtype
!=CODE_ILBM
&& frctx
->formtype
!=CODE_ACBM
) return;
1588 if(ibi
->bytes_per_row_per_plane
<64) return;
1589 pos
= d
->planes_raw
* ibi
->bytes_per_row_per_plane
- 32;
1590 if(dbuf_getbyte(frctx
->frame_buffer
, pos
) != sig
[0]) return;
1591 if(dbuf_memcmp(frctx
->frame_buffer
, pos
, sig
, 31)) return;
1592 de_warn(c
, "This is probably a DCTV image, which is not supported correctly.");
1597 static int do_image_chunk_internal(deark
*c
, lctx
*d
, struct frame_ctx
*frctx
, i64 pos1
, i64 len
, int is_thumb
)
1599 struct imgbody_info
*ibi
= NULL
;
1602 if(d
->errflag
) goto done
;
1603 if(!d
->found_bmhd
) goto done
;
1604 if(!frctx
) goto done
;
1605 if(frctx
->done_flag
) goto done
;
1606 frctx
->done_flag
= 1;
1608 ibi
= de_malloc(c
, sizeof(struct imgbody_info
));
1610 do_before_image_chunk(c
, d
);
1612 if(!init_imgbody_info(c
, d
, ibi
, is_thumb
)) {
1616 if(!frctx
->frame_buffer
) {
1617 frctx
->frame_buffer
= dbuf_create_membuf(c
, ibi
->frame_buffer_size
, 0x1);
1620 if(d
->formtype
==CODE_ACBM
) {
1621 // Note: I don't think ABIT images are ever compressed.
1622 if(!convert_abit(c
, d
, ibi
, pos1
, len
, frctx
->frame_buffer
)) goto done
;
1624 else if(ibi
->compression
==0) {
1625 if(!decompress_method0(c
, d
, pos1
, len
, frctx
->frame_buffer
, ibi
->frame_buffer_size
)) goto done
;
1627 else if(ibi
->compression
==1) {
1628 if(!decompress_method1(c
, d
, pos1
, len
, frctx
->frame_buffer
, ibi
->frame_buffer_size
)) goto done
;
1630 else if(ibi
->compression
==2) {
1631 if(!decompress_method2(c
, d
, ibi
, pos1
, len
, frctx
->frame_buffer
, ibi
->frame_buffer_size
)) goto done
;
1634 de_err(c
, "Unsupported compression method (%d)", (int)ibi
->compression
);
1638 if(ibi
->is_pbm
&& (frctx
->frame_buffer
->len
!= ibi
->frame_buffer_size
) && (ibi
->width
%2)) {
1639 if(frctx
->frame_buffer
->len
== ibi
->width
*ibi
->height
) {
1640 // Hack: I have some PBM images (e.g. BBM thumbnails) that aren't row-padded.
1641 de_dbg(c
, "[assuming rows are not 16-bit padded]");
1642 ibi
->bytes_per_row_per_plane
= ibi
->width
;
1643 ibi
->bits_per_row_per_plane
= ibi
->bytes_per_row_per_plane
* 8;
1644 ibi
->frame_buffer_rowspan
= ibi
->bytes_per_row_per_plane
* ibi
->planes_total
;
1645 ibi
->frame_buffer_size
= ibi
->frame_buffer_rowspan
* ibi
->height
;
1649 if(frctx
->frame_buffer
->len
!= ibi
->frame_buffer_size
) {
1650 de_warn(c
, "Expected %"I64_FMT
" decompressed bytes, got %"I64_FMT
, ibi
->frame_buffer_size
,
1651 frctx
->frame_buffer
->len
);
1654 detect_dctv(c
, d
, ibi
, frctx
);
1655 detect_hame(c
, d
, ibi
, frctx
);
1657 write_frame(c
, d
, ibi
, frctx
);
1666 static void do_body_or_abit(deark
*c
, lctx
*d
, struct de_iffctx
*ictx
, i64 pos1
, i64 len
)
1668 if(!de_good_image_dimensions(c
, d
->width
, d
->height
)) {
1672 if(!do_image_chunk_internal(c
, d
, d
->frctx
, pos1
, len
, 0)) {
1680 static void do_tiny(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
1682 struct frame_ctx
*frctx
= NULL
;
1685 if(len
<=4) goto done
;
1687 d
->thumb_width
= de_getu16be_p(&pos
);
1688 d
->thumb_height
= de_getu16be_p(&pos
);
1689 de_dbg(c
, "thumbnail image, dimensions: %d"DE_CHAR_TIMES
"%d", (int)d
->thumb_width
, (int)d
->thumb_height
);
1690 if(!de_good_image_dimensions_noerr(c
, d
->thumb_width
, d
->thumb_height
)) {
1691 de_warn(c
, "Bad thumbnail image dimensions");
1695 frctx
= create_frame(c
, d
);
1696 (void)do_image_chunk_internal(c
, d
, frctx
, pos
, pos1
+len
-pos
, 1);
1699 destroy_frame(c
, d
, frctx
);
1702 static void get_bits_descr(deark
*c
, lctx
*d
, struct frame_ctx
*frctx
, de_ucstring
*s
)
1704 UI bits
= frctx
->bits
;
1706 if(frctx
->op
==4 || frctx
->op
==5 || frctx
->op
==7 || frctx
->op
==8) {
1708 ucstring_append_flags_item(s
, "long data");
1710 d
->uses_anim_long_data
= 1;
1713 if(frctx
->op
==4 || frctx
->op
==5) {
1715 ucstring_append_flags_item(s
, "XOR");
1717 d
->uses_anim4_5_xor_mode
= 1;
1720 ucstring_append_flags_item(s
, "one info list");
1724 ucstring_append_flags_item(s
, "RLC");
1728 ucstring_append_flags_item(s
, "vertical");
1732 ucstring_append_flags_item(s
, "long info offsets");
1738 ucstring_append_flags_itemf(s
, "0x%08x", bits
);
1742 static void do_anim_anhd(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
1746 de_ucstring
*bits_descr
= NULL
;
1747 struct frame_ctx
*frctx
= d
->frctx
;
1752 frctx
->op
= de_getbyte(pos
++);
1753 de_dbg(c
, "operation: %d (%s)", (int)frctx
->op
, anim_get_op_name(frctx
->op
));
1755 if(frctx
->op
==ANIM_OP_XOR
) {
1765 pos
+= 4; // abstime
1767 tmp
= de_getu32be_p(&pos
); // reltime
1768 de_dbg(c
, "reltime: %.5f sec", ((double)tmp
)/60.0);
1770 ileave_raw
= de_getbyte_p(&pos
);
1771 de_dbg(c
, "interleave: %d", (int)ileave_raw
);
1773 frctx
->interleave
= 2;
1776 frctx
->interleave
= (UI
)ileave_raw
;
1778 if(frctx
->interleave
>2 && !d
->errflag
) {
1779 de_err(c
, "Unsupported interleave");
1785 frctx
->bits
= (UI
)de_getu32be_p(&pos
);
1786 bits_descr
= ucstring_create(c
);
1787 get_bits_descr(c
, d
, frctx
, bits_descr
);
1788 de_dbg(c
, "bits: 0x%08x (%s)", frctx
->bits
, ucstring_getpsz_d(bits_descr
));
1790 ucstring_destroy(bits_descr
);
1793 static void do_camg(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
1803 d
->camg_mode
= (UI
)de_getu32be(pos
);
1804 de_dbg(c
, "CAMG mode: 0x%x", d
->camg_mode
);
1806 if(d
->camg_mode
& 0x0800)
1808 if(d
->camg_mode
& 0x0080)
1811 de_dbg_indent(c
, 1);
1812 de_dbg(c
, "HAM: %d", (int)d
->ham_flag
);
1813 de_dbg(c
, "EHB: %d", (int)d
->ehb_flag
);
1814 de_dbg_indent(c
, -1);
1817 if(d
->planes_raw
==6 || d
->planes_raw
==5) {
1820 else if(d
->planes_raw
==8 || d
->planes_raw
==7) {
1824 de_warn(c
, "Invalid bit depth (%d) for HAM image.", (int)d
->planes_raw
);
1829 static void do_dpi(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
1832 d
->x_dpi
= de_getu16be(pos
);
1833 d
->y_dpi
= de_getu16be(pos
+2);
1834 de_dbg(c
, "dpi: %d"DE_CHAR_TIMES
"%d", (int)d
->x_dpi
, (int)d
->y_dpi
);
1837 static void do_grab(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
1841 d
->hotspot_x
= (int)de_getu16be(pos
);
1842 d
->hotspot_y
= (int)de_getu16be(pos
+2);
1843 de_dbg(c
, "hotspot: (%d, %d)", d
->hotspot_x
, d
->hotspot_y
);
1846 static void do_dpan(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
1850 if(!d
->is_anim
) return;
1852 nframes
= de_getu16be(pos
+2);
1853 de_dbg(c
, "number of frames: %d", (int)nframes
);
1856 static void do_crng(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
1861 tmp1
= (UI
)de_getu16be(pos1
+2);
1862 tmp2
= (UI
)de_getu16be(pos1
+4);
1863 de_dbg(c
, "CRNG flags: 0x%04x", tmp2
);
1865 de_dbg(c
, "rate: %.2f fps", (double)(((double)tmp1
)*(60.0/16384.0)));
1866 on_color_cycling_enabled(c
, d
);
1870 static void do_drng(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
1874 tmp2
= (UI
)de_getu16be(pos1
+4);
1875 de_dbg(c
, "DRNG flags: 0x%04x", tmp2
);
1877 on_color_cycling_enabled(c
, d
);
1881 // Graphicraft Color Cycling Range and Timing
1882 static void do_ccrt(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
1886 tmp1
= de_geti16be(pos1
);
1887 de_dbg(c
, "cycling direction: %d", (int)tmp1
);
1889 d
->uses_color_cycling
= 1;
1893 // Frame sequencing chunk used in ANIM-J
1894 static void do_ansq(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
1899 // TODO: Figure out how critical this ANSQ info is.
1900 // If deltas are supposed to be applied out of sequence, we could at least
1903 num_items
= len
/ 4;
1904 de_dbg(c
, "number of frames in sequence: %d", (int)num_items
);
1905 if(c
->debug_level
<2) return;
1906 de_dbg_indent(c
, 1);
1907 for(i
=0; i
<num_items
&& i
<2000; i
++) {
1910 frnum
= de_getu16be(pos1
+i
*4);
1911 dur
= de_getu16be(pos1
+i
*4+2);
1912 de_dbg2(c
, "item[%d]: frame=%d, dur=%d", (int)i
, (int)frnum
, (int)dur
);
1914 de_dbg_indent(c
, -1);
1917 static void render_pixel_row_ham6(deark
*c
, lctx
*d
, i64 rownum
, const u32
*rowbuf
,
1918 UI rowbuf_size
, de_bitmap
*img
)
1923 // At the beginning of each row, the color accumulators are
1924 // initialized to palette entry 0.
1925 cr
= DE_COLOR_R(d
->pal
[0]);
1926 cg
= DE_COLOR_G(d
->pal
[0]);
1927 cb
= DE_COLOR_B(d
->pal
[0]);
1929 for(i
=0; i
<rowbuf_size
; i
++) {
1931 u8 val
= rowbuf
[i
] & 0xff;
1933 switch((val
>>4)&0x3) {
1934 case 0x1: // Modify blue value
1937 case 0x2: // Modify red value
1940 case 0x3: // Modify green value
1943 default: // 0: Use colormap value
1944 clr
= d
->pal
[(UI
)val
];
1945 cr
= DE_COLOR_R(clr
);
1946 cg
= DE_COLOR_G(clr
);
1947 cb
= DE_COLOR_B(clr
);
1951 de_bitmap_setpixel_rgb(img
, (i64
)i
, rownum
, DE_MAKE_RGB(cr
, cg
, cb
));
1955 static void render_pixel_row_ham8(deark
*c
, lctx
*d
, i64 rownum
, const u32
*rowbuf
,
1956 UI rowbuf_size
, de_bitmap
*img
)
1961 // At the beginning of each row, the color accumulators are
1962 // initialized to palette entry 0.
1963 cr
= DE_COLOR_R(d
->pal
[0]);
1964 cg
= DE_COLOR_G(d
->pal
[0]);
1965 cb
= DE_COLOR_B(d
->pal
[0]);
1967 for(i
=0; i
<rowbuf_size
; i
++) {
1969 u8 val
= rowbuf
[i
] & 0xff;
1971 switch((val
>>6)&0x3) {
1973 cb
= ((val
&0x3f)<<2)|((val
&0x3f)>>4);
1976 cr
= ((val
&0x3f)<<2)|((val
&0x3f)>>4);
1979 cg
= ((val
&0x3f)<<2)|((val
&0x3f)>>4);
1982 clr
= d
->pal
[(UI
)val
];
1983 cr
= DE_COLOR_R(clr
);
1984 cg
= DE_COLOR_G(clr
);
1985 cb
= DE_COLOR_B(clr
);
1989 de_bitmap_setpixel_rgb(img
, (i64
)i
, rownum
, DE_MAKE_RGB(cr
, cg
, cb
));
1993 static void render_pixel_row_normal(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
1994 i64 rownum
, const u32
*rowbuf
, UI rowbuf_size
, de_bitmap
*img
)
1998 for(k
=0; k
<rowbuf_size
; k
++) {
1999 de_bitmap_setpixel_rgb(img
, (i64
)k
, rownum
, d
->pal
[(UI
)rowbuf
[k
] & 0xff]);
2003 static void render_pixel_row_rgb24(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
,
2004 i64 rownum
, const u32
*rowbuf
, UI rowbuf_size
, de_bitmap
*img
)
2008 for(k
=0; k
<rowbuf_size
; k
++) {
2011 r
= (rowbuf
[k
] & 0x0000ff);
2012 g
= (rowbuf
[k
] & 0x00ff00)>>8;
2013 b
= (rowbuf
[k
] & 0xff0000)>>16;
2014 de_bitmap_setpixel_rgb(img
, (i64
)k
, rownum
, DE_MAKE_RGB(r
, g
, b
));
2018 static void set_finfo_data(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
, de_finfo
*fi
)
2024 de_finfo_set_name_from_sz(c
, fi
, "thumb", 0, DE_ENCODING_LATIN1
);
2027 if(d
->x_aspect
>0 && d
->y_aspect
>0) {
2030 if(!ibi
->is_thumb
&& d
->x_dpi
>0 && d
->y_dpi
>0) {
2035 fi
->density
.code
= DE_DENSITY_DPI
;
2036 fi
->density
.xdens
= (double)d
->x_dpi
;
2037 fi
->density
.ydens
= (double)d
->y_dpi
;
2039 else if(has_aspect
) {
2040 fi
->density
.code
= DE_DENSITY_UNK_UNITS
;
2041 fi
->density
.ydens
= (double)d
->x_aspect
;
2042 fi
->density
.xdens
= (double)d
->y_aspect
;
2045 if(!ibi
->is_thumb
&& d
->has_hotspot
) {
2046 fi
->has_hotspot
= 1;
2047 fi
->hotspot_x
= d
->hotspot_x
;
2048 fi
->hotspot_y
= d
->hotspot_y
;
2052 // Generate the final image and write it to a file.
2053 static void write_frame(deark
*c
, lctx
*d
, struct imgbody_info
*ibi
, struct frame_ctx
*frctx
)
2055 de_bitmap
*img
= NULL
;
2057 u32
*rowbuf
= NULL
; // The current row of pixel (palette or RGB) values
2058 u8
*rowbuf_trns
= NULL
; // The current row's 1-bit transparency mask values
2061 de_finfo
*fi
= NULL
;
2066 if(d
->errflag
) goto done
;
2067 if(!frctx
) goto done
;
2068 if(!frctx
->frame_buffer
) {
2072 if(ibi
->colortype
==COLORTYPE_RGB24
) {
2073 if(ibi
->planes_fg
!=24) goto done
;
2075 else if(ibi
->planes_fg
<1 || ibi
->planes_fg
>8) {
2079 if(d
->debug_frame_buffer
) {
2082 fi_fb
= de_finfo_create(c
);
2083 de_finfo_set_name_from_sz(c
, fi_fb
, "fb", 0, DE_ENCODING_LATIN1
);
2084 de_convert_and_write_image_bilevel(frctx
->frame_buffer
, 0,
2085 ibi
->bits_per_row_per_plane
* ibi
->planes_total
,
2086 ibi
->height
, ibi
->frame_buffer_rowspan
, 0, fi_fb
, 0);
2087 de_finfo_destroy(c
, fi_fb
);
2090 rowbuf_size
= (UI
)ibi
->width
;
2091 rowbuf
= de_mallocarray(c
, rowbuf_size
, sizeof(rowbuf
[0]));
2092 rowbuf_trns
= de_mallocarray(c
, rowbuf_size
, sizeof(rowbuf_trns
[0]));
2094 if(d
->found_cmap
&& d
->pal_is_grayscale
&& d
->planes_raw
<=8 && !d
->is_ham6
&& !d
->is_ham8
) {
2101 if(ibi
->use_colorkey_transparency
|| ibi
->masking_code
==MASKINGTYPE_1BITMASK
) {
2102 if(!d
->opt_notrans
) {
2107 img
= de_bitmap_create(c
, ibi
->width
, ibi
->height
, bypp
);
2110 de_convert_image_paletted(frctx
->frame_buffer
, 0, 8, ibi
->frame_buffer_rowspan
,
2115 for(j
=0; j
<ibi
->height
; j
++) {
2120 // Process 8 pixels at a time
2121 for(z
=0; z
<ibi
->bytes_per_row_per_plane
; z
++) {
2122 de_zeromem(pixelval
, sizeof(pixelval
));
2123 de_zeromem(pixeltrnsval
, sizeof(pixeltrnsval
));
2125 // Read the zth byte in each plane
2126 for(plane
=0; plane
<ibi
->planes_total
; plane
++) {
2129 b
= dbuf_getbyte(frctx
->frame_buffer
,
2130 j
*ibi
->frame_buffer_rowspan
+
2131 plane
*ibi
->bytes_per_row_per_plane
+ z
);
2133 for(k
=0; k
<8; k
++) {
2134 if(b
& (1U<<(7-k
))) {
2135 if(plane
< ibi
->planes_fg
) {
2136 pixelval
[k
] |= 1U<<(UI
)plane
;
2139 // The only way this can happen is if this plane is a
2140 // 1-bit transparency mask.
2141 pixeltrnsval
[k
] = 1;
2147 for(k
=0; k
<8; k
++) {
2151 if(idx
< rowbuf_size
) {
2152 rowbuf
[idx
] = pixelval
[k
];
2153 rowbuf_trns
[idx
] = pixeltrnsval
[k
];
2158 if(ibi
->colortype
==COLORTYPE_RGB24
) {
2159 render_pixel_row_rgb24(c
, d
, ibi
, j
, rowbuf
, rowbuf_size
, img
);
2161 else if(d
->is_ham6
) {
2162 render_pixel_row_ham6(c
, d
, j
, rowbuf
, rowbuf_size
, img
);
2164 else if(d
->is_ham8
) {
2165 render_pixel_row_ham8(c
, d
, j
, rowbuf
, rowbuf_size
, img
);
2168 render_pixel_row_normal(c
, d
, ibi
, j
, rowbuf
, rowbuf_size
, img
);
2171 // Handle 1-bit transparency masks here, for all color types.
2172 if(ibi
->masking_code
==MASKINGTYPE_1BITMASK
&& !d
->opt_notrans
) {
2175 for(i
=0; i
<rowbuf_size
; i
++) {
2178 if(rowbuf_trns
[i
]==0) {
2179 clr
= de_bitmap_getpixel(img
, i
, j
);
2180 clr
= DE_SET_ALPHA(clr
, 0);
2181 de_bitmap_setpixel_rgba(img
, i
, j
, clr
);
2188 fi
= de_finfo_create(c
);
2189 set_finfo_data(c
, d
, ibi
, fi
);
2191 createflags
|= DE_CREATEFLAG_IS_AUX
;
2194 createflags
|= DE_CREATEFLAG_OPT_IMAGE
;
2197 de_bitmap_write_to_file_finfo(img
, fi
, createflags
);
2200 de_bitmap_destroy(img
);
2201 de_finfo_destroy(c
, fi
);
2203 de_free(c
, rowbuf_trns
);
2206 static void on_frame_begin(deark
*c
, lctx
*d
, u32 formtype
)
2208 if(d
->frctx
) return;
2209 d
->num_frames_started
++;
2210 d
->frctx
= create_frame(c
, d
);
2211 d
->frctx
->formtype
= formtype
;
2212 d
->frctx
->frame_idx
= d
->num_frames_finished
;
2213 if(d
->is_anim
) de_dbg(c
, "[frame #%d begin]", d
->frctx
->frame_idx
);
2216 static void on_frame_end(deark
*c
, lctx
*d
)
2218 if(!d
->frctx
) return;
2220 if(d
->is_anim
) de_dbg(c
, "[frame #%d end]", d
->frctx
->frame_idx
);
2222 destroy_frame(c
, d
, d
->oldfrctx
[1]); // Destroy the frame that's aged out
2223 d
->oldfrctx
[1] = d
->oldfrctx
[0]; // Make room for the new frame
2224 d
->oldfrctx
[0] = d
->frctx
; // Save the new frame
2226 d
->num_frames_finished
++;
2229 static int my_iff_chunk_handler(struct de_iffctx
*ictx
)
2233 lctx
*d
= (lctx
*)ictx
->userdata
;
2235 if(d
->num_frames_finished
>= ANIM_MAX_FRAMES
) {
2240 // Chunks that we support even if they are not in FORM:ILBM, FORM:PBM, etc. chunk.
2242 switch(ictx
->chunkctx
->chunk4cc
.id
) {
2244 if(ictx
->level
==0) {
2245 // Remember this for later
2246 d
->main_chunk_endpos
= ictx
->chunkctx
->dpos
+ ictx
->chunkctx
->dlen
;
2248 if(ictx
->level
>d
->FORM_level
) break;
2249 ictx
->is_std_container
= 1;
2253 // Chunks that we process only inside a FORM:ILBM, etc. chunk.
2255 if(!d
->frctx
) goto done
;
2257 switch(ictx
->chunkctx
->chunk4cc
.id
) {
2260 if(!do_bmhd(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
)) {
2267 do_anim_anhd(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2272 do_cmap(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2277 do_camg(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2284 do_body_or_abit(c
, d
, ictx
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2289 if(ictx
->curr_container_contentstype4cc
.id
!= CODE_ILBM
) {
2293 do_dlta(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2297 do_tiny(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2302 do_dpi(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2306 do_grab(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2310 do_dpan(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2314 do_crng(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2318 do_drng(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2322 do_ccrt(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2327 on_multipalette_enabled(c
, d
);
2331 on_multipalette_enabled(c
, d
);
2335 on_multipalette_enabled(c
, d
);
2339 on_multipalette_enabled(c
, d
);
2345 do_ansq(c
, d
, ictx
->chunkctx
->dpos
, ictx
->chunkctx
->dlen
);
2349 if(d
->is_anim
&& !d
->found_audio
) {
2350 de_info(c
, "Note: This file includes AnimFX-style audio, which is "
2358 return (quitflag
) ? 0 : 1;
2361 static int my_preprocess_iff_chunk_fn(struct de_iffctx
*ictx
)
2363 lctx
*d
= (lctx
*)ictx
->userdata
;
2364 const char *name
= NULL
;
2366 // frctx will be set if we're in an "image" container, such as FORM:ILBM.
2367 // It is possible, e.g., for an ANIM file to contain FORM:8SVX containers
2368 // which contain BODY chunks that are not "image data".
2370 switch(ictx
->chunkctx
->chunk4cc
.id
) {
2371 case CODE_ANHD
: name
="animation header"; break;
2372 case CODE_BMHD
: name
="bitmap header"; break;
2373 case CODE_BODY
: name
="image data"; break;
2374 case CODE_CAMG
: name
="Amiga viewport mode"; break;
2375 case CODE_CMAP
: name
="color map"; break;
2376 case CODE_CRNG
: name
="color register range info"; break;
2377 case CODE_DLTA
: name
="delta-compressed data"; break;
2378 case CODE_DPI
: name
="dots/inch"; break;
2379 case CODE_DRNG
: name
="color cycle"; break;
2380 case CODE_GRAB
: name
="hotspot"; break;
2381 case CODE_TINY
: name
="thumbnail"; break;
2386 ictx
->chunkctx
->chunk_name
= name
;
2391 static int my_on_std_container_start_fn(struct de_iffctx
*ictx
)
2394 lctx
*d
= (lctx
*)ictx
->userdata
;
2396 if(ictx
->level
==d
->FORM_level
) {
2400 if((ictx
->curr_container_contentstype4cc
.id
== CODE_ILBM
) ||
2401 (ictx
->curr_container_contentstype4cc
.id
== CODE_PBM
) ||
2402 (ictx
->curr_container_contentstype4cc
.id
== CODE_ACBM
))
2404 on_frame_begin(c
, d
, ictx
->curr_container_contentstype4cc
.id
);
2408 if(ictx
->curr_container_contentstype4cc
.id
== CODE_8SVX
) {
2411 if(!d
->extra_content_warned
) {
2412 de_warn(c
, "File includes unsupported content of type '%s'",
2413 ictx
->curr_container_contentstype4cc
.id_sanitized_sz
);
2414 d
->extra_content_warned
= 1;
2418 de_err(c
, "Unsupported ILBM-like format");
2426 static void look_for_RAST(deark
*c
, lctx
*d
, i64 pos
)
2428 if(d
->found_rast
) return;
2429 if(!dbuf_memcmp(c
->infile
, pos
, "RAST", 4)) {
2434 static void do_eof_stuff(deark
*c
, lctx
*d
)
2436 i64 endpos
, endpos_padded
;
2439 endpos
= d
->main_chunk_endpos
;
2440 if(endpos
<1) return;
2441 endpos_padded
= de_pad_to_2(endpos
);
2442 extra_bytes
= c
->infile
->len
- endpos_padded
;
2443 if(extra_bytes
<1) return;
2444 de_dbg(c
, "[found %"I64_FMT
" extra bytes at end of file, starting at %"I64_FMT
"]",
2445 extra_bytes
, endpos_padded
);
2447 look_for_RAST(c
, d
, endpos
);
2448 if(endpos_padded
!=endpos
) {
2449 look_for_RAST(c
, d
, endpos_padded
);
2452 de_warn(c
, "Possible RAST data found, which is not supported. "
2453 "Image might not be decoded correctly.");
2457 static int my_on_container_end_fn(struct de_iffctx
*ictx
)
2459 if(ictx
->level
==0) {
2460 // Stop after the first top-level chunk (the FORM chunk).
2466 static void summary_append(de_ucstring
*s
, const char *fmt
, ...)
2467 de_gnuc_attribute ((format (printf
, 2, 3)));
2469 static void summary_append(de_ucstring
*s
, const char *fmt
, ...)
2473 ucstring_append_char(s
, ' ');
2475 ucstring_vprintf(s
, DE_ENCODING_LATIN1
, fmt
, ap
);
2479 // Print a summary line indicating the main characteristics of this file.
2480 static void print_summary(deark
*c
, lctx
*d
)
2482 de_ucstring
*s
= NULL
;
2485 if(c
->debug_level
<1) goto done
;
2486 if(!d
->found_bmhd
) goto done
;
2488 s
= ucstring_create(c
);
2490 switch(d
->formtype
) {
2491 case CODE_ANIM
: summary_append(s
, "ANIM"); break;
2492 case CODE_ILBM
: summary_append(s
, "ILBM"); break;
2493 case CODE_PBM
: summary_append(s
, "PBM"); break;
2494 case CODE_ACBM
: summary_append(s
, "ACBM"); break;
2495 default: summary_append(s
, "???"); break;
2498 summary_append(s
, "planes=%d", (int)d
->planes_raw
);
2499 if(d
->masking_code
!=0) summary_append(s
, "masking=%d", (int)d
->masking_code
);
2500 summary_append(s
, "cmpr=%d", (int)d
->compression
);
2501 for(k
=0; k
<256; k
++) {
2502 if(d
->delta_ops_used
[k
]) {
2503 summary_append(s
, "delta%u", (UI
)k
);
2506 if(d
->uses_anim_long_data
) summary_append(s
, "long_data");
2507 if(d
->uses_anim4_5_xor_mode
) summary_append(s
, "xor_mode");
2509 if(d
->ham_flag
) summary_append(s
, "HAM");
2510 if(d
->ehb_flag
) summary_append(s
, "EHB");
2511 if(d
->is_sham
) summary_append(s
, "SHAM");
2512 if(d
->is_pchg
) summary_append(s
, "PCHG");
2513 if(d
->is_ctbl
) summary_append(s
, "CBTL");
2514 if(d
->is_beam
) summary_append(s
, "BEAM");
2515 if(d
->is_hame
) summary_append(s
, "HAM-E");
2516 if(d
->is_dctv
) summary_append(s
, "DCTV");
2517 if(d
->found_rast
) summary_append(s
, "RAST");
2518 if(d
->uses_color_cycling
) summary_append(s
, "color-cycling");
2519 if(d
->found_clut
) summary_append(s
, "CLUT");
2520 if(d
->found_audio
) summary_append(s
, "audio");
2521 if(!d
->found_cmap
) summary_append(s
, "no-CMAP");
2523 de_dbg(c
, "summary:%s", ucstring_getpsz(s
));
2526 ucstring_destroy(s
);
2529 static void de_run_ilbm_or_anim(deark
*c
, de_module_params
*mparams
)
2533 struct de_iffctx
*ictx
= NULL
;
2535 d
= de_malloc(c
, sizeof(lctx
));
2536 d
->opt_fixpal
= (u8
)de_get_ext_option_bool(c
, "ilbm:fixpal", 1);
2537 if(de_get_ext_option(c
, "ilbm:notrans")) {
2540 if(de_get_ext_option(c
, "ilbm:allowsham")) {
2541 d
->opt_allowsham
= 1;
2544 id
= (u32
)de_getu32be(0);
2546 de_err(c
, "Not an IFF file");
2549 d
->formtype
= (u32
)de_getu32be(8);
2550 switch(d
->formtype
) {
2552 de_declare_fmt(c
, "IFF-ANIM");
2556 de_declare_fmt(c
, "IFF-ILBM");
2559 de_declare_fmt(c
, "IFF-ACBM");
2562 de_declare_fmt(c
, "IFF-PBM");
2565 de_err(c
, "Not a supported IFF format");
2570 d
->opt_anim_includedups
= (u8
)de_get_ext_option_bool(c
, "anim:includedups", 0);
2573 d
->FORM_level
= d
->is_anim
? 1 : 0;
2575 ictx
= fmtutil_create_iff_decoder(c
);
2576 ictx
->has_standard_iff_chunks
= 1;
2577 ictx
->userdata
= (void*)d
;
2578 ictx
->input_encoding
= de_get_input_encoding(c
, NULL
, DE_ENCODING_ASCII
);
2579 ictx
->handle_chunk_fn
= my_iff_chunk_handler
;
2580 ictx
->preprocess_chunk_fn
= my_preprocess_iff_chunk_fn
;
2581 ictx
->on_std_container_start_fn
= my_on_std_container_start_fn
;
2582 ictx
->on_container_end_fn
= my_on_container_end_fn
;
2583 ictx
->f
= c
->infile
;
2584 fmtutil_read_iff_format(ictx
, 0, c
->infile
->len
);
2590 print_summary(c
, d
);
2593 fmtutil_destroy_iff_decoder(ictx
);
2595 destroy_frame(c
, d
, d
->frctx
);
2596 destroy_frame(c
, d
, d
->oldfrctx
[0]);
2597 destroy_frame(c
, d
, d
->oldfrctx
[1]);
2602 static void de_run_ilbm(deark
*c
, de_module_params
*mparams
)
2604 de_run_ilbm_or_anim(c
, mparams
);
2607 static void de_run_anim(deark
*c
, de_module_params
*mparams
)
2609 de_run_ilbm_or_anim(c
, mparams
);
2612 static int de_identify_ilbm(deark
*c
)
2616 id
= (u32
)de_getu32be(0);
2617 if(id
!=CODE_FORM
) return 0;
2618 id
= (u32
)de_getu32be(8);
2619 if(id
==CODE_ILBM
) return 100;
2620 if(id
==CODE_PBM
) return 100;
2621 if(id
==CODE_ACBM
) return 100;
2625 static int de_identify_anim(deark
*c
)
2629 id
= (u32
)de_getu32be(0);
2630 if(id
!=CODE_FORM
) return 0;
2631 id
= (u32
)de_getu32be(8);
2632 if(id
==CODE_ANIM
) return 100;
2636 static void do_help_ilbm_anim(deark
*c
, int is_anim
)
2638 de_msg(c
, "-opt ilbm:notrans : Disable support for transparency");
2640 de_msg(c
, "-opt ilbm:fixpal=<0|1> : Don't/Do try to fix palettes that are "
2641 "slightly too dark");
2643 de_msg(c
, "-opt ilbm:allowsham : Suppress an error on some images");
2645 de_msg(c
, "-opt anim:includedups : Do not suppress duplicate frames");
2649 static void de_help_ilbm(deark
*c
)
2651 do_help_ilbm_anim(c
, 0);
2654 static void de_help_anim(deark
*c
)
2656 do_help_ilbm_anim(c
, 1);
2659 void de_module_ilbm(deark
*c
, struct deark_module_info
*mi
)
2662 mi
->desc
= "IFF-ILBM and related image formats";
2663 mi
->run_fn
= de_run_ilbm
;
2664 mi
->identify_fn
= de_identify_ilbm
;
2665 mi
->help_fn
= de_help_ilbm
;
2668 void de_module_anim(deark
*c
, struct deark_module_info
*mi
)
2671 mi
->desc
= "IFF-ANIM animation";
2672 mi
->run_fn
= de_run_anim
;
2673 mi
->identify_fn
= de_identify_anim
;
2674 mi
->help_fn
= de_help_anim
;