[Cogl] [PATCH] bitmap: Adds cogl_android_bitmap_new_from_asset()

Robert Bragg robert at sixbynine.org
Wed Jun 20 08:10:07 PDT 2012


From: Robert Bragg <robert at linux.intel.com>

This adds some android specific api for creating a CoglBitmap from an
Android asset.

As part of the work it also seemed like a good time to change the
internal bitmap constructors to take an explicit CoglContext argument
and so the public cogl_bitmap_new_from_file() api was also changed
accordingly to take a CoglContext pointer as the first argument.
---
 cogl/cogl-bitmap-pixbuf.c  |  203 +++++++++++++++++++++++++++++++++++++-------
 cogl/cogl-bitmap-private.h |   17 +++-
 cogl/cogl-bitmap.c         |   24 +++++-
 cogl/cogl-bitmap.h         |   30 ++++++-
 cogl/cogl-texture.c        |    4 +-
 5 files changed, 241 insertions(+), 37 deletions(-)

diff --git a/cogl/cogl-bitmap-pixbuf.c b/cogl/cogl-bitmap-pixbuf.c
index abbf0cd..d30a851 100644
--- a/cogl/cogl-bitmap-pixbuf.c
+++ b/cogl/cogl-bitmap-pixbuf.c
@@ -29,6 +29,7 @@
 #include "cogl-internal.h"
 #include "cogl-bitmap-private.h"
 #include "cogl-context-private.h"
+#include "cogl-private.h"
 
 #include <string.h>
 
