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
{
13 u8 has_alpha
; // 0=no, 1=yes, 2=autodetect
17 typedef struct localctx_struct
{
24 #define RT_BYTE_ENCODED 2
25 #define RT_FORMAT_RGB 3
26 #define RT_FORMAT_TIFF 4
27 #define RT_FORMAT_IFF 5
33 struct color32desc_type color32desc
;
38 #define RMT_EQUAL_RGB 1
52 unsigned int getrgbflags
;
55 static void do_read_palette(deark
*c
, lctx
*d
, i64 pos
)
58 i64 num_entries_to_read
;
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
)
80 for(j
=0; j
<d
->height
; j
++) {
81 for(i
=0; i
<d
->pdwidth
; i
++) {
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) {
88 dbuf_read(unc_pixels
, pixbuf
, d
->rowspan
*j
+i
*d
->src_bypp
, 4);
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
;
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
);
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
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;
144 else if(d
->is_grayscale
) {
147 else if(d
->depth
==32) {
148 if(d
->color32desc
.has_alpha
==0) {
159 if(d
->is_rgb_order
) {
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);
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);
182 de_bitmap_destroy(img
);
185 static const char *get_image_type_name(i64 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;
202 static const char *get_map_type_name(i64 t
)
207 case RMT_NONE
: name
="NONE"; break;
208 case RMT_EQUAL_RGB
: name
="EQUAL_RGB"; break;
209 case RMT_RAW
: name
="RAW"; break;
215 static void read_header(deark
*c
, lctx
*d
, i64 pos
)
217 de_dbg(c
, "header at %d", (int)pos
);
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
) {
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
)
253 // Stop if we reach the end of the input file.
254 if(pos
>= c
->infile
->len
) break;
256 b0
= de_getbyte(pos
++);
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
)
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");
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;
301 static void de_run_sunras(deark
*c
, de_module_params
*mparams
)
304 dbuf
*unc_pixels
= NULL
;
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
);
314 read_header(c
, d
, pos
);
317 if(pos
>= c
->infile
->len
) goto done
;
320 de_dbg(c
, "colormap at %d", (int)pos
);
324 if(d
->maptype
==RMT_EQUAL_RGB
) {
327 do_read_palette(c
, d
, pos
);
330 de_err(c
, "This type of image is not supported");
334 else if(d
->maptype
==RMT_NONE
) {
337 de_make_grayscale_palette(d
->pal
, ((i64
)1)<<d
->depth
, d
->depth
==1 ? 1 : 0);
341 // TODO: Support RMT_RAW
342 de_err(c
, "Colormap type (%d) is not supported", (int)d
->maptype
);
346 de_dbg_indent(c
, -1);
348 if(pos
>= c
->infile
->len
) goto done
;
349 de_dbg(c
, "image data at %d", (int)pos
);
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
;
358 de_err(c
, "This type of image (%d) is not supported", (int)d
->imgtype
);
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
);
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);
381 dbuf_close(unc_pixels
);
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))
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
)
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
;