1 // This file is part of Deark.
2 // Copyright (C) 2017 Jason Summers
3 // See the file COPYING for terms of use.
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_drhalocut
);
11 typedef struct localctx_struct
{
18 static int do_read_header(deark
*c
, lctx
*d
)
20 d
->w
= de_getu16le(0);
21 d
->h
= de_getu16le(2);
22 de_dbg_dimensions(c
, d
->w
, d
->h
);
23 if(!de_good_image_dimensions(c
, d
->w
, d
->h
)) return 0;
27 static int do_decompress_scanline(deark
*c
, lctx
*d
, i64 line_idx
,
28 i64 pos1
, i64 len
, dbuf
*unc_pixels
)
33 i64 opos1
= unc_pixels
->len
;
36 if((pos
-pos1
) >= len
) break;
38 b
= de_getbyte(pos
++);
40 if(b
==0 || b
==0x80) { // end of row
43 else if(b
& 0x80) { // RLE block
44 count
= (i64
)(b
- 0x80);
45 b2
= dbuf_getbyte(c
->infile
, pos
++);
46 dbuf_write_run(unc_pixels
, b2
, count
);
48 else { // uncompressed block
50 dbuf_copy(c
->infile
, pos
, count
, unc_pixels
);
55 de_dbg3(c
, "scanline[%d]: decompressed %d bytes (expected %d) to %d bytes",
56 (int)line_idx
, (int)(pos
-pos1
),
57 (int)len
, (int)(unc_pixels
->len
- opos1
));
61 static int do_decompress(deark
*c
, lctx
*d
, i64 pos1
, dbuf
*unc_pixels
)
66 for(j
=0; j
<d
->h
; j
++) {
69 // Make sure we're at the right place in the uncompressed pixels.
70 dbuf_truncate(unc_pixels
, j
*d
->w
);
72 if(pos
> c
->infile
->len
-2) break;
73 linebytecount
= de_getu16le(pos
);
75 do_decompress_scanline(c
, d
, j
, pos
, linebytecount
, unc_pixels
);
79 de_dbg(c
, "decompressed %d bytes to %d bytes",
80 (int)(pos
-pos1
), (int)unc_pixels
->len
);
85 static void do_write_image_gray(deark
*c
, lctx
*d
, dbuf
*unc_pixels
)
87 de_bitmap
*img
= NULL
;
94 for(k
=0; k
<unc_pixels
->len
; k
++) {
95 b
= dbuf_getbyte(unc_pixels
, k
);
99 de_dbg(c
, "detected max val: %d", (int)max_val
);
100 if(max_val
<1) max_val
=1;
102 img
= de_bitmap_create(c
, d
->w
, d
->h
, 1);
104 for(j
=0; j
<d
->h
; j
++) {
105 for(i
=0; i
<d
->w
; i
++) {
106 b
= dbuf_getbyte(unc_pixels
, j
*d
->w
+ i
);
107 b
= de_scale_n_to_255(max_val
, (i64
)b
);
108 de_bitmap_setpixel_gray(img
, i
, j
, b
);
112 de_bitmap_write_to_file(img
, NULL
, 0);
113 de_bitmap_destroy(img
);
116 static void do_write_image_pal(deark
*c
, lctx
*d
, dbuf
*unc_pixels
)
118 de_bitmap
*img
= NULL
;
122 img
= de_bitmap_create(c
, d
->w
, d
->h
, 3);
124 for(j
=0; j
<d
->h
; j
++) {
125 for(i
=0; i
<d
->w
; i
++) {
126 b
= dbuf_getbyte(unc_pixels
, j
*d
->w
+ i
);
127 de_bitmap_setpixel_rgb(img
, i
, j
, d
->pal
[(unsigned int)b
]);
131 de_bitmap_write_to_file(img
, NULL
, 0);
132 de_bitmap_destroy(img
);
135 static int do_read_pal_file(deark
*c
, lctx
*d
, const char *palfn
)
137 dbuf
*palfile
= NULL
;
146 unsigned int board_id
;
147 unsigned int graphics_mode
;
155 de_dbg(c
, "palette file");
158 palfile
= dbuf_open_input_file(c
, palfn
);
163 sig
= dbuf_getu16le(palfile
, 0);
164 filever
= dbuf_getu16le(palfile
, 2);
165 de_dbg(c
, "file version: %d", (int)filever
);
166 datasize
= dbuf_getu16le(palfile
, 4);
167 de_dbg(c
, "data size: %d", (int)datasize
);
168 filetype
= dbuf_getbyte(palfile
, 6);
169 de_dbg(c
, "file type: 0x%02x", (unsigned int)filever
);
170 filesubtype
= dbuf_getbyte(palfile
, 7);
171 de_dbg(c
, "file subtype: 0x%02x", (unsigned int)filesubtype
);
173 if(sig
!=0x4841 /* "HA" */ || filetype
!=0x0a) {
174 de_err(c
, "Invalid palette file");
178 board_id
= (unsigned int)dbuf_getu16le(palfile
, 8);
179 de_dbg(c
, "board id: 0x%04x", board_id
);
180 graphics_mode
= (unsigned int)dbuf_getu16le(palfile
, 10);
181 de_dbg(c
, "graphics mode: 0x%04x", graphics_mode
);
184 de_warn(c
, "Hardware-specific palettes are not supported");
189 maxidx
= dbuf_getu16le(palfile
, 0x0c);
190 de_dbg(c
, "maxidx: %u", (unsigned int)maxidx
);
193 maxsamp
[k
] = dbuf_getu16le(palfile
, 0x0e + 2*k
);
194 de_dbg(c
, "maxsamp[%d]: %u", (int)k
, (unsigned int)maxsamp
[k
]);
195 if(maxsamp
[k
]<1) maxsamp
[k
]=1;
200 pos
+= 20; // Skip palette name TODO: Display this
202 num_entries
= maxidx
+1;
203 if(num_entries
>256) num_entries
=256;
205 for(k
=0; k
<num_entries
; k
++) {
206 // As far as I can tell:
207 // If we imagine the palette file being split into 512-byte chunks, a
208 // (6-byte) palette entry is not allowed to cross a chunk boundary.
209 // If an entry would do so, it instead starts at the beginning of the
211 while((pos
%512) > 506) {
216 osamp
[z
] = dbuf_getu16le(palfile
, pos
);
218 samp
[z
] = de_scale_n_to_255(maxsamp
[z
], osamp
[z
]);
220 d
->pal
[k
] = DE_MAKE_RGB(samp
[0], samp
[1], samp
[2]);
222 de_snprintf(tmps
, sizeof(tmps
), "(%5d,%5d,%5d) "DE_CHAR_RIGHTARROW
" ",
223 (int)osamp
[0], (int)osamp
[1], (int)osamp
[2]);
224 de_dbg_pal_entry2(c
, k
, d
->pal
[k
], tmps
, NULL
, NULL
);
231 de_dbg_indent(c
, -1);
235 static void de_run_drhalocut(deark
*c
, de_module_params
*mparams
)
239 dbuf
*unc_pixels
= NULL
;
242 d
= de_malloc(c
, sizeof(lctx
));
244 palfn
= de_get_ext_option(c
, "file2");
246 if(!do_read_pal_file(c
, d
, palfn
)) goto done
;
250 if(!do_read_header(c
, d
)) goto done
;
253 unc_pixels
= dbuf_create_membuf(c
, d
->w
*d
->h
, 0x1);
254 if(!do_decompress(c
, d
, pos
, unc_pixels
)) goto done
;
257 do_write_image_pal(c
, d
, unc_pixels
);
259 do_write_image_gray(c
, d
, unc_pixels
);
262 dbuf_close(unc_pixels
);
266 static int de_identify_drhalocut(deark
*c
)
268 if(de_input_file_has_ext(c
, "cut")) return 10;
272 static void de_help_drhalocut(deark
*c
)
274 de_msg(c
, "-file2 <file.pal> : Read the palette from this file");
277 void de_module_drhalocut(deark
*c
, struct deark_module_info
*mi
)
279 mi
->id
= "drhalocut";
280 mi
->desc
= "Dr. Halo .CUT image";
281 mi
->run_fn
= de_run_drhalocut
;
282 mi
->identify_fn
= de_identify_drhalocut
;
283 mi
->help_fn
= de_help_drhalocut
;