1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  * allocimbuf.c
19  */
20 
21 /** \file
22  * \ingroup imbuf
23  */
24 
25 #ifdef _WIN32
26 #  include "mmap_win.h"
27 #  include <io.h>
28 #  include <stddef.h>
29 #  include <sys/types.h>
30 #endif
31 
32 #include "BLI_fileops.h"
33 #include "BLI_path_util.h"
34 #include "BLI_string.h"
35 #include "BLI_utildefines.h"
36 #include <stdlib.h>
37 
38 #include "IMB_allocimbuf.h"
39 #include "IMB_filetype.h"
40 #include "IMB_imbuf.h"
41 #include "IMB_imbuf_types.h"
42 #include "imbuf.h"
43 
44 #include "IMB_colormanagement.h"
45 #include "IMB_colormanagement_intern.h"
46 
imb_handle_alpha(ImBuf * ibuf,int flags,char colorspace[IM_MAX_SPACE],char effective_colorspace[IM_MAX_SPACE])47 static void imb_handle_alpha(ImBuf *ibuf,
48                              int flags,
49                              char colorspace[IM_MAX_SPACE],
50                              char effective_colorspace[IM_MAX_SPACE])
51 {
52   if (colorspace) {
53     if (ibuf->rect != NULL && ibuf->rect_float == NULL) {
54       /* byte buffer is never internally converted to some standard space,
55        * store pointer to its color space descriptor instead
56        */
57       ibuf->rect_colorspace = colormanage_colorspace_get_named(effective_colorspace);
58     }
59 
60     BLI_strncpy(colorspace, effective_colorspace, IM_MAX_SPACE);
61   }
62 
63   bool is_data = (colorspace && IMB_colormanagement_space_name_is_data(colorspace));
64   int alpha_flags = (flags & IB_alphamode_detect) ? ibuf->flags : flags;
65 
66   if (is_data || (flags & IB_alphamode_channel_packed)) {
67     /* Don't touch alpha. */
68     ibuf->flags |= IB_alphamode_channel_packed;
69   }
70   else if (flags & IB_alphamode_ignore) {
71     /* Make opaque. */
72     IMB_rectfill_alpha(ibuf, 1.0f);
73     ibuf->flags |= IB_alphamode_ignore;
74   }
75   else {
76     if (alpha_flags & IB_alphamode_premul) {
77       if (ibuf->rect) {
78         IMB_unpremultiply_alpha(ibuf);
79       }
80       else {
81         /* pass, floats are expected to be premul */
82       }
83     }
84     else {
85       if (ibuf->rect_float) {
86         IMB_premultiply_alpha(ibuf);
87       }
88       else {
89         /* pass, bytes are expected to be straight */
90       }
91     }
92   }
93 
94   /* OCIO_TODO: in some cases it's faster to do threaded conversion,
95    *            but how to distinguish such cases */
96   colormanage_imbuf_make_linear(ibuf, effective_colorspace);
97 }
98 
IMB_ibImageFromMemory(const unsigned char * mem,size_t size,int flags,char colorspace[IM_MAX_SPACE],const char * descr)99 ImBuf *IMB_ibImageFromMemory(const unsigned char *mem,
100                              size_t size,
101                              int flags,
102                              char colorspace[IM_MAX_SPACE],
103                              const char *descr)
104 {
105   ImBuf *ibuf;
106   const ImFileType *type;
107   char effective_colorspace[IM_MAX_SPACE] = "";
108 
109   if (mem == NULL) {
110     fprintf(stderr, "%s: NULL pointer\n", __func__);
111     return NULL;
112   }
113 
114   if (colorspace) {
115     BLI_strncpy(effective_colorspace, colorspace, sizeof(effective_colorspace));
116   }
117 
118   for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
119     if (type->load) {
120       ibuf = type->load(mem, size, flags, effective_colorspace);
121       if (ibuf) {
122         imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace);
123         return ibuf;
124       }
125     }
126   }
127 
128   if ((flags & IB_test) == 0) {
129     fprintf(stderr, "%s: unknown fileformat (%s)\n", __func__, descr);
130   }
131 
132   return NULL;
133 }
134 
IMB_ibImageFromFile(const char * filepath,int flags,char colorspace[IM_MAX_SPACE],const char * descr)135 static ImBuf *IMB_ibImageFromFile(const char *filepath,
136                                   int flags,
137                                   char colorspace[IM_MAX_SPACE],
138                                   const char *descr)
139 {
140   ImBuf *ibuf;
141   const ImFileType *type;
142   char effective_colorspace[IM_MAX_SPACE] = "";
143 
144   if (colorspace) {
145     BLI_strncpy(effective_colorspace, colorspace, sizeof(effective_colorspace));
146   }
147 
148   for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
149     if (type->load_filepath) {
150       ibuf = type->load_filepath(filepath, flags, effective_colorspace);
151       if (ibuf) {
152         imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace);
153         return ibuf;
154       }
155     }
156   }
157 
158   if ((flags & IB_test) == 0) {
159     fprintf(stderr, "%s: unknown fileformat (%s)\n", __func__, descr);
160   }
161 
162   return NULL;
163 }
164 
imb_is_filepath_format(const char * filepath)165 static bool imb_is_filepath_format(const char *filepath)
166 {
167   /* return true if this is one of the formats that can't be loaded from memory */
168   return BLI_path_extension_check_array(filepath, imb_ext_image_filepath_only);
169 }
170 
IMB_loadifffile(int file,const char * filepath,int flags,char colorspace[IM_MAX_SPACE],const char * descr)171 ImBuf *IMB_loadifffile(
172     int file, const char *filepath, int flags, char colorspace[IM_MAX_SPACE], const char *descr)
173 {
174   ImBuf *ibuf;
175   unsigned char *mem;
176   size_t size;
177 
178   if (file == -1) {
179     return NULL;
180   }
181 
182   if (imb_is_filepath_format(filepath)) {
183     return IMB_ibImageFromFile(filepath, flags, colorspace, descr);
184   }
185 
186   size = BLI_file_descriptor_size(file);
187 
188   imb_mmap_lock();
189   mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
190   imb_mmap_unlock();
191 
192   if (mem == (unsigned char *)-1) {
193     fprintf(stderr, "%s: couldn't get mapping %s\n", __func__, descr);
194     return NULL;
195   }
196 
197   ibuf = IMB_ibImageFromMemory(mem, size, flags, colorspace, descr);
198 
199   imb_mmap_lock();
200   if (munmap(mem, size)) {
201     fprintf(stderr, "%s: couldn't unmap file %s\n", __func__, descr);
202   }
203   imb_mmap_unlock();
204 
205   return ibuf;
206 }
207 
imb_cache_filename(char * filename,const char * name,int flags)208 static void imb_cache_filename(char *filename, const char *name, int flags)
209 {
210   /* read .tx instead if it exists and is not older */
211   if (flags & IB_tilecache) {
212     BLI_strncpy(filename, name, IMB_FILENAME_SIZE);
213     if (!BLI_path_extension_replace(filename, IMB_FILENAME_SIZE, ".tx")) {
214       return;
215     }
216 
217     if (BLI_file_older(name, filename)) {
218       return;
219     }
220   }
221 
222   BLI_strncpy(filename, name, IMB_FILENAME_SIZE);
223 }
224 
IMB_loadiffname(const char * filepath,int flags,char colorspace[IM_MAX_SPACE])225 ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_SPACE])
226 {
227   ImBuf *ibuf;
228   int file, a;
229   char filepath_tx[IMB_FILENAME_SIZE];
230 
231   BLI_assert(!BLI_path_is_rel(filepath));
232 
233   imb_cache_filename(filepath_tx, filepath, flags);
234 
235   file = BLI_open(filepath_tx, O_BINARY | O_RDONLY, 0);
236   if (file == -1) {
237     return NULL;
238   }
239 
240   ibuf = IMB_loadifffile(file, filepath, flags, colorspace, filepath_tx);
241 
242   if (ibuf) {
243     BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
244     BLI_strncpy(ibuf->cachename, filepath_tx, sizeof(ibuf->cachename));
245     for (a = 1; a < ibuf->miptot; a++) {
246       BLI_strncpy(ibuf->mipmap[a - 1]->cachename, filepath_tx, sizeof(ibuf->cachename));
247     }
248   }
249 
250   close(file);
251 
252   return ibuf;
253 }
254 
IMB_testiffname(const char * filepath,int flags)255 ImBuf *IMB_testiffname(const char *filepath, int flags)
256 {
257   ImBuf *ibuf;
258   int file;
259   char filepath_tx[IMB_FILENAME_SIZE];
260   char colorspace[IM_MAX_SPACE] = "\0";
261 
262   BLI_assert(!BLI_path_is_rel(filepath));
263 
264   imb_cache_filename(filepath_tx, filepath, flags);
265 
266   file = BLI_open(filepath_tx, O_BINARY | O_RDONLY, 0);
267   if (file == -1) {
268     return NULL;
269   }
270 
271   ibuf = IMB_loadifffile(file, filepath, flags | IB_test | IB_multilayer, colorspace, filepath_tx);
272 
273   if (ibuf) {
274     BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name));
275     BLI_strncpy(ibuf->cachename, filepath_tx, sizeof(ibuf->cachename));
276   }
277 
278   close(file);
279 
280   return ibuf;
281 }
282 
imb_loadtilefile(ImBuf * ibuf,int file,int tx,int ty,unsigned int * rect)283 static void imb_loadtilefile(ImBuf *ibuf, int file, int tx, int ty, unsigned int *rect)
284 {
285   const ImFileType *type;
286   unsigned char *mem;
287   size_t size;
288 
289   if (file == -1) {
290     return;
291   }
292 
293   size = BLI_file_descriptor_size(file);
294 
295   imb_mmap_lock();
296   mem = mmap(NULL, size, PROT_READ, MAP_SHARED, file, 0);
297   imb_mmap_unlock();
298 
299   if (mem == (unsigned char *)-1) {
300     fprintf(stderr, "Couldn't get memory mapping for %s\n", ibuf->cachename);
301     return;
302   }
303 
304   for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) {
305     if (type->load_tile && type->ftype(type, ibuf)) {
306       type->load_tile(ibuf, mem, size, tx, ty, rect);
307     }
308   }
309 
310   imb_mmap_lock();
311   if (munmap(mem, size)) {
312     fprintf(stderr, "Couldn't unmap memory for %s.\n", ibuf->cachename);
313   }
314   imb_mmap_unlock();
315 }
316 
imb_loadtile(ImBuf * ibuf,int tx,int ty,unsigned int * rect)317 void imb_loadtile(ImBuf *ibuf, int tx, int ty, unsigned int *rect)
318 {
319   int file;
320 
321   file = BLI_open(ibuf->cachename, O_BINARY | O_RDONLY, 0);
322   if (file == -1) {
323     return;
324   }
325 
326   imb_loadtilefile(ibuf, file, tx, ty, rect);
327 
328   close(file);
329 }
330