Skip to content

Commit 224ea49

Browse files
committed
FEAT: preliminary use of image native OS codecs on Windows (using Windows Imaging Component)
If `USE_NATIVE_IMAGE_CODECS` is defined, than WIC is used instead of the original code, which supported only PNG, BMP and partially for JPEG and GIF). Using OS to do image de/encoding adds more possibilities, but so far, it still needs some work, especially for encoding, when user may want to specify various output options. For more details what WIC is, check: https://docs.microsoft.com/en-us/windows/win32/wic/
1 parent 407aeea commit 224ea49

12 files changed

+828
-9
lines changed

src/core/n-image.c

+163
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
***********************************************************************/
3030

3131
#include "sys-core.h"
32+
#include "reb-codec.h"
33+
3234

3335
typedef struct REBCLR {
3436
union {
@@ -170,3 +172,164 @@ typedef struct REBCLR {
170172

171173
return R_ARG1;
172174
}
175+
176+
/***********************************************************************
177+
**
178+
*/ REBNATIVE(image)
179+
/*
180+
// image: native [
181+
// "Interface to basic image encoding/decoding (only on Windows so far!)"
182+
// /load "Image file to load or binary to decode"
183+
// src-file [file! binary!]
184+
// /save "Encodes image to file or binary"
185+
// dst-file [none! file! binary!] "If NONE is used, binary is made internally"
186+
// dst-image [none! image!] "If NONE, loaded image may be used if there is any"
187+
// /frame "Some image formats may contain multiple images"
188+
// num [integer!] "1-based index of the image to receive"
189+
// /as "Used to define which codec should be used"
190+
// type [word!] "One of: [PNG JPEG JPEGXR BMP DDS GIF TIFF] read only: [DNG ICO HEIF]"
191+
// /scale
192+
// sc [pair! percent!]
193+
// ]
194+
***********************************************************************/
195+
{
196+
REBOOL ref_load = D_REF(1);
197+
REBVAL *val_src_file = D_ARG(2);
198+
REBOOL ref_save = D_REF(3);
199+
REBVAL *val_dest = D_ARG(4);
200+
REBVAL *val_dst_img = D_ARG(5);
201+
REBOOL ref_frame = D_REF(6);
202+
REBVAL *val_frame = D_ARG(7);
203+
REBOOL ref_as = D_REF(8);
204+
REBVAL *val_type = D_ARG(9);
205+
REBOOL ref_scale = D_REF(10);
206+
REBVAL *val_scale = D_ARG(11);
207+
208+
REBCDI codi;
209+
REBSER *ser = NULL;
210+
REBCNT frm = ref_frame ? VAL_INT32(val_frame) - 1 : 0;
211+
REBVAL *ret = D_RET;
212+
REBCNT length;
213+
214+
215+
#if defined(TO_WINDOWS) && defined(USE_NATIVE_IMAGE_CODECS)
216+
CLEARS(&codi);
217+
if (ref_as) {
218+
switch (VAL_WORD_CANON(val_type)) {
219+
case SYM_PNG: codi.type = CODI_IMG_PNG; break;
220+
case SYM_JPEG:
221+
case SYM_JPG: codi.type = CODI_IMG_JPEG; break;
222+
case SYM_JPEGXR:
223+
case SYM_HDP:
224+
case SYM_JXR: codi.type = CODI_IMG_JXR; break;
225+
case SYM_BMP: codi.type = CODI_IMG_BMP; break;
226+
case SYM_GIF: codi.type = CODI_IMG_GIF; break;
227+
case SYM_DDS: codi.type = CODI_IMG_DDS; break;
228+
case SYM_DNG: codi.type = CODI_IMG_DNG; break;
229+
case SYM_TIFF: codi.type = CODI_IMG_TIFF; break;
230+
case SYM_HEIF: codi.type = CODI_IMG_HEIF; break;
231+
case SYM_WEBP: codi.type = CODI_IMG_WEBP; break;
232+
case SYM_ICO: codi.type = CODI_IMG_ICO; break;
233+
default:
234+
Trap1(RE_BAD_FUNC_ARG, val_type);
235+
}
236+
}
237+
if (ref_load) {
238+
239+
if (IS_FILE(val_src_file)) {
240+
ser = Value_To_Local_Path(val_src_file, TRUE);
241+
} else {
242+
// raw binary data
243+
codi.data = VAL_BIN(val_src_file);
244+
codi.len = VAL_LEN(val_src_file);
245+
}
246+
247+
OS_Load_Image(ser ? SERIES_DATA(ser) : NULL, frm, &codi);
248+
249+
if(codi.error) {
250+
switch (codi.error) {
251+
case WINCODEC_ERR_COMPONENTNOTFOUND:
252+
Trap1(RE_NO_CODEC, val_type);
253+
break;
254+
default:
255+
SET_INTEGER(D_RET, codi.error);
256+
if (IS_BINARY(val_src_file)) {
257+
Trap1(RE_NO_CODEC, D_RET);
258+
} else {
259+
Trap2(RE_CANNOT_OPEN, val_src_file, D_RET); // need better!!!
260+
}
261+
}
262+
} else {
263+
ser = Make_Image(codi.w, codi.h, TRUE);
264+
memcpy(IMG_DATA(ser), codi.data, codi.w * codi.h * 4);
265+
SET_IMAGE(D_RET, ser);
266+
free(codi.data);
267+
codi.data = NULL;
268+
}
269+
}
270+
if (ref_save) {
271+
codi.bits = VAL_IMAGE_BITS(val_dst_img);
272+
codi.w = VAL_IMAGE_WIDE(val_dst_img);
273+
codi.h = VAL_IMAGE_HIGH(val_dst_img);
274+
275+
if (IS_FILE(val_dest)) {
276+
ser = Value_To_Local_Path(val_dest, TRUE);
277+
} else {
278+
// raw binary data...
279+
// ... predict number of bytes large enough to hold the result
280+
length = (codi.w * codi.h * 4) + 1024;
281+
if (IS_NONE(val_dest)) {
282+
ser = Make_Binary(length);
283+
SET_BINARY(val_dest, ser);
284+
codi.len = length;
285+
} else {
286+
ser = VAL_SERIES(val_dest);
287+
REBCNT avail = SERIES_REST(ser) - VAL_INDEX(val_dest);
288+
if (length > avail) {
289+
Extend_Series(ser, length - avail);
290+
avail = SERIES_REST(ser) - VAL_INDEX(val_dest);
291+
}
292+
codi.len = avail;
293+
}
294+
codi.data = VAL_BIN_AT(val_dest);
295+
}
296+
297+
//if (ref_scale) {
298+
// if (IS_PERCENT(val_scale)) {
299+
// codi.w *= VAL_DECIMAL(val_scale);
300+
// codi.h *= VAL_DECIMAL(val_scale);
301+
// } else {
302+
// codi.w = VAL_PAIR_X_INT(val_scale);
303+
// codi.h = VAL_PAIR_Y_INT(val_scale);
304+
// }
305+
//}
306+
307+
OS_Save_Image(IS_FILE(val_dest) ? SERIES_DATA(ser) : NULL, &codi);
308+
309+
if(codi.error) {
310+
switch (codi.error) {
311+
case WINCODEC_ERR_COMPONENTNOTFOUND:
312+
Trap1(RE_NO_CODEC, val_type);
313+
break;
314+
default:
315+
SET_INTEGER(D_RET, codi.error);
316+
if (IS_BINARY(val_dest)) {
317+
Trap1(RE_NO_CODEC, D_RET);
318+
} else {
319+
Trap2(RE_CANNOT_OPEN, val_dest, D_RET); // need better!!!
320+
}
321+
}
322+
}
323+
324+
if (IS_BINARY(val_dest)) {
325+
REBCNT tail = codi.len + VAL_INDEX(val_dest);
326+
if (tail > SERIES_TAIL(ser))
327+
SERIES_TAIL(ser) = tail;
328+
}
329+
*D_RET = *val_dest;
330+
}
331+
#else
332+
Trap0(RE_FEATURE_NA);
333+
#endif
334+
return R_RET;
335+
}

src/include/reb-codec.h

+31-6
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
** Notes:
2626
**
2727
***********************************************************************/
28-
28+
#ifndef CODI_DEFINED
2929
#define CODI_DEFINED
3030

3131
// Codec image interface:
@@ -45,21 +45,26 @@
4545
// the REBNATIVE(do_codec) in n-system.c
4646
// so the deallocation is left to GC
4747
//
48-
typedef struct reb_codec_image {
48+
struct reb_codec_image {
4949
int action;
5050
int w;
5151
int h;
5252
int len;
53-
int alpha;
53+
union {
54+
int alpha;
55+
int type; // used to provide info about prefered image type (codec)
56+
};
5457
unsigned char *data;
5558
union {
56-
u32 *bits;
59+
unsigned int *bits;
5760
void *other;
5861
};
5962
int error;
60-
} REBCDI;
63+
};
64+
65+
typedef struct reb_codec_image REBCDI;
6166

62-
typedef REBINT (*codo)(REBCDI *cdi);
67+
typedef int (*codo)(REBCDI *cdi);
6368

6469
// Media types:
6570
enum {
@@ -89,3 +94,23 @@ enum {
8994
CODI_ERR_BAD_TABLE, // Image tables are wrong
9095
CODI_ERR_BAD_DATA, // Generic
9196
};
97+
98+
enum {
99+
CODI_IMG_PNG, // Portable Network Graphics
100+
CODI_IMG_JPEG, // Joint Photographic Experts Group
101+
CODI_IMG_GIF, // Graphics Interchange Format
102+
CODI_IMG_DDS, // DirectDraw Surface
103+
CODI_IMG_DNG, // Digital Negative
104+
CODI_IMG_BMP, // Device independent bitmap
105+
CODI_IMG_ICO,
106+
CODI_IMG_TIFF, // Tagged Image File Format
107+
CODI_IMG_JXR, // Windows Digital Photo (JpegXR)
108+
CODI_IMG_HEIF, // High Efficiency Image Format
109+
CODI_IMG_WEBP, //
110+
};
111+
112+
#ifndef WINCODEC_ERR_COMPONENTNOTFOUND
113+
#define WINCODEC_ERR_COMPONENTNOTFOUND 0x88982F50
114+
#endif
115+
116+
#endif

src/include/reb-host.h

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "reb-evtypes.h"
3838
#include "reb-net.h"
3939
#include "reb-filereq.h"
40+
#include "reb-codec.h"
4041

4142
#include "reb-gob.h"
4243
#include "reb-lib.h"

src/mezz/codec-image.r

+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
REBOL [
2+
title: "REBOL 3 codec for image file formats"
3+
name: 'codec-image
4+
author: "Oldes"
5+
version: 0.1.0
6+
date: 31-Jul-2019
7+
history: [
8+
0.1.0 31-Jul-2019 "Oldes" {Initial version}
9+
]
10+
note: {Add the most common codec at tail (identify is testing the last codec as first)}
11+
]
12+
13+
register-codec [
14+
name: 'ICO
15+
title: "Computer icons in MS Windows"
16+
suffixes: [%.ico]
17+
18+
decode: func [data [binary!]][lib/image/load/as data 'ICO]
19+
;encode not available!
20+
identify: func [data [binary!]][parse data [#{00000100} to end]]
21+
]
22+
23+
register-codec [
24+
name: 'DNG
25+
title: "Digital Negative"
26+
suffixes: [%.dng]
27+
comment: {Decodes only thumbnail, not RAW data!}
28+
29+
decode: func [data [binary!]][lib/image/load/as data 'DNG]
30+
;encode not available!
31+
identify: func [data [binary!]][none] ; same like TIFF
32+
]
33+
34+
register-codec [
35+
name: 'DDS
36+
title: "DirectDraw Surface"
37+
suffixes: [%.dds]
38+
39+
decode: func [data [binary!]][lib/image/load/as data 'DDS]
40+
encode: func [data [image! ]][lib/image/save/as none data 'DDS]
41+
identify: func [data [binary!]][parse data [#{444453} to end]]
42+
]
43+
44+
register-codec [
45+
name: 'TIFF
46+
title: "Tagged Image File Format"
47+
suffixes: [%.tif %.tiff]
48+
49+
decode: func [data [binary!]][lib/image/load/as data 'TIFF]
50+
encode: func [data [image! ]][lib/image/save/as none data 'TIFF]
51+
identify: func [data [binary!]][parse data [#{4949} to end]]
52+
]
53+
54+
register-codec [
55+
name: 'GIF
56+
title: "Graphics Interchange Format"
57+
suffixes: [%.gif]
58+
59+
decode: func [data [binary!]][lib/image/load/as data 'GIF]
60+
encode: func [data [image! ]][lib/image/save/as none data 'GIF]
61+
identify: func [data [binary!]][parse data [#{4749463839} to end]]
62+
]
63+
64+
register-codec [
65+
name: 'BMP
66+
title: "Portable Bitmap"
67+
suffixes: [%.bmp]
68+
69+
decode: func [data [binary!]][lib/image/load/as data 'BMP]
70+
encode: func [data [image! ]][lib/image/save/as none data 'BMP]
71+
identify: func [data [binary!]][parse data [#{4249} to end]]
72+
]
73+
74+
register-codec [
75+
name: 'JPEGXR
76+
title: "JPEG extended range"
77+
suffixes: [%.jxr %.hdp %.wdp]
78+
79+
decode: func [data [binary!]][lib/image/load/as data 'JPEGXR]
80+
encode: func [data [image! ]][lib/image/save/as none data 'JPEGXR]
81+
identify: func [data [binary!]][parse data [#{4949} to end]]
82+
]
83+
84+
register-codec [
85+
name: 'JPEG
86+
title: "Joint Photographic Experts Group"
87+
suffixes: [%.jpg %.jpeg]
88+
89+
decode: func [data [binary!]][lib/image/load/as data 'JPEG]
90+
encode: func [data [image! ]][lib/image/save/as none data 'JPEG]
91+
identify: func [data [binary!]][parse data [#{FFD8} to end]]
92+
]
93+
94+
register-codec [
95+
name: 'PNG
96+
title: "Portable Network Graphics"
97+
suffixes: [%.png]
98+
99+
decode: func [data [binary!]][lib/image/load/as data 'PNG]
100+
encode: func [data [image! ]][lib/image/save/as none data 'PNG]
101+
identify: func [data [binary!]][parse data [#{89504E47} to end]]
102+
]
103+
104+
105+
106+
107+
108+
109+
110+
111+
112+
113+
114+
115+
116+
117+
118+

src/os/host-main.c

+4
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ int main(int argc, char **argv) {
253253
argv = (char**)CommandLineToArgvW(GetCommandLineW(), &argc);
254254
// Use title string as defined in resources file (.rc) with hardcoded ID 101
255255
LoadStringW(App_Instance, 101, App_Title, MAX_TITLE_LENGTH);
256+
#ifdef USE_NATIVE_IMAGE_CODECS
257+
CoInitialize(0);
258+
#endif
259+
256260
#else //non Windows platforms
257261
int main(int argc, char **argv) {
258262
#endif

0 commit comments

Comments
 (0)