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
;
22 i64 idat_data_size
; // "Data size" reported in idsc (0=unknown)
23 struct de_fourcc cmpr4cc
;
31 static int do_read_idsc(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
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
);
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
);
65 static void do_decode_raw(deark
*c
, lctx
*d
)
67 de_bitmap
*img
= NULL
;
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
);
79 if(d
->fail_gracefully_mode
) {
80 if(!de_good_image_dimensions_noerr(c
, d
->width
, d
->height
)) goto done
;
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);
114 de_bitmap_destroy(img
);
115 de_finfo_destroy(c
, fi
);
118 static void do_write_image(deark
*c
, lctx
*d
)
123 if(!d
->fail_gracefully_mode
)
124 de_err(c
, "Missing idsc atom");
128 dsize
= (d
->idat_data_size
>0) ? d
->idat_data_size
: d
->idat_size
;
131 if(!de_memcmp(d
->cmpr4cc
.bytes
, "raw ", 4)) {
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);
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);
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);
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);
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);
155 if(d
->fail_gracefully_mode
) {
156 de_dbg(c
, "Unsupported compression type: \"%s\"", d
->cmpr4cc
.id_sanitized_sz
);
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
) {
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
);
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
;
195 bctx
->handle_box_fn
= quicktime_box_handler
;
197 fmtutil_read_boxes_format(c
, bctx
);
200 do_write_image(c
, d
);
206 static void do_raw_idsc_data(deark
*c
, lctx
*d
)
210 de_dbg(c
, "QuickTime 'idsc' data");
213 ret
= do_read_idsc(c
, d
, 0, c
->infile
->len
);
214 de_dbg_indent(c
, -1);
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
)
231 d
= de_malloc(c
, sizeof(lctx
));
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
);
244 do_qtif_file_format(c
, d
);
247 if(mparams
&& d
->decoded_ok
) {
248 mparams
->out_params
.flags
|= 0x1;
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;
262 void de_module_qtif(deark
*c
, struct deark_module_info
*mi
)
265 mi
->desc
= "QTIF (QuickTime Image Format)";
266 mi
->run_fn
= de_run_qtif
;
267 mi
->identify_fn
= de_identify_qtif
;