diff options
Diffstat (limited to 'libs/cairo-1.16.0/test/any2ppm.c')
-rw-r--r-- | libs/cairo-1.16.0/test/any2ppm.c | 894 |
1 files changed, 894 insertions, 0 deletions
diff --git a/libs/cairo-1.16.0/test/any2ppm.c b/libs/cairo-1.16.0/test/any2ppm.c new file mode 100644 index 0000000..a92412d --- /dev/null +++ b/libs/cairo-1.16.0/test/any2ppm.c @@ -0,0 +1,894 @@ +/* + * Copyright © 2008 Chris Wilson + * + * 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 + * Chris Wilson not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Chris Wilson makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * CHRIS WILSON DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL CHRIS WILSON 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. + * + * Author: Chris Wilson <chris@chris-wilson.co.uk> + * + * Contributor(s): + * Carlos Garcia Campos <carlosgc@gnome.org> + * + * Adapted from pdf2png.c: + * Copyright © 2005 Red Hat, 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 + * Red Hat, Inc. not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior + * permission. Red Hat, Inc. makes no representations about the + * suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS, IN NO EVENT SHALL RED HAT, INC. 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. + * + * Author: Kristian Høgsberg <krh@redhat.com> + */ + +#if HAVE_CONFIG_H +#include "config.h" +#endif + +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <cairo.h> +#include <cairo-script-interpreter.h> + +#if CAIRO_CAN_TEST_PDF_SURFACE +#include <poppler.h> +#endif + +#if CAIRO_CAN_TEST_SVG_SURFACE +#include <librsvg/rsvg.h> +#ifndef RSVG_CAIRO_H +#include <librsvg/rsvg-cairo.h> +#endif +#endif + +#if CAIRO_HAS_SPECTRE +#include <libspectre/spectre.h> +#endif + +#include <errno.h> + +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#if HAVE_UNISTD_H && HAVE_SIGNAL_H && HAVE_SYS_STAT_H && HAVE_SYS_SOCKET_H && HAVE_SYS_POLL_H && HAVE_SYS_UN_H +#include <signal.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/poll.h> +#include <sys/un.h> + +#define SOCKET_PATH "./.any2ppm" +#define TIMEOUT 60000 /* 60 seconds */ + +#if HAVE_FORK +#define CAN_RUN_AS_DAEMON 1 +#endif +#endif + +#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0]))) + +static int +_cairo_writen (int fd, char *buf, int len) +{ + while (len) { + int ret; + + ret = write (fd, buf, len); + if (ret == -1) { + int err = errno; + switch (err) { + case EINTR: + case EAGAIN: + continue; + default: + return 0; + } + } + len -= ret; + buf += ret; + } + + return 1; +} + +static int +_cairo_write (int fd, + char *buf, int maxlen, int buflen, + const unsigned char *src, int srclen) +{ + if (buflen < 0) + return buflen; + + while (srclen) { + int len; + + len = buflen + srclen; + if (len > maxlen) + len = maxlen; + len -= buflen; + + memcpy (buf + buflen, src, len); + buflen += len; + srclen -= len; + src += len; + + if (buflen == maxlen) { + if (! _cairo_writen (fd, buf, buflen)) + return -1; + + buflen = 0; + } + } + + return buflen; +} + +static const char * +write_ppm (cairo_surface_t *surface, int fd) +{ + char buf[4096]; + cairo_format_t format; + const char *format_str; + const unsigned char *data; + int len; + int width, height, stride; + int i, j; + + data = cairo_image_surface_get_data (surface); + height = cairo_image_surface_get_height (surface); + width = cairo_image_surface_get_width (surface); + stride = cairo_image_surface_get_stride (surface); + format = cairo_image_surface_get_format (surface); + if (format == CAIRO_FORMAT_ARGB32) { + /* see if we can convert to a standard ppm type and trim a few bytes */ + const unsigned char *alpha = data; + for (j = height; j--; alpha += stride) { + for (i = 0; i < width; i++) { + if ((*(unsigned int *) (alpha+4*i) & 0xff000000) != 0xff000000) + goto done; + } + } + format = CAIRO_FORMAT_RGB24; + done: ; + } + + switch (format) { + case CAIRO_FORMAT_ARGB32: + /* XXX need true alpha for svg */ + format_str = "P7"; + break; + case CAIRO_FORMAT_RGB24: + format_str = "P6"; + break; + case CAIRO_FORMAT_A8: + format_str = "P5"; + break; + case CAIRO_FORMAT_A1: + case CAIRO_FORMAT_RGB16_565: + case CAIRO_FORMAT_RGB30: + case CAIRO_FORMAT_INVALID: + default: + return "unhandled image format"; + } + + len = sprintf (buf, "%s %d %d 255\n", format_str, width, height); + for (j = 0; j < height; j++) { + const unsigned int *row = (unsigned int *) (data + stride * j); + + switch ((int) format) { + case CAIRO_FORMAT_ARGB32: + len = _cairo_write (fd, + buf, sizeof (buf), len, + (unsigned char *) row, 4 * width); + break; + case CAIRO_FORMAT_RGB24: + for (i = 0; i < width; i++) { + unsigned char rgb[3]; + unsigned int p = *row++; + rgb[0] = (p & 0xff0000) >> 16; + rgb[1] = (p & 0x00ff00) >> 8; + rgb[2] = (p & 0x0000ff) >> 0; + len = _cairo_write (fd, + buf, sizeof (buf), len, + rgb, 3); + } + break; + case CAIRO_FORMAT_A8: + len = _cairo_write (fd, + buf, sizeof (buf), len, + (unsigned char *) row, width); + break; + } + if (len < 0) + return "write failed"; + } + + if (len && ! _cairo_writen (fd, buf, len)) + return "write failed"; + + return NULL; +} + +#if CAIRO_HAS_INTERPRETER +static cairo_surface_t * +_create_image (void *closure, + cairo_content_t content, + double width, double height, + long uid) +{ + cairo_surface_t **out = closure; + cairo_format_t format; + switch (content) { + case CAIRO_CONTENT_ALPHA: + format = CAIRO_FORMAT_A8; + break; + case CAIRO_CONTENT_COLOR: + format = CAIRO_FORMAT_RGB24; + break; + default: + case CAIRO_CONTENT_COLOR_ALPHA: + format = CAIRO_FORMAT_ARGB32; + break; + } + *out = cairo_image_surface_create (format, width, height); + return cairo_surface_reference (*out); +} + +static const char * +_cairo_script_render_page (const char *filename, + cairo_surface_t **surface_out) +{ + cairo_script_interpreter_t *csi; + cairo_surface_t *surface = NULL; + cairo_status_t status; + const cairo_script_interpreter_hooks_t hooks = { + &surface, + _create_image, + NULL, /* surface_destroy */ + NULL, /* context_create */ + NULL, /* context_destroy */ + NULL, /* show_page */ + NULL /* copy_page */ + }; + + csi = cairo_script_interpreter_create (); + cairo_script_interpreter_install_hooks (csi, &hooks); + status = cairo_script_interpreter_run (csi, filename); + if (status) { + cairo_surface_destroy (surface); + surface = NULL; + } + status = cairo_script_interpreter_destroy (csi); + if (surface == NULL) + return "cairo-script interpreter failed"; + + if (status == CAIRO_STATUS_SUCCESS) + status = cairo_surface_status (surface); + if (status) { + cairo_surface_destroy (surface); + return cairo_status_to_string (status); + } + + *surface_out = surface; + return NULL; +} + +static const char * +cs_convert (char **argv, int fd) +{ + const char *err; + cairo_surface_t *surface = NULL; /* silence compiler warning */ + + err = _cairo_script_render_page (argv[0], &surface); + if (err != NULL) + return err; + + err = write_ppm (surface, fd); + cairo_surface_destroy (surface); + + return err; +} +#else +static const char * +cs_convert (char **argv, int fd) +{ + return "compiled without CairoScript support."; +} +#endif + +#if CAIRO_CAN_TEST_PDF_SURFACE +/* adapted from pdf2png.c */ +static const char * +_poppler_render_page (const char *filename, + const char *page_label, + cairo_surface_t **surface_out) +{ + PopplerDocument *document; + PopplerPage *page; + double width, height; + GError *error = NULL; + gchar *absolute, *uri; + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status; + + if (g_path_is_absolute (filename)) { + absolute = g_strdup (filename); + } else { + gchar *dir = g_get_current_dir (); + absolute = g_build_filename (dir, filename, (gchar *) 0); + g_free (dir); + } + + uri = g_filename_to_uri (absolute, NULL, &error); + g_free (absolute); + if (uri == NULL) + return error->message; /* XXX g_error_free (error) */ + + document = poppler_document_new_from_file (uri, NULL, &error); + g_free (uri); + if (document == NULL) + return error->message; /* XXX g_error_free (error) */ + + page = poppler_document_get_page_by_label (document, page_label); + g_object_unref (document); + if (page == NULL) + return "page not found"; + + poppler_page_get_size (page, &width, &height); + + surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height); + cr = cairo_create (surface); + + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA); + + poppler_page_render (page, cr); + g_object_unref (page); + + cairo_pop_group_to_source (cr); + cairo_paint (cr); + + status = cairo_status (cr); + cairo_destroy (cr); + + if (status) { + cairo_surface_destroy (surface); + return cairo_status_to_string (status); + } + + *surface_out = surface; + return NULL; +} + +static const char * +pdf_convert (char **argv, int fd) +{ + const char *err; + cairo_surface_t *surface = NULL; /* silence compiler warning */ + + err = _poppler_render_page (argv[0], argv[1], &surface); + if (err != NULL) + return err; + + err = write_ppm (surface, fd); + cairo_surface_destroy (surface); + + return err; +} +#else +static const char * +pdf_convert (char **argv, int fd) +{ + return "compiled without PDF support."; +} +#endif + +#if CAIRO_CAN_TEST_SVG_SURFACE +static const char * +_rsvg_render_page (const char *filename, + cairo_surface_t **surface_out) +{ + RsvgHandle *handle; + RsvgDimensionData dimensions; + GError *error = NULL; + cairo_surface_t *surface; + cairo_t *cr; + cairo_status_t status; + + handle = rsvg_handle_new_from_file (filename, &error); + if (handle == NULL) + return error->message; /* XXX g_error_free */ + + rsvg_handle_get_dimensions (handle, &dimensions); + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + dimensions.width, + dimensions.height); + cr = cairo_create (surface); + + rsvg_handle_render_cairo (handle, cr); + g_object_unref (handle); + + status = cairo_status (cr); + cairo_destroy (cr); + + if (status) { + cairo_surface_destroy (surface); + return cairo_status_to_string (status); + } + + *surface_out = surface; + return NULL; +} + +static const char * +svg_convert (char **argv, int fd) +{ + const char *err; + cairo_surface_t *surface = NULL; /* silence compiler warning */ + + err = _rsvg_render_page (argv[0], &surface); + if (err != NULL) + return err; + + err = write_ppm (surface, fd); + cairo_surface_destroy (surface); + + return err; +} +#else +static const char * +svg_convert (char **argv, int fd) +{ + return "compiled without SVG support."; +} +#endif + +#if CAIRO_HAS_SPECTRE +static const char * +_spectre_render_page (const char *filename, + const char *page_label, + cairo_surface_t **surface_out) +{ + static const cairo_user_data_key_t key; + + SpectreDocument *document; + SpectreStatus status; + int width, height, stride; + unsigned char *pixels; + cairo_surface_t *surface; + + document = spectre_document_new (); + spectre_document_load (document, filename); + status = spectre_document_status (document); + if (status) { + spectre_document_free (document); + return spectre_status_to_string (status); + } + + if (page_label) { + SpectrePage *page; + SpectreRenderContext *rc; + + page = spectre_document_get_page_by_label (document, page_label); + spectre_document_free (document); + if (page == NULL) + return "page not found"; + + spectre_page_get_size (page, &width, &height); + rc = spectre_render_context_new (); + spectre_render_context_set_page_size (rc, width, height); + spectre_page_render (page, rc, &pixels, &stride); + spectre_render_context_free (rc); + status = spectre_page_status (page); + spectre_page_free (page); + if (status) { + free (pixels); + return spectre_status_to_string (status); + } + } else { + spectre_document_get_page_size (document, &width, &height); + spectre_document_render (document, &pixels, &stride); + spectre_document_free (document); + } + + surface = cairo_image_surface_create_for_data (pixels, + CAIRO_FORMAT_RGB24, + width, height, + stride); + cairo_surface_set_user_data (surface, &key, + pixels, (cairo_destroy_func_t) free); + *surface_out = surface; + return NULL; +} + +static const char * +ps_convert (char **argv, int fd) +{ + const char *err; + cairo_surface_t *surface = NULL; /* silence compiler warning */ + + err = _spectre_render_page (argv[0], argv[1], &surface); + if (err != NULL) + return err; + + err = write_ppm (surface, fd); + cairo_surface_destroy (surface); + + return err; +} +#else +static const char * +ps_convert (char **argv, int fd) +{ + return "compiled without PostScript support."; +} +#endif + +static const char * +convert (char **argv, int fd) +{ + static const struct converter { + const char *type; + const char *(*func) (char **, int); + } converters[] = { + { "cs", cs_convert }, + { "pdf", pdf_convert }, + { "ps", ps_convert }, + { "svg", svg_convert }, + { NULL, NULL } + }; + const struct converter *converter = converters; + char *type; + + type = strrchr (argv[0], '.'); + if (type == NULL) + return "no file extension"; + type++; + + while (converter->type) { + if (strcmp (type, converter->type) == 0) + return converter->func (argv, fd); + converter++; + } + return "no converter"; +} + +#if CAN_RUN_AS_DAEMON +static int +_getline (int fd, char **linep, size_t *lenp) +{ + char *line; + size_t len, i; + ssize_t ret; + + line = *linep; + if (line == NULL) { + line = malloc (1024); + if (line == NULL) + return -1; + line[0] = '\0'; + len = 1024; + } else + len = *lenp; + + /* XXX simple, but ugly! */ + i = 0; + do { + if (i == len - 1) { + char *nline; + + nline = realloc (line, len + 1024); + if (nline == NULL) + goto out; + + line = nline; + len += 1024; + } + + ret = read (fd, line + i, 1); + if (ret == -1 || ret == 0) + goto out; + } while (line[i++] != '\n'); + +out: + line[i] = '\0'; + *linep = line; + *lenp = len; + return i-1; +} + +static int +split_line (char *line, char *argv[], int max_argc) +{ + int i = 0; + + max_argc--; /* leave one spare for the trailing NULL */ + + argv[i++] = line; + while (i < max_argc && (line = strchr (line, ' ')) != NULL) { + *line++ = '\0'; + argv[i++] = line; + } + + /* chomp the newline */ + line = strchr (argv[i-1], '\n'); + if (line != NULL) + *line = '\0'; + + argv[i] = NULL; + + return i; +} + +static int +any2ppm_daemon_exists (void) +{ + struct stat st; + int fd; + char buf[80]; + int pid; + int ret; + + if (stat (SOCKET_PATH, &st) < 0) + return 0; + + fd = open (SOCKET_PATH ".pid", O_RDONLY); + if (fd < 0) + return 0; + + pid = 0; + ret = read (fd, buf, sizeof (buf) - 1); + if (ret > 0) { + buf[ret] = '\0'; + pid = atoi (buf); + } + close (fd); + + return pid > 0 && kill (pid, 0) == 0; +} + +static int +write_pid_file (void) +{ + int fd; + char buf[80]; + int ret; + + fd = open (SOCKET_PATH ".pid", O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (fd < 0) + return 0; + + ret = sprintf (buf, "%d\n", getpid ()); + ret = write (fd, buf, ret) == ret; + close (fd); + + return ret; +} + +static int +open_devnull_to_fd (int want_fd, int flags) +{ + int error; + int got_fd; + + close (want_fd); + + got_fd = open("/dev/null", flags | O_CREAT, 0700); + if (got_fd == -1) + return -1; + + error = dup2 (got_fd, want_fd); + close (got_fd); + + return error; +} + +static int +daemonize (void) +{ + void (*oldhup) (int); + + /* Let the parent go. */ + switch (fork ()) { + case -1: return -1; + case 0: break; + default: _exit (0); + } + + /* Become session leader. */ + if (setsid () == -1) + return -1; + + /* Refork to yield session leadership. */ + oldhup = signal (SIGHUP, SIG_IGN); + + switch (fork ()) { /* refork to yield session leadership. */ + case -1: return -1; + case 0: break; + default: _exit (0); + } + + signal (SIGHUP, oldhup); + + /* Establish stdio. */ + if (open_devnull_to_fd (0, O_RDONLY) == -1) + return -1; + if (open_devnull_to_fd (1, O_WRONLY | O_APPEND) == -1) + return -1; + if (dup2 (1, 2) == -1) + return -1; + + return 0; +} + +static const char * +any2ppm_daemon (void) +{ + int timeout = TIMEOUT; + struct pollfd pfd; + int sk, fd; + long flags; + struct sockaddr_un addr; + char *line = NULL; + size_t len = 0; + +#ifdef SIGPIPE + signal (SIGPIPE, SIG_IGN); +#endif + + /* XXX racy! */ + if (getenv ("ANY2PPM_FORCE") == NULL && any2ppm_daemon_exists ()) + return "any2ppm daemon already running"; + + unlink (SOCKET_PATH); + + sk = socket (PF_UNIX, SOCK_STREAM, 0); + if (sk == -1) + return "unable to create socket"; + + memset (&addr, 0, sizeof (addr)); + addr.sun_family = AF_UNIX; + strcpy (addr.sun_path, SOCKET_PATH); + if (bind (sk, (struct sockaddr *) &addr, sizeof (addr)) == -1) { + close (sk); + return "unable to bind socket"; + } + + flags = fcntl (sk, F_GETFL); + if (flags == -1 || fcntl (sk, F_SETFL, flags | O_NONBLOCK) == -1) { + close (sk); + return "unable to set socket to non-blocking"; + } + + if (listen (sk, 5) == -1) { + close (sk); + return "unable to listen on socket"; + } + + /* ready for client connection - detach from parent/terminal */ + if (getenv ("ANY2PPM_NODAEMON") == NULL && daemonize () == -1) { + close (sk); + return "unable to detach from parent"; + } + + if (! write_pid_file ()) { + close (sk); + return "unable to write pid file"; + } + + if (getenv ("ANY2PPM_TIMEOUT") != NULL) { + timeout = atoi (getenv ("ANY2PPM_TIMEOUT")); + if (timeout == 0) + timeout = -1; + if (timeout > 0) + timeout *= 1000; /* convert env (in seconds) to milliseconds */ + } + + pfd.fd = sk; + pfd.events = POLLIN; + pfd.revents = 0; /* valgrind */ + while (poll (&pfd, 1, timeout) > 0) { + while ((fd = accept (sk, NULL, NULL)) != -1) { + if (_getline (fd, &line, &len) != -1) { + char *argv[10]; + + if (split_line (line, argv, ARRAY_LENGTH (argv)) > 0) { + const char *err; + + err = convert (argv, fd); + if (err != NULL) { + FILE *file = fopen (".any2ppm.errors", "a"); + if (file != NULL) { + fprintf (file, + "Failed to convert '%s': %s\n", + argv[0], err); + fclose (file); + } + } + } + } + close (fd); + } + } + close (sk); + unlink (SOCKET_PATH); + unlink (SOCKET_PATH ".pid"); + + free (line); + return NULL; +} +#else +static const char * +any2ppm_daemon (void) +{ + return "daemon not compiled in."; +} +#endif + +int +main (int argc, char **argv) +{ + const char *err; + +#if CAIRO_CAN_TEST_PDF_SURFACE || CAIRO_CAN_TEST_SVG_SURFACE +#if GLIB_MAJOR_VERSION <= 2 && GLIB_MINOR_VERSION <= 34 + g_type_init (); +#endif +#endif + +#if CAIRO_CAN_TEST_SVG_SURFACE + rsvg_set_default_dpi (72.0); +#endif + +#if defined(_WIN32) && !defined (__CYGWIN__) + _setmode (1, _O_BINARY); +#endif + + if (argc == 1) + err = any2ppm_daemon (); + else + err = convert (argv + 1, 1); + if (err != NULL) { + fprintf (stderr, "Failed to run converter: %s\n", err); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} |