1 // This file is part of Deark.
2 // Copyright (C) 2017 Jason Summers
3 // See the file COPYING for terms of use.
7 #include <deark-config.h>
8 #include <deark-private.h>
9 #include <deark-fmtutil.h>
10 DE_DECLARE_MODULE(de_module_palmbitmap
);
12 #define PALMBMPFLAG_COMPRESSED 0x8000U
13 #define PALMBMPFLAG_HASCOLORTABLE 0x4000U
14 #define PALMBMPFLAG_HASTRNS 0x2000U
15 #define PALMBMPFLAG_DIRECTCOLOR 0x0400U
18 PCMPR_UNKNOWN
, PCMPR_NONE
, PCMPR_SCANLINE
, PCMPR_RLE
,
19 PCMPR_PACKBITS8
, PCMPR_PACKBITS16
22 #define CMPR_FIELD_SCANLINE 0
23 #define CMPR_FIELD_RLE 1
24 #define CMPR_FIELD_PACKBITS 2
25 #define CMPR_FIELD_NONE 0xff
36 unsigned int cmpr_type_field
;
37 enum palm_cmpr_type cmpr_type
;
39 i64 expected_num_uncmpr_image_bytes
;
43 typedef struct localctx_struct
{
45 int ignore_color_table_flag
;
48 static int de_identify_palmbitmap_internal(deark
*c
, dbuf
*f
, i64 pos
, i64 len
)
55 pixelsize
= de_getbyte(pos
+8);
60 ver
= de_getbyte(pos
+9);
62 w
= dbuf_getu16be(f
, pos
+0);
63 h
= dbuf_getu16be(f
, pos
+2);
64 if(w
==0 || h
==0) return 0;
65 rowbytes
= dbuf_getu16be(f
, pos
+4);
66 pixelsize
= de_getbyte(pos
+8);
67 if((pixelsize
==0 && ver
==0) || pixelsize
==1 || pixelsize
==2 ||
68 pixelsize
==4 || pixelsize
==8 || pixelsize
==16)
75 if(rowbytes
==0 || (rowbytes
&0x1)) return 0;
76 // TODO: Make sure rowbytes is sensible
80 static void do_decompress_scanline_compression(deark
*c
, lctx
*d
, struct page_ctx
*pg
,
81 struct de_dfilter_in_params
*dcmpri
, struct de_dfilter_out_params
*dcmpro
,
82 struct de_dfilter_results
*dres
)
84 i64 srcpos
= dcmpri
->pos
;
88 i64 nbytes_written
= 0;
93 blocksperrow
= (pg
->rowbytes
+7)/8;
95 for(j
=0; j
<pg
->h
; j
++) {
96 i64 bytes_written_this_row
= 0;
98 if(nbytes_written
>= dcmpro
->expected_len
) goto done
;
100 for(blocknum
=0; blocknum
<blocksperrow
; blocknum
++) {
101 // For each byte-per-row, we expect a lead byte, which is a
102 // bitfield that tells us which of the next 8 bytes are stored
103 // in the file, versus being copied from the previous row.
104 bf
= dbuf_getbyte(dcmpri
->f
, srcpos
++);
106 if(bytes_written_this_row
>=pg
->rowbytes
) break;
110 dstb
= dbuf_getbyte(dcmpri
->f
, srcpos
++);
113 // copy from previous row
114 dstb
= dbuf_getbyte(dcmpro
->f
, dcmpro
->f
->len
- pg
->rowbytes
);
116 dbuf_writebyte(dcmpro
->f
, dstb
);
118 bytes_written_this_row
++;
124 dres
->bytes_consumed
= srcpos
- dcmpri
->pos
;
125 dres
->bytes_consumed_valid
= 1;
128 // Note that this is distinct from ImageViewer RLE compression.
129 static void do_decompress_rle_compression(deark
*c
, struct de_dfilter_in_params
*dcmpri
,
130 struct de_dfilter_out_params
*dcmpro
, struct de_dfilter_results
*dres
)
132 i64 srcpos
= dcmpri
->pos
;
133 i64 nbytes_written
= 0;
135 while(srcpos
<= (dcmpri
->pos
+ dcmpri
->len
- 2)) {
139 if(nbytes_written
> dcmpro
->expected_len
) goto done
;
140 count
= (i64
)dbuf_getbyte_p(dcmpri
->f
, &srcpos
);
141 val
= dbuf_getbyte_p(dcmpri
->f
, &srcpos
);
142 dbuf_write_run(dcmpro
->f
, val
, count
);
143 nbytes_written
+= count
;
146 dres
->bytes_consumed
= srcpos
- dcmpri
->pos
;
147 dres
->bytes_consumed_valid
= 1;
150 static void make_stdpal256(deark
*c
, lctx
*d
, u32
*stdpal
)
153 static const u32 supplpal
[15] = {0x111111,
154 0x222222,0x444444,0x555555,0x777777,0x888888,0xaaaaaa,0xbbbbbb,0xdddddd,
155 0xeeeeee,0xc0c0c0,0x800000,0x800080,0x008000,0x008080};
156 static u8 vals
[6] = {0xff, 0xcc, 0x99, 0x66, 0x33, 0x00};
158 for(k
=0; k
<215; k
++) {
160 r
= vals
[(k
%108)/18];
162 b
= vals
[(k
/108)*3 + (k
%18)/6];
163 stdpal
[k
] = DE_MAKE_RGB(r
, g
, b
);
165 for(k
=215; k
<230; k
++) {
166 stdpal
[k
] = DE_MAKE_OPAQUE(supplpal
[k
-215]);
168 for(k
=230; k
<256; k
++) {
169 stdpal
[k
] = DE_STOCKCOLOR_BLACK
;
173 static void do_generate_img_from_unc_pixels(deark
*c
, lctx
*d
, struct page_ctx
*pg
,
180 de_bitmap
*img
= NULL
;
183 de_zeromem(pal
, sizeof(pal
));
184 has_color
= (pg
->bitsperpixel
>4 || pg
->has_custom_pal
);
186 if(pg
->bitsperpixel
==1 && !has_color
) {
187 de_convert_and_write_image_bilevel2(unc_pixels
, 0, pg
->w
, pg
->h
, pg
->rowbytes
,
188 DE_CVTF_WHITEISZERO
, NULL
, 0);
192 pdwidth
= (pg
->rowbytes
*8) / pg
->bitsperpixel
;
193 if(pdwidth
<pg
->w
) pdwidth
= pg
->w
;
195 img
= de_bitmap_create2(c
, pg
->w
, pdwidth
, pg
->h
,
196 (has_color
?3:1) + (pg
->has_trns
?1:0));
198 if(pg
->bitsperpixel
==16) {
199 for(j
=0; j
<pg
->h
; j
++) {
200 for(i
=0; i
<pdwidth
; i
++) {
202 clr1
= (u32
)dbuf_getu16be(unc_pixels
, pg
->rowbytes
*j
+ 2*i
);
203 clr
= de_rgb565_to_888(clr1
);
204 de_bitmap_setpixel_rgb(img
, i
, j
, clr
);
205 if(pg
->has_trns
&& clr1
==pg
->trns_value
) {
206 de_bitmap_setsample(img
, i
, j
, 3, 0);
213 if(pg
->bitsperpixel
>8) goto done
;
214 // TODO: What are the correct colors (esp. for 4bpp)?
215 de_make_grayscale_palette(pal
, 1ULL<<pg
->bitsperpixel
, 0x1);
217 else if(pg
->has_custom_pal
) {
218 de_memcpy(pal
, pg
->custom_pal
, sizeof(pg
->custom_pal
));
221 make_stdpal256(c
, d
, pal
);
224 if(pg
->has_trns
&& pg
->trns_value
<256) {
225 pal
[pg
->trns_value
] = DE_SET_ALPHA(pal
[pg
->trns_value
], 0);
228 de_convert_image_paletted(unc_pixels
, 0,pg
->bitsperpixel
, pg
->rowbytes
,
232 de_bitmap_write_to_file(img
, NULL
, DE_CREATEFLAG_OPT_IMAGE
);
235 de_bitmap_destroy(img
);
238 static int de_decompress_image(deark
*c
, lctx
*d
, struct page_ctx
*pg
,
239 dbuf
*inf
, i64 pos
, i64 len
, dbuf
*unc_pixels
)
241 struct de_dfilter_in_params dcmpri
;
242 struct de_dfilter_out_params dcmpro
;
243 struct de_dfilter_results dres
;
247 de_dfilter_init_objects(c
, &dcmpri
, &dcmpro
, &dres
);
251 dcmpro
.f
= unc_pixels
;
252 dcmpro
.expected_len
= pg
->expected_num_uncmpr_image_bytes
;
253 dcmpro
.len_known
= 1;
255 if(pg
->cmpr_type
==PCMPR_SCANLINE
) {
256 do_decompress_scanline_compression(c
, d
, pg
, &dcmpri
, &dcmpro
, &dres
);
258 else if(pg
->cmpr_type
==PCMPR_RLE
) {
259 dbuf_enable_wbuffer(unc_pixels
);
260 do_decompress_rle_compression(c
, &dcmpri
, &dcmpro
, &dres
);
262 else if(pg
->cmpr_type
==PCMPR_PACKBITS8
) {
263 dbuf_enable_wbuffer(unc_pixels
);
264 fmtutil_decompress_packbits_ex(c
, &dcmpri
, &dcmpro
, &dres
, NULL
);
266 else if(pg
->cmpr_type
==PCMPR_PACKBITS16
) {
267 struct de_packbits_params pbparams
;
269 de_zeromem(&pbparams
, sizeof(struct de_packbits_params
));
270 pbparams
.nbytes_per_unit
= 2;
271 dbuf_enable_wbuffer(unc_pixels
);
272 fmtutil_decompress_packbits_ex(c
, &dcmpri
, &dcmpro
, &dres
, &pbparams
);
275 de_err(c
, "Unsupported compression type: %u", pg
->cmpr_type_field
);
279 dbuf_flush(unc_pixels
);
282 de_err(c
, "%s", de_dfilter_get_errmsg(c
, &dres
));
286 if(dres
.bytes_consumed_valid
) {
287 n
= dres
.bytes_consumed
;
293 de_dbg(c
, "decompressed %"I64_FMT
" bytes to %"I64_FMT
" bytes", n
,
301 // A wrapper that decompresses the image if necessary, then calls
302 // do_generate_img_from_unc_pixels().
303 static void do_generate_image(deark
*c
, lctx
*d
, struct page_ctx
*pg
,
304 dbuf
*inf
, i64 pos
, i64 len
)
306 dbuf
*unc_pixels
= NULL
;
308 pg
->expected_num_uncmpr_image_bytes
= pg
->rowbytes
*pg
->h
;
310 if(pg
->cmpr_type
==PCMPR_NONE
) {
311 if(pg
->expected_num_uncmpr_image_bytes
> len
) {
312 de_err(c
, "Not enough data for image");
315 unc_pixels
= dbuf_open_input_subfile(inf
, pos
, len
);
321 if(pg
->bitmapversion
>= 3) {
323 cmpr_len
= dbuf_getu32x(inf
, pos
, d
->is_le
);
327 cmpr_len
= dbuf_getu16x(inf
, pos
, d
->is_le
);
329 de_dbg(c
, "cmpr len: %d", (int)cmpr_len
); // Note - We don't trust this field
331 // Account for the size of the cmpr_len field.
336 unc_pixels
= dbuf_create_membuf(c
, pg
->expected_num_uncmpr_image_bytes
, 1);
338 if(!de_decompress_image(c
, d
, pg
, inf
, pos
, len
, unc_pixels
)) {
343 do_generate_img_from_unc_pixels(c
, d
, pg
, unc_pixels
);
346 dbuf_close(unc_pixels
);
349 static const char *get_cmpr_type_name(enum palm_cmpr_type cmpr_type
)
354 case PCMPR_NONE
: name
= "none"; break;
355 case PCMPR_SCANLINE
: name
= "ScanLine"; break;
356 case PCMPR_RLE
: name
= "RLE"; break;
357 case PCMPR_PACKBITS8
: name
= "PackBits"; break;
358 case PCMPR_PACKBITS16
: name
= "PackBits16"; break;
359 default: name
= "?"; break;
364 static int read_BitmapType_colortable(deark
*c
, lctx
*d
, struct page_ctx
*pg
,
365 i64 pos1
, i64
*bytes_consumed
)
374 de_dbg(c
, "color table at %d", (int)pos1
);
377 num_entries_raw
= dbuf_getu16x(c
->infile
, pos1
, d
->is_le
);
378 num_entries
= num_entries_raw
;
379 // TODO: Documentation says "High bits (numEntries > 256) reserved."
380 // What exactly does that mean?
381 if(num_entries_raw
>256) {
382 // Files with "4096" entries have been observed, but they actually have 256
384 if(num_entries_raw
!=4096) {
385 de_warn(c
, "This image's color table type might not be supported correctly");
389 if(num_entries
==num_entries_raw
) {
390 de_dbg(c
, "number of entries: %d", (int)num_entries
);
393 de_dbg(c
, "number of entries: 0x%04x (assuming %d)", (unsigned int)num_entries_raw
,
400 // The only custom palettes I've seen in the wild have either 0 (!) or
402 // TODO: It might be better to treat all <=8 bit images as paletted:
403 // Start with a default palette, then overlay it with any custom
404 // palette entries that exist.
405 pg
->has_custom_pal
= 1;
408 *bytes_consumed
= 2+4*num_entries
;
410 for(k
=0; k
<num_entries
&& k
<256; k
++) {
411 idx
= (unsigned int)de_getbyte(pos
);
412 de_snprintf(tmps
, sizeof(tmps
), ",idx=%u", idx
);
413 // Not entirely sure if we should set entry #k, or entry #idx.
414 // idx is documented as "The index of this color in the color table."
415 pg
->custom_pal
[idx
] = dbuf_getRGB(c
->infile
, pos
+1, 0);
416 de_dbg_pal_entry2(c
, k
, pg
->custom_pal
[idx
], NULL
, tmps
, NULL
);
420 de_dbg_indent(c
, -1);
424 static void do_BitmapDirectInfoType(deark
*c
, lctx
*d
, struct page_ctx
*pg
,
430 de_dbg(c
, "BitmapDirectInfoType structure at %d", (int)pos
);
432 cbits
[0] = de_getbyte(pos
);
433 cbits
[1] = de_getbyte(pos
+1);
434 cbits
[2] = de_getbyte(pos
+2);
435 de_dbg(c
, "bits/component: %d,%d,%d", (int)cbits
[0], (int)cbits
[1], (int)cbits
[2]);
437 t
[0] = de_getbyte(pos
+4);
438 t
[1] = de_getbyte(pos
+5);
439 t
[2] = de_getbyte(pos
+6);
440 t
[3] = de_getbyte(pos
+7);
441 de_dbg(c
, "transparentColor: (%d,%d,%d,idx=%d)", (int)t
[1], (int)t
[2],
442 (int)t
[3], (int)t
[0]);
444 // The format of this field (RGBColorType) is not the same as that of
445 // the actual pixels, and I can't find documentation that says how the
447 // This appears to work (though it's quick & dirty, and only supports
450 ((((u32
)t
[1])&0xf8)<<8) |
451 ((((u32
)t
[2])&0xfc)<<3) |
452 ((((u32
)t
[3])&0xf8)>>3);
454 de_dbg_indent(c
, -1);
457 static void do_palm_BitmapType_internal(deark
*c
, lctx
*d
, i64 pos1
, i64 len
,
458 i64
*pnextbitmapoffset
)
464 u8 pixelformat
= 0; // V3 only
468 i64 nextbitmapoffs_in_bytes
= 0;
469 const char *cmpr_type_src_name
= "";
470 const char *bpp_src_name
= "";
471 struct page_ctx
*pg
= NULL
;
472 int saved_indent_level
;
473 de_ucstring
*flagsdescr
;
476 de_dbg_indent_save(c
, &saved_indent_level
);
477 pg
= de_malloc(c
, sizeof(struct page_ctx
));
479 de_dbg(c
, "BitmapType at %"I64_FMT
, pos1
);
481 de_dbg(c
, "bitmap header at %"I64_FMT
, pos1
);
484 // Look ahead to get the version
485 pg
->bitmapversion
= de_getbyte(pos1
+9);
486 de_dbg(c
, "bitmap version: %d", (int)pg
->bitmapversion
);
488 if(pg
->bitmapversion
>3) {
489 // Note that V3 allows the high bit of the version field to
490 // be set (to mean little-endian), but we don't support that.
491 de_err(c
, "Unsupported bitmap version: %d", (int)pg
->bitmapversion
);
495 pg
->w
= dbuf_geti16x(c
->infile
, pos1
, d
->is_le
);
496 pg
->h
= dbuf_geti16x(c
->infile
, pos1
+2, d
->is_le
);
497 de_dbg_dimensions(c
, pg
->w
, pg
->h
);
499 pg
->rowbytes
= dbuf_getu16x(c
->infile
, pos1
+4, d
->is_le
);
500 de_dbg(c
, "rowBytes: %d", (int)pg
->rowbytes
);
502 bitmapflags
= (u32
)dbuf_getu16x(c
->infile
, pos1
+6, d
->is_le
);
503 flagsdescr
= ucstring_create(c
);
504 if(bitmapflags
&PALMBMPFLAG_COMPRESSED
) ucstring_append_flags_item(flagsdescr
, "compressed");
505 if(bitmapflags
&PALMBMPFLAG_HASCOLORTABLE
) ucstring_append_flags_item(flagsdescr
, "hasColorTable");
506 if(bitmapflags
&PALMBMPFLAG_HASTRNS
) ucstring_append_flags_item(flagsdescr
, "hasTransparency");
507 if(bitmapflags
&PALMBMPFLAG_DIRECTCOLOR
) ucstring_append_flags_item(flagsdescr
, "directColor");
508 if(bitmapflags
==0) ucstring_append_flags_item(flagsdescr
, "none");
509 de_dbg(c
, "bitmap flags: 0x%04x (%s)", (unsigned int)bitmapflags
,
510 ucstring_getpsz(flagsdescr
));
511 ucstring_destroy(flagsdescr
);
512 if((bitmapflags
&PALMBMPFLAG_HASCOLORTABLE
) && d
->ignore_color_table_flag
) {
513 bitmapflags
-= PALMBMPFLAG_HASCOLORTABLE
;
515 if((bitmapflags
&PALMBMPFLAG_HASCOLORTABLE
) && pg
->bitmapversion
<1) {
516 de_warn(c
, "BitmapTypeV%d with a color table is not standard", (int)pg
->bitmapversion
);
519 if(pg
->bitmapversion
>=1) {
520 pixelsize_raw
= de_getbyte(pos1
+8);
521 de_dbg(c
, "pixelSize: %d", (int)pixelsize_raw
);
522 bpp_src_name
= "based on pixelSize field";
523 if(pg
->bitmapversion
<2 && pixelsize_raw
==8) {
524 de_warn(c
, "BitmapTypeV%d with pixelSize=%d is not standard",
525 (int)pg
->bitmapversion
, (int)pixelsize_raw
);
531 if(pixelsize_raw
==0) {
532 pg
->bitsperpixel
= 1;
533 bpp_src_name
= "default";
535 else pg
->bitsperpixel
= (i64
)pixelsize_raw
;
536 de_dbg(c
, "bits/pixel: %d (%s)", (int)pg
->bitsperpixel
, bpp_src_name
);
538 if(pg
->bitmapversion
==1 || pg
->bitmapversion
==2) {
539 x
= dbuf_getu16x(c
->infile
, pos1
+10, d
->is_le
);
540 nextbitmapoffs_in_bytes
= 4*x
;
542 de_snprintf(tmps
, sizeof(tmps
), "none");
545 de_snprintf(tmps
, sizeof(tmps
), "%d + 4"DE_CHAR_TIMES
"%d = %d", (int)pos1
, (int)x
, (int)(pos1
+nextbitmapoffs_in_bytes
));
547 de_dbg(c
, "nextDepthOffset: %d (%s)", (int)x
, tmps
);
550 if(pg
->bitmapversion
<3) {
554 headersize
= (i64
)de_getbyte(pos1
+10);
555 de_dbg(c
, "header size: %d", (int)headersize
);
558 if(pg
->bitmapversion
==3) {
559 pixelformat
= de_getbyte(pos1
+11);
560 de_dbg(c
, "pixel format: %d", (int)pixelformat
);
563 if(pg
->bitmapversion
==2 && (bitmapflags
&PALMBMPFLAG_HASTRNS
)) {
565 pg
->trns_value
= (u32
)de_getbyte(pos1
+12);
566 de_dbg(c
, "transparent color: %u", (unsigned int)pg
->trns_value
);
569 cmpr_type_src_name
= "flags";
570 if(bitmapflags
&PALMBMPFLAG_COMPRESSED
) {
571 if(pg
->bitmapversion
>=2) {
572 pg
->cmpr_type_field
= (unsigned int)de_getbyte(pos1
+13);
573 cmpr_type_src_name
= "flags + compression type field";
574 de_dbg(c
, "compression type field: 0x%02x", pg
->cmpr_type_field
);
575 switch(pg
->cmpr_type_field
) {
576 case CMPR_FIELD_SCANLINE
:
577 pg
->cmpr_type
= PCMPR_SCANLINE
;
580 pg
->cmpr_type
= PCMPR_RLE
;
582 case CMPR_FIELD_PACKBITS
:
583 cmpr_type_src_name
= "flags + compression type field + pixelSize";
584 if(pg
->bitsperpixel
==16) {
585 pg
->cmpr_type
= PCMPR_PACKBITS16
;
588 pg
->cmpr_type
= PCMPR_PACKBITS8
;
592 pg
->cmpr_type
= PCMPR_UNKNOWN
;
596 // V1 & V2 have no cmpr_type field, but can still be compressed.
597 pg
->cmpr_type
= PCMPR_SCANLINE
;
601 pg
->cmpr_type
= PCMPR_NONE
;
604 de_dbg(c
, "compression type: %s (based on %s)", get_cmpr_type_name(pg
->cmpr_type
), cmpr_type_src_name
);
606 if(pg
->bitmapversion
==3) {
608 densitycode
= dbuf_getu16x(c
->infile
, pos1
+14, d
->is_le
);
609 de_dbg(c
, "density: %d", (int)densitycode
);
610 // The density is an indication of the target screen density.
611 // It's tempting to interpret it as pixels per inch, and copy it to the
612 // output image -- though the documentation says it "should not be
613 // interpreted as representing pixels per inch".
616 if(pg
->bitmapversion
==3 && (bitmapflags
&PALMBMPFLAG_HASTRNS
) && headersize
>=20) {
617 // I'm assuming the flag affects this field. The spec is ambiguous.
619 pg
->trns_value
= (u32
)dbuf_getu32x(c
->infile
, pos1
+16, d
->is_le
);
620 de_dbg(c
, "transparent color: 0x%08x", (unsigned int)pg
->trns_value
);
623 if(pg
->bitmapversion
==3 && headersize
>=24) {
624 // Documented as the "number of bytes to the next bitmap", but it doesn't
625 // say where it is measured *from*. I'll assume it's the same logic as
626 // the "nextDepthOffset" field.
627 nextbitmapoffs_in_bytes
= dbuf_getu32x(c
->infile
, pos1
+20, d
->is_le
);
628 if(nextbitmapoffs_in_bytes
==0) {
629 de_snprintf(tmps
, sizeof(tmps
), "none");
632 de_snprintf(tmps
, sizeof(tmps
), "%u + %u = %u", (unsigned int)pos1
,
633 (unsigned int)nextbitmapoffs_in_bytes
, (unsigned int)(pos1
+nextbitmapoffs_in_bytes
));
635 de_dbg(c
, "nextBitmapOffset: %u (%s)", (unsigned int)nextbitmapoffs_in_bytes
, tmps
);
638 // Now that we've read the nextBitmapOffset fields, we can stop processing this
639 // image if it's invalid or unsupported.
641 needed_rowbytes
= (pg
->w
* pg
->bitsperpixel
+7)/8;
642 if(pg
->rowbytes
< needed_rowbytes
) {
643 de_err(c
, "Bad rowBytes value (is %d, need at least %d) or unsupported format version",
644 (int)pg
->rowbytes
, (int)needed_rowbytes
);
648 if(!de_good_image_dimensions(c
, pg
->w
, pg
->h
)) goto done
;
650 de_dbg_indent(c
, -1);
652 if(bitmapflags
&PALMBMPFLAG_DIRECTCOLOR
) {
654 if(pg
->bitmapversion
<2) {
655 de_warn(c
, "BitmapTypeV%d with RGB color is not standard", (int)pg
->bitmapversion
);
659 if(pg
->bitmapversion
>=3) {
661 (pixelformat
==0 && pg
->bitsperpixel
>8) ||
662 (pixelformat
==1 && pg
->bitsperpixel
!=16))
664 de_err(c
, "Unsupported pixelFormat (%d) for this image", (int)pixelformat
);
668 if(pixelformat
==1 && pg
->bitsperpixel
==16) {
669 // This should have already been set, by PALMBMPFLAG_DIRECTCOLOR,
670 // but that flag seems kind of obsolete in V3.
675 if(pg
->bitmapversion
==2 && pg
->bitsperpixel
==16 &&
676 !(bitmapflags
&PALMBMPFLAG_DIRECTCOLOR
) && !(bitmapflags
&PALMBMPFLAG_HASCOLORTABLE
))
678 // I have some images like this. I guess they are standard RGB565, with no
679 // BitmapDirectInfoType header.
681 de_warn(c
, "This type of image (16-bit, without directColor flag) might "
682 "not be decoded correctly");
685 if(pg
->bitsperpixel
!=1 && pg
->bitsperpixel
!=2 && pg
->bitsperpixel
!=4 &&
686 pg
->bitsperpixel
!=8 && pg
->bitsperpixel
!=16)
688 de_err(c
, "Unsupported bits/pixel: %d", (int)pg
->bitsperpixel
);
692 if((pg
->is_rgb
&& pg
->bitsperpixel
!=16) ||
693 (!pg
->is_rgb
&& pg
->bitsperpixel
>8))
695 de_err(c
, "This type of image is not supported");
701 if(pos
>= pos1
+len
) goto done
;
703 if(bitmapflags
&PALMBMPFLAG_HASCOLORTABLE
) {
704 if(!read_BitmapType_colortable(c
, d
, pg
, pos
, &bytes_consumed
)) goto done
;
705 pos
+= bytes_consumed
;
708 // If there is both a color table and a DirectInfo struct, I don't know which
709 // one appears first. But that shouldn't happen.
710 if((bitmapflags
&PALMBMPFLAG_DIRECTCOLOR
) && (pg
->bitmapversion
<=2)) {
711 do_BitmapDirectInfoType(c
, d
, pg
, pos
);
715 if(pos
>= pos1
+len
) {
716 de_err(c
, "Unexpected end of file");
720 if(nextbitmapoffs_in_bytes
>0) {
721 pg
->endpos
= pos1
+ nextbitmapoffs_in_bytes
;
724 pg
->endpos
= c
->infile
->len
;
727 de_dbg(c
, "image data at %d", (int)pos
);
729 do_generate_image(c
, d
, pg
, c
->infile
, pos
, pg
->endpos
-pos
);
730 de_dbg_indent(c
, -1);
733 *pnextbitmapoffset
= nextbitmapoffs_in_bytes
;
734 de_dbg_indent_restore(c
, saved_indent_level
);
740 static void do_palm_BitmapType(deark
*c
, lctx
*d
, i64 pos1
, i64 len
)
742 i64 nextbitmapoffs
= 0;
746 if(de_getbyte(pos
+8) == 0xff) {
747 de_dbg(c
, "[skipping dummy bitmap header at %d]", (int)pos
);
751 if(pos
> pos1
+len
-16) {
752 de_err(c
, "Bitmap exceeds its bounds");
755 do_palm_BitmapType_internal(c
, d
, pos
, pos1
+len
-pos
, &nextbitmapoffs
);
756 if(nextbitmapoffs
<=0) break;
757 pos
+= nextbitmapoffs
;
761 static void de_run_palmbitmap(deark
*c
, de_module_params
*mparams
)
765 d
= de_malloc(c
, sizeof(lctx
));
766 if(de_get_ext_option(c
, "palm:le")) {
769 if(de_get_ext_option(c
, "palm:nocolortable")) {
770 // Enables a hack, for files that apparently set the hasColorTable flag
772 d
->ignore_color_table_flag
= 1;
774 do_palm_BitmapType(c
, d
, 0, c
->infile
->len
);
778 static int de_identify_palmbitmap(deark
*c
)
780 if(de_input_file_has_ext(c
, "palm")) {
782 x
= de_identify_palmbitmap_internal(c
, c
->infile
, 0, c
->infile
->len
);
788 static void de_help_palmbitmap(deark
*c
)
790 de_msg(c
, "-opt palm:le : Assume little-endian byte order");
791 de_msg(c
, "-opt palm:nocolortable : Ignore the hasColorTable flag, if set");
794 void de_module_palmbitmap(deark
*c
, struct deark_module_info
*mi
)
796 mi
->id
= "palmbitmap";
797 mi
->desc
= "Palm BitmapType";
798 mi
->run_fn
= de_run_palmbitmap
;
799 mi
->identify_fn
= de_identify_palmbitmap
;
800 mi
->help_fn
= de_help_palmbitmap
;