bmp: Rewrote the RLE decompressor
[deark.git] / modules / qtif.c
blobfc482e641f01aa950a2775b929ed35f57ef30451
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // QTIF (QuickTime Image)
7 #include <deark-config.h>
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_qtif);
12 typedef struct localctx_struct {
13 u8 fail_gracefully_mode;
14 u8 decoded_ok;
16 int idat_found;
17 i64 idat_pos;
18 i64 idat_size;
20 int idsc_found;
21 i64 idsc_size;
22 i64 idat_data_size; // "Data size" reported in idsc (0=unknown)
23 struct de_fourcc cmpr4cc;
25 i64 width, height;
26 i64 bitdepth;
27 i64 palette_id;
28 double hres, vres;
29 } lctx;
31 static int do_read_idsc(deark *c, lctx *d, i64 pos, i64 len)
33 int retval = 0;
35 if(len<8) goto done;
37 d->idsc_found = 1;
39 d->idsc_size = de_getu32be(pos);
40 de_dbg(c, "idsc size: %d", (int)d->idsc_size);
42 dbuf_read_fourcc(c->infile, pos+4, &d->cmpr4cc, 4, 0x0);
43 de_dbg(c, "compression type: \"%s\"", d->cmpr4cc.id_dbgstr);
45 if(len<86) goto done;
46 if(d->idsc_size<86) goto done;
48 d->width = de_getu16be(pos+32);
49 d->height = de_getu16be(pos+34);
50 d->hres = dbuf_fmtutil_read_fixed_16_16(c->infile, pos+36);
51 d->vres = dbuf_fmtutil_read_fixed_16_16(c->infile, pos+40);
52 de_dbg(c, "dpi: %.2f"DE_CHAR_TIMES"%.2f", d->hres, d->vres);
53 d->idat_data_size = de_getu32be(pos+44);
54 de_dbg(c, "reported data size: %d", (int)d->idat_data_size);
55 if(d->idat_data_size>c->infile->len) d->idat_data_size=0;
56 d->bitdepth = de_getu16be(pos+82);
57 d->palette_id = de_getu16be(pos+84);
58 de_dbg(c, "dimensions: %d"DE_CHAR_TIMES"%d, bitdepth: %d, palette: %d", (int)d->width,
59 (int)d->height, (int)d->bitdepth, (int)d->palette_id);
60 retval = 1;
61 done:
62 return retval;
65 static void do_decode_raw(deark *c, lctx *d)
67 de_bitmap *img = NULL;
68 de_finfo *fi = NULL;
69 i64 i, j;
70 i64 rowspan;
71 u32 clr;
73 if(d->bitdepth != 32) {
74 if(!d->fail_gracefully_mode)
75 de_err(c, "Unsupported bit depth for raw image (%d)", (int)d->bitdepth);
76 goto done;
79 if(d->fail_gracefully_mode) {
80 if(!de_good_image_dimensions_noerr(c, d->width, d->height)) goto done;
82 else {
83 if(!de_good_image_dimensions(c, d->width, d->height)) goto done;
86 img = de_bitmap_create(c, d->width, d->height, 3);
88 fi = de_finfo_create(c);
89 fi->density.code = DE_DENSITY_DPI;
90 fi->density.xdens = d->hres;
91 fi->density.ydens = d->vres;
93 // Warning: This code is based on reverse engineering, and may not be correct.
94 // TODO: Is the first sample for transparency?
96 // I don't know how to figure out the bytes per row. This logic works for the
97 // few example files I have.
98 rowspan = d->width * 4;
99 if(d->idat_data_size/d->height > rowspan) {
100 rowspan = d->idat_data_size/d->height;
103 for(j=0; j<d->height; j++) {
104 for(i=0; i<d->width; i++) {
105 clr = dbuf_getRGB(c->infile, d->idat_pos + j*rowspan + i*4+1, 0);
106 de_bitmap_setpixel_rgb(img, i, j, clr);
110 de_bitmap_write_to_file_finfo(img, fi, 0);
111 d->decoded_ok = 1;
113 done:
114 de_bitmap_destroy(img);
115 de_finfo_destroy(c, fi);
118 static void do_write_image(deark *c, lctx *d)
120 i64 dsize;
122 if(!d->idsc_found) {
123 if(!d->fail_gracefully_mode)
124 de_err(c, "Missing idsc atom");
125 return;
128 dsize = (d->idat_data_size>0) ? d->idat_data_size : d->idat_size;
129 if(dsize<=0) return;
131 if(!de_memcmp(d->cmpr4cc.bytes, "raw ", 4)) {
132 do_decode_raw(c, d);
134 else if(!de_memcmp(d->cmpr4cc.bytes, "jpeg", 4)) {
135 dbuf_create_file_from_slice(c->infile, d->idat_pos, dsize, "jpg", NULL, 0);
136 d->decoded_ok = 1;
138 else if(!de_memcmp(d->cmpr4cc.bytes, "tiff", 4)) {
139 dbuf_create_file_from_slice(c->infile, d->idat_pos, dsize, "tif", NULL, 0);
140 d->decoded_ok = 1;
142 else if(!de_memcmp(d->cmpr4cc.bytes, "gif ", 4)) {
143 dbuf_create_file_from_slice(c->infile, d->idat_pos, dsize, "gif", NULL, 0);
144 d->decoded_ok = 1;
146 else if(!de_memcmp(d->cmpr4cc.bytes, "png ", 4)) {
147 dbuf_create_file_from_slice(c->infile, d->idat_pos, dsize, "png", NULL, 0);
148 d->decoded_ok = 1;
150 else if(!de_memcmp(d->cmpr4cc.bytes, "kpcd", 4)) { // Kodak Photo CD
151 dbuf_create_file_from_slice(c->infile, d->idat_pos, dsize, "pcd", NULL, 0);
152 d->decoded_ok = 1;
154 else {
155 if(d->fail_gracefully_mode) {
156 de_dbg(c, "Unsupported compression type: \"%s\"", d->cmpr4cc.id_sanitized_sz);
158 else {
159 de_err(c, "Unsupported compression type: \"%s\"", d->cmpr4cc.id_sanitized_sz);
164 #define BOX_idat 0x69646174U
165 #define BOX_idsc 0x69647363U
167 static int quicktime_box_handler(deark *c, struct de_boxesctx *bctx)
169 lctx *d = (lctx*)bctx->userdata;
170 struct de_boxdata *curbox = bctx->curbox;
172 if(curbox->boxtype==BOX_idat) {
173 d->idat_found = 1;
174 d->idat_pos = curbox->payload_pos;
175 d->idat_size = curbox->payload_len;
177 else if(curbox->boxtype==BOX_idsc) {
178 do_read_idsc(c, d, curbox->payload_pos, curbox->payload_len);
180 else if(curbox->is_uuid) {
181 return fmtutil_default_box_handler(c, bctx);
184 return 1;
187 static void do_qtif_file_format(deark *c, lctx *d)
189 struct de_boxesctx *bctx = NULL;
191 bctx = de_malloc(c, sizeof(struct de_boxesctx));
193 bctx->userdata = (void*)d;
194 bctx->f = c->infile;
195 bctx->handle_box_fn = quicktime_box_handler;
197 fmtutil_read_boxes_format(c, bctx);
199 if(d->idat_found) {
200 do_write_image(c, d);
203 de_free(c, bctx);
206 static void do_raw_idsc_data(deark *c, lctx *d)
208 int ret;
210 de_dbg(c, "QuickTime 'idsc' data");
212 de_dbg_indent(c, 1);
213 ret = do_read_idsc(c, d, 0, c->infile->len);
214 de_dbg_indent(c, -1);
215 if(!ret) return;
217 d->idat_pos = d->idsc_size;
218 d->idat_size = c->infile->len - d->idat_pos;
219 do_write_image(c, d);
222 // mparams->codes "I": Read raw 'idsc' data.
223 // (mparams->in_params.flags & 0x1) = "fail gracefully mode": If we don't think
224 // we can decode the image, give up quickly and don't report an error. Used
225 // by the PICT module.
226 // (mparams->out_params.flags & 0x1) = Image decoding was apparently successful
227 static void de_run_qtif(deark *c, de_module_params *mparams)
229 lctx *d = NULL;
231 d = de_malloc(c, sizeof(lctx));
233 if(mparams) {
234 if(mparams->in_params.flags & 0x1) {
235 d->fail_gracefully_mode = 1;
239 if(de_havemodcode(c, mparams, 'I')) {
240 // Raw data from a PICT file
241 do_raw_idsc_data(c, d);
243 else {
244 do_qtif_file_format(c, d);
247 if(mparams && d->decoded_ok) {
248 mparams->out_params.flags |= 0x1;
251 de_free(c, d);
254 static int de_identify_qtif(deark *c)
256 if(de_input_file_has_ext(c, "qtif")) return 20;
257 if(de_input_file_has_ext(c, "qti")) return 5;
258 if(de_input_file_has_ext(c, "qif")) return 5;
259 return 0;
262 void de_module_qtif(deark *c, struct deark_module_info *mi)
264 mi->id = "qtif";
265 mi->desc = "QTIF (QuickTime Image Format)";
266 mi->run_fn = de_run_qtif;
267 mi->identify_fn = de_identify_qtif;