1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Segmented Hypergraphics (SHG) and Multiple Resolution Bitmap (MRB)
7 #include <deark-config.h>
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_shg
);
18 i64 bitcount
; // per plane
19 i64 rowspan
; // per plane
21 i64 pal_size_in_colors
;
22 i64 pal_size_in_bytes
;
29 typedef struct localctx_struct
{
38 int compressed_run_pending
;
39 i64 compressed_run_count
;
40 i64 uncompressed_run_bytes_left
;
44 static void my_shgrle_codec_addbuf(struct de_dfilter_ctx
*dfctx
,
45 const u8
*buf
, i64 buf_len
)
48 struct rlectx
*rctx
= (struct rlectx
*)dfctx
->codec_private
;
50 for(k
=0; k
<buf_len
; k
++) {
51 if(rctx
->uncompressed_run_bytes_left
>0) {
52 dbuf_writebyte(rctx
->outf
, buf
[k
]);
53 rctx
->uncompressed_run_bytes_left
--;
54 rctx
->nbytes_consumed
++;
58 if(rctx
->compressed_run_pending
) {
59 dbuf_write_run(rctx
->outf
, buf
[k
], rctx
->compressed_run_count
);
60 rctx
->compressed_run_pending
= 0;
61 rctx
->nbytes_consumed
+= 2;
65 if(buf
[k
] & 0x80) { // beginning of uncompressed run
66 rctx
->uncompressed_run_bytes_left
= (i64
)(buf
[k
] & 0x7f);
67 rctx
->nbytes_consumed
++;
71 rctx
->compressed_run_count
= (i64
)buf
[k
];
72 rctx
->compressed_run_pending
= 1;
76 static void my_shgrle_codec_finish(struct de_dfilter_ctx
*dfctx
)
78 struct rlectx
*rctx
= (struct rlectx
*)dfctx
->codec_private
;
80 dfctx
->dres
->bytes_consumed_valid
= 1;
81 dfctx
->dres
->bytes_consumed
= rctx
->nbytes_consumed
;
84 static void my_shgrle_codec_destroy(struct de_dfilter_ctx
*dfctx
)
86 struct rlectx
*rctx
= (struct rlectx
*)dfctx
->codec_private
;
88 de_free(dfctx
->c
, rctx
);
91 static void dfilter_shgrle_codec(struct de_dfilter_ctx
*dfctx
, void *codec_private_params
)
93 struct rlectx
*rctx
= NULL
;
95 rctx
= de_malloc(dfctx
->c
, sizeof(struct rlectx
));
96 rctx
->outf
= dfctx
->dcmpro
->f
;
98 dfctx
->codec_private
= (void*)rctx
;
99 dfctx
->codec_finish_fn
= my_shgrle_codec_finish
;
100 dfctx
->codec_destroy_fn
= my_shgrle_codec_destroy
;
101 dfctx
->codec_addbuf_fn
= my_shgrle_codec_addbuf
;
105 static void do_decompress_type_1(deark
*c
, lctx
*d
,
106 struct de_dfilter_in_params
*dcmpri
, struct de_dfilter_out_params
*dcmpro
,
107 struct de_dfilter_results
*dres
)
109 de_dbg(c
, "doing RLE decompression");
110 de_dfilter_decompress_oneshot(c
, dfilter_shgrle_codec
, NULL
,
111 dcmpri
, dcmpro
, dres
);
115 static void do_decompress_type_2(deark
*c
, lctx
*d
,
116 struct de_dfilter_in_params
*dcmpri
, struct de_dfilter_out_params
*dcmpro
,
117 struct de_dfilter_results
*dres
)
119 de_dbg(c
, "doing LZ77 decompression");
120 fmtutil_hlp_lz77_codectype1(c
, dcmpri
, dcmpro
, dres
, NULL
);
124 static void do_decompress_type_3(deark
*c
, lctx
*d
,
125 struct de_dfilter_in_params
*dcmpri
, struct de_dfilter_out_params
*dcmpro
,
126 struct de_dfilter_results
*dres
)
128 struct de_dcmpr_two_layer_params tlp
;
130 de_dbg(c
, "doing LZ77+RLE decompression");
132 de_zeromem(&tlp
, sizeof(struct de_dcmpr_two_layer_params
));
133 tlp
.codec1_type1
= fmtutil_hlp_lz77_codectype1
;
134 tlp
.codec1_private_params
= NULL
;
135 tlp
.codec2
= dfilter_shgrle_codec
;
139 de_dfilter_decompress_two_layer(c
, &tlp
);
142 static int do_uncompress_picture_data(deark
*c
, lctx
*d
,
143 struct picture_ctx
*pctx
,
144 i64 compressed_offset
, i64 compressed_size
,
145 dbuf
*pixels_final
, i64 final_image_size
)
148 struct de_dfilter_in_params dcmpri
;
149 struct de_dfilter_out_params dcmpro
;
150 struct de_dfilter_results dres
;
152 if(pctx
->packing_method
>3) {
153 de_err(c
, "Unsupported compression type: %d", (int)pctx
->packing_method
);
157 de_dfilter_init_objects(c
, &dcmpri
, &dcmpro
, &dres
);
158 dcmpri
.f
= c
->infile
;
159 dcmpri
.pos
= compressed_offset
;
160 dcmpri
.len
= compressed_size
;
161 dcmpro
.f
= pixels_final
;
162 dcmpro
.len_known
= 1;
163 dcmpro
.expected_len
= final_image_size
;
165 switch(pctx
->packing_method
) {
167 do_decompress_type_1(c
, d
, &dcmpri
, &dcmpro
, &dres
);
170 do_decompress_type_2(c
, d
, &dcmpri
, &dcmpro
, &dres
);
173 do_decompress_type_3(c
, d
, &dcmpri
, &dcmpro
, &dres
);
175 default: // 0, uncompressed
176 fmtutil_decompress_uncompressed(c
, &dcmpri
, &dcmpro
, &dres
, 0);
180 de_err(c
, "%s", de_dfilter_get_errmsg(c
, &dres
));
184 if(pixels_final
->len
< final_image_size
) {
185 de_warn(c
, "Expected %"I64_FMT
" bytes after decompression, only got %"I64_FMT
,
186 final_image_size
, pixels_final
->len
);
195 static i64
per_inch_to_per_meter(i64 dpi
)
197 return (i64
)(0.5 + (100.0/2.54)*(double)dpi
);
200 // Translate the picture into a BMP for output.
201 static void reconstruct_bmp(deark
*c
, lctx
*d
, struct picture_ctx
*pctx
,
205 struct de_bmpinfo bi
;
207 outf
= dbuf_create_output_file(c
, "bmp", NULL
, 0);
210 de_zeromem(&bi
, sizeof(struct de_bmpinfo
));
211 bi
.size_of_headers_and_pal
= 40 + pctx
->pal_size_in_bytes
;
212 bi
.total_size
= bi
.size_of_headers_and_pal
+ pctx
->final_image_size
;
213 fmtutil_generate_bmpfileheader(c
, outf
, &bi
, 0);
216 dbuf_writeu32le(outf
, 40);
217 dbuf_writeu32le(outf
, pctx
->width
);
218 dbuf_writeu32le(outf
, pctx
->height
);
219 dbuf_writeu16le(outf
, pctx
->planes
);
220 dbuf_writeu16le(outf
, pctx
->bitcount
);
221 dbuf_writeu32le(outf
, 0); // compression
222 dbuf_writeu32le(outf
, 0); // SizeImage
223 dbuf_writeu32le(outf
, per_inch_to_per_meter(pctx
->xdpi
));
224 dbuf_writeu32le(outf
, per_inch_to_per_meter(pctx
->ydpi
));
225 dbuf_writeu32le(outf
, pctx
->colors_used
);
226 dbuf_writeu32le(outf
, pctx
->colors_important
);
229 dbuf_copy(c
->infile
, pctx
->pal_offset
, pctx
->pal_size_in_bytes
, outf
);
232 dbuf_copy(pixels_final
, 0, pctx
->final_image_size
, outf
);
237 // Translate the picture into a DDB, then call the ddb module.
238 static void reconstruct_ddb(deark
*c
, lctx
*d
, struct picture_ctx
*pctx
,
243 de_module_params
*mparams
= NULL
;
245 tmpf
= dbuf_create_membuf(c
, 14+pctx
->final_image_size
, 0);
248 dbuf_writeu16le(tmpf
, 0); // bmType
249 dbuf_writeu16le(tmpf
, pctx
->width
); // bmWidth
250 dbuf_writeu16le(tmpf
, pctx
->height
); // bmHeight
251 dbuf_writeu16le(tmpf
, pctx
->rowspan
); // bmWidthBytes
252 dbuf_writebyte(tmpf
, (u8
)pctx
->planes
); // bmPlanes
253 dbuf_writebyte(tmpf
, (u8
)pctx
->bitcount
); // bmBitsPixel
254 dbuf_writeu32le(tmpf
, 0); // bmBits
256 dbuf_copy(pixels_final
, 0, pctx
->final_image_size
, tmpf
);
258 de_dbg(c
, "processing decompressed DDB");
260 fi
= de_finfo_create(c
);
261 fi
->density
.code
= DE_DENSITY_DPI
;
262 fi
->density
.xdens
= (double)pctx
->xdpi
;
263 fi
->density
.ydens
= (double)pctx
->ydpi
;
264 mparams
= de_malloc(c
, sizeof(de_module_params
));
265 mparams
->in_params
.codes
= "N";
266 mparams
->in_params
.fi
= fi
;
267 de_run_module_by_id_on_slice(c
, "ddb", mparams
, tmpf
, 0, tmpf
->len
);
269 de_dbg_indent(c
, -1);
272 de_finfo_destroy(c
, fi
);
275 // Handle a picture of type DIB or DDB.
276 static int do_dib_ddb(deark
*c
, lctx
*d
, struct picture_ctx
*pctx
, i64 pos1
)
280 i64 compressed_offset_rel
, compressed_offset_abs
;
281 i64 hotspot_offset_rel
, hotspot_offset_abs
;
283 dbuf
*pixels_final
= NULL
;
288 pctx
->xdpi
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
289 pctx
->ydpi
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
290 de_dbg(c
, "dpi: %d"DE_CHAR_TIMES
"%d", (int)pctx
->xdpi
, (int)pctx
->ydpi
);
291 if(pctx
->xdpi
<10 || pctx
->ydpi
<10 || pctx
->xdpi
>30000 || pctx
->ydpi
>30000) {
296 pctx
->planes
= fmtutil_hlp_get_cus_p(c
->infile
, &pos
);
297 de_dbg(c
, "planes: %d", (int)pctx
->planes
);
298 pctx
->bitcount
= fmtutil_hlp_get_cus_p(c
->infile
, &pos
);
299 de_dbg(c
, "bitcount: %d", (int)pctx
->bitcount
);
300 pctx
->width
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
301 pctx
->height
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
302 de_dbg_dimensions(c
, pctx
->width
, pctx
->height
);
304 pctx
->colors_used
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
305 pctx
->colors_important
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
306 de_dbg(c
, "colors used=%d, important=%d", (int)pctx
->colors_used
,
307 (int)pctx
->colors_important
);
308 if(pctx
->colors_important
==1) {
309 de_warn(c
, "This image might have transparency, which is not supported");
310 pctx
->colors_important
= 0;
313 compressed_size
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
314 hotspot_size
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
315 compressed_offset_rel
= de_getu32le_p(&pos
);
316 compressed_offset_abs
= pos1
+ compressed_offset_rel
;
317 hotspot_offset_rel
= de_getu32le_p(&pos
);
318 hotspot_offset_abs
= pos1
+ hotspot_offset_rel
;
319 de_dbg(c
, "bits offset=%"I64_FMT
" (+%"I64_FMT
"=%"I64_FMT
"), size=%"I64_FMT
,
320 compressed_offset_rel
, pos1
, compressed_offset_abs
, compressed_size
);
321 de_dbg(c
, "hotspot offset=%"I64_FMT
" (+%"I64_FMT
"=%"I64_FMT
"), size=%"I64_FMT
,
322 hotspot_offset_rel
, pos1
, hotspot_offset_abs
, hotspot_size
);
324 if(pctx
->picture_type
==5) {
325 if(pctx
->bitcount
!=1 && pctx
->bitcount
!=4 &&pctx
-> bitcount
!=8)
327 de_err(c
, "Unsupported bit count: %d", (int)pctx
->bitcount
);
331 if(pctx
->planes
<1 || pctx
->planes
>8) {
332 de_err(c
, "Unsupported planes: %d", (int)pctx
->planes
);
336 else if(pctx
->picture_type
==6) {
337 if(pctx
->bitcount
!=1 && pctx
->bitcount
!=4 &&pctx
-> bitcount
!=8 &&
338 pctx
->bitcount
!=16 && pctx
->bitcount
!=24)
340 de_err(c
, "Unsupported bit count: %d", (int)pctx
->bitcount
);
344 if(pctx
->planes
!=1) {
345 de_err(c
, "Unsupported planes: %d", (int)pctx
->planes
);
350 if(!de_good_image_dimensions(c
, pctx
->width
, pctx
->height
)) goto done
;
352 if(compressed_offset_abs
+ compressed_size
> c
->infile
->len
) {
353 de_err(c
, "Image goes beyond end of file");
357 pctx
->pal_offset
= pos
;
359 if(pctx
->picture_type
==5) {
360 pctx
->pal_size_in_colors
= 0;
362 else if(pctx
->bitcount
>8) {
363 pctx
->pal_size_in_colors
= 0;
365 else if(pctx
->colors_used
==0) {
366 pctx
->pal_size_in_colors
= ((i64
)1)<<pctx
->bitcount
;
369 pctx
->pal_size_in_colors
= pctx
->colors_used
;
370 if(pctx
->pal_size_in_colors
<1 ||
371 pctx
->pal_size_in_colors
>(((i64
)1)<<pctx
->bitcount
))
377 de_dbg(c
, "image data at %"I64_FMT
", len=%"I64_FMT
, compressed_offset_abs
,
380 pctx
->pal_size_in_bytes
= 4*pctx
->pal_size_in_colors
;
382 if(pctx
->picture_type
==5) {
383 pctx
->rowspan
= (((pctx
->width
*pctx
->bitcount
+15)/16)*2);
386 pctx
->rowspan
= (((pctx
->width
*pctx
->bitcount
+31)/32)*4);
388 pctx
->final_image_size
= pctx
->height
* pctx
->planes
* pctx
->rowspan
;
390 pixels_final
= dbuf_create_membuf(c
, 0, 0);
391 if(!do_uncompress_picture_data(c
, d
, pctx
,
392 compressed_offset_abs
, compressed_size
,
393 pixels_final
, pctx
->final_image_size
))
398 if(pctx
->picture_type
==5) {
399 reconstruct_ddb(c
, d
, pctx
, pixels_final
);
401 else if(pctx
->picture_type
==6) {
402 reconstruct_bmp(c
, d
, pctx
, pixels_final
);
407 dbuf_close(pixels_final
);
411 static int do_wmf(deark
*c
, lctx
*d
, struct picture_ctx
*pctx
, i64 pos1
)
416 i64 decompressed_size
;
419 i64 compressed_offset
;
421 dbuf
*pixels_final
= NULL
;
427 mapping_mode
= fmtutil_hlp_get_cus_p(c
->infile
, &pos
);
428 width
= de_getu16le(pos
);
430 height
= de_getu16le(pos
);
432 de_dbg(c
, "mapping mode: %d, nominal dimensions: %d"DE_CHAR_TIMES
"%d",
433 (int)mapping_mode
, (int)width
, (int)height
);
434 decompressed_size
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
435 compressed_size
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
436 hotspot_size
= fmtutil_hlp_get_cul_p(c
->infile
, &pos
);
437 compressed_offset
= de_getu32le(pos
);
439 compressed_offset
+= pos1
;
440 hotspot_offset
= de_getu32le(pos
);
442 hotspot_offset
+= pos1
;
444 de_dbg(c
, "wmf offset=%d, size=%d", (int)compressed_offset
,
445 (int)compressed_size
);
446 de_dbg(c
, "hotspot offset=%d, size=%d", (int)hotspot_offset
,
448 if(compressed_offset
+compressed_size
>c
->infile
->len
) {
449 de_err(c
, "WMF data goes beyond end of file");
453 pixels_final
= dbuf_create_membuf(c
, decompressed_size
, 0x1);
454 if(!do_uncompress_picture_data(c
, d
, pctx
, compressed_offset
, compressed_size
,
455 pixels_final
, decompressed_size
))
460 if(pixels_final
->len
!= decompressed_size
) {
461 de_warn(c
, "Expected %d bytes after decompression, got %d",
462 (int)decompressed_size
, (int)pixels_final
->len
);
465 outf
= dbuf_create_output_file(c
, "wmf", NULL
, 0);
466 dbuf_copy(pixels_final
, 0, pixels_final
->len
, outf
);
471 dbuf_close(pixels_final
);
475 static int do_picture(deark
*c
, lctx
*d
, i64 pic_index
)
479 struct picture_ctx
*pctx
= NULL
;
482 pctx
= de_malloc(c
, sizeof(struct picture_ctx
));
483 de_dbg(c
, "picture #%d", (int)pic_index
);
486 pic_offset
= de_getu32le(d
->shg_startpos
+ 4 + 4*pic_index
);
487 pic_offset
+= d
->shg_startpos
;
488 de_dbg(c
, "picture data at %d", (int)pic_offset
);
489 if(pic_offset
>= c
->infile
->len
) {
493 pctx
->picture_type
= de_getbyte(pic_offset
);
494 pctx
->packing_method
= de_getbyte(pic_offset
+1);
496 switch(pctx
->picture_type
) {
497 case 5: ptname
="DDB"; break;
498 case 6: ptname
="DIB"; break;
499 case 8: ptname
="metafile"; break;
502 de_dbg(c
, "picture type: %d (%s)", (int)pctx
->picture_type
, ptname
);
503 de_dbg(c
, "packing method: %d", (int)pctx
->packing_method
);
505 if(pctx
->picture_type
==5 || pctx
->picture_type
==6) { // DDB or DIB
506 do_dib_ddb(c
, d
, pctx
, pic_offset
);
508 else if(pctx
->picture_type
==8) { // WMF
509 do_wmf(c
, d
, pctx
, pic_offset
);
512 de_warn(c
, "Unsupported picture type: %d", (int)pctx
->picture_type
);
518 de_dbg_indent(c
, -1);
522 static void do_shg(deark
*c
, lctx
*d
)
526 d
->num_pictures
= de_getu16le(d
->shg_startpos
+2);
527 de_dbg(c
, "number of pictures in file: %d", (int)d
->num_pictures
);
528 if(!de_good_image_count(c
, d
->num_pictures
)) {
532 for(k
=0; k
<d
->num_pictures
; k
++) {
533 if(!do_picture(c
, d
, k
)) {
542 static void de_run_shg(deark
*c
, de_module_params
*mparams
)
546 d
= de_malloc(c
, sizeof(lctx
));
549 d
->signature
= de_getu16le(d
->shg_startpos
);
550 if(d
->signature
==0x506c) {
551 de_declare_fmt(c
, "SHG");
553 else if(d
->signature
==0x706c) {
554 de_declare_fmt(c
, "MRB");
557 de_warn(c
, "This is probably not an SHG/MRB file.");
565 static int de_identify_shg(deark
*c
)
569 if(buf
[0]==0x6c && (buf
[1]==0x50 || buf
[1]==0x70)) {
575 void de_module_shg(deark
*c
, struct deark_module_info
*mi
)
578 mi
->desc
= "SHG (Segmented Hypergraphics), MRB (Multiple Resolution Bitmap)";
579 mi
->run_fn
= de_run_shg
;
580 mi
->identify_fn
= de_identify_shg
;