cleanup specfile for packaging
[profile/ivi/cogl.git] / cogl / cogl-bitmap-pixbuf.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2007,2008,2009 Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "cogl-util.h"
29 #include "cogl-internal.h"
30 #include "cogl-bitmap-private.h"
31 #include "cogl-context-private.h"
32
33 #include <string.h>
34
35 #ifdef USE_QUARTZ
36 #include <ApplicationServices/ApplicationServices.h>
37 #elif defined(USE_GDKPIXBUF)
38 #include <gdk-pixbuf/gdk-pixbuf.h>
39 #endif
40
41 #ifdef USE_QUARTZ
42
43 gboolean
44 _cogl_bitmap_get_size_from_file (const char *filename,
45                                  int        *width,
46                                  int        *height)
47 {
48   if (width)
49     *width = 0;
50
51   if (height)
52     *height = 0;
53
54   return TRUE;
55 }
56
57 /* the error does not contain the filename as the caller already has it */
58 CoglBitmap *
59 _cogl_bitmap_from_file (const char  *filename,
60                         GError     **error)
61 {
62   CFURLRef url;
63   CGImageSourceRef image_source;
64   CGImageRef image;
65   int save_errno;
66   CFStringRef type;
67   gsize width, height, rowstride;
68   guint8 *out_data;
69   CGColorSpaceRef color_space;
70   CGContextRef bitmap_context;
71   CoglBitmap *bmp;
72
73   _COGL_GET_CONTEXT (ctx, NULL);
74
75   g_assert (filename != NULL);
76   g_assert (error == NULL || *error == NULL);
77
78   url = CFURLCreateFromFileSystemRepresentation (NULL,
79                                                  (guchar *) filename,
80                                                  strlen (filename),
81                                                  false);
82   image_source = CGImageSourceCreateWithURL (url, NULL);
83   save_errno = errno;
84   CFRelease (url);
85
86   if (image_source == NULL)
87     {
88       /* doesn't exist, not readable, etc. */
89       g_set_error_literal (error,
90                            COGL_BITMAP_ERROR,
91                            COGL_BITMAP_ERROR_FAILED,
92                            g_strerror (save_errno));
93       return NULL;
94     }
95
96   /* Unknown images would be cleanly caught as zero width/height below, but try
97    * to provide better error message
98    */
99   type = CGImageSourceGetType (image_source);
100   if (type == NULL)
101     {
102       CFRelease (image_source);
103       g_set_error_literal (error,
104                            COGL_BITMAP_ERROR,
105                            COGL_BITMAP_ERROR_UNKNOWN_TYPE,
106                            "Unknown image type");
107       return NULL;
108     }
109
110   CFRelease (type);
111
112   image = CGImageSourceCreateImageAtIndex (image_source, 0, NULL);
113   CFRelease (image_source);
114
115   width = CGImageGetWidth (image);
116   height = CGImageGetHeight (image);
117   if (width == 0 || height == 0)
118     {
119       /* incomplete or corrupt */
120       CFRelease (image);
121       g_set_error_literal (error,
122                            COGL_BITMAP_ERROR,
123                            COGL_BITMAP_ERROR_CORRUPT_IMAGE,
124                            "Image has zero width or height");
125       return NULL;
126     }
127
128   /* allocate buffer big enough to hold pixel data */
129   bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
130                                              width, height,
131                                              COGL_PIXEL_FORMAT_ARGB_8888);
132   rowstride = cogl_bitmap_get_rowstride (bmp);
133   out_data = _cogl_bitmap_map (bmp,
134                                COGL_BUFFER_ACCESS_WRITE,
135                                COGL_BUFFER_MAP_HINT_DISCARD);
136
137   /* render to buffer */
138   color_space = CGColorSpaceCreateWithName (kCGColorSpaceGenericRGB);
139   bitmap_context = CGBitmapContextCreate (out_data,
140                                           width, height, 8,
141                                           rowstride, color_space,
142                                           kCGImageAlphaPremultipliedFirst);
143   CGColorSpaceRelease (color_space);
144
145   {
146     const CGRect rect = {{0, 0}, {width, height}};
147
148     CGContextDrawImage (bitmap_context, rect, image);
149   }
150
151   CGImageRelease (image);
152   CGContextRelease (bitmap_context);
153
154   _cogl_bitmap_unmap (bmp);
155
156   /* store bitmap info */
157   return bmp;
158 }
159
160 #elif defined(USE_GDKPIXBUF)
161
162 gboolean
163 _cogl_bitmap_get_size_from_file (const char *filename,
164                                  int        *width,
165                                  int        *height)
166 {
167   _COGL_RETURN_VAL_IF_FAIL (filename != NULL, FALSE);
168
169   if (gdk_pixbuf_get_file_info (filename, width, height) != NULL)
170     return TRUE;
171
172   return FALSE;
173 }
174
175 CoglBitmap *
176 _cogl_bitmap_from_file (const char   *filename,
177                         GError      **error)
178 {
179   static CoglUserDataKey pixbuf_key;
180   GdkPixbuf        *pixbuf;
181   gboolean          has_alpha;
182   GdkColorspace     color_space;
183   CoglPixelFormat   pixel_format;
184   int               width;
185   int               height;
186   int               rowstride;
187   int               bits_per_sample;
188   int               n_channels;
189   CoglBitmap       *bmp;
190
191   _COGL_GET_CONTEXT (ctx, NULL);
192
193   _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, FALSE);
194
195   /* Load from file using GdkPixbuf */
196   pixbuf = gdk_pixbuf_new_from_file (filename, error);
197   if (pixbuf == NULL)
198     return FALSE;
199
200   /* Get pixbuf properties */
201   has_alpha       = gdk_pixbuf_get_has_alpha (pixbuf);
202   color_space     = gdk_pixbuf_get_colorspace (pixbuf);
203   width           = gdk_pixbuf_get_width (pixbuf);
204   height          = gdk_pixbuf_get_height (pixbuf);
205   rowstride       = gdk_pixbuf_get_rowstride (pixbuf);
206   bits_per_sample = gdk_pixbuf_get_bits_per_sample (pixbuf);
207   n_channels      = gdk_pixbuf_get_n_channels (pixbuf);
208
209   /* According to current docs this should be true and so
210    * the translation to cogl pixel format below valid */
211   g_assert (bits_per_sample == 8);
212
213   if (has_alpha)
214     g_assert (n_channels == 4);
215   else
216     g_assert (n_channels == 3);
217
218   /* Translate to cogl pixel format */
219   switch (color_space)
220     {
221     case GDK_COLORSPACE_RGB:
222       /* The only format supported by GdkPixbuf so far */
223       pixel_format = has_alpha ?
224         COGL_PIXEL_FORMAT_RGBA_8888 :
225         COGL_PIXEL_FORMAT_RGB_888;
226       break;
227
228     default:
229       /* Ouch, spec changed! */
230       g_object_unref (pixbuf);
231       return FALSE;
232     }
233
234   /* We just use the data directly from the pixbuf so that we don't
235      have to copy to a seperate buffer. Note that Cogl is expected not
236      to read past the end of bpp*width on the last row even if the
237      rowstride is much larger so we don't need to worry about
238      GdkPixbuf's semantics that it may under-allocate the buffer. */
239   bmp = cogl_bitmap_new_for_data (ctx,
240                                   width,
241                                   height,
242                                   pixel_format,
243                                   rowstride,
244                                   gdk_pixbuf_get_pixels (pixbuf));
245
246   cogl_object_set_user_data (COGL_OBJECT (bmp),
247                              &pixbuf_key,
248                              pixbuf,
249                              g_object_unref);
250
251   return bmp;
252 }
253
254 #else
255
256 #include "stb_image.c"
257
258 gboolean
259 _cogl_bitmap_get_size_from_file (const char *filename,
260                                  int        *width,
261                                  int        *height)
262 {
263   if (width)
264     *width = 0;
265
266   if (height)
267     *height = 0;
268
269   return TRUE;
270 }
271
272 CoglBitmap *
273 _cogl_bitmap_from_file (const char  *filename,
274                         GError     **error)
275 {
276   static CoglUserDataKey bitmap_data_key;
277   CoglBitmap *bmp;
278   int      stb_pixel_format;
279   int      width;
280   int      height;
281   guint8  *pixels;
282
283   _COGL_GET_CONTEXT (ctx, NULL);
284
285   _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, FALSE);
286
287   /* Load from file using stb */
288   pixels = stbi_load (filename,
289                       &width, &height, &stb_pixel_format,
290                       STBI_rgb_alpha);
291   if (pixels == NULL)
292     return FALSE;
293
294   /* Store bitmap info */
295   bmp = cogl_bitmap_new_for_data (ctx,
296                                   width, height,
297                                   COGL_PIXEL_FORMAT_RGBA_8888,
298                                   width * 4, /* rowstride */
299                                   pixels);
300   /* Register a destroy function so the pixel data will be freed
301      automatically when the bitmap object is destroyed */
302   cogl_object_set_user_data (COGL_OBJECT (bmp), &bitmap_data_key, pixels, free);
303
304   return bmp;
305 }
306 #endif