1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
6 // Supported: Most .MAG, .MKI
7 // Not supported: .MAX, some variant formats
9 #include <deark-config.h>
10 #include <deark-private.h>
11 DE_DECLARE_MODULE(de_module_makichan
);
13 typedef struct localctx_struct
{
24 i64 width_adj
, height_adj
;
35 static i64
de_int_round_up(i64 n
, i64 m
)
37 return ((n
+(m
-1))/m
)*m
;
40 static void read_palette(deark
*c
, lctx
*d
, i64 pos
)
45 de_dbg(c
, "palette at %d", (int)pos
);
48 for(k
=0; k
<d
->num_colors
; k
++) {
49 cg
= de_getbyte(pos
+3*k
);
50 cr
= de_getbyte(pos
+3*k
+1);
51 cb
= de_getbyte(pos
+3*k
+2);
52 d
->pal
[k
] = DE_MAKE_RGB(cr
,cg
,cb
);
53 de_dbg_pal_entry(c
, k
, d
->pal
[k
]);
59 static int read_mki_header(deark
*c
, lctx
*d
)
62 i64 width_raw
, height_raw
;
67 i64 expected_file_size
;
68 unsigned int extension_flags
;
71 de_dbg(c
, "MKI header at %d", (int)d
->header_pos
);
76 d
->flag_b_size
= de_getu16be(pos
+0);
77 pix_data_a_size
= de_getu16be(pos
+2);
78 pix_data_b_size
= de_getu16be(pos
+4);
79 d
->pixels_size
= pix_data_a_size
+ pix_data_b_size
;
81 extension_flags
= (unsigned int)de_getu16be(pos
+6);
82 de_dbg(c
, "extension flags: 0x%04x", extension_flags
);
84 d
->aspect_ratio_flag
= extension_flags
&0x0001;
85 if(extension_flags
&0x0002) {
90 d
->bits_per_pixel
= 4;
92 de_dbg(c
, "number of colors: %d", (int)d
->num_colors
);
95 xoffset
= de_getu16be(pos
+8);
96 yoffset
= de_getu16be(pos
+10);
97 de_dbg(c
, "image offset: (%d,%d)", (int)xoffset
, (int)yoffset
);
99 width_raw
= de_getu16be(pos
+12);
100 d
->width
= width_raw
- xoffset
;
101 height_raw
= de_getu16be(pos
+14);
102 d
->height
= height_raw
- yoffset
;
103 de_dbg_dimensions(c
, d
->width
, d
->height
);
104 if(d
->width
%64 != 0) {
105 de_warn(c
, "Width is not a multiple of 64. This image may not be handled correctly.");
107 d
->width_adj
= de_int_round_up(d
->width
, 64);
108 if(d
->height
%4 != 0) {
109 de_warn(c
, "Height is not a multiple of 4. This image may not be handled correctly.");
111 d
->height_adj
= de_int_round_up(d
->height
, 4);
113 d
->flag_a_offset
= pos
+ 16 + 48;
114 // The documentation seems to say that flag A is *always* 1000 bytes, regardless of
115 // how many bytes would actually be needed.
116 // This would imply that a MAKI image can't have more than 256000 pixels.
118 //flag_a_size = (d->width_adj*d->height_adj)/256;
120 d
->flag_b_offset
= d
->flag_a_offset
+ flag_a_size
;
121 d
->pixels_offset
= d
->flag_b_offset
+ d
->flag_b_size
;
122 expected_file_size
= d
->pixels_offset
+ d
->pixels_size
;
123 de_dbg(c
, "flag A offset=%d, size=%d", (int)d
->flag_a_offset
, (int)flag_a_size
);
124 de_dbg(c
, "flag B calculated_offset=%d, size=%d", (int)d
->flag_b_offset
, (int)d
->flag_b_size
);
125 de_dbg(c
, "pix data size_A=%d, size_B=%d", (int)pix_data_a_size
, (int)pix_data_b_size
);
126 de_dbg(c
, "pix data calculated_offset=%d, calculated_size=%d", (int)d
->pixels_offset
, (int)d
->pixels_size
);
127 de_dbg(c
, "calculated file size: %d", (int)expected_file_size
);
129 if(d
->bits_per_pixel
!=4 && d
->bits_per_pixel
!=8) {
130 de_err(c
, "Unsupported or unknown bits/pixel");
137 de_dbg_indent(c
, -1);
141 static void mki_decompress_virtual_screen(deark
*c
, lctx
*d
)
152 vs_rowspan
= d
->width_adj
/16;
153 a_pos
= d
->flag_a_offset
;
155 b_pos
= d
->flag_b_offset
;
156 d
->virtual_screen
= dbuf_create_membuf(c
, vs_rowspan
*d
->height_adj
, 1);
158 for(j
=0; j
<d
->height_adj
/4; j
++) {
159 for(i
=0; i
<d
->width_adj
/8; i
++) {
162 // Read next flag A bit
164 a_byte
= de_getbyte(a_pos
++);
167 flag_a_bit
= a_byte
& (1 << a_bitnum
--);
172 // Read the next two bytes from flag B, and split them into 4 nibbles.
173 tmpn
[0] = de_getbyte(b_pos
++);
174 tmpn
[2] = de_getbyte(b_pos
++);
175 tmpn
[1] = tmpn
[0]&0x0f;
176 tmpn
[3] = tmpn
[2]&0x0f;
183 vs_pos
= (4*j
+k
)*vs_rowspan
+ i
/2;
188 v
= dbuf_getbyte(d
->virtual_screen
, vs_pos
) | tmpn
[k
];
190 dbuf_writebyte_at(d
->virtual_screen
, vs_pos
, v
);
196 static void mki_decompress_pixels(deark
*c
, lctx
*d
)
205 d
->rowspan
= d
->width_adj
/2;
208 p_pos
= d
->pixels_offset
;
209 delta_y
= d
->is_mki_b
? 4 : 2;
210 d
->unc_pixels
= dbuf_create_membuf(c
, d
->rowspan
*d
->height_adj
, 1);
212 for(j
=0; j
<d
->height
; j
++) {
213 for(i
=0; i
<d
->rowspan
; i
++) {
217 // Read the next virtual-screen bit
219 vs_byte
= dbuf_getbyte(d
->virtual_screen
, vs_pos
++);
222 vs_bit
= vs_byte
& (1 << vs_bitnum
--);
225 v
= de_getbyte(p_pos
++);
232 v
^= dbuf_getbyte(d
->unc_pixels
, (j
-delta_y
)*d
->rowspan
+ i
);
234 dbuf_writebyte(d
->unc_pixels
, v
);
239 static int read_mag_header(deark
*c
, lctx
*d
)
241 i64 xoffset
, yoffset
;
242 i64 width_raw
, height_raw
;
250 de_dbg(c
, "header at %d", (int)d
->header_pos
);
255 model_code
= de_getbyte(pos
+1);
256 model_flags
= de_getbyte(pos
+2);
257 de_dbg(c
, "model code: 0x%02x, flags: 0x%02x",
258 (unsigned int)model_code
, (unsigned int)model_flags
);
259 if(model_code
==0x03 && (model_flags
==0x44 || model_flags
==0x24)) {
260 de_warn(c
, "This looks like MAX format, which is not correctly supported.");
264 screen_mode
= de_getbyte(pos
+3);
265 de_dbg(c
, "screen mode: %d", (int)screen_mode
);
267 d
->aspect_ratio_flag
= screen_mode
&0x01;
268 colors_code
= screen_mode
&0x82;
269 if(colors_code
==0x00) {
271 d
->bits_per_pixel
= 4;
273 else if(colors_code
==0x80) {
275 d
->bits_per_pixel
= 8;
277 else if(colors_code
==0x02) {
279 // TODO: Support 8 color images
281 de_dbg(c
, "number of colors: %d", (int)d
->num_colors
);
282 de_dbg_indent(c
, -1);
284 xoffset
= de_getu16le(pos
+4);
285 yoffset
= de_getu16le(pos
+6);
286 de_dbg(c
, "image offset: (%d,%d)", (int)xoffset
, (int)yoffset
);
288 width_raw
= de_getu16le(pos
+8);
289 height_raw
= de_getu16le(pos
+10);
290 d
->width
= width_raw
- xoffset
+ 1;
291 d
->height
= height_raw
- yoffset
+ 1;
292 de_dbg_dimensions(c
, d
->width
, d
->height
);
294 d
->flag_a_offset
= de_getu32le(pos
+12);
295 d
->flag_a_offset
+= d
->header_pos
;
296 de_dbg(c
, "flag A offset: %d", (int)d
->flag_a_offset
);
298 d
->flag_b_offset
= de_getu32le(pos
+16);
299 d
->flag_b_offset
+= d
->header_pos
;
300 d
->flag_b_size
= de_getu32le(pos
+20);
301 de_dbg(c
, "flag B offset: %d, size=%d", (int)d
->flag_b_offset
, (int)d
->flag_b_size
);
303 d
->pixels_offset
= de_getu32le(pos
+24);
304 d
->pixels_offset
+= d
->header_pos
;
305 d
->pixels_size
= de_getu32le(pos
+28);
306 de_dbg(c
, "pixels offset: %d, size=%d", (int)d
->pixels_offset
, (int)d
->pixels_size
);
308 if(d
->bits_per_pixel
!=4 && d
->bits_per_pixel
!=8) {
309 de_err(c
, "Unsupported or unknown bits/pixel");
315 de_dbg_indent(c
, -1);
319 static int do_mag_decompress(deark
*c
, lctx
*d
)
321 static const u8 delta_x
[16] = { 0,1,2,4,0,1,0,1,2,0,1,2,0,1,2, 0 };
322 static const u8 delta_y
[16] = { 0,0,0,0,1,1,2,2,2,4,4,4,8,8,8,16 };
326 int a_bitnum
; // Index of next bit to read. -1 = no more bits in a_byte.
331 u8
*action_byte_buf
= NULL
;
334 de_dbg(c
, "decompressing pixels");
336 // Presumably, due to the compression scheme, every row must have a
337 // multiple of 4 bytes.
338 d
->rowspan
= ((d
->width
* d
->bits_per_pixel
+ 31)/32)*4;
340 d
->unc_pixels
= dbuf_create_membuf(c
, d
->rowspan
* d
->height
, 1);
342 a_pos
= d
->flag_a_offset
;
344 b_pos
= d
->flag_b_offset
;
345 p_pos
= d
->pixels_offset
;
347 action_byte_buf
= de_malloc(c
, d
->rowspan
/4);
349 for(y
=0; y
<d
->height
; y
++) {
350 for(x
=0; x
<d
->rowspan
/4; x
++) {
354 // Read next flag A bit
356 a_byte
= de_getbyte(a_pos
++);
359 flag_a_bit
= a_byte
& (1 << a_bitnum
--);
362 // If flag_a_bit is unset, re-use the action byte from the
364 // If flag bit A is set, the new action byte is the one from the
365 // previous row XORed with the next B byte (don't ask me why).
366 b_byte
= de_getbyte(b_pos
++);
367 action_byte_buf
[x
] ^= b_byte
;
370 action_byte
= action_byte_buf
[x
];
372 // Produce 4 uncompressed bytes, 2 for each nibble in the
378 dcode
= (unsigned int)((action_byte
&0xf0)>>4);
380 dcode
= (unsigned int)(action_byte
&0x0f);
383 // An "uncompressed" data word. Read it from the source file.
384 de_read(wordbuf
, p_pos
, 2);
388 // Copy the data word from an earlier location in the image.
389 dpos
= d
->unc_pixels
->len
-
390 d
->rowspan
*(i64
)delta_y
[dcode
] -
391 2*(i64
)delta_x
[dcode
];
392 dbuf_read(d
->unc_pixels
, wordbuf
, dpos
, 2);
394 dbuf_write(d
->unc_pixels
, wordbuf
, 2);
399 de_free(c
, action_byte_buf
);
403 static void do_create_image(deark
*c
, lctx
*d
)
405 de_bitmap
*img
= NULL
;
408 img
= de_bitmap_create(c
, d
->width
, d
->height
, 3);
410 fi
= de_finfo_create(c
);
412 if(d
->aspect_ratio_flag
) {
413 fi
->density
.code
= DE_DENSITY_UNK_UNITS
;
414 fi
->density
.xdens
= 2.0;
415 fi
->density
.ydens
= 1.0;
418 de_convert_image_paletted(d
->unc_pixels
, 0,
419 d
->bits_per_pixel
, d
->rowspan
, d
->pal
, img
, 0);
421 de_bitmap_write_to_file_finfo(img
, fi
, 0);
422 de_bitmap_destroy(img
);
423 de_finfo_destroy(c
, fi
);
426 // Sets d->header_pos
427 static int find_mag_header(deark
*c
, lctx
*d
)
432 // Find the first 0x1a byte.
433 ret
= dbuf_search_byte(c
->infile
, '\x1a', 0, c
->infile
->len
, &pos_1a
);
435 // Find the first 0x00 byte after the first 0x1a byte.
436 // TODO: Is this the correct algorithm, or should we just assume the
437 // header starts immediately after the first 0x1a byte?
438 ret
= dbuf_search_byte(c
->infile
, '\0', pos_1a
+1, c
->infile
->len
-pos_1a
-1, &d
->header_pos
);
440 de_dbg(c
, "header found at %d", (int)d
->header_pos
);
445 de_err(c
, "Failed to find header. This is probably not a MAKIchan file.");
449 static void do_mag(deark
*c
, lctx
*d
)
451 if(!find_mag_header(c
, d
)) goto done
;
452 if(!read_mag_header(c
, d
)) goto done
;
453 read_palette(c
, d
, d
->header_pos
+32);
454 if(!de_good_image_dimensions(c
, d
->width
, d
->height
)) goto done
;
455 if(!do_mag_decompress(c
, d
)) goto done
;
456 do_create_image(c
, d
);
461 static void do_mki(deark
*c
, lctx
*d
)
464 if(!read_mki_header(c
, d
)) goto done
;
465 read_palette(c
, d
, d
->header_pos
+16);
466 if(!de_good_image_dimensions(c
, d
->width
, d
->height
)) goto done
;
467 mki_decompress_virtual_screen(c
, d
);
468 mki_decompress_pixels(c
, d
);
469 do_create_image(c
, d
);
474 static void de_run_makichan(deark
*c
, de_module_params
*mparams
)
478 d
= de_malloc(c
, sizeof(lctx
));
480 if(!dbuf_memcmp(c
->infile
, 0, "MAKI01", 6)) {
482 if(de_getbyte(6)=='B') {
494 dbuf_close(d
->unc_pixels
);
495 dbuf_close(d
->virtual_screen
);
499 static int de_identify_makichan(deark
*c
)
501 if(!dbuf_memcmp(c
->infile
, 0, "MAKI0", 5))
506 void de_module_makichan(deark
*c
, struct deark_module_info
*mi
)
509 mi
->desc
= "MAKIchan graphics";
510 mi
->run_fn
= de_run_makichan
;
511 mi
->identify_fn
= de_identify_makichan
;