New "ea_data" module
[deark.git] / modules / qtif.c
blob687882f8e296face305cb8b857224bfa8607b10d
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 int idat_found;
14 i64 idat_pos;
15 i64 idat_size;
17 int idsc_found;
18 i64 idsc_size;
19 i64 idat_data_size; // "Data size" reported in idsc (0=unknown)
20 struct de_fourcc cmpr4cc;
22 i64 width, height;
23 i64 bitdepth;
24 i64 palette_id;
25 double hres, vres;
26 } lctx;
28 static int do_read_idsc(deark *c, lctx *d, i64 pos, i64 len)
30 int retval = 0;
32 if(len<8) goto done;
34 d->idsc_found = 1;
36 d->idsc_size = de_getu32be(pos);
37 de_dbg(c, "idsc size: %d", (int)d->idsc_size);
39 dbuf_read_fourcc(c->infile, pos+4, &d->cmpr4cc, 4, 0x0);
40 de_dbg(c, "compression type: \"%s\"", d->cmpr4cc.id_dbgstr);
42 if(len<86) goto done;
43 if(d->idsc_size<86) goto done;
45 d->width = de_getu16be(pos+32);
46 d->height = de_getu16be(pos+34);
47 d->hres = dbuf_fmtutil_read_fixed_16_16(c->infile, pos+36);
48 d->vres = dbuf_fmtutil_read_fixed_16_16(c->infile, pos+40);
49 de_dbg(c, "dpi: %.2f"DE_CHAR_TIMES"%.2f", d->hres, d->vres);
50 d->idat_data_size = de_getu32be(pos+44);
51 de_dbg(c, "reported data size: %d", (int)d->idat_data_size);
52 if(d->idat_data_size>c->infile->len) d->idat_data_size=0;
53 d->bitdepth = de_getu16be(pos+82);
54 d->palette_id = de_getu16be(pos+84);
55 de_dbg(c, "dimensions: %d"DE_CHAR_TIMES"%d, bitdepth: %d, palette: %d", (int)d->width,
56 (int)d->height, (int)d->bitdepth, (int)d->palette_id);
57 retval = 1;
58 done:
59 return retval;
62 static void do_decode_raw(deark *c, lctx *d)
64 de_bitmap *img = NULL;
65 de_finfo *fi = NULL;
66 i64 i, j;
67 i64 rowspan;
68 u32 clr;
70 if(d->bitdepth != 32) {
71 de_err(c, "Unsupported bit depth for raw image (%d)", (int)d->bitdepth);
72 goto done;
74 if(!de_good_image_dimensions(c, d->width, d->height)) goto done;
76 img = de_bitmap_create(c, d->width, d->height, 3);
78 fi = de_finfo_create(c);
79 fi->density.code = DE_DENSITY_DPI;
80 fi->density.xdens = d->hres;
81 fi->density.ydens = d->vres;
83 // Warning: This code is based on reverse engineering, and may not be correct.
84 // TODO: Is the first sample for transparency?
86 // I don't know how to figure out the bytes per row. This logic works for the
87 // few example files I have.
88 rowspan = d->width * 4;
89 if(d->idat_data_size/d->height > rowspan) {
90 rowspan = d->idat_data_size/d->height;
93 for(j=0; j<d->height; j++) {
94 for(i=0; i<d->width; i++) {
95 clr = dbuf_getRGB(c->infile, d->idat_pos + j*rowspan + i*4+1, 0);
96 de_bitmap_setpixel_rgb(img, i, j, clr);
100 de_bitmap_write_to_file_finfo(img, fi, 0);
101 done:
102 de_bitmap_destroy(img);
103 de_finfo_destroy(c, fi);
106 static void do_write_image(deark *c, lctx *d)
108 i64 dsize;
110 if(!d->idsc_found) {
111 de_err(c, "Missing idsc atom");
112 return;
115 dsize = (d->idat_data_size>0) ? d->idat_data_size : d->idat_size;
116 if(dsize<=0) return;
118 if(!de_memcmp(d->cmpr4cc.bytes, "raw ", 4)) {
119 do_decode_raw(c, d);
121 else if(!de_memcmp(d->cmpr4cc.bytes, "jpeg", 4)) {
122 dbuf_create_file_from_slice(c->infile, d->idat_pos, dsize, "jpg", NULL, 0);
124 else if(!de_memcmp(d->cmpr4cc.bytes, "tiff", 4)) {
125 dbuf_create_file_from_slice(c->infile, d->idat_pos, dsize, "tif", NULL, 0);
127 else if(!de_memcmp(d->cmpr4cc.bytes, "gif ", 4)) {
128 dbuf_create_file_from_slice(c->infile, d->idat_pos, dsize, "gif", NULL, 0);
130 else if(!de_memcmp(d->cmpr4cc.bytes, "png ", 4)) {
131 dbuf_create_file_from_slice(c->infile, d->idat_pos, dsize, "png", NULL, 0);
133 else if(!de_memcmp(d->cmpr4cc.bytes, "kpcd", 4)) { // Kodak Photo CD
134 dbuf_create_file_from_slice(c->infile, d->idat_pos, dsize, "pcd", NULL, 0);
136 else {
137 de_err(c, "Unsupported compression type: \"%s\"", d->cmpr4cc.id_sanitized_sz);
141 #define BOX_idat 0x69646174U
142 #define BOX_idsc 0x69647363U
144 static int quicktime_box_handler(deark *c, struct de_boxesctx *bctx)
146 lctx *d = (lctx*)bctx->userdata;
147 struct de_boxdata *curbox = bctx->curbox;
149 if(curbox->boxtype==BOX_idat) {
150 d->idat_found = 1;
151 d->idat_pos = curbox->payload_pos;
152 d->idat_size = curbox->payload_len;
154 else if(curbox->boxtype==BOX_idsc) {
155 do_read_idsc(c, d, curbox->payload_pos, curbox->payload_len);
157 else if(curbox->is_uuid) {
158 return fmtutil_default_box_handler(c, bctx);
161 return 1;
164 static void do_qtif_file_format(deark *c, lctx *d)
166 struct de_boxesctx *bctx = NULL;
168 bctx = de_malloc(c, sizeof(struct de_boxesctx));
170 bctx->userdata = (void*)d;
171 bctx->f = c->infile;
172 bctx->handle_box_fn = quicktime_box_handler;
174 fmtutil_read_boxes_format(c, bctx);
176 if(d->idat_found) {
177 do_write_image(c, d);
180 de_free(c, bctx);
183 static void do_raw_idsc_data(deark *c, lctx *d)
185 int ret;
187 de_dbg(c, "QuickTime 'idsc' data");
189 de_dbg_indent(c, 1);
190 ret = do_read_idsc(c, d, 0, c->infile->len);
191 de_dbg_indent(c, -1);
192 if(!ret) return;
194 d->idat_pos = d->idsc_size;
195 d->idat_size = c->infile->len - d->idat_pos;
196 do_write_image(c, d);
199 static void de_run_qtif(deark *c, de_module_params *mparams)
201 lctx *d = NULL;
203 d = de_malloc(c, sizeof(lctx));
205 if(de_havemodcode(c, mparams, 'I')) {
206 // Raw data from a PICT file
207 do_raw_idsc_data(c, d);
209 else {
210 do_qtif_file_format(c, d);
213 de_free(c, d);
216 static int de_identify_qtif(deark *c)
218 if(de_input_file_has_ext(c, "qtif")) return 20;
219 if(de_input_file_has_ext(c, "qti")) return 5;
220 if(de_input_file_has_ext(c, "qif")) return 5;
221 return 0;
224 void de_module_qtif(deark *c, struct deark_module_info *mi)
226 mi->id = "qtif";
227 mi->desc = "QTIF (QuickTime Image Format)";
228 mi->run_fn = de_run_qtif;
229 mi->identify_fn = de_identify_qtif;