bmp: Rewrote the RLE decompressor
[deark.git] / modules / eps.c
blob06b9e66324e2f19900bac1da68d5ecde6a289b3a
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 npwidth, h;
13 i64 pdwidth;
14 i64 depth;
15 i64 src_rowspan;
16 i64 lines;
18 i64 hex_digit_count;
19 i64 xpos, ypos;
20 u8 pending_byte;
22 de_color pal[256];
23 } lctx;
26 static void de_run_eps_binary(deark *c)
28 i64 eps_offset, eps_len;
29 i64 wmf_offset, wmf_len;
30 i64 tiff_offset, tiff_len;
32 de_declare_fmt(c, "EPS binary");
34 eps_offset = de_getu32le(4);
35 eps_len = de_getu32le(8);
36 wmf_offset = de_getu32le(12);
37 wmf_len = de_getu32le(16);
38 tiff_offset = de_getu32le(20);
39 tiff_len = de_getu32le(24);
41 if(eps_len>0) {
42 de_dbg(c, "Extracting EPS offs=%d len=%d", (int)eps_offset, (int)eps_len);
43 dbuf_create_file_from_slice(c->infile, eps_offset, eps_len, "eps", NULL, 0);
45 if(wmf_len>0) {
46 de_dbg(c, "Extracting WMF offs=%d len=%d", (int)wmf_offset, (int)wmf_len);
47 dbuf_create_file_from_slice(c->infile, wmf_offset, wmf_len, "preview.wmf", NULL, DE_CREATEFLAG_IS_AUX);
49 if(tiff_len>0) {
50 de_dbg(c, "Extracting TIFF offs=%d len=%d", (int)tiff_offset, (int)tiff_len);
51 dbuf_create_file_from_slice(c->infile, tiff_offset, tiff_len, "preview.tif", NULL, DE_CREATEFLAG_IS_AUX);
55 static void process_hex_digit(deark *c, lctx *d, u8 hexdigit, dbuf *outf)
57 u8 x;
58 int errorflag;
60 x = de_decode_hex_digit(hexdigit, &errorflag);
61 if(errorflag) return; // Ignore non hex-digits
63 if(d->hex_digit_count%2 == 0) {
64 d->pending_byte = x;
65 d->hex_digit_count++;
66 // Wait for the next hex digit
67 return;
70 dbuf_writebyte(outf, (d->pending_byte<<4) | x);
71 d->hex_digit_count++;
72 return;
75 static void do_decode_epsi_image(deark *c, lctx *d, i64 pos1)
77 de_bitmap *img = NULL;
78 dbuf *tmpf = NULL;
79 i64 content_len, total_len;
80 i64 pos;
81 i64 i, k;
82 UI createflags;
84 pos = pos1;
85 d->hex_digit_count = 0;
87 tmpf = dbuf_create_membuf(c, d->pdwidth * d->h, 0);
89 // Convert from hex-encoded (base16) to binary.
90 for(i=0; i<d->lines; i++) {
91 if(!dbuf_find_line(c->infile, pos, &content_len, &total_len))
92 break;
93 for(k=0; k<content_len; k++) {
94 process_hex_digit(c, d, de_getbyte(pos+k), tmpf);
96 pos += total_len;
99 // Convert from binary to an image
101 img = de_bitmap_create2(c, d->npwidth, d->pdwidth, d->h, 1);
103 de_make_grayscale_palette(d->pal, 1ULL<<d->depth, 0x1);
104 de_convert_image_paletted(tmpf, 0, d->depth, d->src_rowspan, d->pal, img, 0);
106 createflags = DE_CREATEFLAG_IS_AUX;
107 if(d->depth==1) {
108 createflags |= DE_CREATEFLAG_IS_BWIMG;
110 else {
111 createflags |= DE_CREATEFLAG_OPT_IMAGE;
113 de_bitmap_write_to_file(img, "preview", createflags);
114 de_bitmap_destroy(img);
115 dbuf_close(tmpf);
118 static void do_decode_epsi(deark *c, const char *hdrfields, i64 pos1)
120 int width, height, depth, lines;
121 int ret;
122 lctx *d = NULL;
124 d = de_malloc(c, sizeof(lctx));
126 // EPSI is a text-based format, and deark isn't very good at text formats.
127 // But we'll give it a try.
129 ret = de_sscanf(hdrfields, " %d %d %d %d", &width, &height, &depth, &lines);
130 if(ret!=4) {
131 de_err(c, "Failed to parse EPSI header line");
132 return;
134 de_dbg(c, "w=%d h=%d d=%d l=%d", width, height, depth, lines);
135 d->npwidth = width;
136 d->h = height;
137 d->depth = depth;
138 d->lines = lines;
140 if(d->depth!=1 && d->depth!=2 && d->depth!=4 && d->depth!=8) {
141 de_err(c, "Unsupported EPSI bit depth (%d)", (int)d->depth);
142 goto done;
145 d->src_rowspan = (d->npwidth * d->depth +7)/8;
146 d->pdwidth = (d->src_rowspan*8) / d->depth;
148 if(!de_good_image_dimensions(c, d->pdwidth, d->h)) {
149 goto done;
151 if(d->lines>100000 || d->lines<1) {
152 de_err(c, "Bad EPSI header");
153 goto done;
156 do_decode_epsi_image(c, d, pos1);
158 done:
159 de_free(c, d);
162 static void de_run_eps_normal(deark *c)
164 i64 pos;
165 u8 linebuf[1024];
166 i64 content_len, total_len;
168 de_declare_fmt(c, "Encapsulated PostScript");
170 pos = 0;
171 while(dbuf_find_line(c->infile, pos, &content_len, &total_len)) {
172 de_dbg2(c, "line: pos=%d c_len=%d t_len=%d", (int)pos, (int)content_len, (int)total_len);
174 if(content_len > (i64)(sizeof(linebuf)-1))
175 content_len = sizeof(linebuf)-1;
177 de_read(linebuf, pos, content_len);
178 linebuf[content_len] = '\0';
180 if(!de_memcmp(linebuf, "%%BeginPreview:", 15)) {
181 do_decode_epsi(c, (const char*)(linebuf+15), pos+total_len);
182 break;
185 pos += total_len;
189 static void de_run_eps(deark *c, de_module_params *mparams)
191 u8 b[2];
193 de_read(b, 0, (i64)sizeof(b));
195 if(b[0]==0xc5 && b[1]==0xd0) {
196 de_run_eps_binary(c);
198 else if(b[0]=='%' && b[1]=='!') {
199 de_run_eps_normal(c);
201 else {
202 de_err(c, "Not an EPS file");
206 static int de_identify_eps(deark *c)
208 u8 b[20];
209 de_read(b, 0, (i64)sizeof(b));
211 if(b[0]==0xc5 && b[1]==0xd0 && b[2]==0xd3 && b[3]==0xc6)
212 return 100;
214 if(!de_memcmp(b, "%!PS-Adobe-", 11) &&
215 !de_memcmp(&b[14], " EPSF-", 6) )
217 return 100;
220 return 0;
223 void de_module_eps(deark *c, struct deark_module_info *mi)
225 mi->id = "eps";
226 mi->desc = "Encapsulated PostScript";
227 mi->desc2 = "extract preview image";
228 mi->run_fn = de_run_eps;
229 mi->identify_fn = de_identify_eps;