aboutsummaryrefslogtreecommitdiff
path: root/src/image.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/image.c')
-rw-r--r--src/image.c362
1 files changed, 362 insertions, 0 deletions
diff --git a/src/image.c b/src/image.c
new file mode 100644
index 0000000..af52ae7
--- /dev/null
+++ b/src/image.c
@@ -0,0 +1,362 @@
+/****************************************************************************
+ * Functions to load images.
+ * Copyright (C) 2005 Joe Wingbermuehle
+ ****************************************************************************/
+
+#include "jwm.h"
+#include "image.h"
+#include "main.h"
+#include "error.h"
+#include "color.h"
+
+static ImageNode *LoadPNGImage(const char *fileName);
+static ImageNode *LoadXPMImage(const char *fileName);
+static ImageNode *CreateImageFromXImages(XImage *image, XImage *shape);
+
+#ifdef USE_XPM
+static int AllocateColor(Display *d, Colormap cmap, char *name,
+ XColor *c, void *closure);
+static int FreeColors(Display *d, Colormap cmap, Pixel *pixels, int n,
+ void *closure);
+#endif
+
+/****************************************************************************
+ ****************************************************************************/
+ImageNode *LoadImage(const char *fileName) {
+
+ ImageNode *result;
+
+ if(!fileName) {
+ return NULL;
+ }
+
+ /* Attempt to load the file as a PNG image. */
+ result = LoadPNGImage(fileName);
+ if(result) {
+ return result;
+ }
+
+ /* Attempt to load the file as an XPM image. */
+ result = LoadXPMImage(fileName);
+ if(result) {
+ return result;
+ }
+
+ return NULL;
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+ImageNode *LoadImageFromData(char **data) {
+
+ ImageNode *result = NULL;
+
+#ifdef USE_XPM
+
+ XpmAttributes attr;
+ XImage *image;
+ XImage *shape;
+ int rc;
+
+ Assert(data);
+
+ attr.valuemask = XpmAllocColor | XpmFreeColors | XpmColorClosure;
+ attr.alloc_color = AllocateColor;
+ attr.free_colors = FreeColors;
+ attr.color_closure = NULL;
+ rc = XpmCreateImageFromData(display, data, &image, &shape, &attr);
+ if(rc == XpmSuccess) {
+ result = CreateImageFromXImages(image, shape);
+ JXDestroyImage(image);
+ if(shape) {
+ JXDestroyImage(shape);
+ }
+ }
+
+#endif
+
+ return result;
+
+}
+
+/****************************************************************************
+ * Load a PNG image from the given file name. Returns NULL on error.
+ * Since libpng uses longjmp, this function is not reentrant to simplify
+ * the issues surrounding longjmp and local variables.
+ ****************************************************************************/
+ImageNode *LoadPNGImage(const char *fileName) {
+
+#ifdef USE_PNG
+
+ static ImageNode *result;
+ static FILE *fd;
+ static unsigned char **rows;
+ static png_structp pngData;
+ static png_infop pngInfo;
+ static png_infop pngEndInfo;
+ static unsigned char *data;
+
+ unsigned char header[8];
+ unsigned long rowBytes;
+ int bitDepth, colorType;
+ unsigned int x, y;
+ unsigned long temp;
+
+ Assert(fileName);
+
+ result = NULL;
+ fd = NULL;
+ rows = NULL;
+ pngData = NULL;
+ pngInfo = NULL;
+ pngEndInfo = NULL;
+ data = NULL;
+
+ fd = fopen(fileName, "rb");
+ if(!fd) {
+ return NULL;
+ }
+
+ x = fread(header, 1, sizeof(header), fd);
+ if(x != sizeof(header) || png_sig_cmp(header, 0, sizeof(header))) {
+ fclose(fd);
+ return NULL;
+ }
+
+ pngData = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if(!pngData) {
+ fclose(fd);
+ Warning("could not create read struct for PNG image: %s", fileName);
+ return NULL;
+ }
+
+ if(setjmp(png_jmpbuf(pngData))) {
+ png_destroy_read_struct(&pngData, &pngInfo, &pngEndInfo);
+ if(fd) {
+ fclose(fd);
+ }
+ if(rows) {
+ Release(rows);
+ }
+ if(result) {
+ if(result->data) {
+ Release(result->data);
+ }
+ Release(result);
+ }
+ Warning("error reading PNG image: %s", fileName);
+ }
+
+ pngInfo = png_create_info_struct(pngData);
+ if(!pngInfo) {
+ png_destroy_read_struct(&pngData, NULL, NULL);
+ fclose(fd);
+ Warning("could not create info struct for PNG image: %s", fileName);
+ return NULL;
+ }
+
+ pngEndInfo = png_create_info_struct(pngData);
+ if(!pngEndInfo) {
+ png_destroy_read_struct(&pngData, &pngInfo, NULL);
+ fclose(fd);
+ Warning("could not create end info struct for PNG image: %s", fileName);
+ return NULL;
+ }
+
+ png_init_io(pngData, fd);
+ png_set_sig_bytes(pngData, sizeof(header));
+
+ png_read_info(pngData, pngInfo);
+
+ result = Allocate(sizeof(ImageNode));
+
+ png_get_IHDR(pngData, pngInfo, &result->width, &result->height,
+ &bitDepth, &colorType, NULL, NULL, NULL);
+
+ png_set_expand(pngData);
+
+ if(bitDepth == 16) {
+ png_set_strip_16(pngData);
+ } else if(bitDepth < 8) {
+ png_set_packing(pngData);
+ }
+
+ png_set_swap_alpha(pngData);
+ png_set_filler(pngData, 0xFF, PNG_FILLER_BEFORE);
+
+ if(colorType == PNG_COLOR_TYPE_GRAY
+ || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
+ png_set_gray_to_rgb(pngData);
+ }
+
+ png_read_update_info(pngData, pngInfo);
+
+ rowBytes = png_get_rowbytes(pngData, pngInfo);
+ data = Allocate(rowBytes * result->height);
+
+ rows = AllocateStack(result->height * sizeof(result->data));
+
+ y = 0;
+ for(x = 0; x < result->height; x++) {
+ rows[x] = &data[y];
+ y += result->width * 4;
+ }
+
+ png_read_image(pngData, rows);
+
+ png_read_end(pngData, pngInfo);
+ png_destroy_read_struct(&pngData, &pngInfo, &pngEndInfo);
+
+ fclose(fd);
+
+ /* Convert the row data to ARGB format. */
+ /* Source is stored ARGB bytes. */
+ /* Destination is stored in unsigned longs with A most significant. */
+ result->data = Allocate(sizeof(unsigned long)
+ * result->width * result->height);
+ for(y = 0; y < result->height; y++) {
+ for(x = 0; x < result->width; x++) {
+ temp = (unsigned long)rows[y][4 * x + 0] << 24;
+ temp |= (unsigned long)rows[y][4 * x + 1] << 16;
+ temp |= (unsigned long)rows[y][4 * x + 2] << 8;
+ temp |= (unsigned long)rows[y][4 * x + 3] << 0;
+ result->data[y * result->width + x] = temp;
+ }
+ }
+
+ ReleaseStack(rows);
+ Release(data);
+
+ return result;
+
+#else
+
+ return NULL;
+
+#endif
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+ImageNode *LoadXPMImage(const char *fileName) {
+
+ ImageNode *result = NULL;
+
+#ifdef USE_XPM
+
+ XpmAttributes attr;
+ XImage *image;
+ XImage *shape;
+ int rc;
+
+ Assert(fileName);
+
+ attr.valuemask = XpmAllocColor | XpmFreeColors | XpmColorClosure;
+ attr.alloc_color = AllocateColor;
+ attr.free_colors = FreeColors;
+ attr.color_closure = NULL;
+ rc = XpmReadFileToImage(display, (char*)fileName, &image, &shape, &attr);
+ if(rc == XpmSuccess) {
+ result = CreateImageFromXImages(image, shape);
+
+ JXDestroyImage(image);
+ if(shape) {
+ JXDestroyImage(shape);
+ }
+ }
+
+#endif
+
+ return result;
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+ImageNode *CreateImageFromXImages(XImage *image, XImage *shape) {
+
+ ImageNode *result;
+ XColor color;
+ unsigned long red, green, blue, alpha;
+ int index;
+ int x, y;
+
+ result = Allocate(sizeof(ImageNode));
+ result->data = Allocate(sizeof(unsigned long)
+ * image->width * image->height);
+ result->width = image->width;
+ result->height = image->height;
+
+ index = 0;
+ for(y = 0; y < image->height; y++) {
+ for(x = 0; x < image->width; x++) {
+
+ color.pixel = XGetPixel(image, x, y);
+ GetColorFromIndex(&color);
+
+ red = color.red >> 8;
+ green = color.green >> 8;
+ blue = color.blue >> 8;
+
+ alpha = 0;
+ if(!shape || XGetPixel(shape, x, y)) {
+ alpha = 255;
+ }
+
+ result->data[index] = alpha << 24;
+ result->data[index] |= red << 16;
+ result->data[index] |= green << 8;
+ result->data[index] |= blue;
+ ++index;
+
+ }
+ }
+
+ return result;
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+void DestroyImage(ImageNode *image) {
+ if(image) {
+ Release(image->data);
+ Release(image);
+ }
+}
+
+/****************************************************************************
+ * Function to allocate a color for libxpm.
+ ****************************************************************************/
+#ifdef USE_XPM
+int AllocateColor(Display *d, Colormap cmap, char *name,
+ XColor *c, void *closure)
+{
+
+ if(name) {
+ if(!JXParseColor(d, cmap, name, c)) {
+ return -1;
+ }
+ }
+
+ GetColorIndex(c);
+ return 1;
+
+}
+#endif
+
+/****************************************************************************
+ * Function to free colors allocated by libxpm.
+ * We don't need to do anything here as color.c takes care of this.
+ ****************************************************************************/
+#ifdef USE_XPM
+int FreeColors(Display *d, Colormap cmap, Pixel *pixels, int n,
+ void *closure) {
+
+ return 1;
+
+}
+#endif
+