New "videomaster" module
[deark.git] / modules / printptnr.c
blob7376202988a5a53bf9f9c9a169d0f35b3f712673
1 // This file is part of Deark.
2 // Copyright (C) 2017 Jason Summers
3 // See the file COPYING for terms of use.
5 // PrintPartner .GPH
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_pp_gph);
11 struct page_ctx {
12 i64 width, height;
13 i64 width_raw;
14 u8 cmpr_type;
15 de_ucstring *imgname;
18 typedef struct localctx_struct {
19 int reserved;
20 } lctx;
22 static void do_write_image_frombitmap(deark *c, lctx *d, struct page_ctx *pg,
23 de_bitmap *img)
25 de_finfo *fi = NULL;
27 fi = de_finfo_create(c);
28 fi->density.code = DE_DENSITY_UNK_UNITS;
29 fi->density.xdens = 2;
30 fi->density.ydens = 1;
32 if(c->filenames_from_file && pg->imgname && (pg->imgname->len > 0)) {
33 de_finfo_set_name_from_ucstring(c, fi, pg->imgname, 0);
35 de_bitmap_write_to_file_finfo(img, fi, 0);
36 de_finfo_destroy(c, fi);
39 static void do_write_image_fromuncpixels(deark *c, lctx *d, struct page_ctx *pg,
40 dbuf *unc_pixels)
42 de_bitmap *img = NULL;
44 img = de_bitmap_create(c, pg->width, pg->height, 1);
45 de_convert_image_bilevel(unc_pixels, 0, pg->width_raw, img, DE_CVTF_WHITEISZERO);
46 do_write_image_frombitmap(c, d, pg, img);
47 de_bitmap_destroy(img);
50 // Decode the pixels of an uncompressed image
51 static void do_image_cmpr1(deark *c, lctx *d, struct page_ctx *pg, i64 pos1,
52 i64 *bytes_consumed)
54 dbuf *unc_pixels = NULL;
56 *bytes_consumed = pg->width_raw*pg->height;
57 unc_pixels = dbuf_open_input_subfile(c->infile, pos1,
58 pg->width_raw*pg->height);
59 do_write_image_fromuncpixels(c, d, pg, unc_pixels);
60 dbuf_close(unc_pixels);
63 // A simple byte-oriented RLE scheme.
64 static void do_image_cmpr2(deark *c, lctx *d, struct page_ctx *pg, i64 pos1,
65 i64 *bytes_consumed)
67 i64 cmpr_len;
68 i64 pos = pos1;
69 dbuf *unc_pixels = NULL;
71 cmpr_len = de_getu16le(pos);
72 de_dbg(c, "cmpr data len: %d bytes", (int)cmpr_len);
73 pos += 2;
74 *bytes_consumed = 2 + cmpr_len;
76 unc_pixels = dbuf_create_membuf(c, pg->width_raw*pg->height, 0x1);
78 while(1) {
79 i64 count;
80 u8 b, b2;
82 if(pos >= pos1+2+cmpr_len) break;
83 b = de_getbyte(pos++);
84 count = (i64)(b & 0x7f);
85 if(b & 0x80) { // compressed run
86 b2 = de_getbyte(pos);
87 pos++;
88 dbuf_write_run(unc_pixels, b2, count);
90 else { // uncompressed run
91 dbuf_copy(c->infile, pos, count, unc_pixels);
92 pos += count;
96 do_write_image_fromuncpixels(c, d, pg, unc_pixels);
97 dbuf_close(unc_pixels);
100 // A simple pixel-oriented RLE scheme. Each nibble represents a run of 1 to 7
101 // white or black pixels.
102 // It is unknown how run lengths of 0 are handled.
103 static void do_image_cmpr3(deark *c, lctx *d, struct page_ctx *pg, i64 pos1,
104 i64 *bytes_consumed)
106 de_bitmap *img = NULL;
107 i64 pos = pos1;
108 i64 nibble_count;
109 i64 nibble_idx;
110 i64 pixel_idx;
111 u8 b;
113 img = de_bitmap_create(c, pg->width, pg->height, 1);
115 // Start with an all-white image:
116 de_bitmap_rect(img, 0, 0, pg->width, pg->height, DE_STOCKCOLOR_WHITE, 0);
118 nibble_count = de_getu16le(pos);
119 de_dbg(c, "cmpr data len: %d nibbles", (int)nibble_count);
120 pos += 2;
122 *bytes_consumed = 2 + (nibble_count+1)/2;
124 b = 0;
125 pixel_idx = 0;
126 for(nibble_idx=0; nibble_idx<nibble_count; nibble_idx++) {
127 i64 count;
128 int isblack;
129 u8 nibble_val;
130 i64 k;
132 if((nibble_idx&0x1) == 0) {
133 b = de_getbyte(pos++);
134 nibble_val = b>>4;
136 else {
137 nibble_val = b&0x0f;
140 count = (i64)(nibble_val&0x7);
141 isblack = (nibble_val>=8);
143 for(k=0; k<count; k++) {
144 if(isblack)
145 de_bitmap_setpixel_gray(img, pixel_idx%pg->width, pixel_idx/pg->width, 0x00);
146 pixel_idx++;
150 do_write_image_frombitmap(c, d, pg, img);
151 de_bitmap_destroy(img);
154 static int do_one_image(deark *c, lctx *d, i64 pos1, int img_idx, i64 *bytes_consumed)
156 i64 namelen;
157 i64 pos = pos1;
158 i64 bytes_consumed2 = 0;
159 int retval = 0;
161 struct page_ctx *pg = NULL;
163 pg = de_malloc(c, sizeof(struct page_ctx));
165 de_dbg(c, "image #%d at %d", img_idx, (int)pos1);
166 de_dbg_indent(c, 1);
167 namelen = (i64)de_getbyte(pos++);
168 if(namelen>20) {
169 de_err(c, "Invalid image");
170 goto done;
173 pg->imgname = ucstring_create(c);
174 dbuf_read_to_ucstring(c->infile, pos, namelen, pg->imgname, 0, DE_ENCODING_ASCII);
175 de_dbg(c, "name: \"%s\"", ucstring_getpsz(pg->imgname));
176 pos += 20;
178 pg->cmpr_type = (i64)de_getbyte(pos++);
179 de_dbg(c, "cmpr type: %d", (int)pg->cmpr_type);
180 pg->height = (i64)de_getbyte(pos++);
181 pg->width_raw = (i64)de_getbyte(pos++);
182 pg->width = pg->width_raw*8;
183 de_dbg_dimensions(c, pg->width, pg->height);
185 if(pg->cmpr_type==1) {
186 do_image_cmpr1(c, d, pg, pos, &bytes_consumed2);
187 pos += bytes_consumed2;
189 else if(pg->cmpr_type==2) {
190 do_image_cmpr2(c, d, pg, pos, &bytes_consumed2);
191 pos += bytes_consumed2;
193 else if(pg->cmpr_type==3) {
194 do_image_cmpr3(c, d, pg, pos, &bytes_consumed2);
195 pos += bytes_consumed2;
197 else {
198 de_err(c, "Unsupported compression type: %d", (int)pg->cmpr_type);
199 goto done;
202 *bytes_consumed = pos - pos1;
203 retval = 1;
204 done:
205 de_dbg_indent(c, -1);
206 if(pg) {
207 ucstring_destroy(pg->imgname);
208 de_free(c, pg);
210 return retval;
213 static void de_run_pp_gph(deark *c, de_module_params *mparams)
215 lctx *d = NULL;
216 i64 pos;
217 i64 bytes_consumed;
218 int img_idx = 0;
219 u8 *bufptr;
220 u8 buf[256];
222 d = de_malloc(c, sizeof(lctx));
224 de_read(buf, 0, sizeof(buf)-1);
225 buf[sizeof(buf)-1] = '\0';
226 bufptr = (u8*)de_strchr((const char*)buf, 0x1a);
227 if(!bufptr) {
228 de_err(c, "This doesn't look like a valid .GPH file");
229 goto done;
232 pos = (bufptr - buf);
233 de_dbg(c, "end of header found at %d", (int)pos);
235 pos++;
237 while(1) {
238 if(pos > (c->infile->len - 24)) break;
239 bytes_consumed = 0;
240 if(!do_one_image(c, d, pos, img_idx, &bytes_consumed)) goto done;
241 if(bytes_consumed<1) goto done;
242 pos += bytes_consumed;
243 img_idx++;
246 done:
247 de_free(c, d);
250 static int de_identify_pp_gph(deark *c)
252 if(!de_input_file_has_ext(c, "gph")) return 0;
254 if(!dbuf_memcmp(c->infile, 0, "PrintPartner", 12)) {
255 return 100;
257 return 0;
260 void de_module_pp_gph(deark *c, struct deark_module_info *mi)
262 mi->id = "pp_gph";
263 mi->desc = "PrintPartner .GPH";
264 mi->run_fn = de_run_pp_gph;
265 mi->identify_fn = de_identify_pp_gph;