Cleanup: fix compiler warnings.
[blender.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 // NOTE: Keep first, BLI_path_util conflicts with OIIO's format.
39 #include <memory>
40 #include <openimageio_api.h>
41 #include <OpenImageIO/imageio.h>
42
43 extern "C"
44 {
45 #include "MEM_guardedalloc.h"
46
47 #include "BLI_blenlib.h"
48
49 #include "IMB_imbuf_types.h"
50 #include "IMB_imbuf.h"
51 #include "IMB_allocimbuf.h"
52 #include "IMB_colormanagement.h"
53 #include "IMB_colormanagement_intern.h"
54 }
55
56 OIIO_NAMESPACE_USING
57
58 using std::string;
59 using std::unique_ptr;
60
61 typedef unsigned char uchar;
62
63 template <class T, class Q>
64 static void fill_all_channels(T *pixels, int width, int height, int components, Q alpha)
65 {
66         if (components == 2) {
67                 for (int i = width * height - 1; i >= 0; i--) {
68                         pixels[i * 4 + 3] = pixels[i * 2 + 1];
69                         pixels[i * 4 + 2] = pixels[i * 2 + 0];
70                         pixels[i * 4 + 1] = pixels[i * 2 + 0];
71                         pixels[i * 4 + 0] = pixels[i * 2 + 0];
72                 }
73         }
74         else if (components == 3) {
75                 for (int i = width * height - 1; i >= 0; i--) {
76                         pixels[i * 4 + 3] = alpha;
77                         pixels[i * 4 + 2] = pixels[i * 3 + 2];
78                         pixels[i * 4 + 1] = pixels[i * 3 + 1];
79                         pixels[i * 4 + 0] = pixels[i * 3 + 0];
80
81                 }
82         }
83         else if (components == 1) {
84                 for (int i = width * height - 1; i >= 0; i--) {
85                         pixels[i * 4 + 3] = alpha;
86                         pixels[i * 4 + 2] = pixels[i];
87                         pixels[i * 4 + 1] = pixels[i];
88                         pixels[i * 4 + 0] = pixels[i];
89                 }
90         }
91
92 }
93
94 static ImBuf *imb_oiio_load_image(ImageInput *in, int width, int height, int components, int flags, bool is_alpha)
95 {
96         ImBuf *ibuf;
97         int scanlinesize = width * components * sizeof(uchar);
98
99         /* allocate the memory for the image */
100         ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, flags | IB_rect);
101
102         try
103         {
104                 if (!in->read_image(TypeDesc::UINT8,
105                                     (uchar *)ibuf->rect + (height - 1) * scanlinesize,
106                                     AutoStride,
107                                     -scanlinesize,
108                                     AutoStride))
109                 {
110                         std::cerr << __func__ << ": ImageInput::read_image() failed:" << std::endl
111                                   << in->geterror() << std::endl;
112
113                         if (ibuf)
114                                 IMB_freeImBuf(ibuf);
115
116                         return NULL;
117                 }
118         }
119         catch (const std::exception &exc)
120         {
121                 std::cerr << exc.what() << std::endl;
122                 if (ibuf) IMB_freeImBuf(ibuf);
123
124                 return NULL;
125         }
126
127         /* ImBuf always needs 4 channels */
128         fill_all_channels((uchar *)ibuf->rect, width, height, components, 0xFF);
129
130         return ibuf;
131 }
132
133 static ImBuf *imb_oiio_load_image_float(ImageInput *in, int width, int height, int components, int flags, bool is_alpha)
134 {
135         ImBuf *ibuf;
136         int scanlinesize = width * components * sizeof(float);
137
138         /* allocate the memory for the image */
139         ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, flags | IB_rectfloat);
140
141         try
142         {
143                 if (!in->read_image(TypeDesc::FLOAT,
144                                     (uchar *)ibuf->rect_float + (height - 1) * scanlinesize,
145                                     AutoStride,
146                                     -scanlinesize,
147                                     AutoStride))
148                 {
149                         std::cerr << __func__ << ": ImageInput::read_image() failed:" << std::endl
150                                   << in->geterror() << std::endl;
151
152                         if (ibuf)
153                                 IMB_freeImBuf(ibuf);
154
155                         return NULL;
156                 }
157         }
158         catch (const std::exception &exc)
159         {
160                 std::cerr << exc.what() << std::endl;
161                 if (ibuf) IMB_freeImBuf(ibuf);
162
163                 return NULL;
164         }
165
166         /* ImBuf always needs 4 channels */
167         fill_all_channels((float *)ibuf->rect_float, width, height, components, 1.0f);
168
169         /* note: Photoshop 16 bit files never has alpha with it, so no need to handle associated/unassociated alpha */
170         return ibuf;
171 }
172
173 extern "C"
174 {
175
176 int imb_is_a_photoshop(const char *filename)
177 {
178         const char *photoshop_extension[] = {
179                 ".psd",
180                 ".pdd",
181                 ".psb",
182                 NULL
183         };
184
185         return BLI_path_extension_check_array(filename, photoshop_extension);
186 }
187
188 int imb_save_photoshop(struct ImBuf *ibuf, const char * /*name*/, int flags)
189 {
190         if (flags & IB_mem) {
191                 std::cerr << __func__ << ": Photoshop PSD-save: Create PSD in memory"
192                           << " currently not supported" << std::endl;
193                 imb_addencodedbufferImBuf(ibuf);
194                 ibuf->encodedsize = 0;
195                 return(0);
196         }
197
198         return(0);
199 }
200
201 struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspace[IM_MAX_SPACE])
202 {
203         struct ImBuf *ibuf = NULL;
204         int width, height, components;
205         bool is_float, is_alpha;
206         int basesize;
207         char file_colorspace[IM_MAX_SPACE];
208
209         /* load image from file through OIIO */
210         if (imb_is_a_photoshop(filename) == 0) return (NULL);
211
212         colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
213
214         unique_ptr<ImageInput> in(ImageInput::create(filename));
215         if (!in) {
216                 std::cerr << __func__ << ": ImageInput::create() failed:" << std::endl
217                           << OIIO_NAMESPACE::geterror() << std::endl;
218                 return NULL;
219         }
220
221         ImageSpec spec, config;
222         config.attribute("oiio:UnassociatedAlpha", (int) 1);
223
224         if (!in->open(filename, spec, config)) {
225                 std::cerr << __func__ << ": ImageInput::open() failed:" << std::endl
226                           << in->geterror() << std::endl;
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                 }
253                 return NULL;
254         }
255
256         if (is_float)
257                 ibuf = imb_oiio_load_image_float(in.get(), width, height, components, flags, is_alpha);
258         else
259                 ibuf = imb_oiio_load_image(in.get(), width, height, components, flags, is_alpha);
260
261         if (in) {
262                 in->close();
263         }
264
265         if (!ibuf)
266                 return NULL;
267
268         /* ImBuf always needs 4 channels */
269         ibuf->ftype = IMB_FTYPE_PSD;
270         ibuf->channels = 4;
271         ibuf->planes = (3 + (is_alpha ? 1 : 0)) * 4 << basesize;
272
273         try
274         {
275                 return ibuf;
276         }
277         catch (const std::exception &exc)
278         {
279                 std::cerr << exc.what() << std::endl;
280                 if (ibuf) IMB_freeImBuf(ibuf);
281
282                 return NULL;
283         }
284 }
285
286 int OIIO_getVersionHex(void)
287 {
288         return openimageio_version();
289 }
290
291 } // export "C"