lzah: Improved some debug messages
[deark.git] / modules / psionpic.c
blob76191d4b88a7cc27b8d1beb6ce14827b33d310c3
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Psion PIC
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_psionpic);
11 struct plane_info_struct {
12 i64 width, height;
13 i64 image_pos; // absolute position in file
14 i64 rowspan;
17 typedef struct localctx_struct {
18 i64 num_planes;
19 int bw;
20 struct plane_info_struct *plane_info; // Array of plane_info_structs
21 } lctx;
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;
54 i64 i, j;
55 u8 n0, n1;
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)
76 i64 i;
77 if( (d->num_planes - startpos)%2 != 0) {
78 // Not an even number of bitmaps.
79 return 0;
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.
86 return 0;
89 return 1;
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)
99 if(d->bw)
100 return PPIC_FMT_1_1;
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 &&
105 could_be_2bit(d, 1))
107 return PPIC_FMT_1_2;
110 if(d->num_planes>=1 &&
111 d->plane_info[0].width==24 && d->plane_info[0].height==24)
113 return PPIC_FMT_1_1;
116 if(d->num_planes>=2 && could_be_2bit(d, 0)) {
117 return PPIC_FMT_2_2;
120 return PPIC_FMT_1_1;
123 static void de_run_psionpic(deark *c, de_module_params *mparams)
125 lctx *d = NULL;
126 i64 i;
127 int format;
128 const char *s;
130 d = de_malloc(c, sizeof(lctx));
132 s = de_get_ext_option(c, "psionpic:bw");
133 if(s) {
134 d->bw = 1;
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);
153 switch(format) {
154 case PPIC_FMT_2_2:
155 for(i=0; i+1<d->num_planes; i+=2) {
156 do_bitmap_2planes(c, d, i, i+1);
158 break;
159 case PPIC_FMT_1_2:
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);
164 break;
165 default:
166 for(i=0; i<d->num_planes; i++) {
167 do_bitmap_1plane(c, d, i);
171 de_free(c, d->plane_info);
172 de_free(c, d);
175 static int de_identify_psionpic(deark *c)
177 if(!dbuf_memcmp(c->infile, 0, "PIC\xdc\x30\x30", 6))
178 return 100;
179 return 0;
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)
189 mi->id = "psionpic";
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;