New "videomaster" module
[deark.git] / modules / jovianvi.c
blob49227adbb8b0f61f31a8ccb34eb67acd1efdb42b
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Jovian Logic VI (.vi)
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_jovianvi);
11 typedef struct localctx_struct {
12 u8 imgtype;
13 u8 pal_code;
14 i64 npwidth, h;
15 i64 pdwidth;
16 i64 bitdepth;
17 i64 bits_alloc;
18 i64 rowspan;
19 i64 palpos;
20 i64 bitspos;
21 i64 pal_first_entry_idx;
22 i64 num_pal_colors;
23 u32 pal[256];
24 } lctx;
26 static void do_read_palette(deark *c, lctx *d)
28 i64 k, z;
29 i64 idx;
30 u8 b1[3];
31 u8 b2[3];
33 de_dbg(c, "palette at %d", (int)d->palpos);
34 de_dbg_indent(c, 1);
36 for(k=0; k<d->num_pal_colors; k++) {
37 idx = d->pal_first_entry_idx + k;
38 if(idx > 255) break;
40 de_read(b1, d->palpos + 3*k, 3);
41 for(z=0; z<3; z++) {
42 if(d->pal_code==0) {
43 b2[z] = de_scale_63_to_255(b1[z]); // 6-bit palette samples
45 else {
46 b2[z] = b1[z]; // 8-bit palette samples
50 d->pal[idx] = DE_MAKE_RGB(b2[0],b2[1],b2[2]);
52 if(d->pal_code==0) {
53 char tmps[64];
54 de_snprintf(tmps, sizeof(tmps), "(%2d,%2d,%2d) "DE_CHAR_RIGHTARROW" ",
55 (int)b1[0], (int)b1[1], (int)b1[2]);
56 de_dbg_pal_entry2(c, k, d->pal[idx], tmps, NULL, NULL);
58 else {
59 de_dbg_pal_entry(c, k, d->pal[idx]);
63 de_dbg_indent(c, -1);
66 static void do_convert_grayscale(deark *c, lctx *d, de_bitmap *img)
68 int i, j;
69 u8 v;
71 if(d->bitdepth==1) {
72 de_convert_image_bilevel(c->infile, d->bitspos, d->rowspan, img, 0);
73 goto done;
76 for(j=0; j<d->h; j++) {
77 for(i=0; i<d->pdwidth; i++) {
78 v = de_get_bits_symbol(c->infile, d->bits_alloc, d->bitspos + j*d->rowspan, i);
79 if(d->bitdepth==4) v *= 17;
80 else if(d->bitdepth==6) {
81 if(v<=63) v = de_scale_63_to_255(v);
82 else v=0;
84 de_bitmap_setpixel_gray(img, i, j, v);
88 done:
92 static void do_convert_rgb(deark *c, lctx *d, de_bitmap *img)
94 i64 i, j;
95 u32 clr;
96 u8 b0, b1;
98 for(j=0; j<d->h; j++) {
99 for(i=0; i<d->pdwidth; i++) {
100 if(d->bitdepth==16) {
101 b0 = de_getbyte(d->bitspos + j*d->rowspan + i*2);
102 b1 = de_getbyte(d->bitspos + j*d->rowspan + i*2 + 1);
103 clr = (((u32)b1)<<8) | b0;
104 clr = de_rgb565_to_888(clr);
106 else {
107 clr = dbuf_getRGB(c->infile, d->bitspos+j*d->rowspan+i*3, 0);
109 de_bitmap_setpixel_rgb(img, i, j, clr);
114 static void de_run_jovianvi(deark *c, de_module_params *mparams)
116 lctx *d = NULL;
117 de_bitmap *img = NULL;
118 int has_palette = 0;
119 int is_grayscale = 0;
120 const char *imgtypename;
122 // Warning: This decoder is based on reverse engineering, and may be
123 // incorrect or incomplete.
125 d = de_malloc(c, sizeof(lctx));
127 d->imgtype = de_getbyte(2);
128 de_dbg(c, "image type: 0x%02x", (unsigned int)d->imgtype);
130 switch(d->imgtype) {
131 case 0x10:
132 d->bitdepth = 16;
133 break;
134 case 0x11:
135 d->bitdepth = 24;
136 break;
137 case 0x20:
138 d->bitdepth = 4;
139 is_grayscale = 1;
140 break;
141 case 0x21:
142 d->bitdepth = 6;
143 is_grayscale = 1;
144 break;
145 case 0x22:
146 d->bitdepth = 8;
147 is_grayscale = 1;
148 break;
149 case 0x23:
150 d->bitdepth = 1;
151 is_grayscale = 1;
152 break;
153 case 0x30:
154 d->bitdepth = 8;
155 has_palette = 1;
156 break;
157 case 0x31:
158 d->bitdepth = 4;
159 has_palette = 1;
160 break;
161 default:
162 de_err(c, "Unknown VI image type: 0x%02x", (unsigned int)d->imgtype);
163 goto done;
166 if(d->bitdepth==6)
167 d->bits_alloc = 8;
168 else
169 d->bits_alloc = d->bitdepth;
171 de_dbg_indent(c, 1);
173 if(is_grayscale) imgtypename="grayscale";
174 else if(has_palette) imgtypename="palette color";
175 else imgtypename="RGB";
176 de_dbg(c, "%d bits/pixel, %s", (int)d->bitdepth, imgtypename);
177 de_dbg_indent(c, -1);
178 if(is_grayscale && (d->bitdepth!=1 && d->bitdepth!=4 && d->bitdepth!=6 && d->bitdepth!=8)) {
179 de_err(c, "This type of VI image is not supported");
180 goto done;
183 d->npwidth = de_getu16le(3);
184 d->h = de_getu16le(5);
185 de_dbg_dimensions(c, d->npwidth, d->h);
186 if(!de_good_image_dimensions(c, d->npwidth, d->h)) goto done;
188 if(has_palette) {
189 d->pal_code = de_getbyte(9);
190 de_dbg(c, "palette code: 0x%02x", (unsigned int)d->pal_code);
192 d->pal_first_entry_idx = (i64)de_getbyte(10);
193 d->num_pal_colors = (i64)de_getbyte(11);
194 if(d->num_pal_colors==0)
195 d->num_pal_colors = 256;
196 de_dbg(c, "index of first palette color: %d", (int)d->pal_first_entry_idx);
197 de_dbg(c, "number of palette colors: %d", (int)d->num_pal_colors);
200 d->palpos = de_getu16le(12);
201 d->bitspos = de_getu16le(14);
203 // Read palette, if applicable
204 if(has_palette) {
205 do_read_palette(c, d);
208 // Convert the image
209 de_dbg(c, "bitmap at %d", (int)d->bitspos);
210 d->rowspan = (d->npwidth*d->bits_alloc + 7)/8;
211 // Note that a partial pixel's worth of padding is possible in some cases, but
212 // it's not worth the trouble to make -padpix support it.
213 d->pdwidth = (d->rowspan*8)/(d->bits_alloc);
215 img = de_bitmap_create2(c, d->npwidth, d->pdwidth, d->h, is_grayscale?1:3);
216 if(has_palette) {
217 de_convert_image_paletted(c->infile, d->bitspos, d->bitdepth, d->rowspan, d->pal, img, 0);
219 else if(is_grayscale) {
220 do_convert_grayscale(c, d, img);
222 else {
223 do_convert_rgb(c, d, img);
225 de_bitmap_write_to_file(img, NULL, 0);
227 done:
228 de_bitmap_destroy(img);
229 de_free(c, d);
232 static int de_identify_jovianvi(deark *c)
234 u8 t;
236 if(dbuf_memcmp(c->infile, 0, "VI", 2)) return 0;
237 t = de_getbyte(2);
238 if((t>=0x10 && t<=0x11) ||
239 (t>=0x20 && t<=0x23) ||
240 (t>=0x30 && t<=0x31))
242 return 100;
244 return 0;
247 void de_module_jovianvi(deark *c, struct deark_module_info *mi)
249 mi->id = "jovianvi";
250 mi->desc = "Jovian Logic VI";
251 mi->run_fn = de_run_jovianvi;
252 mi->identify_fn = de_identify_jovianvi;