bmp: Rewrote the RLE decompressor
[deark.git] / modules / sunras.c
blobb90ddd5ce4183b3e9a14c50651f6d567338aec20
1 // This file is part of Deark.
2 // Copyright (C) 2016 Jason Summers
3 // See the file COPYING for terms of use.
5 // Sun Raster image format
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_sunras);
11 struct color32desc_type {
12 u8 channel_shift[4];
13 u8 has_alpha; // 0=no, 1=yes, 2=autodetect
14 const char *name;
17 typedef struct localctx_struct {
18 i64 npwidth, height;
19 i64 pdwidth;
20 i64 depth;
22 #define RT_OLD 0
23 #define RT_STANDARD 1
24 #define RT_BYTE_ENCODED 2
25 #define RT_FORMAT_RGB 3
26 #define RT_FORMAT_TIFF 4
27 #define RT_FORMAT_IFF 5
28 i64 imgtype;
29 int is_compressed;
30 int is_rgb_order;
31 int user_set_fmt32;
33 struct color32desc_type color32desc;
35 i64 imglen;
37 #define RMT_NONE 0
38 #define RMT_EQUAL_RGB 1
39 #define RMT_RAW 2
40 i64 maptype;
42 i64 maplen;
44 i64 rowspan;
45 i64 unc_pixels_size;
46 int is_paletted;
47 int is_grayscale;
49 u32 pal[256];
51 i64 src_bypp;
52 unsigned int getrgbflags;
53 } lctx;
55 static void do_read_palette(deark *c, lctx *d, i64 pos)
57 i64 num_entries;
58 i64 num_entries_to_read;
59 i64 k;
60 u8 r, g, b;
62 num_entries = d->maplen/3;
63 num_entries_to_read = num_entries;
64 if(num_entries_to_read>256) num_entries_to_read = 256;
66 for(k=0; k<num_entries_to_read; k++) {
67 r = de_getbyte(pos + k);
68 g = de_getbyte(pos+num_entries + k);
69 b = de_getbyte(pos+num_entries*2 + k);
70 d->pal[k] = DE_MAKE_RGB(r, g, b);
71 de_dbg_pal_entry(c, k, d->pal[k]);
75 static void decode_image_24_32(deark *c, lctx *d, dbuf *unc_pixels, de_bitmap *img)
77 u32 clr;
78 i64 i, j;
80 for(j=0; j<d->height; j++) {
81 for(i=0; i<d->pdwidth; i++) {
82 if(d->depth==24) {
83 clr = dbuf_getRGB(unc_pixels, d->rowspan*j+i*d->src_bypp, d->getrgbflags);
84 de_bitmap_setpixel_rgb(img, i, j, clr);
86 else if(d->depth==32) {
87 u8 pixbuf[4];
88 dbuf_read(unc_pixels, pixbuf, d->rowspan*j+i*d->src_bypp, 4);
89 clr =
90 ((unsigned int)pixbuf[0] << d->color32desc.channel_shift[0]) |
91 ((unsigned int)pixbuf[1] << d->color32desc.channel_shift[1]) |
92 ((unsigned int)pixbuf[2] << d->color32desc.channel_shift[2]) |
93 ((unsigned int)pixbuf[3] << d->color32desc.channel_shift[3]);
94 de_bitmap_setpixel_rgba(img, i, j, clr);
100 static void do_image(deark *c, lctx *d, dbuf *unc_pixels)
102 de_bitmap *img = NULL;
103 i64 dst_bypp;
105 if(d->depth!=1 && d->depth!=4 && d->depth!=8 && d->depth!=24 && d->depth!=32) {
106 de_err(c, "Bit depth %d not supported", (int)d->depth);
107 goto done;
109 if(d->depth==32 && !d->user_set_fmt32) {
110 // Some apps think the extra channel comes first (e.g. xBGR); others
111 // think it comes last (BGRx).
112 // Some apps think the extra channel is for alpha; others think it is
113 // unused.
114 // Some apps think the color channels are always in BGR order; others
115 // think the order is RGB for RT_FORMAT_RGB format.
117 // By default we use ARGB for RT_FORMAT_RGB, and ABGR otherwise, with
118 // alpha autodetected (alpha channel is ignored if all values are 0).
120 de_warn(c, "32-bit Sun Raster files are not portable. You may have to use "
121 "\"-opt sunras:fmt32=...\".");
123 d->color32desc.channel_shift[0] = 24; // A or x
124 d->color32desc.channel_shift[2] = 8; // G
125 if(d->is_rgb_order) { // xrgb or argb
126 d->color32desc.channel_shift[1] = 16; // R
127 d->color32desc.channel_shift[3] = 0; // B
129 else { // xbgr or abgr
130 d->color32desc.channel_shift[1] = 0; // B
131 d->color32desc.channel_shift[3] = 16; // R
134 d->color32desc.has_alpha = 2;
137 if(!de_good_image_dimensions(c, d->npwidth, d->height)) goto done;
139 d->src_bypp = d->depth/8;
141 if(d->is_paletted) {
142 dst_bypp = 3;
144 else if(d->is_grayscale) {
145 dst_bypp = 1;
147 else if(d->depth==32) {
148 if(d->color32desc.has_alpha==0) {
149 dst_bypp = 3;
151 else {
152 dst_bypp = 4;
155 else {
156 dst_bypp = 3;
159 if(d->is_rgb_order) {
160 d->getrgbflags = 0;
162 else {
163 d->getrgbflags = DE_GETRGBFLAG_BGR;
166 img = de_bitmap_create2(c, d->npwidth, d->pdwidth, d->height, (int)dst_bypp);
168 if(d->is_paletted || d->is_grayscale) {
169 de_convert_image_paletted(unc_pixels, 0, d->depth, d->rowspan, d->pal, img, 0);
171 else {
172 decode_image_24_32(c, d, unc_pixels, img);
175 if(d->depth==32 && d->color32desc.has_alpha==2) { // autodetect alpha
176 de_bitmap_optimize_alpha(img, 0x1);
179 de_bitmap_write_to_file(img, NULL, 0);
181 done:
182 de_bitmap_destroy(img);
185 static const char *get_image_type_name(i64 t)
187 const char *name;
189 switch(t) {
190 case RT_OLD: name="old"; break;
191 case RT_STANDARD: name="standard"; break;
192 case RT_BYTE_ENCODED: name="RLE"; break;
193 case RT_FORMAT_RGB: name="RGB"; break;
194 case RT_FORMAT_TIFF: name="TIFF"; break;
195 case RT_FORMAT_IFF: name="IFF"; break;
196 case 0xffff: name="experimental"; break;
197 default: name="?";
199 return name;
202 static const char *get_map_type_name(i64 t)
204 const char *name;
206 switch(t) {
207 case RMT_NONE: name="NONE"; break;
208 case RMT_EQUAL_RGB: name="EQUAL_RGB"; break;
209 case RMT_RAW: name="RAW"; break;
210 default: name="?";
212 return name;
215 static void read_header(deark *c, lctx *d, i64 pos)
217 de_dbg(c, "header at %d", (int)pos);
218 de_dbg_indent(c, 1);
220 d->npwidth = de_getu32be(pos+4);
221 d->height = de_getu32be(pos+8);
222 de_dbg_dimensions(c, d->npwidth, d->height);
224 d->depth = de_getu32be(pos+12);
225 de_dbg(c, "depth: %d", (int)d->depth);
227 d->imglen = de_getu32be(pos+16);
228 d->imgtype = de_getu32be(pos+20);
229 de_dbg(c, "image type=%d (%s), len=%d", (int)d->imgtype,
230 get_image_type_name(d->imgtype), (int)d->imglen);
231 if(d->imgtype==RT_BYTE_ENCODED) {
232 d->is_compressed = 1;
234 if(d->imgtype==RT_FORMAT_RGB) {
235 d->is_rgb_order = 1;
238 d->maptype = de_getu32be(pos+24);
239 d->maplen = de_getu32be(pos+28);
240 de_dbg(c, "map type=%d (%s), len=%d", (int)d->maptype,
241 get_map_type_name(d->maptype), (int)d->maplen);
243 de_dbg_indent(c, -1);
246 static void do_uncompress_image(deark *c, lctx *d, i64 pos1, i64 len, dbuf *unc_pixels)
248 i64 pos = pos1;
250 while(1) {
251 u8 b0, b1, b2;
253 // Stop if we reach the end of the input file.
254 if(pos >= c->infile->len) break;
256 b0 = de_getbyte(pos++);
257 if(b0==0x80) {
258 b1 = de_getbyte(pos++);
259 if(b1==0x00) { // An escaped 0x80 byte
260 dbuf_writebyte(unc_pixels, 0x80);
262 else { // A compressed run
263 b2 = de_getbyte(pos++);
264 dbuf_write_run(unc_pixels, b2, (i64)b1+1);
267 else { // An uncompressed byte
268 dbuf_writebyte(unc_pixels, b0);
273 static void handle_options(deark *c, lctx *d)
275 const char *fmt32;
276 // Table of user-configurable color "descriptors" for 32-bit images.
277 static const struct color32desc_type color32desc_arr[] = {
278 { { 0, 8, 16, 24 }, 0, "bgrx" },
279 { { 0, 8, 16, 24 }, 1, "bgra" },
280 { {16, 8, 0, 24 }, 0, "rgbx" },
281 { {16, 8, 0, 24 }, 1, "rgba" },
282 { {24, 0, 8, 16 }, 0, "xbgr" },
283 { {24, 0, 8, 16 }, 1, "abgr" },
284 { {24, 16, 8, 0 }, 0, "xrgb" },
285 { {24, 16, 8, 0 }, 1, "argb" }
288 fmt32 = de_get_ext_option(c, "sunras:fmt32");
289 if(fmt32) {
290 size_t k;
291 for(k=0; k<DE_ARRAYCOUNT(color32desc_arr); k++) {
292 if(!de_strcmp(fmt32, color32desc_arr[k].name)) {
293 d->color32desc = color32desc_arr[k]; // struct copy
294 d->user_set_fmt32 = 1;
295 break;
301 static void de_run_sunras(deark *c, de_module_params *mparams)
303 lctx *d = NULL;
304 dbuf *unc_pixels = NULL;
305 i64 pos;
306 i64 bits_per_row;
307 int saved_indent_level;
308 de_dbg_indent_save(c, &saved_indent_level);
310 d = de_malloc(c, sizeof(lctx));
311 handle_options(c, d);
313 pos = 0;
314 read_header(c, d, pos);
315 pos += 32;
317 if(pos >= c->infile->len) goto done;
319 if(d->maplen > 0)
320 de_dbg(c, "colormap at %d", (int)pos);
322 de_dbg_indent(c, 1);
324 if(d->maptype==RMT_EQUAL_RGB) {
325 if(d->depth<=8) {
326 d->is_paletted = 1;
327 do_read_palette(c, d, pos);
329 else {
330 de_err(c, "This type of image is not supported");
331 goto done;
334 else if(d->maptype==RMT_NONE) {
335 if(d->depth<=8) {
336 d->is_grayscale = 1;
337 de_make_grayscale_palette(d->pal, ((i64)1)<<d->depth, d->depth==1 ? 1 : 0);
340 else {
341 // TODO: Support RMT_RAW
342 de_err(c, "Colormap type (%d) is not supported", (int)d->maptype);
343 goto done;
345 pos += d->maplen;
346 de_dbg_indent(c, -1);
348 if(pos >= c->infile->len) goto done;
349 de_dbg(c, "image data at %d", (int)pos);
350 de_dbg_indent(c, 1);
352 bits_per_row = de_pad_to_n(d->npwidth * d->depth, 16);
353 d->rowspan = bits_per_row / 8;
354 d->pdwidth = bits_per_row / d->depth;
355 d->unc_pixels_size = d->rowspan * d->height;
357 if(d->imgtype>5) {
358 de_err(c, "This type of image (%d) is not supported", (int)d->imgtype);
359 goto done;
362 if((d->imgtype==RT_STANDARD || d->imgtype==RT_FORMAT_RGB) && d->imglen!=d->unc_pixels_size) {
363 de_warn(c, "Inconsistent image length: reported=%d, calculated=%d",
364 (int)d->imglen, (int)d->unc_pixels_size);
367 if(d->is_compressed) {
368 unc_pixels = dbuf_create_membuf(c, d->unc_pixels_size, 0x1);
369 dbuf_enable_wbuffer(unc_pixels);
370 do_uncompress_image(c, d, pos, c->infile->len - pos, unc_pixels);
371 dbuf_flush(unc_pixels);
373 else {
374 unc_pixels = dbuf_open_input_subfile(c->infile, pos, c->infile->len - pos);
377 do_image(c, d, unc_pixels);
378 de_dbg_indent(c, -1);
380 done:
381 dbuf_close(unc_pixels);
382 de_free(c, d);
383 de_dbg_indent_restore(c, saved_indent_level);
386 static int de_identify_sunras(deark *c)
388 if(!dbuf_memcmp(c->infile, 0, "\x59\xa6\x6a\x95", 4))
389 return 100;
390 return 0;
393 static void de_help_sunras(deark *c)
395 de_msg(c, "-opt sunras:fmt32=<"
396 "xbgr|abgr|xrgb|argb|"
397 "bgrx|bgra|rgbx|rgba> : The interpretation of a 32-bit pixel");
400 void de_module_sunras(deark *c, struct deark_module_info *mi)
402 mi->id = "sunras";
403 mi->desc = "Sun Raster";
404 mi->run_fn = de_run_sunras;
405 mi->identify_fn = de_identify_sunras;
406 mi->help_fn = de_help_sunras;