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
{
19 i64 idat_data_size
; // "Data size" reported in idsc (0=unknown)
20 struct de_fourcc cmpr4cc
;
28 static int do_read_idsc(deark
*c
, lctx
*d
, i64 pos
, i64 len
)
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
);
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
);
62 static void do_decode_raw(deark
*c
, lctx
*d
)
64 de_bitmap
*img
= NULL
;
70 if(d
->bitdepth
!= 32) {
71 de_err(c
, "Unsupported bit depth for raw image (%d)", (int)d
->bitdepth
);
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);
102 de_bitmap_destroy(img
);
103 de_finfo_destroy(c
, fi
);
106 static void do_write_image(deark
*c
, lctx
*d
)
111 de_err(c
, "Missing idsc atom");
115 dsize
= (d
->idat_data_size
>0) ? d
->idat_data_size
: d
->idat_size
;
118 if(!de_memcmp(d
->cmpr4cc
.bytes
, "raw ", 4)) {
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);
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
) {
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
);
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
;
172 bctx
->handle_box_fn
= quicktime_box_handler
;
174 fmtutil_read_boxes_format(c
, bctx
);
177 do_write_image(c
, d
);
183 static void do_raw_idsc_data(deark
*c
, lctx
*d
)
187 de_dbg(c
, "QuickTime 'idsc' data");
190 ret
= do_read_idsc(c
, d
, 0, c
->infile
->len
);
191 de_dbg_indent(c
, -1);
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
)
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
);
210 do_qtif_file_format(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;
224 void de_module_qtif(deark
*c
, struct deark_module_info
*mi
)
227 mi
->desc
= "QTIF (QuickTime Image Format)";
228 mi
->run_fn
= de_run_qtif
;
229 mi
->identify_fn
= de_identify_qtif
;