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 static void do_read_palette(deark
*c
, lctx
*d
, i64 pos
)
55 i64 num_entries_to_read
;
59 num_entries
= d
->maplen
/3;
60 num_entries_to_read
= num_entries
;
61 if(num_entries_to_read
>256) num_entries_to_read
= 256;
63 for(k
=0; k
<num_entries_to_read
; k
++) {
64 r
= de_getbyte(pos
+ k
);
65 g
= de_getbyte(pos
+num_entries
+ k
);
66 b
= de_getbyte(pos
+num_entries
*2 + k
);
67 d
->pal
[k
] = DE_MAKE_RGB(r
, g
, b
);
68 de_dbg_pal_entry(c
, k
, d
->pal
[k
]);
72 static void do_image(deark
*c
, lctx
*d
, dbuf
*unc_pixels
)
74 de_bitmap
*img
= NULL
;
78 i64 src_bypp
, dst_bypp
;
79 unsigned int getrgbflags
;
81 if(d
->depth
!=1 && d
->depth
!=4 && d
->depth
!=8 && d
->depth
!=24 && d
->depth
!=32) {
82 de_err(c
, "Bit depth %d not supported", (int)d
->depth
);
85 if(d
->depth
==32 && !d
->user_set_fmt32
) {
86 // Some apps think the extra channel comes first (e.g. xBGR); others
87 // think it comes last (BGRx).
88 // Some apps think the extra channel is for alpha; others think it is
90 // Some apps think the color channels are always in BGR order; others
91 // think the order is RGB for RT_FORMAT_RGB format.
93 // By default we use ARGB for RT_FORMAT_RGB, and ABGR otherwise, with
94 // alpha autodetected (alpha channel is ignored if all values are 0).
96 de_warn(c
, "32-bit Sun Raster files are not portable. You may have to use "
97 "\"-opt sunras:fmt32=...\".");
99 d
->color32desc
.channel_shift
[0] = 24; // A or x
100 d
->color32desc
.channel_shift
[2] = 8; // G
101 if(d
->is_rgb_order
) { // xrgb or argb
102 d
->color32desc
.channel_shift
[1] = 16; // R
103 d
->color32desc
.channel_shift
[3] = 0; // B
105 else { // xbgr or abgr
106 d
->color32desc
.channel_shift
[1] = 0; // B
107 d
->color32desc
.channel_shift
[3] = 16; // R
110 d
->color32desc
.has_alpha
= 2;
113 if(!de_good_image_dimensions(c
, d
->npwidth
, d
->height
)) goto done
;
115 src_bypp
= d
->depth
/8;
120 else if(d
->is_grayscale
) {
123 else if(d
->depth
==32) {
124 if(d
->color32desc
.has_alpha
==0) {
135 if(d
->is_rgb_order
) {
139 getrgbflags
= DE_GETRGBFLAG_BGR
;
142 img
= de_bitmap_create2(c
, d
->npwidth
, d
->pdwidth
, d
->height
, (int)dst_bypp
);
144 for(j
=0; j
<d
->height
; j
++) {
145 for(i
=0; i
<d
->pdwidth
; i
++) {
146 if(d
->is_paletted
|| d
->is_grayscale
) {
147 b
= de_get_bits_symbol(unc_pixels
, d
->depth
, d
->rowspan
*j
, i
);
148 clr
= d
->pal
[(unsigned int)b
];
149 de_bitmap_setpixel_rgb(img
, i
, j
, clr
);
151 else if(d
->depth
==24) {
152 clr
= dbuf_getRGB(unc_pixels
, d
->rowspan
*j
+i
*src_bypp
, getrgbflags
);
153 de_bitmap_setpixel_rgb(img
, i
, j
, clr
);
155 else if(d
->depth
==32) {
157 dbuf_read(unc_pixels
, pixbuf
, d
->rowspan
*j
+i
*src_bypp
, 4);
159 ((unsigned int)pixbuf
[0] << d
->color32desc
.channel_shift
[0]) |
160 ((unsigned int)pixbuf
[1] << d
->color32desc
.channel_shift
[1]) |
161 ((unsigned int)pixbuf
[2] << d
->color32desc
.channel_shift
[2]) |
162 ((unsigned int)pixbuf
[3] << d
->color32desc
.channel_shift
[3]);
163 de_bitmap_setpixel_rgba(img
, i
, j
, clr
);
168 if(d
->depth
==32 && d
->color32desc
.has_alpha
==2) { // autodetect alpha
169 de_bitmap_optimize_alpha(img
, 0x1);
172 de_bitmap_write_to_file(img
, NULL
, 0);
175 de_bitmap_destroy(img
);
178 static const char *get_image_type_name(i64 t
)
183 case RT_OLD
: name
="old"; break;
184 case RT_STANDARD
: name
="standard"; break;
185 case RT_BYTE_ENCODED
: name
="RLE"; break;
186 case RT_FORMAT_RGB
: name
="RGB"; break;
187 case RT_FORMAT_TIFF
: name
="TIFF"; break;
188 case RT_FORMAT_IFF
: name
="IFF"; break;
189 case 0xffff: name
="experimental"; break;
195 static const char *get_map_type_name(i64 t
)
200 case RMT_NONE
: name
="NONE"; break;
201 case RMT_EQUAL_RGB
: name
="EQUAL_RGB"; break;
202 case RMT_RAW
: name
="RAW"; break;
208 static void read_header(deark
*c
, lctx
*d
, i64 pos
)
210 de_dbg(c
, "header at %d", (int)pos
);
213 d
->npwidth
= de_getu32be(pos
+4);
214 d
->height
= de_getu32be(pos
+8);
215 de_dbg_dimensions(c
, d
->npwidth
, d
->height
);
217 d
->depth
= de_getu32be(pos
+12);
218 de_dbg(c
, "depth: %d", (int)d
->depth
);
220 d
->imglen
= de_getu32be(pos
+16);
221 d
->imgtype
= de_getu32be(pos
+20);
222 de_dbg(c
, "image type=%d (%s), len=%d", (int)d
->imgtype
,
223 get_image_type_name(d
->imgtype
), (int)d
->imglen
);
224 if(d
->imgtype
==RT_BYTE_ENCODED
) {
225 d
->is_compressed
= 1;
227 if(d
->imgtype
==RT_FORMAT_RGB
) {
231 d
->maptype
= de_getu32be(pos
+24);
232 d
->maplen
= de_getu32be(pos
+28);
233 de_dbg(c
, "map type=%d (%s), len=%d", (int)d
->maptype
,
234 get_map_type_name(d
->maptype
), (int)d
->maplen
);
236 de_dbg_indent(c
, -1);
239 static void do_uncompress_image(deark
*c
, lctx
*d
, i64 pos1
, i64 len
, dbuf
*unc_pixels
)
246 // Stop if we reach the end of the input file.
247 if(pos
>= c
->infile
->len
) break;
249 b0
= de_getbyte(pos
++);
251 b1
= de_getbyte(pos
++);
252 if(b1
==0x00) { // An escaped 0x80 byte
253 dbuf_writebyte(unc_pixels
, 0x80);
255 else { // A compressed run
256 b2
= de_getbyte(pos
++);
257 dbuf_write_run(unc_pixels
, b2
, (i64
)b1
+1);
260 else { // An uncompressed byte
261 dbuf_writebyte(unc_pixels
, b0
);
266 static void handle_options(deark
*c
, lctx
*d
)
269 // Table of user-configurable color "descriptors" for 32-bit images.
270 static const struct color32desc_type color32desc_arr
[] = {
271 { { 0, 8, 16, 24 }, 0, "bgrx" },
272 { { 0, 8, 16, 24 }, 1, "bgra" },
273 { {16, 8, 0, 24 }, 0, "rgbx" },
274 { {16, 8, 0, 24 }, 1, "rgba" },
275 { {24, 0, 8, 16 }, 0, "xbgr" },
276 { {24, 0, 8, 16 }, 1, "abgr" },
277 { {24, 16, 8, 0 }, 0, "xrgb" },
278 { {24, 16, 8, 0 }, 1, "argb" }
281 fmt32
= de_get_ext_option(c
, "sunras:fmt32");
284 for(k
=0; k
<DE_ARRAYCOUNT(color32desc_arr
); k
++) {
285 if(!de_strcmp(fmt32
, color32desc_arr
[k
].name
)) {
286 d
->color32desc
= color32desc_arr
[k
]; // struct copy
287 d
->user_set_fmt32
= 1;
294 static void de_run_sunras(deark
*c
, de_module_params
*mparams
)
297 dbuf
*unc_pixels
= NULL
;
300 int saved_indent_level
;
301 de_dbg_indent_save(c
, &saved_indent_level
);
303 d
= de_malloc(c
, sizeof(lctx
));
304 handle_options(c
, d
);
307 read_header(c
, d
, pos
);
310 if(pos
>= c
->infile
->len
) goto done
;
313 de_dbg(c
, "colormap at %d", (int)pos
);
317 if(d
->maptype
==RMT_EQUAL_RGB
) {
320 do_read_palette(c
, d
, pos
);
323 de_err(c
, "This type of image is not supported");
327 else if(d
->maptype
==RMT_NONE
) {
330 de_make_grayscale_palette(d
->pal
, ((i64
)1)<<d
->depth
, d
->depth
==1 ? 1 : 0);
334 // TODO: Support RMT_RAW
335 de_err(c
, "Colormap type (%d) is not supported", (int)d
->maptype
);
339 de_dbg_indent(c
, -1);
341 if(pos
>= c
->infile
->len
) goto done
;
342 de_dbg(c
, "image data at %d", (int)pos
);
345 bits_per_row
= de_pad_to_n(d
->npwidth
* d
->depth
, 16);
346 d
->rowspan
= bits_per_row
/ 8;
347 d
->pdwidth
= bits_per_row
/ d
->depth
;
348 d
->unc_pixels_size
= d
->rowspan
* d
->height
;
351 de_err(c
, "This type of image (%d) is not supported", (int)d
->imgtype
);
355 if((d
->imgtype
==RT_STANDARD
|| d
->imgtype
==RT_FORMAT_RGB
) && d
->imglen
!=d
->unc_pixels_size
) {
356 de_warn(c
, "Inconsistent image length: reported=%d, calculated=%d",
357 (int)d
->imglen
, (int)d
->unc_pixels_size
);
360 if(d
->is_compressed
) {
361 unc_pixels
= dbuf_create_membuf(c
, d
->unc_pixels_size
, 0x1);
362 do_uncompress_image(c
, d
, pos
, c
->infile
->len
- pos
, unc_pixels
);
365 unc_pixels
= dbuf_open_input_subfile(c
->infile
, pos
, c
->infile
->len
- pos
);
368 do_image(c
, d
, unc_pixels
);
369 de_dbg_indent(c
, -1);
372 dbuf_close(unc_pixels
);
374 de_dbg_indent_restore(c
, saved_indent_level
);
377 static int de_identify_sunras(deark
*c
)
379 if(!dbuf_memcmp(c
->infile
, 0, "\x59\xa6\x6a\x95", 4))
384 static void de_help_sunras(deark
*c
)
386 de_msg(c
, "-opt sunras:fmt32=<"
387 "xbgr|abgr|xrgb|argb|"
388 "bgrx|bgra|rgbx|rgba> : The interpretation of a 32-bit pixel");
391 void de_module_sunras(deark
*c
, struct deark_module_info
*mi
)
394 mi
->desc
= "Sun Raster";
395 mi
->run_fn
= de_run_sunras
;
396 mi
->identify_fn
= de_identify_sunras
;
397 mi
->help_fn
= de_help_sunras
;