zoo: Various improvements
[deark.git] / modules / eps.c
blobc38dcfbf0afd5b6ee0e10903bd36b60cb5d56ddd
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Encapsulated PostScript
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_eps);
11 typedef struct localctx_struct {
12 i64 w, h;
13 i64 depth;
14 i64 lines;
16 i64 hex_digit_count;
17 i64 xpos, ypos;
18 u8 pending_byte;
19 } lctx;
22 static void de_run_eps_binary(deark *c)
24 i64 eps_offset, eps_len;
25 i64 wmf_offset, wmf_len;
26 i64 tiff_offset, tiff_len;
28 de_declare_fmt(c, "EPS binary");
30 eps_offset = de_getu32le(4);
31 eps_len = de_getu32le(8);
32 wmf_offset = de_getu32le(12);
33 wmf_len = de_getu32le(16);
34 tiff_offset = de_getu32le(20);
35 tiff_len = de_getu32le(24);
37 if(eps_len>0) {
38 de_dbg(c, "Extracting EPS offs=%d len=%d", (int)eps_offset, (int)eps_len);
39 dbuf_create_file_from_slice(c->infile, eps_offset, eps_len, "eps", NULL, 0);
41 if(wmf_len>0) {
42 de_dbg(c, "Extracting WMF offs=%d len=%d", (int)wmf_offset, (int)wmf_len);
43 dbuf_create_file_from_slice(c->infile, wmf_offset, wmf_len, "preview.wmf", NULL, DE_CREATEFLAG_IS_AUX);
45 if(tiff_len>0) {
46 de_dbg(c, "Extracting TIFF offs=%d len=%d", (int)tiff_offset, (int)tiff_len);
47 dbuf_create_file_from_slice(c->infile, tiff_offset, tiff_len, "preview.tif", NULL, DE_CREATEFLAG_IS_AUX);
51 static void process_hex_digit(deark *c, lctx *d, u8 hexdigit, dbuf *outf)
53 u8 x;
54 int errorflag;
56 x = de_decode_hex_digit(hexdigit, &errorflag);
57 if(errorflag) return; // Ignore non hex-digits
59 if(d->hex_digit_count%2 == 0) {
60 d->pending_byte = x;
61 d->hex_digit_count++;
62 // Wait for the next hex digit
63 return;
66 dbuf_writebyte(outf, (d->pending_byte<<4) | x);
67 d->hex_digit_count++;
68 return;
71 static void convert_row_gray(dbuf *f, i64 fpos, de_bitmap *img,
72 i64 rownum, int depth)
74 i64 i;
75 u8 b;
77 for(i=0; i<img->width; i++) {
78 b = de_get_bits_symbol(f, depth, fpos, i);
79 if(depth==1) b*=255;
80 else if(depth==2) b*=85;
81 else if(depth==4) b*=17;
82 de_bitmap_setpixel_gray(img, i, rownum, 255-b);
86 static void do_decode_epsi_image(deark *c, lctx *d, i64 pos1)
88 de_bitmap *img = NULL;
89 dbuf *tmpf = NULL;
90 i64 content_len, total_len;
91 i64 pos;
92 i64 i, j, k;
93 i64 src_rowspan;
96 pos = pos1;
97 d->hex_digit_count = 0;
99 tmpf = dbuf_create_membuf(c, d->w * d->h, 0);
101 // Convert from hex-encoded (base16) to binary.
102 for(i=0; i<d->lines; i++) {
103 if(!dbuf_find_line(c->infile, pos, &content_len, &total_len))
104 break;
105 for(k=0; k<content_len; k++) {
106 process_hex_digit(c, d, de_getbyte(pos+k), tmpf);
108 pos += total_len;
111 // Convert from binary to an image
113 img = de_bitmap_create(c, d->w, d->h, 1);
115 src_rowspan = (d->w * d->depth +7)/8;
117 for(j=0; j<d->h; j++) {
118 convert_row_gray(tmpf, j*src_rowspan, img, j, (int)d->depth);
121 de_bitmap_write_to_file(img, "preview", DE_CREATEFLAG_IS_AUX);
122 de_bitmap_destroy(img);
123 dbuf_close(tmpf);
126 static void do_decode_epsi(deark *c, const char *hdrfields, i64 pos1)
128 int width, height, depth, lines;
129 int ret;
130 lctx *d = NULL;
132 d = de_malloc(c, sizeof(lctx));
134 // EPSI is a text-based format, and deark isn't very good at text formats.
135 // But we'll give it a try.
137 ret = de_sscanf(hdrfields, " %d %d %d %d", &width, &height, &depth, &lines);
138 if(ret!=4) {
139 de_err(c, "Failed to parse EPSI header line");
140 return;
142 de_dbg(c, "w=%d h=%d d=%d l=%d", width, height, depth, lines);
143 d->w = width;
144 d->h = height;
145 d->depth = depth;
146 d->lines = lines;
148 if(!de_good_image_dimensions(c, d->w, d->h)) {
149 goto done;
151 if(d->depth!=1 && d->depth!=2 && d->depth!=4 && d->depth!=8) {
152 de_err(c, "Unsupported EPSI bit depth (%d)", (int)d->depth);
153 goto done;
155 if(d->lines>100000 || d->lines<1) {
156 de_err(c, "Bad EPSI header");
157 goto done;
160 do_decode_epsi_image(c, d, pos1);
162 done:
163 de_free(c, d);
166 static void de_run_eps_normal(deark *c)
168 i64 pos;
169 u8 linebuf[1024];
170 i64 content_len, total_len;
172 de_declare_fmt(c, "Encapsulated PostScript");
174 pos = 0;
175 while(dbuf_find_line(c->infile, pos, &content_len, &total_len)) {
176 de_dbg2(c, "line: pos=%d c_len=%d t_len=%d", (int)pos, (int)content_len, (int)total_len);
178 if(content_len > (i64)(sizeof(linebuf)-1))
179 content_len = sizeof(linebuf)-1;
181 de_read(linebuf, pos, content_len);
182 linebuf[content_len] = '\0';
184 if(!de_memcmp(linebuf, "%%BeginPreview:", 15)) {
185 do_decode_epsi(c, (const char*)(linebuf+15), pos+total_len);
186 break;
189 pos += total_len;
193 static void de_run_eps(deark *c, de_module_params *mparams)
195 u8 b[2];
197 de_read(b, 0, (i64)sizeof(b));
199 if(b[0]==0xc5 && b[1]==0xd0) {
200 de_run_eps_binary(c);
202 else if(b[0]=='%' && b[1]=='!') {
203 de_run_eps_normal(c);
205 else {
206 de_err(c, "Not an EPS file");
210 static int de_identify_eps(deark *c)
212 u8 b[20];
213 de_read(b, 0, (i64)sizeof(b));
215 if(b[0]==0xc5 && b[1]==0xd0 && b[2]==0xd3 && b[3]==0xc6)
216 return 100;
218 if(!de_memcmp(b, "%!PS-Adobe-", 11) &&
219 !de_memcmp(&b[14], " EPSF-", 6) )
221 return 100;
224 return 0;
227 void de_module_eps(deark *c, struct deark_module_info *mi)
229 mi->id = "eps";
230 mi->desc = "Encapsulated PostScript";
231 mi->desc2 = "extract preview image";
232 mi->run_fn = de_run_eps;
233 mi->identify_fn = de_identify_eps;