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_pp_gph
);
18 typedef struct localctx_struct
{
22 static void do_write_image_frombitmap(deark
*c
, lctx
*d
, struct page_ctx
*pg
,
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
, DE_CREATEFLAG_IS_BWIMG
);
36 de_finfo_destroy(c
, fi
);
39 static void do_write_image_fromuncpixels(deark
*c
, lctx
*d
, struct page_ctx
*pg
,
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
,
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
,
69 dbuf
*unc_pixels
= NULL
;
71 cmpr_len
= de_getu16le(pos
);
72 de_dbg(c
, "cmpr data len: %d bytes", (int)cmpr_len
);
74 *bytes_consumed
= 2 + cmpr_len
;
76 unc_pixels
= dbuf_create_membuf(c
, pg
->width_raw
*pg
->height
, 0x1);
82 if(pos
>= pos1
+2+cmpr_len
) break;
83 b
= de_getbyte(pos
++);
84 count
= (i64
)(b
& 0x7f);
85 if(b
& 0x80) { // compressed run
88 dbuf_write_run(unc_pixels
, b2
, count
);
90 else { // uncompressed run
91 dbuf_copy(c
->infile
, pos
, count
, unc_pixels
);
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
,
106 de_bitmap
*img
= NULL
;
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
);
122 *bytes_consumed
= 2 + (nibble_count
+1)/2;
126 for(nibble_idx
=0; nibble_idx
<nibble_count
; nibble_idx
++) {
132 if((nibble_idx
&0x1) == 0) {
133 b
= de_getbyte(pos
++);
140 count
= (i64
)(nibble_val
&0x7);
141 isblack
= (nibble_val
>=8);
143 for(k
=0; k
<count
; k
++) {
145 de_bitmap_setpixel_gray(img
, pixel_idx
%pg
->width
, pixel_idx
/pg
->width
, 0x00);
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
)
158 i64 bytes_consumed2
= 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
);
167 namelen
= (i64
)de_getbyte(pos
++);
169 de_err(c
, "Invalid image");
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
));
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
;
198 de_err(c
, "Unsupported compression type: %d", (int)pg
->cmpr_type
);
202 *bytes_consumed
= pos
- pos1
;
205 de_dbg_indent(c
, -1);
207 ucstring_destroy(pg
->imgname
);
213 static void de_run_pp_gph(deark
*c
, de_module_params
*mparams
)
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);
228 de_err(c
, "This doesn't look like a valid .GPH file");
232 pos
= (bufptr
- buf
);
233 de_dbg(c
, "end of header found at %d", (int)pos
);
238 if(pos
> (c
->infile
->len
- 24)) break;
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
;
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)) {
260 void de_module_pp_gph(deark
*c
, struct deark_module_info
*mi
)
263 mi
->desc
= "PrintPartner .GPH";
264 mi
->run_fn
= de_run_pp_gph
;
265 mi
->identify_fn
= de_identify_pp_gph
;