1 // This file is part of Deark.
2 // Copyright (C) 2021 Jason Summers
3 // See the file COPYING for terms of use.
7 #include <deark-private.h>
8 DE_DECLARE_MODULE(de_module_pkm
);
11 de_encoding input_encoding
;
25 static void pkm_decompress_image(deark
*c
, struct pkm_ctx
*d
, i64 pos1
)
30 de_dbg(c
, "compressed image at %"I64_FMT
, pos1
);
38 if(nbytes_dcmpr
>= d
->unc_image_size
) goto done
; // Sufficient output
39 if(pos
>= c
->infile
->len
) goto done
; // No more input
41 b
= de_getbyte_p(&pos
);
43 b2
= de_getbyte_p(&pos
);
44 count
= (i64
)de_getbyte_p(&pos
);
45 dbuf_write_run(d
->unc_pixels
, b2
, count
);
46 nbytes_dcmpr
+= count
;
48 else if(b
==d
->pack_word
) {
49 b2
= de_getbyte_p(&pos
);
50 count
= de_getu16be_p(&pos
);
51 dbuf_write_run(d
->unc_pixels
, b2
, count
);
52 nbytes_dcmpr
+= count
;
55 dbuf_writebyte(d
->unc_pixels
, b
);
61 de_dbg(c
, "decompressed %"I64_FMT
" bytes to %"I64_FMT
, pos
-pos1
, nbytes_dcmpr
);
65 static void pkm_read_comment(deark
*c
, struct pkm_ctx
*d
, i64 pos
, i64 len
)
67 de_ucstring
*s
= NULL
;
68 s
= ucstring_create(c
);
69 dbuf_read_to_ucstring(c
->infile
, pos
, len
, s
, 0, d
->input_encoding
);
70 de_dbg(c
, "comment: \"%s\"", ucstring_getpsz_d(s
));
74 static void pkm_read_orig_screen_size(deark
*c
, struct pkm_ctx
*d
, i64 pos
, i64 len
)
76 // TODO: Maybe this could be used to set the density, but I suspect it's
79 d
->orig_w
= de_getu16le(pos
);
80 d
->orig_h
= de_getu16le(pos
+2);
81 de_dbg(c
, "original dimensions: %u"DE_CHAR_TIMES
"%u", (UI
)d
->orig_w
, (UI
)d
->orig_h
);
84 static void pkm_read_back_color(deark
*c
, struct pkm_ctx
*d
, i64 pos
, i64 len
)
87 d
->back_clr
= de_getbyte(pos
);
89 de_dbg(c
, "back color: 0x%02x", (UI
)d
->back_clr
);
92 static void pkm_read_postheader(deark
*c
, struct pkm_ctx
*d
, i64 pos1
)
95 i64 endpos
= pos1
+ d
->ph_size
;
96 int saved_indent_level
;
98 de_dbg(c
, "post-header at %"I64_FMT
, pos1
);
100 de_dbg_indent_save(c
, &saved_indent_level
);
109 if(field_pos
+2 > endpos
) goto done
;
110 id
= de_getbyte_p(&pos
);
111 field_size
= (i64
)de_getbyte_p(&pos
);
112 de_dbg(c
, "field at %"I64_FMT
", type=%u, dlen=%u", field_pos
, (UI
)id
,
117 pkm_read_comment(c
, d
, pos
, field_size
);
120 pkm_read_orig_screen_size(c
, d
, pos
, field_size
);
123 pkm_read_back_color(c
, d
, pos
, field_size
);
126 de_dbg_hexdump(c
, c
->infile
, pos
, field_size
, 256, NULL
, 0x1);
128 de_dbg_indent(c
, -1);
133 de_dbg_indent_restore(c
, saved_indent_level
);
136 static void de_run_pkm(deark
*c
, de_module_params
*mparams
)
138 struct pkm_ctx
*d
= NULL
;
139 de_bitmap
*img
= NULL
;
142 int saved_indent_level
;
144 de_dbg_indent_save(c
, &saved_indent_level
);
145 d
= de_malloc(c
, sizeof(struct pkm_ctx
));
146 d
->input_encoding
= de_get_input_encoding(c
, NULL
, DE_ENCODING_CP437
);
147 d
->respect_trns
= (u8
)de_get_ext_option_bool(c
, "pkm:trans", 0);
149 de_dbg(c
, "header at %"I64_FMT
, pos
);
151 pos
+= 3; // signature
153 d
->pack_byte
= de_getbyte_p(&pos
);
154 d
->pack_word
= de_getbyte_p(&pos
);
156 d
->w
= de_getu16le_p(&pos
);
157 d
->h
= de_getu16le_p(&pos
);
158 de_dbg_dimensions(c
, d
->w
, d
->h
);
159 if(!de_good_image_dimensions(c
, d
->w
, d
->h
)) goto done
;
161 de_read_simple_palette(c
, c
->infile
, pos
, 256, 3, d
->pal
, 256, DE_RDPALTYPE_VGA18BIT
, 0);
164 d
->ph_size
= de_getu16le_p(&pos
);
165 de_dbg(c
, "post-header size: %u", (UI
)d
->ph_size
);
166 de_dbg_indent(c
, -1);
168 pkm_read_postheader(c
, d
, pos
);
171 d
->unc_image_size
= d
->w
* d
->h
;
172 d
->unc_pixels
= dbuf_create_membuf(c
, d
->unc_image_size
, 0x1);
173 dbuf_enable_wbuffer(d
->unc_pixels
);
174 pkm_decompress_image(c
, d
, pos
);
175 dbuf_flush(d
->unc_pixels
);
177 if(d
->respect_trns
&& d
->has_back_clr
) {
179 // TODO: Understand the "background/transparent" color field better.
180 // Making it transparent messes up some images.
181 d
->pal
[(UI
)d
->back_clr
] = DE_SET_ALPHA(d
->pal
[(UI
)d
->back_clr
], 0);
186 img
= de_bitmap_create(c
, d
->w
, d
->h
, bypp
);
187 de_convert_image_paletted(d
->unc_pixels
, 0, 8, d
->w
, d
->pal
, img
, 0);
188 de_bitmap_write_to_file(img
, NULL
, 0);
191 de_bitmap_destroy(img
);
193 dbuf_close(d
->unc_pixels
);
196 de_dbg_indent_restore(c
, saved_indent_level
);
199 static int de_identify_pkm(deark
*c
)
201 if(!dbuf_memcmp(c
->infile
, 0, "PKM\0", 4))
206 static void de_help_pkm(deark
*c
)
208 de_msg(c
, "-opt pkm:trans : Make the background color transparent");
211 void de_module_pkm(deark
*c
, struct deark_module_info
*mi
)
214 mi
->desc
= "PKM (GrafX2)";
215 mi
->run_fn
= de_run_pkm
;
216 mi
->identify_fn
= de_identify_pkm
;
217 mi
->help_fn
= de_help_pkm
;