Remove MinGW support
[blender-staging.git] / source / blender / imbuf / intern / oiio / openimageio_api.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 Blender Foundation
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Dalai Felinto and Brecht van Lommel
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/imbuf/intern/oiio/openimageio_api.cpp
29  *  \ingroup openimageio
30  */
31
32 #include <set>
33
34 #if defined(WIN32)
35 #include "utfconv.h"
36 #endif
37
38 extern "C"
39 {
40 #include "MEM_guardedalloc.h"
41
42 #include "BLI_blenlib.h"
43
44 #include "IMB_imbuf_types.h"
45 #include "IMB_imbuf.h"
46 #include "IMB_allocimbuf.h"
47 #include "IMB_colormanagement.h"
48 #include "IMB_colormanagement_intern.h"
49 }
50
51 #include <openimageio_api.h>
52 #include <OpenImageIO/imageio.h>
53
54 OIIO_NAMESPACE_USING
55
56 using std::string;
57
58 typedef unsigned char uchar;
59
60 template <class T, class Q>
61 static void fill_all_channels(T *pixels, int width, int height, int components, Q alpha)
62 {
63         if (components == 2) {
64                 for (int i = width * height - 1; i >= 0; i--) {
65                         pixels[i * 4 + 3] = pixels[i * 2 + 1];
66                         pixels[i * 4 + 2] = pixels[i * 2 + 0];
67                         pixels[i * 4 + 1] = pixels[i * 2 + 0];
68                         pixels[i * 4 + 0] = pixels[i * 2 + 0];
69                 }
70         }
71         else if (components == 3) {
72                 for (int i = width * height - 1; i >= 0; i--) {
73                         pixels[i * 4 + 3] = alpha;
74                         pixels[i * 4 + 2] = pixels[i * 3 + 2];
75                         pixels[i * 4 + 1] = pixels[i * 3 + 1];
76                         pixels[i * 4 + 0] = pixels[i * 3 + 0];
77
78                 }
79         }
80         else if (components == 1) {
81                 for (int i = width * height - 1; i >= 0; i--) {
82                         pixels[i * 4 + 3] = alpha;
83                         pixels[i * 4 + 2] = pixels[i];
84                         pixels[i * 4 + 1] = pixels[i];
85                         pixels[i * 4 + 0] = pixels[i];
86                 }
87         }
88
89 }
90
91 static ImBuf *imb_oiio_load_image(ImageInput *in, int width, int height, int components, int flags, bool is_alpha)
92 {
93         ImBuf *ibuf;
94         int scanlinesize = width * components * sizeof(uchar);
95
96         /* allocate the memory for the image */
97         ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, flags | IB_rect);
98
99         try
100         {
101                 if (!in->read_image(TypeDesc::UINT8,
102                                     (uchar *)ibuf->rect + (height - 1) * scanlinesize,
103                                     AutoStride,
104                                     -scanlinesize,
105                                     AutoStride))
106                 {
107                         std::cerr << __func__ << ": ImageInput::read_image() failed:" << std::endl
108                                   << in->geterror() << std::endl;
109
110                         if (ibuf)
111                                 IMB_freeImBuf(ibuf);
112
113                         return NULL;
114                 }
115         }
116         catch (const std::exception &exc)
117         {
118                 std::cerr << exc.what() << std::endl;
119                 if (ibuf) IMB_freeImBuf(ibuf);
120
121                 return NULL;
122         }
123
124         /* ImBuf always needs 4 channels */
125         fill_all_channels((uchar *)ibuf->rect, width, height, components, 0xFF);
126
127         return ibuf;
128 }
129
130 static ImBuf *imb_oiio_load_image_float(ImageInput *in, int width, int height, int components, int flags, bool is_alpha)
131 {
132         ImBuf *ibuf;
133         int scanlinesize = width * components * sizeof(float);
134
135         /* allocate the memory for the image */
136         ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, flags | IB_rectfloat);
137
138         try
139         {
140                 if (!in->read_image(TypeDesc::FLOAT,
141                                     (uchar *)ibuf->rect_float + (height - 1) * scanlinesize,
142                                     AutoStride,
143                                     -scanlinesize,
144                                     AutoStride))
145                 {
146                         std::cerr << __func__ << ": ImageInput::read_image() failed:" << std::endl
147                                   << in->geterror() << std::endl;
148
149                         if (ibuf)
150                                 IMB_freeImBuf(ibuf);
151
152                         return NULL;
153                 }
154         }
155         catch (const std::exception &exc)
156         {
157                 std::cerr << exc.what() << std::endl;
158                 if (ibuf) IMB_freeImBuf(ibuf);
159
160                 return NULL;
161         }
162
163         /* ImBuf always needs 4 channels */
164         fill_all_channels((float *)ibuf->rect_float, width, height, components, 1.0f);
165
166         /* note: Photoshop 16 bit files never has alpha with it, so no need to handle associated/unassociated alpha */
167         return ibuf;
168 }
169
170 extern "C"
171 {
172
173 int imb_is_a_photoshop(const char *filename)
174 {
175         const char *photoshop_extension[] = {
176                 ".psd",
177                 ".pdd",
178                 ".psb",
179                 NULL
180         };
181
182         return BLI_testextensie_array(filename, photoshop_extension);
183 }
184
185 int imb_save_photoshop(struct ImBuf *ibuf, const char * /*name*/, int flags)
186 {
187         if (flags & IB_mem) {
188                 std::cerr << __func__ << ": Photoshop PSD-save: Create PSD in memory"
189                           << " currently not supported" << std::endl;
190                 imb_addencodedbufferImBuf(ibuf);
191                 ibuf->encodedsize = 0;
192                 return(0);
193         }
194
195         return(0);
196 }
197
198 struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspace[IM_MAX_SPACE])
199 {
200         ImageInput *in = NULL;
201         struct ImBuf *ibuf = NULL;
202         int width, height, components;
203         bool is_float, is_alpha;
204         TypeDesc typedesc;
205         int basesize;
206         char file_colorspace[IM_MAX_SPACE];
207
208         /* load image from file through OIIO */
209         if (imb_is_a_photoshop(filename) == 0) return (NULL);
210
211         colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
212
213         in = ImageInput::create(filename);
214         if (!in) {
215                 std::cerr << __func__ << ": ImageInput::create() failed:" << std::endl
216                           << OIIO_NAMESPACE::geterror() << std::endl;
217                 return NULL;
218         }
219
220         ImageSpec spec, config;
221         config.attribute("oiio:UnassociatedAlpha", (int) 1);
222
223         if (!in->open(filename, spec, config)) {
224                 std::cerr << __func__ << ": ImageInput::open() failed:" << std::endl
225                           << in->geterror() << std::endl;
226                 delete in;
227                 return NULL;
228         }
229
230         string ics = spec.get_string_attribute("oiio:ColorSpace");
231         BLI_strncpy(file_colorspace, ics.c_str(), IM_MAX_SPACE);
232
233         /* only use colorspaces exis */
234         if (colormanage_colorspace_get_named(file_colorspace))
235                 strcpy(colorspace, file_colorspace);
236         else
237                 std::cerr << __func__ << ": The embed colorspace (\"" << file_colorspace
238                           << "\") not supported in existent OCIO configuration file. Fallback "
239                           << "to system default colorspace (\"" << colorspace << "\")." << std::endl;
240
241         width = spec.width;
242         height = spec.height;
243         components = spec.nchannels;
244         is_alpha = spec.alpha_channel != -1;
245         basesize = spec.format.basesize();
246         is_float = basesize > 1;
247
248         /* we only handle certain number of components */
249         if (!(components >= 1 && components <= 4)) {
250                 if (in) {
251                         in->close();
252                         delete in;
253                 }
254                 return NULL;
255         }
256
257         if (is_float)
258                 ibuf = imb_oiio_load_image_float(in, width, height, components, flags, is_alpha);
259         else
260                 ibuf = imb_oiio_load_image(in, width, height, components, flags, is_alpha);
261
262         if (in) {
263                 in->close();
264                 delete in;
265         }
266
267         if (!ibuf)
268                 return NULL;
269
270         /* ImBuf always needs 4 channels */
271         ibuf->ftype = IMB_FTYPE_PSD;
272         ibuf->channels = 4;
273         ibuf->planes = (3 + (is_alpha ? 1 : 0)) * 4 << basesize;
274
275         try
276         {
277                 return ibuf;
278         }
279         catch (const std::exception &exc)
280         {
281                 std::cerr << exc.what() << std::endl;
282                 if (ibuf) IMB_freeImBuf(ibuf);
283
284                 return NULL;
285         }
286 }
287
288 int OIIO_getVersionHex(void)
289 {
290         return openimageio_version();
291 }
292
293 } // export "C"
294
295