Blame src/gd_xbm.c

Packit ed3af9
/**
Packit ed3af9
 * File: XBM IO
Packit ed3af9
 *
Packit ed3af9
 * Read and write XBM images.
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
#ifdef HAVE_CONFIG_H
Packit ed3af9
#	include "config.h"
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#include <ctype.h>
Packit ed3af9
#include <stdio.h>
Packit ed3af9
#include <math.h>
Packit ed3af9
#include <string.h>
Packit ed3af9
#include <stdlib.h>
Packit ed3af9
#include <stdarg.h>
Packit ed3af9
#include "gd.h"
Packit ed3af9
#include "gd_errors.h"
Packit ed3af9
#include "gdhelpers.h"
Packit ed3af9
Packit ed3af9
#ifdef _MSC_VER
Packit ed3af9
# define strcasecmp _stricmp
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#define MAX_XBM_LINE_SIZE 255
Packit ed3af9
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
  Function: gdImageCreateFromXbm
Packit ed3af9
Packit ed3af9
    <gdImageCreateFromXbm> is called to load images from X bitmap
Packit ed3af9
    format files. Invoke <gdImageCreateFromXbm> with an already opened
Packit ed3af9
    pointer to a file containing the desired
Packit ed3af9
    image. <gdImageCreateFromXbm> returns a <gdImagePtr> to the new
Packit ed3af9
    image, or NULL if unable to load the image (most often because the
Packit ed3af9
    file is corrupt or does not contain an X bitmap format
Packit ed3af9
    image). <gdImageCreateFromXbm> does not close the file.
Packit ed3af9
Packit ed3af9
    You can inspect the sx and sy members of the image to determine
Packit ed3af9
    its size. The image must eventually be destroyed using
Packit ed3af9
    <gdImageDestroy>.
Packit ed3af9
Packit ed3af9
    X11 X bitmaps (which define a char[]) as well as X10 X bitmaps (which define
Packit ed3af9
    a short[]) are supported.
Packit ed3af9
Packit ed3af9
  Parameters:
Packit ed3af9
Packit ed3af9
    fd - The input FILE pointer
Packit ed3af9
Packit ed3af9
  Returns:
Packit ed3af9
Packit ed3af9
    A pointer to the new image or NULL if an error occurred.
Packit ed3af9
Packit ed3af9
  Example:
Packit ed3af9
    (start code)
Packit ed3af9
Packit ed3af9
    gdImagePtr im;
Packit ed3af9
    FILE *in;
Packit ed3af9
    in = fopen("myxbm.xbm", "rb");
Packit ed3af9
    im = gdImageCreateFromXbm(in);
Packit ed3af9
    fclose(in);
Packit ed3af9
    // ... Use the image ...
Packit ed3af9
    gdImageDestroy(im);
Packit ed3af9
Packit ed3af9
    (end code)
Packit ed3af9
*/
Packit ed3af9
BGD_DECLARE(gdImagePtr) gdImageCreateFromXbm(FILE * fd)
Packit ed3af9
{
Packit ed3af9
	char fline[MAX_XBM_LINE_SIZE];
Packit ed3af9
	char iname[MAX_XBM_LINE_SIZE];
Packit ed3af9
	char *type;
Packit ed3af9
	int value;
Packit ed3af9
	unsigned int width = 0, height = 0;
Packit ed3af9
	int fail = 0;
Packit ed3af9
	int max_bit = 0;
Packit ed3af9
Packit ed3af9
	gdImagePtr im;
Packit ed3af9
	int bytes = 0, i;
Packit ed3af9
	int bit, x = 0, y = 0;
Packit ed3af9
	int ch;
Packit ed3af9
	char h[8];
Packit ed3af9
	unsigned int b;
Packit ed3af9
Packit ed3af9
	rewind(fd);
Packit ed3af9
	while (fgets(fline, MAX_XBM_LINE_SIZE, fd)) {
Packit ed3af9
		fline[MAX_XBM_LINE_SIZE-1] = '\0';
Packit ed3af9
		if (strlen(fline) == MAX_XBM_LINE_SIZE-1) {
Packit ed3af9
			return 0;
Packit ed3af9
		}
Packit ed3af9
		if (sscanf(fline, "#define %s %d", iname, &value) == 2) {
Packit ed3af9
			if (!(type = strrchr(iname, '_'))) {
Packit ed3af9
				type = iname;
Packit ed3af9
			} else {
Packit ed3af9
				type++;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			if (!strcmp("width", type)) {
Packit ed3af9
				width = (unsigned int) value;
Packit ed3af9
			}
Packit ed3af9
			if (!strcmp("height", type)) {
Packit ed3af9
				height = (unsigned int) value;
Packit ed3af9
			}
Packit ed3af9
		} else {
Packit ed3af9
			if ( sscanf(fline, "static unsigned char %s = {", iname) == 1
Packit ed3af9
			  || sscanf(fline, "static char %s = {", iname) == 1)
Packit ed3af9
			{
Packit ed3af9
				max_bit = 128;
Packit ed3af9
			} else if (sscanf(fline, "static unsigned short %s = {", iname) == 1
Packit ed3af9
					|| sscanf(fline, "static short %s = {", iname) == 1)
Packit ed3af9
			{
Packit ed3af9
				max_bit = 32768;
Packit ed3af9
			}
Packit ed3af9
			if (max_bit) {
Packit ed3af9
                bytes = (width + 7) / 8 * height;
Packit ed3af9
				if (!bytes) {
Packit ed3af9
					return 0;
Packit ed3af9
				}
Packit ed3af9
				if (!(type = strrchr(iname, '_'))) {
Packit ed3af9
					type = iname;
Packit ed3af9
				} else {
Packit ed3af9
					type++;
Packit ed3af9
				}
Packit ed3af9
				if (!strcmp("bits[]", type)) {
Packit ed3af9
					break;
Packit ed3af9
				}
Packit ed3af9
			}
Packit ed3af9
 		}
Packit ed3af9
	}
Packit ed3af9
	if (!bytes || !max_bit) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if(!(im = gdImageCreate(width, height))) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
	gdImageColorAllocate(im, 255, 255, 255);
Packit ed3af9
	gdImageColorAllocate(im, 0, 0, 0);
Packit ed3af9
	h[2] = '\0';
Packit ed3af9
	h[4] = '\0';
Packit ed3af9
	for (i = 0; i < bytes; i++) {
Packit ed3af9
		while (1) {
Packit ed3af9
			if ((ch=getc(fd)) == EOF) {
Packit ed3af9
				fail = 1;
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
			if (ch == 'x') {
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		if (fail) {
Packit ed3af9
			break;
Packit ed3af9
		}
Packit ed3af9
		/* Get hex value */
Packit ed3af9
		if ((ch=getc(fd)) == EOF) {
Packit ed3af9
			break;
Packit ed3af9
		}
Packit ed3af9
		h[0] = ch;
Packit ed3af9
		if ((ch=getc(fd)) == EOF) {
Packit ed3af9
			break;
Packit ed3af9
		}
Packit ed3af9
		h[1] = ch;
Packit ed3af9
		if (max_bit == 32768) {
Packit ed3af9
			if ((ch=getc(fd)) == EOF) {
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
			h[2] = ch;
Packit ed3af9
			if ((ch=getc(fd)) == EOF) {
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
			h[3] = ch;
Packit ed3af9
		}
Packit ed3af9
		sscanf(h, "%x", &b);
Packit ed3af9
		for (bit = 1; bit <= max_bit; bit = bit << 1) {
Packit ed3af9
			gdImageSetPixel(im, x++, y, (b & bit) ? 1 : 0);
Packit ed3af9
			if (x == im->sx) {
Packit ed3af9
				x = 0;
Packit ed3af9
				y++;
Packit ed3af9
				if (y == im->sy) {
Packit ed3af9
					return im;
Packit ed3af9
				}
Packit ed3af9
				break;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	gd_error("EOF before image was complete");
Packit ed3af9
	gdImageDestroy(im);
Packit ed3af9
	return 0;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
Packit ed3af9
/* {{{ gdCtxPrintf */
Packit ed3af9
static void gdCtxPrintf(gdIOCtx * out, const char *format, ...)
Packit ed3af9
{
Packit ed3af9
	char buf[1024];
Packit ed3af9
	int len;
Packit ed3af9
	va_list args;
Packit ed3af9
Packit ed3af9
	va_start(args, format);
Packit ed3af9
	len = vsnprintf(buf, sizeof(buf)-1, format, args);
Packit ed3af9
	va_end(args);
Packit ed3af9
	out->putBuf(out, buf, len);
Packit ed3af9
}
Packit ed3af9
/* }}} */
Packit ed3af9
Packit ed3af9
/* The compiler will optimize strlen(constant) to a constant number. */
Packit ed3af9
#define gdCtxPuts(out, s) out->putBuf(out, s, strlen(s))
Packit ed3af9
Packit ed3af9
Packit ed3af9
/**
Packit ed3af9
 * Function: gdImageXbmCtx
Packit ed3af9
 *
Packit ed3af9
 *  Writes an image to an IO context in X11 bitmap format.
Packit ed3af9
 *
Packit ed3af9
 * Parameters:
Packit ed3af9
 *
Packit ed3af9
 *  image     - The <gdImagePtr> to write.
Packit ed3af9
 *  file_name - The prefix of the XBM's identifiers. Illegal characters are
Packit ed3af9
 *              automatically stripped.
Packit ed3af9
 *  gd        - Which color to use as forground color. All pixels with another
Packit ed3af9
 *              color are unset.
Packit ed3af9
 *  out       - The <gdIOCtx> to write the image file to.
Packit ed3af9
 * 
Packit ed3af9
 */
Packit ed3af9
BGD_DECLARE(void) gdImageXbmCtx(gdImagePtr image, char* file_name, int fg, gdIOCtx * out)
Packit ed3af9
{
Packit ed3af9
	int x, y, c, b, sx, sy, p;
Packit ed3af9
	char *name, *f;
Packit ed3af9
	size_t i, l;
Packit ed3af9
Packit ed3af9
	name = file_name;
Packit ed3af9
	if ((f = strrchr(name, '/')) != NULL) name = f+1;
Packit ed3af9
	if ((f = strrchr(name, '\\')) != NULL) name = f+1;
Packit ed3af9
	name = strdup(name);
Packit ed3af9
	if ((f = strrchr(name, '.')) != NULL && !strcasecmp(f, ".XBM")) *f = '\0';
Packit ed3af9
	if ((l = strlen(name)) == 0) {
Packit ed3af9
		free(name);
Packit ed3af9
		name = strdup("image");
Packit ed3af9
	} else {
Packit ed3af9
		for (i=0; i
Packit ed3af9
			/* only in C-locale isalnum() would work */
Packit ed3af9
			if (!isupper(name[i]) && !islower(name[i]) && !isdigit(name[i])) {
Packit ed3af9
				name[i] = '_';
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* Since "name" comes from the user, run it through a direct puts.
Packit ed3af9
	 * Trying to printf it into a local buffer means we'd need a large
Packit ed3af9
	 * or dynamic buffer to hold it all. */
Packit ed3af9
Packit ed3af9
	/* #define <name>_width 1234 */
Packit ed3af9
	gdCtxPuts(out, "#define ");
Packit ed3af9
	gdCtxPuts(out, name);
Packit ed3af9
	gdCtxPuts(out, "_width ");
Packit ed3af9
	gdCtxPrintf(out, "%d\n", gdImageSX(image));
Packit ed3af9
Packit ed3af9
	/* #define <name>_height 1234 */
Packit ed3af9
	gdCtxPuts(out, "#define ");
Packit ed3af9
	gdCtxPuts(out, name);
Packit ed3af9
	gdCtxPuts(out, "_height ");
Packit ed3af9
	gdCtxPrintf(out, "%d\n", gdImageSY(image));
Packit ed3af9
Packit ed3af9
	/* static unsigned char <name>_bits[] = {\n */
Packit ed3af9
	gdCtxPuts(out, "static unsigned char ");
Packit ed3af9
	gdCtxPuts(out, name);
Packit ed3af9
	gdCtxPuts(out, "_bits[] = {\n  ");
Packit ed3af9
Packit ed3af9
	free(name);
Packit ed3af9
Packit ed3af9
	b = 1;
Packit ed3af9
	p = 0;
Packit ed3af9
	c = 0;
Packit ed3af9
	sx = gdImageSX(image);
Packit ed3af9
	sy = gdImageSY(image);
Packit ed3af9
	for (y = 0; y < sy; y++) {
Packit ed3af9
		for (x = 0; x < sx; x++) {
Packit ed3af9
			if (gdImageGetPixel(image, x, y) == fg) {
Packit ed3af9
				c |= b;
Packit ed3af9
			}
Packit ed3af9
			if ((b == 128) || (x == sx - 1)) {
Packit ed3af9
				b = 1;
Packit ed3af9
				if (p) {
Packit ed3af9
					gdCtxPuts(out, ", ");
Packit ed3af9
					if (!(p%12)) {
Packit ed3af9
						gdCtxPuts(out, "\n  ");
Packit ed3af9
						p = 12;
Packit ed3af9
					}
Packit ed3af9
				}
Packit ed3af9
				p++;
Packit ed3af9
				gdCtxPrintf(out, "0x%02X", c);
Packit ed3af9
				c = 0;
Packit ed3af9
			} else {
Packit ed3af9
				b <<= 1;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
	gdCtxPuts(out, "};\n");
Packit ed3af9
}