aboutsummaryrefslogtreecommitdiff
path: root/img-load.c
diff options
context:
space:
mode:
Diffstat (limited to 'img-load.c')
-rw-r--r--img-load.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/img-load.c b/img-load.c
new file mode 100644
index 0000000..d4f4bea
--- /dev/null
+++ b/img-load.c
@@ -0,0 +1,219 @@
+#include "plugin-img.h"
+
+static inline void
+rgb565_to_rgb(const guint16 * rgb565, guint8 * res)
+{
+ /*
+ * How to:
+ * | 16 bits |
+ * | high || low |
+ * 11111 111111 11111
+ * | B | | G | | R |
+ * 111110001111110011111000
+ * | B || G || R |
+ * | 24 bits |
+ *
+ */
+ res[0] = (guint8) (((*rgb565) & 0x1F) << 3); /* Red */
+ res[1] = (guint8) (((*rgb565) & 0x7E0) >> 3); /* Green */
+ res[2] = (guint8) (((*rgb565) & 0xF800) >> 8); /* Blue */
+}
+
+static void
+img_map_rgb565_to_rgb(const guint8 * src, guint8 * dest, size_t src_size)
+{
+ size_t s, d;
+
+ /*
+ * 5+6+5=16bits (2 bytes) per pixel
+ */
+ for (s = 0, d = 0; s < src_size;)
+ {
+ rgb565_to_rgb((const guint16 *)&(src[s]), &(dest[d]));
+ s += 2;
+ d += 3;
+ }
+}
+
+gint32
+img_load_image(const gchar * filename, ImageParasite * meta, GError ** error)
+{
+ FILE *fp;
+ size_t nread;
+ size_t src_size;
+ guint8 *src, *dest;
+ FileHeader hdr;
+ ColorKey ckey;
+ guint32 row, col, width, height;
+ gint32 frame, nframes, *frames;
+ gchar buf[20];
+ gint32 image, layer;
+ GimpDrawable *drawable;
+ GimpPixelRgn pixel_rgn;
+ GimpImageType image_type;
+
+ ckey.is = 0;
+ ckey.R = 0;
+ ckey.G = 0;
+ ckey.B = 0;
+ gimp_progress_init_printf("Opening '%s'", gimp_filename_to_utf8(filename));
+
+ D(("*** Loading \"%s\"\n", filename));
+ fp = g_fopen(filename, "rb");
+ if (!fp)
+ {
+ g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno), "%s",
+ g_strerror(errno));
+ return -1;
+ }
+
+ /*
+ * Read common header
+ */
+ nread = fread((void *)&hdr, sizeof(hdr), 1, fp);
+ if (nread != 1)
+ {
+ D(("Error reading file header: %s\n", g_strerror(errno)));
+ g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno),
+ "Error reading file header: %s\n", g_strerror(errno));
+ fclose(fp);
+ return -1;
+ }
+ hdr.nrows = GUINT32_FROM_LE(hdr.nrows);
+ hdr.ncols = GUINT32_FROM_LE(hdr.ncols);
+ hdr.width = GUINT32_FROM_LE(hdr.width);
+ hdr.height = GUINT32_FROM_LE(hdr.height);
+
+ /*
+ * Width and height are TOTAL ones
+ */
+ if ((0 == hdr.ncols) || (0 == hdr.nrows) || (hdr.width % hdr.ncols) ||
+ (hdr.height % hdr.nrows))
+ {
+ D(("Invalid file geometry: frames: %ux%u, size: %ux%u\n", hdr.ncols,
+ hdr.nrows, hdr.width, hdr.height));
+ g_set_error(error, 0, 0,
+ "Invalid file geometry: frames: %ux%u, size: %ux%u\n",
+ hdr.ncols, hdr.nrows, hdr.width, hdr.height);
+ fclose(fp);
+ return -1;
+ }
+ width = hdr.width / hdr.ncols;
+ height = hdr.height / hdr.nrows;
+
+ src_size = width * height;
+ switch (hdr.fmt)
+ {
+ case FMT_RGB565:
+ src_size *= 2;
+ image_type = GIMP_RGB_IMAGE;
+ break;
+ case FMT_RGB:
+ src_size *= 3;
+ image_type = GIMP_RGB_IMAGE;
+ /*
+ * Read color key
+ */
+ nread = fread((void *)&ckey, sizeof(ckey), 1, fp);
+ if (nread != 1)
+ {
+ D(("Error reading color key: %s\n", g_strerror(errno)));
+ g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno),
+ "Error reading color key: %s\n", g_strerror(errno));
+ fclose(fp);
+ return -1;
+ }
+ if (ckey.is != 0)
+ ckey.is = 1; /* Normalize */
+
+ break;
+ case FMT_RGBA:
+ src_size *= 4; /* Alpha only for RGBA */
+ image_type = GIMP_RGBA_IMAGE;
+ break;
+ default:
+ D(("Invalid file format: %1u\n", hdr.fmt));
+ g_set_error(error, 0, 0, "Invalid file format: %1u\n", hdr.fmt);
+ fclose(fp);
+ return -1;
+ }
+
+ D(("Format: %s (%u), frames: %ux%u, size: %ux%u\n", FMT[hdr.fmt], hdr.fmt,
+ hdr.ncols, hdr.nrows, hdr.width, hdr.height));
+ __DEBUG(if (ckey.is)
+ D(("Has color key: (%1u, %1u, %1u)\n", ckey.R, ckey.G, ckey.B)));
+
+ /*
+ * We are ready to make image with layers
+ */
+ image = gimp_image_new(width, height, GIMP_RGB);
+ gimp_image_set_filename(image, filename);
+
+ frame = 0;
+ nframes = hdr.nrows * hdr.ncols;
+ src = g_new(guint8, src_size);
+ dest = (hdr.fmt == FMT_RGB565) ? g_new(guint8, width * height * 3) : NULL;
+ for (row = 1; row <= hdr.nrows; row++)
+ {
+ for (col = 1; col <= hdr.ncols; col++)
+ {
+ frame++;
+ gimp_progress_update((gdouble) frame / (gdouble) nframes);
+ D(("Reading frame #%u of %u (%ux%u, %u bytes)\n", frame, nframes,
+ width, height, src_size));
+ g_snprintf(buf, sizeof(buf), "#%i", frame);
+ layer =
+ gimp_layer_new(image, buf, width, height, image_type, 100,
+ GIMP_NORMAL_MODE);
+ gimp_image_add_layer(image, layer, frame - 1);
+ drawable = gimp_drawable_get(layer);
+ gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, width, height, TRUE,
+ FALSE);
+
+ nread = fread((char *)src, src_size, 1, fp);
+ if (nread != 1)
+ {
+ D(("Invalid image data\n"));
+ g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno),
+ "Invalid image data\n");
+
+ if (dest)
+ g_free(dest);
+ g_free(src);
+ fclose(fp);
+ return -1;
+ }
+ if (hdr.fmt == FMT_RGB565)
+ {
+ img_map_rgb565_to_rgb(src, dest, src_size);
+ gimp_pixel_rgn_set_rect(&pixel_rgn, (const guchar *)dest, 0, 0,
+ width, height);
+ }
+ else
+ {
+ gimp_pixel_rgn_set_rect(&pixel_rgn, (const guchar *)src, 0, 0,
+ width, height);
+ }
+ gimp_drawable_detach(drawable);
+ }
+ }
+
+ frames = gimp_image_get_layers(image, (gint32 *) & nframes);
+ if (nframes > 0)
+ {
+ gimp_image_set_active_layer(image, frames[0]);
+ g_free(frames);
+ }
+
+ if (dest)
+ g_free(dest);
+ g_free(src);
+ fclose(fp);
+
+ meta->format = hdr.fmt;
+ meta->ckey = ckey;
+ gimp_progress_update(1.0);
+ D(("*** Loaded \"%s\"\n", filename));
+
+ return image;
+}