1 // This file is part of Deark.
2 // Copyright (C) 2016 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_psionpic
);
11 struct plane_info_struct
{
13 i64 image_pos
; // absolute position in file
17 typedef struct localctx_struct
{
20 struct plane_info_struct
*plane_info
; // Array of plane_info_structs
23 static void do_read_plane_info(deark
*c
, lctx
*d
, struct plane_info_struct
*pi
, i64 pos
)
25 i64 image_relative_pos
;
26 i64 image_size_in_bytes
;
28 de_zeromem(pi
, sizeof(struct plane_info_struct
));
29 pi
->width
= de_getu16le(pos
+2);
30 pi
->height
= de_getu16le(pos
+4);
31 image_size_in_bytes
= de_getu16le(pos
+6);
32 image_relative_pos
= de_getu32le(pos
+8);
33 pi
->image_pos
= pos
+ 12 + image_relative_pos
;
34 pi
->rowspan
= ((pi
->width
+15)/16)*2; // 2-byte alignment
36 de_dbg(c
, "bitmap: descriptor at %d, image at %d (size %d)",
37 (int)pos
, (int)pi
->image_pos
, (int)image_size_in_bytes
);
38 de_dbg_dimensions(c
, pi
->width
, pi
->height
);
41 static void do_bitmap_1plane(deark
*c
, lctx
*d
, i64 plane_num
)
43 struct plane_info_struct
*pi
= &d
->plane_info
[plane_num
];
45 de_dbg(c
, "making a bilevel image from plane %d", (int)plane_num
);
47 de_convert_and_write_image_bilevel2(c
->infile
, pi
->image_pos
, pi
->width
, pi
->height
,
48 pi
->rowspan
, DE_CVTF_WHITEISZERO
|DE_CVTF_LSBFIRST
, NULL
, 0);
51 static void do_bitmap_2planes(deark
*c
, lctx
*d
, i64 pn1
, i64 pn2
)
53 de_bitmap
*img
= NULL
;
57 de_dbg(c
, "making a grayscale image from planes %d and %d", (int)pn1
, (int)pn2
);
59 // TODO: Support -padpix (need samples with width not a multiple of 16)
60 img
= de_bitmap_create(c
, d
->plane_info
[pn1
].width
, d
->plane_info
[pn1
].height
, 1);
62 for(j
=0; j
<d
->plane_info
[pn1
].height
; j
++) {
63 for(i
=0; i
<d
->plane_info
[pn1
].width
; i
++) {
64 n0
= de_get_bits_symbol_lsb(c
->infile
, 1, d
->plane_info
[pn1
].image_pos
+ j
*d
->plane_info
[pn1
].rowspan
, i
);
65 n1
= de_get_bits_symbol_lsb(c
->infile
, 1, d
->plane_info
[pn2
].image_pos
+ j
*d
->plane_info
[pn2
].rowspan
, i
);
66 de_bitmap_setpixel_gray(img
, i
, j
, (3-(n0
*2+n1
))*85);
69 de_bitmap_write_to_file(img
, NULL
, 0);
71 de_bitmap_destroy(img
);
74 static int could_be_2bit(lctx
*d
, int startpos
)
77 if( (d
->num_planes
- startpos
)%2 != 0) {
78 // Not an even number of bitmaps.
81 for(i
=startpos
; i
<d
->num_planes
; i
+=2) {
82 if(d
->plane_info
[i
].width
!=d
->plane_info
[i
+1].width
||
83 d
->plane_info
[i
].height
!=d
->plane_info
[i
+1].height
)
85 // Bitmaps aren't the same size.
92 #define PPIC_FMT_1_1 1
93 #define PPIC_FMT_1_2 2
94 #define PPIC_FMT_2_2 3
96 // This detection logic is just a wild guess. Copy it at your own risk.
97 static int detect_format(deark
*c
, lctx
*d
)
102 if(d
->num_planes
>=3 &&
103 d
->plane_info
[0].width
==24 && d
->plane_info
[0].height
==24 &&
104 d
->plane_info
[1].width
==48 && d
->plane_info
[1].height
==48 &&
110 if(d
->num_planes
>=1 &&
111 d
->plane_info
[0].width
==24 && d
->plane_info
[0].height
==24)
116 if(d
->num_planes
>=2 && could_be_2bit(d
, 0)) {
123 static void de_run_psionpic(deark
*c
, de_module_params
*mparams
)
130 d
= de_malloc(c
, sizeof(lctx
));
132 s
= de_get_ext_option(c
, "psionpic:bw");
137 d
->num_planes
= de_getu16le(6);
138 de_dbg(c
, "number of planes/bitmaps: %d", (int)d
->num_planes
);
140 // After the 8-byte header are [num_images] 12-byte bitmap descriptors.
141 d
->plane_info
= de_mallocarray(c
, d
->num_planes
, sizeof(struct plane_info_struct
));
142 for(i
=0; i
<d
->num_planes
; i
++) {
143 do_read_plane_info(c
, d
, &d
->plane_info
[i
], 8+12*i
);
146 // The PIC format seems like it was intended to store an arbitrary
147 // number of bilevel images, but some of them are clearly planes that
148 // are intended to be combined to form an image. I don't know for sure
149 // how I'm supposed to do that.
151 format
= detect_format(c
, d
);
155 for(i
=0; i
+1<d
->num_planes
; i
+=2) {
156 do_bitmap_2planes(c
, d
, i
, i
+1);
160 do_bitmap_1plane(c
, d
, 0);
161 for(i
=1; i
+1<d
->num_planes
; i
+=2) {
162 do_bitmap_2planes(c
, d
, i
, i
+1);
166 for(i
=0; i
<d
->num_planes
; i
++) {
167 do_bitmap_1plane(c
, d
, i
);
171 de_free(c
, d
->plane_info
);
175 static int de_identify_psionpic(deark
*c
)
177 if(!dbuf_memcmp(c
->infile
, 0, "PIC\xdc\x30\x30", 6))
182 static void de_help_psionpic(deark
*c
)
184 de_msg(c
, "-opt psionpic:bw : Do not try to detect grayscale images");
187 void de_module_psionpic(deark
*c
, struct deark_module_info
*mi
)
190 mi
->desc
= "Psion PIC, a.k.a. EPOC PIC";
191 mi
->run_fn
= de_run_psionpic
;
192 mi
->identify_fn
= de_identify_psionpic
;
193 mi
->help_fn
= de_help_psionpic
;