1 // This file is part of Deark.
2 // Copyright (C) 2020 Jason Summers
3 // See the file COPYING for terms of use.
5 // NIE - One of the "Naive Image Formats" used with the Wuffs project.
7 #include <deark-config.h>
8 #include <deark-private.h>
9 DE_DECLARE_MODULE(de_module_nie
);
11 typedef struct localctx_struct
{
12 #define SIG_NIA 0x6ec3af41U
13 #define SIG_NIE 0x6ec3af45U
14 #define SIG_NII 0x6ec3af49U
18 int premultiplied_alpha
;
22 int found_last_frame_flag
;
25 static u8
unpremultiply_alpha(u8 cval
, u8 a
)
36 return (u8
)(0.5 + (double)cval
/ ((double)a
/255.0));
39 // 8-byte "NII payload"
40 static void read_NIIpayload(deark
*c
, lctx
*d
, i64 pos
, int printCCD
)
45 ccd_code
= dbuf_getu64le(c
->infile
, pos
);
47 d
->found_last_frame_flag
= 1;
50 ccd
= (i64
)(ccd_code
>>2);
51 de_dbg(c
, "CCD: %"I64_FMT
" (%f seconds)", ccd
,
52 (double)ccd
/705600000.0);
56 // Decode the header, after the 4-byte signature.
57 // That's 12 bytes for NIE, 20 bytes for NII/NIA.
58 // On parse error, prints an error and returns 0.
59 // If the image has invalid attributes, sets d->bad_image_flag (only NIE cares
61 static int do_header(deark
*c
, lctx
*d
, i64 pos
)
65 b
= de_getbyte_p(&pos
);
67 de_err(c
, "Unknown %s version", d
->fmtname
);
75 b
= de_getbyte_p(&pos
);
80 d
->bad_image_flag
= 1;
82 de_dbg(c
, "sample order: %sA", (d
->is_bgra
?"BGR":"RGB"));
84 b
= de_getbyte_p(&pos
);
86 d
->premultiplied_alpha
= 1;
89 d
->bad_image_flag
= 1;
91 de_dbg(c
, "premultiplied alpha: %d", d
->premultiplied_alpha
);
93 b
= de_getbyte_p(&pos
);
95 d
->bytes_per_pixel
= 8;
98 d
->bytes_per_pixel
= 4;
101 d
->bad_image_flag
= 1;
103 de_dbg(c
, "bytes/pixel: %d", (int)d
->bytes_per_pixel
);
106 d
->width
= de_getu32le_p(&pos
);
107 d
->height
= de_getu32le_p(&pos
);
108 de_dbg_dimensions(c
, d
->width
, d
->height
);
110 if(d
->sig
==SIG_NIE
) return 1;
112 read_NIIpayload(c
, d
, pos
, 0);
116 static void do_decode_nie(deark
*c
, lctx
*d
)
121 i64 sample_offset
[4]; // R, G, B, A
122 de_bitmap
*img
= NULL
;
124 pos
+= 4; // signature, already read
126 if(!do_header(c
, d
, pos
)) goto done
;
127 if(d
->bad_image_flag
) {
128 de_err(c
, "Bad or unsupported NIE format");
133 if(!de_good_image_dimensions(c
, d
->width
, d
->height
)) {
137 // Make a sample-to-byte-offset map.
139 sample_offset
[k
] = k
; // Defaults
142 sample_offset
[0] = 2; // R sample is byte 2
143 sample_offset
[2] = 0; // B sample is byte 0
145 if(d
->bytes_per_pixel
==8) { // If 16 bits/sample, look only at the high byte
147 sample_offset
[k
] = sample_offset
[k
]*2 + 1;
151 img
= de_bitmap_create(c
, d
->width
, d
->height
, 4);
153 for(j
=0; j
<d
->height
; j
++) {
154 for(i
=0; i
<d
->width
; i
++) {
158 de_read(pbuf
, pos
, d
->bytes_per_pixel
);
159 pos
+= d
->bytes_per_pixel
;
162 s
[k
] = pbuf
[sample_offset
[k
]];
165 if(d
->premultiplied_alpha
&& (s
[3]!=0xff)) {
167 s
[k
] = unpremultiply_alpha(s
[k
], s
[3]);
171 de_bitmap_setpixel_rgba(img
, i
, j
, DE_MAKE_RGBA(s
[0],s
[1],s
[2],s
[3]));
175 de_bitmap_write_to_file(img
, NULL
, DE_CREATEFLAG_OPT_IMAGE
);
178 de_bitmap_destroy(img
);
181 static void do_decode_nii(deark
*c
, lctx
*d
)
185 if(!do_header(c
, d
, pos
)) goto done
;
189 if(d
->found_last_frame_flag
) break;
190 de_dbg(c
, "frame info at %"I64_FMT
, pos
);
192 read_NIIpayload(c
, d
, pos
, 1);
194 de_dbg_indent(c
, -1);
201 static void do_decode_nia(deark
*c
, lctx
*d
)
204 i64 frame_size
, frame_size_padded
;
206 if(!do_header(c
, d
, pos
)) goto done
;
209 frame_size
= 16 + d
->width
*d
->height
*d
->bytes_per_pixel
;
210 de_dbg(c
, "frame size: %"I64_FMT
" bytes", frame_size
);
211 if(frame_size
<16 || frame_size
>DE_MAX_SANE_OBJECT_SIZE
) {
214 frame_size_padded
= de_pad_to_n(frame_size
, 8);
217 if(d
->found_last_frame_flag
) break;
218 if(pos
+frame_size_padded
> c
->infile
->len
) goto done
;
219 de_dbg(c
, "frame at %"I64_FMT
, pos
);
221 dbuf_create_file_from_slice(c
->infile
, pos
, frame_size
, "nie", NULL
, 0x0);
222 pos
+= frame_size_padded
;
223 read_NIIpayload(c
, d
, pos
, 1);
225 de_dbg_indent(c
, -1);
232 static void de_run_nie(deark
*c
, de_module_params
*mparams
)
236 d
= de_malloc(c
, sizeof(lctx
));
237 d
->sig
= (unsigned int)de_getu32be(0);
239 if(d
->sig
==SIG_NIE
) {
242 else if(d
->sig
==SIG_NII
) {
245 else if(d
->sig
==SIG_NIA
) {
249 de_err(c
, "File not in NIE/NII/NIA format");
253 de_declare_fmt(c
, d
->fmtname
);
255 if(d
->sig
==SIG_NIE
) {
258 else if(d
->sig
==SIG_NII
) {
261 else if(d
->sig
==SIG_NIA
) {
269 static int de_identify_nie(deark
*c
)
273 sig
= (unsigned int)de_getu32be(0);
274 if(sig
==SIG_NIE
|| sig
==SIG_NII
|| sig
==SIG_NIA
) return 100;
278 void de_module_nie(deark
*c
, struct deark_module_info
*mi
)
281 mi
->desc
= "NIE/NII/NIA (Naive Image Formats)";
282 mi
->run_fn
= de_run_nie
;
283 mi
->identify_fn
= de_identify_nie
;