lha: Enabled lh1 compression by default
[deark.git] / modules / pcx.c
blob383e8b136d476134367218f91351f82f88a8a086
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // PCX (PC Paintbrush) and DCX (multi-image PCX)
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_pcx);
10 DE_DECLARE_MODULE(de_module_mswordscr);
11 DE_DECLARE_MODULE(de_module_dcx);
13 #define PCX_HDRSIZE 128
15 enum resmode_type {
16 RESMODE_IGNORE = 0,
17 RESMODE_AUTO,
18 RESMODE_DPI,
19 RESMODE_SCREENDIMENSIONS
22 typedef struct localctx_struct {
23 u8 version;
24 u8 encoding;
25 enum resmode_type resmode;
26 i64 bits;
27 i64 bits_per_pixel;
28 i64 margin_L, margin_T, margin_R, margin_B;
29 i64 planes;
30 i64 rowspan_raw;
31 i64 rowspan;
32 i64 ncolors;
33 u8 palette_info;
34 u8 reserved1;
35 i64 width, height;
36 int is_mswordscr;
37 int has_vga_pal;
38 int has_transparency;
40 // Identifier of the palette to use, if there is no palette in the file
41 int default_pal_num;
42 int default_pal_set;
44 dbuf *unc_pixels;
45 de_finfo *fi;
46 u32 pal[256];
47 } lctx;
49 static void simplify_dens(i64 *pxdens, i64 *pydens, i64 factor)
51 while(*pxdens>factor && *pydens>factor &&
52 (*pxdens%factor==0) && (*pydens%factor==0))
54 *pxdens /= factor;
55 *pydens /= factor;
59 static void set_density_from_screen_res(deark *c, lctx *d, i64 hres, i64 vres)
61 i64 xdens, ydens;
63 d->fi->density.code = DE_DENSITY_UNK_UNITS;
64 xdens = hres*3; // Assume 4:3 screen
65 ydens = vres*4;
67 simplify_dens(&xdens, &ydens, 2);
68 simplify_dens(&xdens, &ydens, 3);
69 simplify_dens(&xdens, &ydens, 5);
71 d->fi->density.xdens = (double)xdens;
72 d->fi->density.ydens = (double)ydens;
75 // The resolution field is unreliable. It might contain:
76 // * Zeroes
77 // * The DPI
78 // * The pixel dimensions of the target screen mode
79 // * The dimensions of the image itself
80 // * A corrupted attempt at one of the above things (perhaps copied from an
81 // older version of the image)
82 static void do_decode_resolution(deark *c, lctx *d, i64 hres, i64 vres)
84 enum resmode_type resmode = d->resmode;
86 if(hres==0 || vres==0) return;
88 if(resmode==RESMODE_AUTO) {
89 if((hres==320 && vres==200) ||
90 (hres==640 && vres==480) ||
91 (hres==640 && vres==350) ||
92 (hres==640 && vres==200) ||
93 (hres==800 && vres==600) ||
94 (hres==1024 && vres==768))
96 if(d->width<=hres && d->height<=hres) {
97 // Looks like screen dimensions, and image fits on the screen
98 resmode = RESMODE_SCREENDIMENSIONS;
101 else if(hres==d->width && vres==d->height) {
104 else {
105 if(hres==vres && hres>=50 && hres<=600) {
106 resmode = RESMODE_DPI;
111 if(resmode==RESMODE_DPI) { // dpi
112 d->fi->density.code = DE_DENSITY_DPI;
113 d->fi->density.xdens = (double)hres;
114 d->fi->density.ydens = (double)vres;
116 else if(resmode==RESMODE_SCREENDIMENSIONS) {
117 set_density_from_screen_res(c, d, hres, vres);
121 static int do_read_header(deark *c, lctx *d)
123 int retval = 0;
124 i64 hres, vres;
125 const char *imgtypename = "";
127 de_dbg(c, "header at %d", 0);
128 de_dbg_indent(c, 1);
130 d->version = de_getbyte(1);
131 d->encoding = de_getbyte(2);
132 d->bits = (i64)de_getbyte(3); // Bits per pixel per plane
133 d->margin_L = de_getu16le(4);
134 d->margin_T = de_getu16le(6);
135 d->margin_R = de_getu16le(8);
136 d->margin_B = de_getu16le(10);
138 hres = de_getu16le(12);
139 vres = de_getu16le(14);
141 // The palette (offset 16-63) will be read later.
143 // For older versions of PCX, this field might be useful to help identify
144 // the intended video mode. Documentation is lacking, though.
145 d->reserved1 = de_getbyte(64);
147 d->planes = (i64)de_getbyte(65);
148 d->rowspan_raw = de_getu16le(66);
149 d->palette_info = de_getbyte(68);
151 de_dbg(c, "format version: %d, encoding: %d, planes: %d, bits: %d", (int)d->version,
152 (int)d->encoding, (int)d->planes, (int)d->bits);
153 de_dbg(c, "bytes/plane/row: %d, palette info: %d, vmode: 0x%02x", (int)d->rowspan_raw,
154 (int)d->palette_info, (unsigned int)d->reserved1);
155 de_dbg(c, "margins: %d, %d, %d, %d", (int)d->margin_L, (int)d->margin_T,
156 (int)d->margin_R, (int)d->margin_B);
158 de_dbg(c, "resolution: %d"DE_CHAR_TIMES"%d", (int)hres, (int)vres);
160 d->width = d->margin_R - d->margin_L +1;
161 d->height = d->margin_B - d->margin_T +1;
162 de_dbg_dimensions(c, d->width, d->height);
163 if(!de_good_image_dimensions(c, d->width, d->height)) goto done;
165 d->rowspan = d->rowspan_raw * d->planes;
166 de_dbg(c, "calculated bytes/row: %d", (int)d->rowspan);
168 d->bits_per_pixel = d->bits * d->planes;
170 if(d->encoding!=0 && d->encoding!=1) {
171 de_err(c, "Unsupported compression type: %d", (int)d->encoding);
172 goto done;
175 // Enumerate the known PCX image types.
176 if(d->planes==1 && d->bits==1) {
177 imgtypename = "2-color";
178 d->ncolors = 2;
180 //else if(d->planes==2 && d->bits==1) {
181 // d->ncolors = 4;
183 else if(d->planes==1 && d->bits==2) {
184 imgtypename = "4-color";
185 d->ncolors = 4;
187 else if(d->planes==3 && d->bits==1) {
188 imgtypename = "8-color";
189 d->ncolors = 8;
191 else if(d->planes==4 && d->bits==1) {
192 imgtypename = "16-color";
193 d->ncolors = 16;
195 //else if(d->planes==1 && d->bits==4) {
196 // d->ncolors = 16;
198 //else if(d->planes==4 && d->bits==2) {
199 // d->ncolors = 16; (?)
201 else if(d->planes==1 && d->bits==8) {
202 imgtypename = "256-color";
203 d->ncolors = 256;
205 //else if(d->planes==4 && d->bits==4) {
206 // d->ncolors = 4096;
208 else if(d->planes==3 && d->bits==8) {
209 imgtypename = "truecolor";
210 d->ncolors = 16777216;
212 else if(d->planes==4 && d->bits==8) {
213 // I can't find a PCX spec that mentions 32-bit RGBA images, but
214 // ImageMagick and Wikipedia act like they're perfectly normal.
215 imgtypename = "truecolor+alpha";
216 d->ncolors = 16777216;
217 d->has_transparency = 1;
219 else {
220 de_err(c, "Unsupported image type (bits=%d, planes=%d)",
221 (int)d->bits, (int)d->planes);
222 goto done;
225 de_dbg(c, "image type: %s", imgtypename);
227 // Sanity check
228 if(d->rowspan > d->width * 4 + 100) {
229 de_err(c, "Bad bytes/line (%d)", (int)d->rowspan_raw);
230 goto done;
233 do_decode_resolution(c, d, hres, vres);
235 retval = 1;
236 done:
237 de_dbg_indent(c, -1);
238 return retval;
241 static int do_read_vga_palette(deark *c, lctx *d)
243 i64 pos;
245 if(d->version<5) return 0;
246 if(d->ncolors!=256) return 0;
247 pos = c->infile->len - 769;
248 if(pos<PCX_HDRSIZE) return 0;
250 if(de_getbyte(pos) != 0x0c) {
251 return 0;
254 de_dbg(c, "VGA palette at %d", (int)pos);
255 d->has_vga_pal = 1;
256 pos++;
257 de_dbg_indent(c, 1);
258 de_read_palette_rgb(c->infile, pos, 256, 3, d->pal, 256, 0);
259 de_dbg_indent(c, -1);
261 return 1;
264 // Maybe read the palette from a separate file.
265 // Returns 1 if the palette was read.
266 static int do_read_alt_palette_file(deark *c, lctx *d)
268 const char *palfn;
269 dbuf *palfile = NULL;
270 int retval = 0;
271 i64 k,z;
272 u8 b1[3];
273 u8 b2[3];
274 int badflag = 0;
275 char tmps[64];
277 palfn = de_get_ext_option(c, "file2");
278 if(!palfn) goto done;
280 palfile = dbuf_open_input_file(c, palfn);
281 if(!palfile) goto done;
282 de_dbg(c, "using palette from separate file");
284 if(palfile->len != d->ncolors*3) {
285 badflag = 1;
288 de_dbg_indent(c, 1);
289 for(k=0; k<d->ncolors && k*3<palfile->len; k++) {
290 dbuf_read(palfile, b1, 3*k, 3);
291 for(z=0; z<3; z++) {
292 if(b1[z]>0x3f) badflag = 1;
293 b2[z] = de_scale_63_to_255(b1[z]);
295 d->pal[k] = DE_MAKE_RGB(b2[0],b2[1],b2[2]);
297 de_snprintf(tmps, sizeof(tmps), "(%2d,%2d,%2d) "DE_CHAR_RIGHTARROW" ",
298 (int)b1[0], (int)b1[1], (int)b1[2]);
299 de_dbg_pal_entry2(c, k, d->pal[k], tmps, NULL, NULL);
301 de_dbg_indent(c, -1);
303 if(badflag) {
304 de_warn(c, "%s doesn't look like the right kind of palette file", palfn);
307 retval = 1;
309 done:
310 dbuf_close(palfile);
311 return retval;
314 // 16-color palettes to use, if there is no palette in the file.
315 // (8-color version-3 PCXs apparently use only the first 8 colors of the
316 // palette.)
317 static const u32 ega16pal[2][16] = {
318 // This palette seems to be correct for at least some files.
319 {0x000000,0x000080,0x008000,0x008080,0x800000,0x800080,0x808000,0x808080,
320 0xc0c0c0,0x0000ff,0x00ff00,0x00ffff,0xff0000,0xff00ff,0xffff00,0xffffff},
322 // This is the "default EGA palette" used by several PCX viewers.
323 // I don't know its origin.
324 {0x000000,0xbf0000,0x00bf00,0xbfbf00,0x0000bf,0xbf00bf,0x00bfbf,0xc0c0c0,
325 0x808080,0xff0000,0x00ff00,0xffff00,0x0000ff,0xff00ff,0x00ffff,0xffffff}
328 static void do_palette_stuff(deark *c, lctx *d)
330 i64 k;
332 if(d->ncolors>256) {
333 return;
336 if(d->ncolors==256) {
337 // For 256-color images, start with a default grayscale palette.
338 for(k=0; k<256; k++) {
339 d->pal[k] = DE_MAKE_GRAY((unsigned int)k);
343 if(do_read_alt_palette_file(c, d)) {
344 return;
347 if(d->ncolors==2) {
348 // TODO: Allegedly, some 2-color PCXs are not simply white-on-black,
349 // and at least the foreground color can be something other than white.
350 // The color information would be stored in the palette area, but
351 // different files use different ways of conveying that information,
352 // and it seems hopeless to reliably determine the correct format.
353 return;
356 if(d->version==3 && d->ncolors>=8 && d->ncolors<=16) {
357 if(!d->default_pal_set) {
358 de_info(c, "Note: This paletted PCX file does not contain a palette. "
359 "If it is not decoded correctly, try \"-opt pcx:pal=1\".");
361 de_dbg(c, "using a default EGA palette");
362 for(k=0; k<16; k++) {
363 d->pal[k] = ega16pal[d->default_pal_num][k];
365 return;
368 if(d->version>=5 && d->ncolors==256) {
369 if(do_read_vga_palette(c, d)) {
370 return;
372 de_warn(c, "Expected VGA palette was not found");
373 // (Use the grayscale palette created earlier, as a last resort.)
374 return;
377 if(d->ncolors==4) {
378 u8 p0, p3;
379 unsigned int bgcolor;
380 unsigned int fgpal;
382 de_warn(c, "4-color PCX images might not be supported correctly");
384 p0 = de_getbyte(16);
385 p3 = de_getbyte(19);
386 bgcolor = p0>>4;
387 fgpal = p3>>5;
388 de_dbg(c, "using a CGA palette: palette #%d, bkgd color %d", (int)fgpal, (int)bgcolor);
390 // Set first pal entry to background color
391 d->pal[0] = de_palette_pc16(bgcolor);
393 // TODO: These palettes are quite possibly incorrect. I can't find good
394 // information about them.
395 switch(fgpal) {
396 case 0: case 2: // C=0 P=? I=0
397 d->pal[1]=0x00aaaa; d->pal[2]=0xaa0000; d->pal[3]=0xaaaaaa; break;
398 case 1: case 3: // C=0 P=? I=1
399 d->pal[1]=0x55ffff; d->pal[2]=0xff5555; d->pal[3]=0xffffff; break;
400 case 4: // C=1 P=0 I=0
401 d->pal[1]=0x00aa00; d->pal[2]=0xaa0000; d->pal[3]=0xaa5500; break;
402 case 5: // C=1 P=0 I=1
403 d->pal[1]=0x55ff55; d->pal[2]=0xff5555; d->pal[3]=0xffff55; break;
404 case 6: // C=1 P=1 I=0
405 d->pal[1]=0x00aaaa; d->pal[2]=0xaa00aa; d->pal[3]=0xaaaaaa; break;
406 case 7: // C=1 P=1 I=1
407 d->pal[1]=0x55ffff; d->pal[2]=0xff55ff; d->pal[3]=0xffffff; break;
409 return;
412 if(d->ncolors>16 && d->ncolors<=256) {
413 de_warn(c, "No suitable palette found");
416 de_dbg(c, "using 16-color palette from header");
418 de_dbg_indent(c, 1);
419 de_read_palette_rgb(c->infile, 16, 16, 3, d->pal, 256, 0);
420 de_dbg_indent(c, -1);
423 static int do_uncompress(deark *c, lctx *d)
425 i64 pos;
426 u8 b, b2;
427 i64 count;
428 i64 expected_bytes;
429 i64 endpos;
431 pos = PCX_HDRSIZE;
432 de_dbg(c, "compressed bitmap at %d", (int)pos);
434 expected_bytes = d->rowspan * d->height;
435 d->unc_pixels = dbuf_create_membuf(c, expected_bytes, 0);
437 endpos = c->infile->len;
438 if(d->has_vga_pal) {
439 // The last 769 bytes of this file are reserved for the palette.
440 // Don't try to decode them as pixels.
441 endpos -= 769;
444 while(1) {
445 if(pos>=endpos) {
446 break; // Reached the end of source data
448 if(d->unc_pixels->len >= expected_bytes) {
449 break; // Reached the end of the image
451 b = de_getbyte(pos++);
453 if(b>=0xc0) {
454 count = (i64)(b&0x3f);
455 b2 = de_getbyte(pos++);
456 dbuf_write_run(d->unc_pixels, b2, count);
458 else {
459 dbuf_writebyte(d->unc_pixels, b);
463 if(d->unc_pixels->len < expected_bytes) {
464 de_warn(c, "Expected %d bytes of image data, only found %d",
465 (int)expected_bytes, (int)d->unc_pixels->len);
468 return 1;
471 static void do_bitmap_1bpp(deark *c, lctx *d)
473 // The paletted algorithm would work here (if we construct a palette),
474 // but this special case is easy and efficient.
475 de_convert_and_write_image_bilevel2(d->unc_pixels, 0,
476 d->width, d->height, d->rowspan_raw, 0, d->fi, 0);
479 static void do_bitmap_paletted(deark *c, lctx *d)
481 de_bitmap *img = NULL;
482 i64 pdwidth;
483 i64 i, j;
484 i64 plane;
485 u8 b;
486 unsigned int palent;
488 // bits_per_plane(_per_row) / bits_per_pixel_per_plane
489 pdwidth = (d->rowspan_raw*8) / d->bits;
491 img = de_bitmap_create2(c, d->width, pdwidth, d->height, 3);
493 for(j=0; j<d->height; j++) {
494 for(i=0; i<pdwidth; i++) {
495 palent = 0;
496 for(plane=0; plane<d->planes; plane++) {
497 b = de_get_bits_symbol(d->unc_pixels, d->bits,
498 j*d->rowspan + plane*d->rowspan_raw, i);
499 palent |= b<<(plane*d->bits);
501 if(palent>255) palent=0; // Should be impossible.
502 de_bitmap_setpixel_rgb(img, i, j, d->pal[palent]);
506 de_bitmap_write_to_file_finfo(img, d->fi, 0);
507 de_bitmap_destroy(img);
510 static void do_bitmap_24bpp(deark *c, lctx *d)
512 de_bitmap *img = NULL;
513 i64 pdwidth;
514 i64 i, j;
515 i64 plane;
516 u8 s[4];
518 de_memset(s, 0xff, sizeof(s));
519 pdwidth = (d->rowspan_raw*8) / d->bits;
520 img = de_bitmap_create2(c, d->width, pdwidth, d->height, d->has_transparency?4:3);
522 for(j=0; j<d->height; j++) {
523 for(i=0; i<pdwidth; i++) {
524 for(plane=0; plane<d->planes; plane++) {
525 s[plane] = dbuf_getbyte(d->unc_pixels, j*d->rowspan + plane*d->rowspan_raw +i);
527 de_bitmap_setpixel_rgba(img, i, j, DE_MAKE_RGBA(s[0], s[1], s[2], s[3]));
531 de_bitmap_write_to_file_finfo(img, d->fi, 0);
532 de_bitmap_destroy(img);
535 static void do_bitmap(deark *c, lctx *d)
537 if(d->bits_per_pixel==1) {
538 do_bitmap_1bpp(c, d);
540 else if(d->bits_per_pixel<=8) {
541 do_bitmap_paletted(c, d);
543 else if(d->bits_per_pixel>=24) {
544 do_bitmap_24bpp(c, d);
546 else {
547 de_err(c, "Unsupported bits/pixel: %d", (int)d->bits_per_pixel);
551 static void de_run_pcx_internal(deark *c, lctx *d, de_module_params *mparams)
553 const char *s;
555 s = de_get_ext_option(c, "pcx:pal");
556 if(s) {
557 d->default_pal_num = de_atoi(s);
558 if(d->default_pal_num<0 || d->default_pal_num>1) {
559 d->default_pal_num = 0;
561 d->default_pal_set = 1;
564 d->resmode = RESMODE_AUTO;
565 s = de_get_ext_option(c, "pcx:resmode");
566 if(s) {
567 if(!de_strcmp(s, "auto")) {
568 d->resmode = RESMODE_AUTO;
570 else if(!de_strcmp(s, "dpi")) {
571 d->resmode = RESMODE_DPI;
573 else if(!de_strcmp(s, "screen")) {
574 d->resmode = RESMODE_SCREENDIMENSIONS;
578 d->fi = de_finfo_create(c);
580 if(!do_read_header(c, d)) {
581 goto done;
584 do_palette_stuff(c, d);
586 if(d->encoding==0) {
587 // Uncompressed PCXs are probably not standard, but support for them is not
588 // uncommon. Imagemagick, for example, will create them if you ask it to.
589 de_dbg(c, "uncompressed bitmap at %d", (int)PCX_HDRSIZE);
590 d->unc_pixels = dbuf_open_input_subfile(c->infile,
591 PCX_HDRSIZE, c->infile->len-PCX_HDRSIZE);
593 else {
594 if(!do_uncompress(c, d)) {
595 goto done;
599 do_bitmap(c, d);
601 done:
602 dbuf_close(d->unc_pixels);
603 d->unc_pixels = NULL;
604 de_finfo_destroy(c, d->fi);
605 d->fi = NULL;
608 static void de_run_pcx(deark *c, de_module_params *mparams)
610 lctx *d = NULL;
612 d = de_malloc(c, sizeof(lctx));
613 de_run_pcx_internal(c, d, mparams);
614 de_free(c, d);
617 static int de_identify_pcx(deark *c)
619 u8 buf[8];
621 de_read(buf, 0, 8);
622 if(buf[0]==0x0a && (buf[1]==0 || buf[1]==2 || buf[1]==3
623 || buf[1]==4 || buf[1]==5) &&
624 (buf[2]==0 || buf[2]==1) )
626 if(de_input_file_has_ext(c, "pcx"))
627 return 100;
629 return 16;
631 return 0;
634 static void de_help_pcx(deark *c)
636 de_msg(c, "-opt pcx:pal=<0|1> : Code for the predefined palette to use, "
637 "if there is no palette in the file");
638 de_msg(c, "-opt pcx:resmode=<ignore|dpi|screen|auto> : How to interpret the "
639 "\"resolution\" field");
640 de_msg(c, "-file2 <file.p13> : Read the palette from a separate file");
643 void de_module_pcx(deark *c, struct deark_module_info *mi)
645 mi->id = "pcx";
646 mi->desc = "PCX image";
647 mi->run_fn = de_run_pcx;
648 mi->identify_fn = de_identify_pcx;
649 mi->help_fn = de_help_pcx;
652 // **************************************************************************
653 // MS Word for DOS Screen Capture
654 // **************************************************************************
656 static void de_run_mswordscr(deark *c, de_module_params *mparams)
658 lctx *d = NULL;
660 d = de_malloc(c, sizeof(lctx));
661 d->is_mswordscr = 1;
662 de_run_pcx_internal(c, d, mparams);
663 de_free(c, d);
666 static int de_identify_mswordscr(deark *c)
668 u8 buf[8];
670 de_read(buf, 0, 8);
671 if(buf[0]==0xcd && (buf[1]==0 || buf[1]==2 || buf[1]==3
672 || buf[1]==4 || buf[1]==5) &&
673 buf[2]==1 )
675 if(de_input_file_has_ext(c, "scr") || de_input_file_has_ext(c, "mwg"))
676 return 100;
678 return 10;
680 return 0;
683 void de_module_mswordscr(deark *c, struct deark_module_info *mi)
685 mi->id = "mswordscr";
686 mi->desc = "MS Word for DOS Screen Capture";
687 mi->run_fn = de_run_mswordscr;
688 mi->identify_fn = de_identify_mswordscr;
691 // **************************************************************************
692 // DCX
693 // **************************************************************************
695 static void de_run_dcx(deark *c, de_module_params *mparams)
697 u32 *page_offset;
698 i64 num_pages;
699 i64 page;
700 i64 page_size;
702 page_offset = de_mallocarray(c, 1023, sizeof(u32));
703 num_pages = 0;
704 while(num_pages < 1023) {
705 page_offset[num_pages] = (u32)de_getu32le(4 + 4*num_pages);
706 if(page_offset[num_pages]==0)
707 break;
708 num_pages++;
711 de_dbg(c, "number of pages: %d", (int)num_pages);
713 for(page=0; page<num_pages; page++) {
714 if(page == num_pages-1) {
715 // Last page. Asssume it goes to the end of file.
716 page_size = c->infile->len - page_offset[page];
718 else {
719 page_size = page_offset[page+1] - page_offset[page];
721 if(page_size<0) page_size=0;
722 de_dbg(c, "page %d at %d, size=%d", (int)page, (int)page_offset[page],
723 (int)page_size);
725 dbuf_create_file_from_slice(c->infile, page_offset[page], page_size, "pcx", NULL, 0);
729 static int de_identify_dcx(deark *c)
731 if(!dbuf_memcmp(c->infile, 0, "\xb1\x68\xde\x3a", 4))
732 return 100;
733 return 0;
736 void de_module_dcx(deark *c, struct deark_module_info *mi)
738 mi->id = "dcx";
739 mi->desc = "DCX (multi-image PCX)";
740 mi->run_fn = de_run_dcx;
741 mi->identify_fn = de_identify_dcx;