1 // This file is part of Deark.
2 // Copyright (C) 2022 Jason Summers
3 // See the file COPYING for terms of use.
7 #include <deark-private.h>
8 DE_DECLARE_MODULE(de_module_adex
);
10 // We follow Image Alchemy's implementation of ADEX, which is different from
12 // (I wouldn't want to bet that either of them get it exactly right.)
16 u8 bpp
; // bits per pixel
17 i64 npwidth
, pdwidth
, h
;
19 i64 expected_imgsize
; // uncompressed size in bytes
24 // TODO: Make de_convert_image_paletted() support this.
25 static void convert_image_pal4_lsb(dbuf
*f
, i64 fpos
,
26 i64 rowspan
, const de_color
*pal
, de_bitmap
*img
)
30 for(j
=0; j
<img
->height
; j
++) {
31 for(i
=0; i
<rowspan
; i
++) {
35 x
= dbuf_getbyte(f
, fpos
+rowspan
*j
+i
);
37 de_bitmap_setpixel_rgba(img
, i
*2, j
, pal
[palent
]);
39 de_bitmap_setpixel_rgba(img
, i
*2+1, j
, pal
[palent
]);
44 // I'm not sure how well I understand RLE format. It has a lot of extra "space"
45 // for more features to exist.
46 // So we go to some effort to fail if something unexpected happens -- otherwise
47 // this code could be much shorter.
48 // The format as I know it is very simple:
49 // Treat the format as byte-oriented (it decompressed to bytes, not pixels).
50 // Read 4 bytes at a time.
51 // First two bytes are a repeat-count.
52 // Last two bytes are the bytes to repeat.
53 // Note: Each row ends with an item with repeat-count=0.
54 static int adex_decompress_rle(deark
*c
, struct adexctx
*d
, i64 pos1
, dbuf
*outf
)
56 i64 nbytes_written
= 0;
59 i64 nbytes_this_row
= 0;
66 if(nbytes_written
>= d
->expected_imgsize
) break;
67 if(pos
> c
->infile
->len
) {
70 if(nbytes_this_row
> d
->rowspan
) {
74 count
= de_getu16le_p(&pos
);
78 if(count
==0) { // end-of-row marker
79 if(nbytes_this_row
!= d
->rowspan
) {
85 for(k
=0; k
<count
; k
++) {
86 dbuf_write(outf
, buf
, 2);
88 nbytes_written
+= 2*count
;
89 nbytes_this_row
+= 2*count
;
96 de_err(c
, "RLE decompression failed");
101 static void de_run_adex(deark
*c
, de_module_params
*mparams
)
103 struct adexctx
*d
= NULL
;
105 de_bitmap
*img
= NULL
;
106 dbuf
*unc_pixels
= NULL
;
109 d
= de_malloc(c
, sizeof(struct adexctx
));
111 d
->cmpr_meth
= de_getbyte_p(&pos
);
112 de_dbg(c
, "cmpr meth: %u", (UI
)d
->cmpr_meth
);
113 d
->bpp
= de_getbyte_p(&pos
);
114 de_dbg(c
, "bits/pixel: %u", (UI
)d
->bpp
);
115 d
->npwidth
= de_getu16le_p(&pos
);
116 d
->h
= de_getu16le_p(&pos
);
117 de_dbg_dimensions(c
, d
->npwidth
, d
->h
);
118 d
->palentries
= de_getu16le_p(&pos
);
119 de_dbg(c
, "palette entries: %u", (UI
)d
->palentries
);
121 if(d
->palentries
>256) { need_errmsg
= 1; goto done
; }
122 if(d
->palentries
==0) {
123 // This is likely legal, but we'd have to get the palette from a different file
127 de_read_simple_palette(c
, c
->infile
, pos
, d
->palentries
, 3, d
->pal
, 256,
128 DE_RDPALTYPE_24BIT
, 0);
129 pos
+= 3*d
->palentries
;
130 pos
+= 2; // After the palette are two bytes of unknown purpose.
132 de_dbg(c
, "image data at %"I64_FMT
, pos
);
134 if(d
->cmpr_meth
>1) { need_errmsg
= 1; goto done
; }
135 if(d
->bpp
!=4 && d
->bpp
!=8) { need_errmsg
= 1; goto done
; }
136 if(!de_good_image_dimensions(c
, d
->npwidth
, d
->h
)) goto done
;
138 d
->rowspan
= de_pad_to_n(d
->npwidth
*d
->bpp
, 16)/8;
139 d
->pdwidth
= (d
->rowspan
*d
->bpp
)/2;
140 d
->expected_imgsize
= d
->h
* d
->rowspan
;
142 if(d
->cmpr_meth
==1) {
143 unc_pixels
= dbuf_create_membuf(c
, d
->expected_imgsize
, 0x1);
144 dbuf_enable_wbuffer(unc_pixels
);
145 if(!adex_decompress_rle(c
, d
, pos
, unc_pixels
)) goto done
;
146 dbuf_flush(unc_pixels
);
149 unc_pixels
= dbuf_open_input_subfile(c
->infile
, pos
, c
->infile
->len
- pos
);
152 img
= de_bitmap_create2(c
, d
->npwidth
, d
->pdwidth
, d
->h
, 3);
154 convert_image_pal4_lsb(unc_pixels
, 0, d
->rowspan
, d
->pal
, img
);
157 de_convert_image_paletted(unc_pixels
, 0, d
->bpp
, d
->rowspan
, d
->pal
, img
, 0);
160 de_bitmap_write_to_file(img
, NULL
, DE_CREATEFLAG_FLIP_IMAGE
);
162 de_bitmap_destroy(img
);
163 dbuf_close(unc_pixels
);
165 de_err(c
, "Bad or unsupported image type");
170 static int de_identify_adex(deark
*c
)
174 if((u32
)de_getu32be(0)!=0x50494354U
) return 0; // "PICT"
176 if(b
!=0 && b
!=1) return 0;
178 if(b
!=4 && b
!=8) return 0;
182 void de_module_adex(deark
*c
, struct deark_module_info
*mi
)
185 mi
->desc
= "ADEX IMG/RLE";
186 mi
->run_fn
= de_run_adex
;
187 mi
->identify_fn
= de_identify_adex
;