summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:58 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:58 +0000
commit439e6e965ce471e53cd740549743fea761c46dda (patch)
treedd7f3160d48ff24e1b30213b3e3478dc149ebd72
Initial revisionXORG-STABLE
-rw-r--r--xcursorgen.c413
-rw-r--r--xcursorgen.man47
2 files changed, 460 insertions, 0 deletions
diff --git a/xcursorgen.c b/xcursorgen.c
new file mode 100644
index 0000000..f418f99
--- /dev/null
+++ b/xcursorgen.c
@@ -0,0 +1,413 @@
+/* $XFree86: xc/programs/xcursorgen/xcursorgen.c,v 1.8 2002/11/23 02:33:20 keithp Exp $ */
+/*
+ * xcursorgen.c
+ *
+ * Copyright (C) 2002 Manish Singh
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Manish Singh not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. Manish Singh makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * MANISH SINGH DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xcursor/Xcursor.h>
+
+#include <png.h>
+
+#define VERSION_STR "0.1"
+
+struct flist
+{
+ int size;
+ int xhot, yhot;
+ char *pngfile;
+ int delay;
+ struct flist *next;
+};
+
+static void
+usage (char *name)
+{
+ fprintf (stderr, "usage: %s [-Vh] [--version] [--help] [-p <dir>] [--prefix <dir>] [CONFIG [OUT]]\n",
+ name);
+
+ fprintf (stderr, "Generate an Xcursor file from a series of PNG images\n");
+ fprintf (stderr, "\n");
+ fprintf (stderr, " -V, --version display the version number and exit\n");
+ fprintf (stderr, " -?, --help display this message and exit\n");
+ fprintf (stderr, " -p, --prefix <dir> find cursor images in <dir>\n");
+ fprintf (stderr, "\n");
+ fprintf (stderr, "With no CONFIG, or when CONFIG is -, read standard input. "
+ "Same with OUT and\n");
+ fprintf (stderr, "standard output.\n");
+}
+
+static int
+read_config_file (char *config, struct flist **list)
+{
+ FILE *fp;
+ char line[4096], pngfile[4000];
+ int size, xhot, yhot, delay;
+ struct flist *start = NULL, *end = NULL, *curr;
+ int count = 0;
+
+ if (strcmp (config, "-") != 0)
+ {
+ fp = fopen (config, "r");
+ if (!fp)
+ {
+ *list = NULL;
+ return 0;
+ }
+ }
+ else
+ fp = stdin;
+
+ while (fgets (line, sizeof (line), fp) != NULL)
+ {
+ if (line[0] == '#')
+ continue;
+
+ switch (sscanf (line, "%d %d %d %3999s %d", &size, &xhot, &yhot, pngfile, &delay))
+ {
+ case 4:
+ delay = 50;
+ break;
+ case 5:
+ break;
+ default:
+ {
+ fprintf (stderr, "Bad config file data!\n");
+ fclose (fp);
+ return 0;
+ }
+ }
+
+ curr = malloc (sizeof (struct flist));
+
+ curr->size = size;
+ curr->xhot = xhot;
+ curr->yhot = yhot;
+
+ curr->delay = delay;
+
+ curr->pngfile = malloc (strlen (pngfile) + 1);
+ strcpy (curr->pngfile, pngfile);
+
+ curr->next = NULL;
+
+ if (start)
+ {
+ end->next = curr;
+ end = curr;
+ }
+ else
+ {
+ start = curr;
+ end = curr;
+ }
+
+ count++;
+ }
+
+ fclose (fp);
+
+ *list = start;
+ return count;
+}
+
+static void
+premultiply_data (png_structp png, png_row_infop row_info, png_bytep data)
+{
+ int i;
+
+ for (i = 0; i < row_info->rowbytes; i += 4)
+ {
+ unsigned char *base = &data[i];
+ unsigned char blue = base[0];
+ unsigned char green = base[1];
+ unsigned char red = base[2];
+ unsigned char alpha = base[3];
+ XcursorPixel p;
+
+ red = (unsigned) red * (unsigned) alpha / 255;
+ green = (unsigned) green * (unsigned) alpha / 255;
+ blue = (unsigned) blue * (unsigned) alpha / 255;
+ p = (alpha << 24) | (red << 16) | (green << 8) | (blue << 0);
+ memcpy (base, &p, sizeof (XcursorPixel));
+ }
+}
+
+static XcursorImage *
+load_image (struct flist *list, char *prefix)
+{
+ XcursorImage *image;
+ png_structp png;
+ png_infop info;
+ png_bytepp rows;
+ FILE *fp;
+ int i;
+ png_uint_32 width, height;
+ int depth, color, interlace;
+ char *file;
+
+ png = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (png == NULL)
+ return NULL;
+
+ info = png_create_info_struct (png);
+ if (info == NULL)
+ {
+ png_destroy_read_struct (&png, NULL, NULL);
+ return NULL;
+ }
+
+ if (setjmp (png->jmpbuf))
+ {
+ png_destroy_read_struct (&png, &info, NULL);
+ return NULL;
+ }
+
+ if (prefix)
+ {
+ file = malloc (strlen (prefix) + 1 + strlen (list->pngfile) + 1);
+ strcpy (file, prefix);
+ strcat (file, "/");
+ strcat (file, list->pngfile);
+ }
+ else
+ file = list->pngfile;
+ fp = fopen (file, "rb");
+ if (prefix)
+ free (file);
+
+ if (fp == NULL)
+ {
+ png_destroy_read_struct (&png, &info, NULL);
+ return NULL;
+ }
+
+ png_init_io (png, fp);
+ png_read_info (png, info);
+ png_get_IHDR (png, info, &width, &height, &depth, &color, &interlace,
+ NULL, NULL);
+
+ /* TODO: More needs to be done here maybe */
+
+ if (color == PNG_COLOR_TYPE_PALETTE && depth <= 8)
+ png_set_expand (png);
+
+ if (color == PNG_COLOR_TYPE_GRAY && depth < 8)
+ png_set_expand (png);
+
+ if (png_get_valid (png, info, PNG_INFO_tRNS))
+ png_set_expand (png);
+
+ if (depth == 16)
+ png_set_strip_16 (png);
+
+ if (depth < 8)
+ png_set_packing (png);
+
+ if (color == PNG_COLOR_TYPE_GRAY || color == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb (png);
+
+ if (interlace != PNG_INTERLACE_NONE)
+ png_set_interlace_handling (png);
+
+ png_set_bgr (png);
+ png_set_filler (png, 255, PNG_FILLER_AFTER);
+
+ png_set_read_user_transform_fn (png, premultiply_data);
+
+ png_read_update_info (png, info);
+
+ image = XcursorImageCreate (width, height);
+
+ image->size = list->size;
+ image->xhot = list->xhot;
+ image->yhot = list->yhot;
+ image->delay = list->delay;
+
+ rows = malloc (sizeof (png_bytep) * height);
+
+ for (i = 0; i < height; i++)
+ rows[i] = (png_bytep) (image->pixels + i * width);
+
+ png_read_image (png, rows);
+ png_read_end (png, info);
+
+ free (rows);
+ fclose (fp);
+ png_destroy_read_struct (&png, &info, NULL);
+
+ return image;
+}
+
+static int
+write_cursors (int count, struct flist *list, char *filename, char *prefix)
+{
+ XcursorImages *cimages;
+ XcursorImage *image;
+ int i;
+ FILE *fp;
+ int ret;
+
+ if (strcmp (filename, "-") != 0)
+ {
+ fp = fopen (filename, "wb");
+ if (!fp)
+ return 1;
+ }
+ else
+ fp = stdout;
+
+ cimages = XcursorImagesCreate (count);
+
+ cimages->nimage = count;
+
+ for (i = 0; i < count; i++, list = list->next)
+ {
+ image = load_image (list, prefix);
+ if (image == NULL)
+ {
+ fprintf (stderr, "PNG error while reading %s!\n", list->pngfile);
+ return 1;
+ }
+
+ cimages->images[i] = image;
+ }
+
+ ret = XcursorFileSaveImages (fp, cimages);
+
+ fclose (fp);
+
+ return ret ? 0 : 1;
+}
+
+static int
+check_image (char *image)
+{
+ unsigned int width, height;
+ unsigned char *data;
+ int x_hot, y_hot;
+ XImage ximage;
+ unsigned char hash[XCURSOR_BITMAP_HASH_SIZE];
+ int i;
+
+ if (XReadBitmapFileData (image, &width, &height, &data, &x_hot, &y_hot) != BitmapSuccess)
+ {
+ fprintf (stderr, "Can't open bitmap file \"%s\"\n", image);
+ return 1;
+ }
+ ximage.height = height;
+ ximage.width = width;
+ ximage.depth = 1;
+ ximage.bits_per_pixel = 1;
+ ximage.xoffset = 0;
+ ximage.format = XYPixmap;
+ ximage.data = (char *)data;
+ ximage.byte_order = LSBFirst;
+ ximage.bitmap_unit = 8;
+ ximage.bitmap_bit_order = LSBFirst;
+ ximage.bitmap_pad = 8;
+ ximage.bytes_per_line = (width+7)/8;
+ XcursorImageHash (&ximage, hash);
+ printf ("%s: ", image);
+ for (i = 0; i < XCURSOR_BITMAP_HASH_SIZE; i++)
+ printf ("%02x", hash[i]);
+ printf ("\n");
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ struct flist *list;
+ int count;
+ char *in = 0, *out = 0;
+ char *prefix = 0;
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], "-V") == 0 || strcmp (argv[i], "--version") == 0)
+ {
+ printf ("xcursorgen version %s\n", VERSION_STR);
+ return 0;
+ }
+
+ if (strcmp (argv[i], "-?") == 0 || strcmp (argv[i], "--help") == 0)
+ {
+ usage (argv[0]);
+ return 0;
+ }
+ if (strcmp (argv[i], "-image") == 0)
+ {
+ int i = 2;
+ int ret = 0;
+ while (argv[i])
+ {
+ if (check_image (argv[i]))
+ ret = i;
+ i++;
+ }
+ return ret;
+ }
+ if (strcmp (argv[i], "-p") == 0 || strcmp (argv[i], "--prefix") == 0)
+ {
+ i++;
+ if (argv[i] == 0)
+ {
+ usage (argv[0]);
+ return 1;
+ }
+ prefix = argv[i];
+ continue;
+ }
+
+ if (!in)
+ in = argv[i];
+ else if (!out)
+ out = argv[i];
+ else
+ {
+ usage (argv[0]);
+ return 1;
+ }
+ }
+
+ if (!in)
+ in = "-";
+ if (!out)
+ out = "-";
+
+ count = read_config_file (in, &list);
+ if (count == 0)
+ {
+ fprintf (stderr, "Error reading config file!\n");
+ return 1;
+ }
+
+ return write_cursors (count, list, out, prefix);
+}
diff --git a/xcursorgen.man b/xcursorgen.man
new file mode 100644
index 0000000..91921e6
--- /dev/null
+++ b/xcursorgen.man
@@ -0,0 +1,47 @@
+.\"
+.\" Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of Keith Packard not be used in
+.\" advertising or publicity pertaining to distribution of the software without
+.\" specific, written prior permission. Keith Packard makes no
+.\" representations about the suitability of this software for any purpose. It
+.\" is provided "as is" without express or implied warranty.
+.\"
+.\" KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+.\" EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+.\" CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+.\" DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+.\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+.\" PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\"
+.\" $XFree86: xc/programs/xcursorgen/xcursorgen.man,v 1.2 2003/01/04 02:59:18 dawes Exp $
+.\"
+.TH XCURSORGEN 1 __vendorversion__
+.SH NAME
+xcursorgen \- create an X cursor file from a collection of PNG images
+.SH SYNOPSIS
+.B "xcursorgen"
+.RI [ config-file ]
+.RI [ output-file ]
+.SH DESCRIPTION
+Xcursorgen reads the config-file to find the list of cursor images along
+with their hotspot and nominal size information. Xcursorgen converts all of
+the images to Xcursor format and writes them to the output-file.
+.P
+Each line in the config file is of the form:
+.br
+<size> <xhot> <yhot> <filename> <ms-delay>
+.br
+.P
+Multiple images with the same <size> are used to create animated cursors,
+the <ms-delay> value on each line indicates how long each image should be
+displayed before switching to the next. <ms-delay> can be elided for static
+cursors.
+.SH "SEE ALSO"
+Xcursor(3x)