Refactoring the iff decoder
[deark.git] / modules / tim.c
blob91d8f6d9df4677b800f408800635df5b43392f98
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Playstation .TIM image format
6 // (Limited support. Probably works for 8-bits/pixel.)
8 #include <deark-config.h>
9 #include <deark-private.h>
10 DE_DECLARE_MODULE(de_module_tim);
12 typedef struct localctx_struct {
13 unsigned int bpp_code;
14 unsigned int palette_flag;
15 i64 bpp;
16 i64 width, height;
17 u32 pal[256];
18 } lctx;
20 static void do_read_palette(deark *c, lctx *d, i64 pos, i64 ncolors)
22 i64 k;
23 u32 n1, n2;
24 char tmps[32];
26 de_dbg(c, "CLUT block at %d", (int)pos);
27 de_dbg_indent(c, 1);
29 for(k=0; k<ncolors && k<256; k++) {
30 n1 = (u32)de_getu16le(pos + 2*k);
31 n2 = de_bgr555_to_888(n1);
32 de_snprintf(tmps, sizeof(tmps), "0x%04x "DE_CHAR_RIGHTARROW" ", (unsigned int)n1);
33 de_dbg_pal_entry2(c, k, n2, tmps, NULL, NULL);
34 d->pal[k] = n2;
37 de_dbg_indent(c, -1);
40 static void do_pal8(deark *c, lctx *d)
42 de_bitmap *img = NULL;
43 i64 clut_size;
44 i64 ncolors_per_clut;
45 i64 num_cluts;
46 i64 second_header_blk_pos;
47 i64 img_data_size_field;
48 i64 width_field;
49 i64 rowspan;
50 i64 pos;
51 int saved_indent_level;
53 de_dbg_indent_save(c, &saved_indent_level);
54 de_dbg_indent(c, 1); // still in the first header block
56 if(!d->palette_flag) {
57 de_err(c, "8-bit images without a palette aren't supported");
58 goto done;
61 clut_size = de_getu32le(8);
63 ncolors_per_clut = de_getu16le(16);
64 num_cluts = de_getu16le(18);
66 de_dbg(c, "clut 'size': %d", (int)clut_size);
67 de_dbg(c, "colors per clut: %d", (int)ncolors_per_clut);
68 de_dbg(c, "num cluts: %d", (int)num_cluts);
69 de_dbg_indent(c, -1); // end of first header block
71 do_read_palette(c, d, 20, ncolors_per_clut);
73 second_header_blk_pos = 20 + num_cluts*ncolors_per_clut*2;
74 de_dbg(c, "second header block at %d", (int)second_header_blk_pos);
75 de_dbg_indent(c, 1);
76 img_data_size_field = de_getu32le(second_header_blk_pos);
77 de_dbg(c, "image data size field: %d", (int)img_data_size_field);
78 width_field = de_getu16le(second_header_blk_pos+8);
79 d->width = 2*width_field;
80 d->height = de_getu16le(second_header_blk_pos+10);
81 de_dbg(c, "width field: %d (width=%d)", (int)width_field, (int)d->width);
82 de_dbg(c, "height: %d", (int)d->height);
83 if(!de_good_image_dimensions(c, d->width, d->height)) goto done;
84 de_dbg_indent(c, -1);
86 img = de_bitmap_create(c, d->width, d->height, 3);
88 pos = second_header_blk_pos + 12;
89 de_dbg(c, "image data block at %d", (int)pos);
90 rowspan = d->width;
92 de_convert_image_paletted(c->infile, pos,
93 8, rowspan, d->pal, img, 0);
95 de_bitmap_write_to_file(img, NULL, 0);
96 done:
97 de_dbg_indent_restore(c, saved_indent_level);
98 de_bitmap_destroy(img);
101 static void de_run_tim(deark *c, de_module_params *mparams)
103 lctx *d = NULL;
104 unsigned int tim_type;
105 int saved_indent_level;
107 de_dbg_indent_save(c, &saved_indent_level);
108 d = de_malloc(c, sizeof(lctx));
110 de_dbg(c, "first header block at %d", 0);
111 de_dbg_indent(c, 1);
113 tim_type = (unsigned int)de_getu32le(4);
114 d->bpp_code = tim_type & 0x07;
115 d->palette_flag = (tim_type>>3)&0x01;
117 de_dbg(c, "TIM type: 0x%08x", tim_type);
118 de_dbg_indent(c, 1);
120 switch(d->bpp_code) {
121 case 0: d->bpp = 4; break;
122 case 1: d->bpp = 8; break;
123 case 2: d->bpp = 16; break;
124 case 3: d->bpp = 24; break;
125 case 4:
126 de_err(c, "Mixed Format not supported");
127 goto done;
128 default:
129 de_err(c, "Unknown bits/pixel code (%u)", d->bpp_code);
130 goto done;
133 de_dbg(c, "bits/pixel: %d, has-palette: %u", (int)d->bpp, d->palette_flag);
135 de_dbg_indent(c, -1); // end of TIM type field
137 // Hack: Unindent as if the first header block were complete.
138 // But it probably isn't. We'll re-indent if needed.
139 de_dbg_indent(c, -1);
141 switch(d->bpp) {
142 case 8:
143 do_pal8(c, d);
144 break;
145 default:
146 de_err(c, "Unsupported bits/pixel (%d)", (int)d->bpp);
147 goto done;
150 done:
151 de_dbg_indent_restore(c, saved_indent_level);
152 de_free(c, d);
155 static int de_identify_tim(deark *c)
157 i64 x;
159 if(dbuf_memcmp(c->infile, 0, "\x10\x00\x00\x00", 4))
160 return 0;
162 x = de_getu32le(4);
163 if(x<=3 || x==8 || x==9) {
164 if(de_input_file_has_ext(c, "tim")) return 100;
165 return 15;
167 return 0;
170 void de_module_tim(deark *c, struct deark_module_info *mi)
172 mi->id = "tim";
173 mi->desc = "PlayStation graphics";
174 mi->run_fn = de_run_tim;
175 mi->identify_fn = de_identify_tim;