Coin Logo Coin3D is Free Software,
published under the BSD 3-clause license.
https://coin3d.github.io
https://www.kongsberg.com/en/kogt/
simage_cgimage.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) Kongsberg Oil & Gas Technologies
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <simage_cgimage.h>
18 
19 #include <CoreFoundation/CoreFoundation.h>
20 #include <ApplicationServices/ApplicationServices.h>
21 
22 enum {
31 };
32 
34 
35 static CGImageSourceRef
36 create_image_source(const char * file)
37 {
38  CFStringRef cfname;
39  CFURLRef image_url;
40  CGImageSourceRef image_source;
41 
42  cfname = CFStringCreateWithCString(kCFAllocatorDefault,
43  file,
44  kCFStringEncodingUTF8);
45 
46  if (!cfname) {
47  return NULL;
48  }
49 
50  image_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
51  cfname,
52  kCFURLPOSIXPathStyle,
53  false);
54 
55  if (!image_url) {
56  CFRelease(cfname);
57  return NULL;
58  }
59 
60  image_source = CGImageSourceCreateWithURL(image_url, NULL);
61  CFRelease(image_url);
62  CFRelease(cfname);
63 
64  if (image_source &&
65  (CGImageSourceGetStatus(image_source) != kCGImageStatusComplete ||
66  CGImageSourceGetCount(image_source) == 0)) {
67  CFRelease(image_source);
68  image_source = NULL;
69  }
70  return image_source;
71 }
72 
73 int
74 simage_cgimage_error(char * cstr, int buflen)
75 {
76  int errval = cgimageerror;
77  switch (cgimageerror) {
78  case ERR_OPEN:
79  strncpy(cstr, "CGImage loader: Error loading file", buflen);
80  break;
81  }
83  return errval;
84 }
85 
86 int
87 simage_cgimage_identify(const char * file, const unsigned char * header,
88  int headerlen)
89 {
90  CGImageSourceRef image_source = create_image_source(file);
91  if (image_source) {
92  CFRelease(image_source);
93  return 1;
94  }
95  return 0;
96 }
97 
98 unsigned char *
99 simage_cgimage_load(const char * file, int * width, int * height, int * numcomponents)
100 {
101  CGColorSpaceRef color_space;
102  CGImageSourceRef image_source;
103  CGImageRef image;
104  CGContextRef context;
105  unsigned char * newpx;
106 
107  image_source = create_image_source(file);
108  if (!image_source) {
110  return NULL;
111  }
112 
113  image = CGImageSourceCreateImageAtIndex(image_source, 0, NULL);
114  assert(image);
115 
116  *width = CGImageGetWidth(image);
117  *height = CGImageGetHeight(image);
118  *numcomponents = CGImageGetBitsPerPixel(image)/CGImageGetBitsPerComponent(image);
119 
120  if (*numcomponents <= 2) {
121  *numcomponents = 1;
122  color_space = CGColorSpaceCreateDeviceGray();
123  }
124  else {
125  *numcomponents = 4;
126  color_space = CGColorSpaceCreateDeviceRGB();
127  }
128  assert(color_space);
129 
130  newpx = (unsigned char *)malloc(*width * *height * *numcomponents);
131 
132  context = CGBitmapContextCreate(newpx, *width, *height, 8, *width * *numcomponents,
133  color_space,
134  (*numcomponents == 1) ?
135  kCGImageAlphaNone :
136  kCGImageAlphaPremultipliedLast);
137  assert(context);
138  /* flip Y axis */
139  CGContextScaleCTM(context, 1.0f, -1.0f);
140  CGContextTranslateCTM(context, 0.0f, -*height);
141 
142  CGContextDrawImage(context, CGRectMake(0, 0, *width, *height), image);
143 
144  CFRelease(context);
145  CFRelease(color_space);
146  CFRelease(image);
147  CFRelease(image_source);
148 
149  return newpx;
150 }
151 
152 char *
154 {
155  unsigned int idx;
156  unsigned int formats_size = 0;
157  char * format;
158  char * formats = NULL;
159 
160  CFArrayRef destinationTypes;
161  CFIndex fileext_len = 0;
162  CFStringRef fileext;
163  CFStringRef jpegStr;
164  CFStringRef tiffStr;
165 
166  format = (char*)malloc(5);
167  memset(format, 0, 5);
168 
169  jpegStr = CFSTR("jpeg");
170  tiffStr = CFSTR("tiff");
171 
172  destinationTypes = CGImageDestinationCopyTypeIdentifiers();
173  for (idx = 0; idx < CFArrayGetCount(destinationTypes); idx++) {
174  fileext = UTTypeCopyPreferredTagWithClass(CFArrayGetValueAtIndex(destinationTypes, idx),
175  kUTTagClassFilenameExtension);
176 
177  fileext_len = CFStringGetLength(fileext);
178 
179  /* make JPEG and TIFF strings 3 letter extensions */
180  /* FIXME: dirty. wash it! 20100224 tamer. */
181  if (fileext_len == 4) {
182  if (!CFStringCompare(fileext, jpegStr, 0)) {
183  CFRelease(fileext);
184  fileext = CFSTR("jpg");
185  fileext_len = 3;
186  } else if (!CFStringCompare(fileext, tiffStr, 0)) {
187  CFRelease(fileext);
188  fileext = CFSTR("tif");
189  fileext_len = 3;
190  }
191  }
192 
193  formats_size += fileext_len + ((idx == 0) ? 1 : 2);
194  formats = (char *)realloc(formats, formats_size);
195 
196  /* Assumption: file extension tag not bigger than 4 characters,
197  therefore the hardcoded value of 5. 20100224 tamer. */
198  CFStringGetCString(fileext, format, 5, kCFStringEncodingUTF8);
199 
200  if (idx == 0) {
201  strncpy(formats, format, fileext_len+1);
202  } else {
203  strncat(formats, ",", 2);
204  strncat(formats, format, fileext_len+1);
205  }
206 
207  CFRelease(fileext);
208  }
209 
210  CFRelease(destinationTypes);
211  free(format);
212 
213  return formats;
214 }
215 
216 int
218  const unsigned char * bytes,
219  int width,
220  int height,
221  int numcomponents,
222  const char * ext)
223 {
224  CFStringRef cfname;
225  CFStringRef file_ext;
226  CFStringRef type_name;
227  CFURLRef image_url;
228  CGImageRef image_source;
229  CGImageDestinationRef image_dest;
230  CGColorSpaceRef color_space;
231  CGDataProviderRef provider;
232 
233  int bitsPerComponent, bitsPerPixel, bytesPerRow;
234  int finalized;
235 
236  unsigned int pos = 0, imgbufsize = width*height*numcomponents;
237  unsigned char * bytes_flipped = NULL;
238 
239  /* FIXME: Flipping manually as CGBitmapContexts leads to headaches
240  by not supporting 24bits per pixel buffers. 20100225 tamer. */
241  bytes_flipped = (unsigned char *)malloc(imgbufsize);
242  /* flip buffer horizontally */
243  for (pos = 0; pos < imgbufsize; pos+=width*numcomponents) {
244  memcpy(bytes_flipped+pos,
245  bytes+imgbufsize-width*numcomponents-pos,
246  width*numcomponents);
247  }
248 
249  provider = CGDataProviderCreateWithData(NULL, bytes_flipped,
250  imgbufsize,
251  NULL);
252 
253  bitsPerComponent = 8;
254  bitsPerPixel = bitsPerComponent*numcomponents;
255  bytesPerRow = numcomponents * width;
256  color_space = CGColorSpaceCreateDeviceRGB();
257  image_source = CGImageCreate(width, height, 8, 8*numcomponents,
258  numcomponents*width,
259  color_space,
260  kCGBitmapByteOrderDefault,
261  provider,
262  NULL, 0,
263  kCGRenderingIntentDefault);
264 
265  CGDataProviderRelease(provider);
266  CGColorSpaceRelease(color_space);
267  free(bytes_flipped);
268 
269  file_ext = CFStringCreateWithCString(kCFAllocatorDefault,
270  ext,
271  kCFStringEncodingUTF8);
272  type_name = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension,
273  file_ext,
274  kUTTypeImage);
275 
276  CFRelease(file_ext);
277 
278  if (!type_name) {
280  CFRelease(image_source);
281  return 0;
282  }
283 
284  cfname = CFStringCreateWithCString(kCFAllocatorDefault,
285  filename,
286  kCFStringEncodingUTF8);
287 
288  if (!cfname) {
290  CFRelease(type_name);
291  CFRelease(image_source);
292  return 0;
293  }
294 
295  image_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
296  cfname,
297  kCFURLPOSIXPathStyle,
298  false);
299 
300  CFRelease(cfname);
301 
302  if (!image_url) {
304  CFRelease(type_name);
305  CFRelease(image_source);
306  return 0;
307  }
308 
309  image_dest = CGImageDestinationCreateWithURL(image_url, type_name, 1, NULL);
310 
311  CFRelease(type_name);
312  CFRelease(image_url);
313 
314  if (!image_dest) {
316  CFRelease(image_source);
317  return 0;
318  }
319 
320  CGImageDestinationAddImage(image_dest, image_source, NULL);
321 
322  finalized = CGImageDestinationFinalize(image_dest);
323  if (!finalized) {
325  }
326 
327  CGImageRelease(image_source);
328  CFRelease(image_dest);
329 
330  return finalized;
331 }
char * filename
Definition: stream.c:38
int simage_cgimage_save(const char *filename, const unsigned char *bytes, int width, int height, int numcomponents, const char *ext)
int simage_cgimage_identify(const char *file, const unsigned char *header, int headerlen)
void * context
Definition: stream.c:49
static CGImageSourceRef create_image_source(const char *file)
int simage_cgimage_error(char *cstr, int buflen)
char * simage_cgimage_get_savers(void)
unsigned char * simage_cgimage_load(const char *file, int *width, int *height, int *numcomponents)
static int cgimageerror