@@ -56,8 +57,9 @@ _cogl_bitmap_get_size_from_file (const char *filename,
 
 /* the error does not contain the filename as the caller already has it */
 CoglBitmap *
-_cogl_bitmap_from_file (const char  *filename,
-			GError     **error)
+_cogl_bitmap_from_file (CoglContext *ctx,
+                        const char *filename,
+			GError **error)
 {
   CFURLRef url;
   CGImageSourceRef image_source;
@@ -70,11 +72,6 @@ _cogl_bitmap_from_file (const char  *filename,
   CGContextRef bitmap_context;
   CoglBitmap *bmp;
 
-  _COGL_GET_CONTEXT (ctx, NULL);
-
-  g_assert (filename != NULL);
-  g_assert (error == NULL || *error == NULL);
-
   url = CFURLCreateFromFileSystemRepresentation (NULL,
                                                  (guchar *) filename,
                                                  strlen (filename),
@@ -173,8 +170,9 @@ _cogl_bitmap_get_size_from_file (const char *filename,
 }
 
 CoglBitmap *
-_cogl_bitmap_from_file (const char   *filename,
-			GError      **error)
+_cogl_bitmap_from_file (CoglContext *ctx,
+                        const char *filename,
+			GError **error)
 {
   static CoglUserDataKey pixbuf_key;
   GdkPixbuf        *pixbuf;
@@ -188,10 +186,6 @@ _cogl_bitmap_from_file (const char   *filename,
   int               n_channels;
   CoglBitmap       *bmp;
 
-  _COGL_GET_CONTEXT (ctx, NULL);
-
-  _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, FALSE);
-
   /* Load from file using GdkPixbuf */
   pixbuf = gdk_pixbuf_new_from_file (filename, error);
   if (pixbuf == NULL)
@@ -269,38 +263,187 @@ _cogl_bitmap_get_size_from_file (const char *filename,
   return TRUE;
 }
 
-CoglBitmap *
-_cogl_bitmap_from_file (const char  *filename,
-			GError     **error)
+/* stb_image.c supports an STBI_grey_alpha format which we don't have
+ * a corresponding CoglPixelFormat for so as a special case we
+ * convert this to rgba8888.
+ *
+ * If we have a use case where this is an important format to consider
+ * then it could be worth adding a corresponding CoglPixelFormat
+ * instead.
+ */
+static uint8_t *
+convert_ra_88_to_rgba_8888 (uint8_t *pixels,
+                            int width,
+                            int height)
+{
+  int x, y;
+  uint8_t *buf;
+  size_t in_stride = width * 2;
+  size_t out_stride = width * 4;
+
+  buf = malloc (width * height * 4);
+  if (buf)
+    return NULL;
+
+  for (y = 0; y < height; y++)
+    for (x = 0; x < width; x++)
+      {
+        uint8_t *src = pixels + in_stride * y + 2 * x;
+        uint8_t *dst = buf + out_stride * y + 4 * x;
+
+        dst[0] = src[0];
+        dst[1] = src[0];
+        dst[2] = src[0];
+        dst[3] = src[1];
+      }
+
+  return buf;
+}
+
+static CoglBitmap *
+_cogl_bitmap_new_from_stb_pixels (CoglContext *ctx,
+                                  uint8_t *pixels,
+                                  int stb_pixel_format,
+                                  int width,
+                                  int height,
+                                  GError **error)
 {
   static CoglUserDataKey bitmap_data_key;
   CoglBitmap *bmp;
-  int      stb_pixel_format;
-  int      width;
-  int      height;
-  uint8_t  *pixels;
+  CoglPixelFormat cogl_format;
+  size_t stride;
 
-  _COGL_GET_CONTEXT (ctx, NULL);
+  if (pixels == NULL)
+    {
+      g_set_error_literal (error,
+                           COGL_BITMAP_ERROR,
+                           COGL_BITMAP_ERROR_FAILED,
+                           "Failed to load image with stb image library");
+      return NULL;
+    }
 
-  _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, FALSE);
+  switch (stb_pixel_format)
+    {
+    case STBI_grey:
+      cogl_format = COGL_PIXEL_FORMAT_A_8;
+      break;
+    case STBI_grey_alpha:
+      {
+        uint8_t *tmp = pixels;
+
+        pixels = convert_ra_88_to_rgba_8888 (pixels, width, height);
+        free (tmp);
+
+        if (!pixels)
+          {
+            g_set_error_literal (error,
+                                 COGL_BITMAP_ERROR,
+                                 COGL_BITMAP_ERROR_FAILED,
+                                 "Failed to alloc memory to convert "
+                                 "gray_alpha to rgba8888");
+            return NULL;
+          }
+
+        cogl_format = COGL_PIXEL_FORMAT_RGBA_8888;
+        break;
+      }
+    case STBI_rgb:
+      cogl_format = COGL_PIXEL_FORMAT_RGB_888;
+      break;
+    case STBI_rgb_alpha:
+      cogl_format = COGL_PIXEL_FORMAT_RGBA_8888;
+      break;
 
-  /* Load from file using stb */
-  pixels = stbi_load (filename,
-                      &width, &height, &stb_pixel_format,
-                      STBI_rgb_alpha);
-  if (pixels == NULL)
-    return FALSE;
+    default:
+      g_warn_if_reached ();
+      return NULL;
+    }
+
+  stride = width * _cogl_pixel_format_get_bytes_per_pixel (cogl_format);
 
   /* Store bitmap info */
   bmp = cogl_bitmap_new_for_data (ctx,
                                   width, height,
-                                  COGL_PIXEL_FORMAT_RGBA_8888,
-                                  width * 4, /* rowstride */
+                                  cogl_format,
+                                  stride,
                                   pixels);
+
   /* Register a destroy function so the pixel data will be freed
      automatically when the bitmap object is destroyed */
   cogl_object_set_user_data (COGL_OBJECT (bmp), &bitmap_data_key, pixels, free);
 
   return bmp;
 }
+
+CoglBitmap *
+_cogl_bitmap_from_file (CoglContext *ctx,
+                        const char *filename,
+			GError **error)
+{
+  int stb_pixel_format;
+  int width;
+  int height;
+  uint8_t *pixels;
+
+  pixels = stbi_load (filename,
+                      &width, &height, &stb_pixel_format,
+                      STBI_default);
+
+  return _cogl_bitmap_new_from_stb_pixels (ctx, pixels, stb_pixel_format,
+                                           width, height,
+                                           error);
+}
+
+#ifdef COGL_HAS_ANDROID_SUPPORT
+CoglBitmap *
+_cogl_android_bitmap_new_from_asset (CoglContext *ctx,
+                                     AAssetManager *manager,
+                                     const char *filename,
+                                     GError **error)
+{
+  AAsset *asset;
+  const void *data;
+  off_t len;
+  int stb_pixel_format;
+  int width;
+  int height;
+  uint8_t *pixels;
+  CoglBitmap *bmp;
+
+  asset = AAssetManager_open (manager, filename, AASSET_MODE_BUFFER);
+  if (!asset)
+    {
+      g_set_error_literal (error,
+                           COGL_BITMAP_ERROR,
+                           COGL_BITMAP_ERROR_FAILED,
+                           "Failed to open asset");
+      return NULL;
+    }
+
+  data = AAsset_getBuffer (asset);
+  if (!data)
+    {
+      g_set_error_literal (error,
+                           COGL_BITMAP_ERROR,
+                           COGL_BITMAP_ERROR_FAILED,
+                           "Failed to ::getBuffer from asset");
+      return NULL;
+    }
+
+  len = AAsset_getLength (asset);
+
+  pixels = stbi_load_from_memory (data, len,
+                                  &width, &height,
+                                  &stb_pixel_format, STBI_default);
+
+  bmp = _cogl_bitmap_new_from_stb_pixels (ctx, pixels, stb_pixel_format,
+                                          width, height,
+                                          error);
+
+  AAsset_close (asset);
+
+  return bmp;
+}
+#endif
+
 #endif
diff --git a/cogl/cogl-bitmap-private.h b/cogl/cogl-bitmap-private.h
index a95754a..c74c862 100644
--- a/cogl/cogl-bitmap-private.h
+++ b/cogl/cogl-bitmap-private.h
@@ -32,6 +32,10 @@
 #include "cogl-buffer.h"
 #include "cogl-bitmap.h"
 
+#ifdef COGL_HAS_ANDROID_SUPPORT
+#include <android/asset_manager.h>
+#endif
+
 struct _CoglBitmap
 {
   CoglObject _parent;
@@ -103,8 +107,17 @@ _cogl_bitmap_convert_into_bitmap (CoglBitmap *src_bmp,
                                   CoglBitmap *dst_bmp);
 
 CoglBitmap *
-_cogl_bitmap_from_file (const char *filename,
-			GError     **error);
+_cogl_bitmap_from_file (CoglContext *ctx,
+                        const char *filename,
+			GError **error);
+
+#ifdef COGL_HAS_ANDROID_SUPPORT
+CoglBitmap *
+_cogl_android_bitmap_new_from_asset (CoglContext *ctx,
+                                     AAssetManager *manager,
+                                     const char *filename,
+                                     GError **error);
+#endif
 
 CoglBool
 _cogl_bitmap_unpremult (CoglBitmap *dst_bmp);
diff --git a/cogl/cogl-bitmap.c b/cogl/cogl-bitmap.c
index fb233df..af52de8 100644
--- a/cogl/cogl-bitmap.c
+++ b/cogl/cogl-bitmap.c
@@ -227,12 +227,14 @@ _cogl_bitmap_new_shared (CoglBitmap              *shared_bmp,
 }
 
 CoglBitmap *
-cogl_bitmap_new_from_file (const char  *filename,
-                           GError     **error)
+cogl_bitmap_new_from_file (CoglContext *ctx,
+                           const char *filename,
+                           GError **error)
 {
+  _COGL_RETURN_VAL_IF_FAIL (filename != NULL, NULL);
   _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL);
 
-  return _cogl_bitmap_from_file (filename, error);
+  return _cogl_bitmap_from_file (ctx, filename, error);
 }
 
 CoglBitmap *
@@ -293,6 +295,22 @@ cogl_bitmap_new_with_size (CoglContext *context,
   return bitmap;
 }
 
+#ifdef COGL_HAS_ANDROID_SUPPORT
+CoglBitmap *
+cogl_android_bitmap_new_from_asset (CoglContext *ctx,
+                                    AAssetManager *manager,
+                                    const char *filename,
+                                    GError **error)
+{
+  _COGL_RETURN_VAL_IF_FAIL (ctx != NULL, NULL);
+  _COGL_RETURN_VAL_IF_FAIL (manager != NULL, NULL);
+  _COGL_RETURN_VAL_IF_FAIL (filename != NULL, NULL);
+  _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL);
+
+  return _cogl_android_bitmap_new_from_asset (ctx, manager, filename, error);
+}
+#endif
+
 CoglPixelFormat
 cogl_bitmap_get_format (CoglBitmap *bitmap)
 {
diff --git a/cogl/cogl-bitmap.h b/cogl/cogl-bitmap.h
index 7900306..372315f 100644
--- a/cogl/cogl-bitmap.h
+++ b/cogl/cogl-bitmap.h
@@ -33,6 +33,10 @@
 #include <cogl/cogl-context.h>
 #include <cogl/cogl-pixel-buffer.h>
 
+#ifdef COGL_HAS_ANDROID_SUPPORT
+#include <android/asset_manager.h>
+#endif
+
 G_BEGIN_DECLS
 
 typedef struct _CoglBitmap CoglBitmap;
@@ -50,6 +54,7 @@ typedef struct _CoglBitmap CoglBitmap;
 
 /**
  * cogl_bitmap_new_from_file:
+ * @context: A #CoglContext
  * @filename: the file to load.
  * @error: a #GError or %NULL.
  *
@@ -62,9 +67,32 @@ typedef struct _CoglBitmap CoglBitmap;
  * Since: 1.0
  */
 CoglBitmap *
-cogl_bitmap_new_from_file (const char *filename,
+cogl_bitmap_new_from_file (CoglContext *context,
+                           const char *filename,
                            GError **error);
 
+#ifdef COGL_HAS_ANDROID_SUPPORT
+/**
+ * cogl_android_bitmap_new_from_asset:
+ * @context: A #CoglContext
+ * @manager: An Android Asset Manager.
+ * @filename: The file name for the asset
+ * @error: A return location for a GError exception.
+ *
+ * Loads an Android asset into a newly allocated #CoglBitmap.
+ *
+ * Return value: A newly allocated #CoglBitmap holding the image data of the
+ *               specified asset.
+ *
+ * Since: 2.0
+ */
+CoglBitmap *
+cogl_android_bitmap_new_from_asset (CoglContext *context,
+                                    AAssetManager *manager,
+                                    const char *filename,
+                                    GError **error);
+#endif
+
 #if defined (COGL_ENABLE_EXPERIMENTAL_API)
 
 /**
diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c
index d01072e..e5fdc70 100644
--- a/cogl/cogl-texture.c
+++ b/cogl/cogl-texture.c
@@ -450,9 +450,11 @@ cogl_texture_new_from_file (const char        *filename,
   CoglTexture *texture = NULL;
   CoglPixelFormat src_format;
 
+  _COGL_GET_CONTEXT (ctx, NULL);
+
   _COGL_RETURN_VAL_IF_FAIL (error == NULL || *error == NULL, NULL);
 
-  bmp = cogl_bitmap_new_from_file (filename, error);
+  bmp = cogl_bitmap_new_from_file (ctx, filename, error);
   if (bmp == NULL)
     return NULL;
 
-- 
1.7.7.6



More information about the Cogl mailing list