xcursorgen.c (10631B)
- /*
- * xcursorgen.c
- *
- * Copyright (C) 2002 Manish Singh
- *
- * SPDX-License-Identifier: MIT
- *
- * 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 MANISH SINGH 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.
- */
- #define _POSIX_C_SOURCE 200809L
- #include "Xcursor/Xcursor.h"
- #include "config.h"
- #include <ctype.h>
- #include <errno.h>
- #include <png.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- static const char *ProgramName;
- struct flist
- {
- int size;
- int xhot, yhot;
- int delay;
- char *pngfile;
- struct flist *next;
- };
- static void
- usage(const char *name)
- {
- fprintf(stderr,
- "usage: %s [-V] [--version] [-?] [--help] [-p <dir>] [--prefix <dir>] [CONFIG [OUT]]\n%s",
- name,
- "Generate an Xcursor file from a series of PNG images\n"
- "\n"
- " -V, --version display the version number and exit\n"
- " -?, --help display this message and exit\n"
- " -p, --prefix <dir> find cursor images in <dir>\n"
- "\n"
- "With no CONFIG, or when CONFIG is -, read standard input. "
- "Same with OUT and\n"
- "standard output.\n");
- }
- static int
- read_config_file(const 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,
- "%s: Bad config file data on line %d of %s\n",
- ProgramName,
- count + 1,
- strcmp(config, "-") ? config : "stdin");
- fclose(fp);
- return 0;
- }
- }
- curr = malloc(sizeof(struct flist));
- if(curr == NULL)
- {
- fprintf(stderr, "%s: malloc() failed: %s\n", ProgramName, strerror(errno));
- fclose(fp);
- return 0;
- }
- curr->size = size;
- curr->xhot = xhot;
- curr->yhot = yhot;
- curr->delay = delay;
- curr->pngfile = strdup(pngfile);
- if(curr->pngfile == NULL)
- {
- fprintf(stderr, "%s: strdup() failed: %s\n", ProgramName, strerror(errno));
- fclose(fp);
- free(curr);
- return 0;
- }
- curr->next = NULL;
- if(start)
- {
- end->next = curr;
- end = curr;
- }
- else
- {
- start = curr;
- end = curr;
- }
- count++;
- }
- fclose(fp);
- *list = start;
- return count;
- }
- #define div_255(x) (((x) + 0x80 + (((x) + 0x80) >> 8)) >> 8)
- static void
- premultiply_data(png_structp png, png_row_infop row_info, png_bytep data)
- {
- png_size_t 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 char)div_255((unsigned)red * (unsigned)alpha);
- green = (unsigned char)div_255((unsigned)green * (unsigned)alpha);
- blue = (unsigned char)div_255((unsigned)blue * (unsigned)alpha);
- p = ((unsigned int)alpha << 24) | ((unsigned int)red << 16) | ((unsigned int)green << 8) |
- ((unsigned int)blue << 0);
- memcpy(base, &p, sizeof(XcursorPixel));
- }
- }
- static XcursorImage *
- load_image(struct flist *list, const char *prefix)
- {
- XcursorImage *image;
- png_structp png;
- png_infop info;
- png_bytepp rows;
- FILE *fp;
- png_uint_32 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)))
- {
- png_destroy_read_struct(&png, &info, NULL);
- return NULL;
- }
- if(prefix)
- {
- #ifdef HAVE_ASPRINTF
- if(asprintf(&file, "%s/%s", prefix, list->pngfile) == -1)
- {
- fprintf(stderr, "%s: asprintf() failed: %s\n", ProgramName, strerror(errno));
- png_destroy_read_struct(&png, &info, NULL);
- return NULL;
- }
- #else
- file = malloc(strlen(prefix) + 1 + strlen(list->pngfile) + 1);
- if(file == NULL)
- {
- fprintf(stderr, "%s: malloc() failed: %s\n", ProgramName, strerror(errno));
- png_destroy_read_struct(&png, &info, NULL);
- return NULL;
- }
- strcpy(file, prefix);
- strcat(file, "/");
- strcat(file, list->pngfile);
- #endif
- }
- 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((int)width, (int)height);
- if(image == NULL)
- {
- fprintf(stderr,
- "%s: XcursorImageCreate() failed to create %u x %u image\n"
- " for file %s\n",
- ProgramName,
- width,
- height,
- list->pngfile);
- fclose(fp);
- png_destroy_read_struct(&png, &info, NULL);
- return NULL;
- }
- image->size = (XcursorDim)list->size;
- image->xhot = (XcursorDim)list->xhot;
- image->yhot = (XcursorDim)list->yhot;
- image->delay = (XcursorUInt)list->delay;
- rows = malloc(sizeof(png_bytep) * height);
- if(rows == NULL)
- {
- fclose(fp);
- png_destroy_read_struct(&png, &info, NULL);
- return NULL;
- }
- 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, const char *filename, const 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, "%s: PNG error while reading %s\n", ProgramName, list->pngfile);
- fclose(fp);
- return 1;
- }
- cimages->images[i] = image;
- }
- ret = XcursorFileSaveImages(fp, cimages);
- fclose(fp);
- return ret ? 0 : 1;
- }
- #if 0
- static int
- check_image(char *image)
- {
- unsigned int width, height;
- unsigned char *data;
- int x_hot, y_hot;
- unsigned char hash[XCURSOR_BITMAP_HASH_SIZE];
- int i;
- if (XReadBitmapFileData(image, &width, &height, &data, &x_hot, &y_hot)
- != BitmapSuccess) {
- fprintf(stderr, "%s: Can't open bitmap file \"%s\"\n", ProgramName,
- image);
- return 1;
- }
- else {
- XImage ximage = {
- .width = (int) width,
- .height = (int) height,
- .depth = 1,
- .bits_per_pixel = 1,
- .xoffset = 0,
- .format = XYPixmap,
- .data = (char *) data,
- .byte_order = LSBFirst,
- .bitmap_unit = 8,
- .bitmap_bit_order = LSBFirst,
- .bitmap_pad = 8,
- .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;
- }
- #endif
- int
- main(int argc, char *argv[])
- {
- struct flist *list;
- int count;
- const char *in = NULL, *out = NULL;
- const char *prefix = NULL;
- int i;
- ProgramName = argv[0];
- for(i = 1; i < argc; i++)
- {
- if(strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0)
- {
- printf("xcursorgen version %s\n", PACKAGE_VERSION);
- return 0;
- }
- if(strcmp(argv[i], "-?") == 0 || strcmp(argv[i], "--help") == 0)
- {
- usage(argv[0]);
- return 0;
- }
- #if 0
- if (strcmp(argv[i], "-image") == 0) {
- int ret = 0;
- while (argv[++i]) {
- if (check_image(argv[i]))
- ret = i;
- }
- return ret;
- }
- #endif
- if(strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--prefix") == 0)
- {
- i++;
- if(argv[i] == NULL)
- {
- fprintf(stderr, "%s: %s requires an argument\n", argv[0], argv[i - 1]);
- usage(argv[0]);
- return 1;
- }
- prefix = argv[i];
- continue;
- }
- if(!in)
- in = argv[i];
- else if(!out)
- out = argv[i];
- else
- {
- fprintf(stderr, "%s: unexpected argument '%s'\n", argv[0], argv[i]);
- usage(argv[0]);
- return 1;
- }
- }
- if(!in) in = "-";
- if(!out) out = "-";
- count = read_config_file(in, &list);
- if(count == 0)
- {
- fprintf(
- stderr, "%s: Error reading config file %s\n", argv[0], strcmp(in, "-") ? in : "from stdin");
- return 1;
- }
- return write_cursors(count, list, out, prefix);
- }