2008-08-18 18:50:00 +01:00
|
|
|
/*
|
|
|
|
|
* 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>
|
|
|
|
|
*
|
2008-10-09 12:11:51 +01:00
|
|
|
* Contributor(s):
|
|
|
|
|
* Carlos Garcia Campos <carlosgc@gnome.org>
|
|
|
|
|
*
|
2008-08-18 18:50:00 +01:00
|
|
|
* 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>
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
|
|
#if HAVE_UNISTD_H
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include <cairo.h>
|
2008-11-04 10:45:34 +00:00
|
|
|
#include <cairo-script-interpreter.h>
|
|
|
|
|
|
2008-08-18 18:50:00 +01:00
|
|
|
#if CAIRO_CAN_TEST_PDF_SURFACE
|
|
|
|
|
#include <poppler.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if CAIRO_CAN_TEST_SVG_SURFACE
|
2021-04-18 11:18:10 +01:00
|
|
|
#define RSVG_DISABLE_DEPRECATION_WARNINGS
|
2008-08-18 18:50:00 +01:00
|
|
|
#include <librsvg/rsvg.h>
|
2014-02-18 18:10:20 -08:00
|
|
|
#ifndef RSVG_CAIRO_H
|
2008-08-18 18:50:00 +01:00
|
|
|
#include <librsvg/rsvg-cairo.h>
|
|
|
|
|
#endif
|
2014-02-18 18:10:20 -08:00
|
|
|
#endif
|
2008-08-18 18:50:00 +01:00
|
|
|
|
2008-10-11 18:10:16 +01:00
|
|
|
#if CAIRO_HAS_SPECTRE
|
2008-10-09 12:11:51 +01:00
|
|
|
#include <libspectre/spectre.h>
|
2008-08-18 18:50:00 +01:00
|
|
|
#endif
|
|
|
|
|
|
2011-11-11 18:16:04 +01:00
|
|
|
#include <errno.h>
|
|
|
|
|
|
2014-07-23 12:09:17 -04:00
|
|
|
#if HAVE_FCNTL_H
|
2008-08-18 18:50:00 +01:00
|
|
|
#include <fcntl.h>
|
2014-07-23 12:09:17 -04:00
|
|
|
#endif
|
|
|
|
|
|
2020-08-31 01:36:20 -06:00
|
|
|
#if HAVE_UNISTD_H && HAVE_SIGNAL_H && HAVE_SYS_STAT_H && HAVE_SYS_SOCKET_H && (HAVE_POLL_H || HAVE_SYS_POLL_H) && HAVE_SYS_UN_H
|
2008-08-18 18:50:00 +01:00
|
|
|
#include <signal.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
|
2020-08-31 01:36:20 -06:00
|
|
|
#if defined(HAVE_POLL_H)
|
|
|
|
|
#include <poll.h>
|
|
|
|
|
#elif defined(HAVE_SYS_POLL_H)
|
|
|
|
|
#include <sys/poll.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-08-18 18:50:00 +01:00
|
|
|
#define SOCKET_PATH "./.any2ppm"
|
|
|
|
|
#define TIMEOUT 60000 /* 60 seconds */
|
|
|
|
|
|
2014-05-09 21:22:04 +02:00
|
|
|
#if HAVE_FORK
|
2008-08-18 18:50:00 +01:00
|
|
|
#define CAN_RUN_AS_DAEMON 1
|
|
|
|
|
#endif
|
2014-05-09 21:22:04 +02:00
|
|
|
#endif
|
2008-08-18 18:50:00 +01:00
|
|
|
|
2014-11-20 12:19:47 -08:00
|
|
|
#define ARRAY_LENGTH(__array) ((int) (sizeof (__array) / sizeof (__array[0])))
|
2008-08-18 18:50:00 +01:00
|
|
|
|
2008-09-25 00:16:45 +01:00
|
|
|
static int
|
2012-04-09 21:33:49 +02:00
|
|
|
_cairo_writen (int fd, char *buf, int len)
|
2008-09-25 00:16:45 +01:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-18 18:50:00 +01:00
|
|
|
static int
|
2012-04-09 21:33:49 +02:00
|
|
|
_cairo_write (int fd,
|
2008-08-18 18:50:00 +01:00
|
|
|
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) {
|
2012-04-09 21:33:49 +02:00
|
|
|
if (! _cairo_writen (fd, buf, buflen))
|
2008-08-18 18:50:00 +01:00
|
|
|
return -1;
|
2008-09-25 00:16:45 +01:00
|
|
|
|
2008-08-18 18:50:00 +01:00
|
|
|
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;
|
|
|
|
|
|
2008-11-04 10:45:34 +00:00
|
|
|
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);
|
2008-08-18 18:50:00 +01:00
|
|
|
format = cairo_image_surface_get_format (surface);
|
2008-11-04 10:45:34 +00:00
|
|
|
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;
|
2008-11-13 11:07:45 +00:00
|
|
|
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: ;
|
2008-11-04 10:45:34 +00:00
|
|
|
}
|
|
|
|
|
|
2008-08-18 18:50:00 +01:00
|
|
|
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:
|
2011-02-18 18:53:29 +01:00
|
|
|
case CAIRO_FORMAT_RGB16_565:
|
2012-04-10 22:34:05 +09:30
|
|
|
case CAIRO_FORMAT_RGB30:
|
2018-12-03 15:13:40 +01:00
|
|
|
case CAIRO_FORMAT_RGB96F:
|
|
|
|
|
case CAIRO_FORMAT_RGBA128F:
|
2010-02-28 23:31:06 +02:00
|
|
|
case CAIRO_FORMAT_INVALID:
|
2008-08-18 18:50:00 +01:00
|
|
|
default:
|
|
|
|
|
return "unhandled image format";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = sprintf (buf, "%s %d %d 255\n", format_str, width, height);
|
|
|
|
|
for (j = 0; j < height; j++) {
|
2008-11-07 18:35:39 +00:00
|
|
|
const unsigned int *row = (unsigned int *) (data + stride * j);
|
2008-08-18 18:50:00 +01:00
|
|
|
|
|
|
|
|
switch ((int) format) {
|
|
|
|
|
case CAIRO_FORMAT_ARGB32:
|
2012-04-09 21:33:49 +02:00
|
|
|
len = _cairo_write (fd,
|
2008-08-18 18:50:00 +01:00
|
|
|
buf, sizeof (buf), len,
|
2008-11-07 18:35:39 +00:00
|
|
|
(unsigned char *) row, 4 * width);
|
2008-08-18 18:50:00 +01:00
|
|
|
break;
|
|
|
|
|
case CAIRO_FORMAT_RGB24:
|
|
|
|
|
for (i = 0; i < width; i++) {
|
2008-11-07 18:35:39 +00:00
|
|
|
unsigned char rgb[3];
|
|
|
|
|
unsigned int p = *row++;
|
|
|
|
|
rgb[0] = (p & 0xff0000) >> 16;
|
|
|
|
|
rgb[1] = (p & 0x00ff00) >> 8;
|
|
|
|
|
rgb[2] = (p & 0x0000ff) >> 0;
|
2012-04-09 21:33:49 +02:00
|
|
|
len = _cairo_write (fd,
|
2008-08-18 18:50:00 +01:00
|
|
|
buf, sizeof (buf), len,
|
2008-11-07 18:35:39 +00:00
|
|
|
rgb, 3);
|
2008-08-18 18:50:00 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case CAIRO_FORMAT_A8:
|
2012-04-09 21:33:49 +02:00
|
|
|
len = _cairo_write (fd,
|
2008-08-18 18:50:00 +01:00
|
|
|
buf, sizeof (buf), len,
|
2008-11-07 18:35:39 +00:00
|
|
|
(unsigned char *) row, width);
|
2008-08-18 18:50:00 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (len < 0)
|
|
|
|
|
return "write failed";
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-09 21:33:49 +02:00
|
|
|
if (len && ! _cairo_writen (fd, buf, len))
|
2008-09-25 00:16:45 +01:00
|
|
|
return "write failed";
|
2008-08-18 18:50:00 +01:00
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-16 19:47:21 +10:30
|
|
|
#if CAIRO_HAS_INTERPRETER
|
2008-11-04 10:45:34 +00:00
|
|
|
static cairo_surface_t *
|
|
|
|
|
_create_image (void *closure,
|
2009-03-03 10:25:05 +00:00
|
|
|
cairo_content_t content,
|
2009-11-01 08:40:41 +00:00
|
|
|
double width, double height,
|
|
|
|
|
long uid)
|
2008-11-04 10:45:34 +00:00
|
|
|
{
|
|
|
|
|
cairo_surface_t **out = closure;
|
2009-07-04 18:31:49 +01:00
|
|
|
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);
|
2008-11-13 11:07:45 +00:00
|
|
|
return cairo_surface_reference (*out);
|
2008-11-04 10:45:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
2008-11-13 11:07:45 +00:00
|
|
|
const cairo_script_interpreter_hooks_t hooks = {
|
2011-11-11 18:16:04 +01:00
|
|
|
&surface,
|
|
|
|
|
_create_image,
|
|
|
|
|
NULL, /* surface_destroy */
|
|
|
|
|
NULL, /* context_create */
|
|
|
|
|
NULL, /* context_destroy */
|
|
|
|
|
NULL, /* show_page */
|
|
|
|
|
NULL /* copy_page */
|
2008-11-13 11:07:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
csi = cairo_script_interpreter_create ();
|
|
|
|
|
cairo_script_interpreter_install_hooks (csi, &hooks);
|
2010-03-21 20:40:54 +00:00
|
|
|
status = cairo_script_interpreter_run (csi, filename);
|
|
|
|
|
if (status) {
|
|
|
|
|
cairo_surface_destroy (surface);
|
|
|
|
|
surface = NULL;
|
|
|
|
|
}
|
2008-11-13 11:07:45 +00:00
|
|
|
status = cairo_script_interpreter_destroy (csi);
|
2010-03-21 20:40:54 +00:00
|
|
|
if (surface == NULL)
|
2008-11-04 10:45:34 +00:00
|
|
|
return "cairo-script interpreter failed";
|
|
|
|
|
|
2008-11-13 11:07:45 +00:00
|
|
|
if (status == CAIRO_STATUS_SUCCESS)
|
|
|
|
|
status = cairo_surface_status (surface);
|
2008-11-04 10:45:34 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2009-09-08 17:51:33 +01:00
|
|
|
#else
|
|
|
|
|
static const char *
|
|
|
|
|
cs_convert (char **argv, int fd)
|
|
|
|
|
{
|
|
|
|
|
return "compiled without CairoScript support.";
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2008-11-04 10:45:34 +00:00
|
|
|
|
2008-08-18 18:50:00 +01:00
|
|
|
#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);
|
|
|
|
|
|
2010-06-11 14:06:15 +01:00
|
|
|
surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
|
2008-08-18 18:50:00 +01:00
|
|
|
cr = cairo_create (surface);
|
|
|
|
|
|
2010-06-11 14:06:15 +01:00
|
|
|
cairo_set_source_rgb (cr, 1., 1., 1.);
|
|
|
|
|
cairo_paint (cr);
|
|
|
|
|
cairo_push_group_with_content (cr, CAIRO_CONTENT_COLOR_ALPHA);
|
|
|
|
|
|
2010-06-11 12:04:39 +01:00
|
|
|
poppler_page_render (page, cr);
|
|
|
|
|
g_object_unref (page);
|
|
|
|
|
|
2010-06-11 14:06:15 +01:00
|
|
|
cairo_pop_group_to_source (cr);
|
2010-06-11 12:54:15 +01:00
|
|
|
cairo_paint (cr);
|
|
|
|
|
|
2008-08-18 18:50:00 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2008-10-11 18:10:16 +01:00
|
|
|
#else
|
|
|
|
|
static const char *
|
|
|
|
|
pdf_convert (char **argv, int fd)
|
|
|
|
|
{
|
|
|
|
|
return "compiled without PDF support.";
|
|
|
|
|
}
|
2008-08-18 18:50:00 +01:00
|
|
|
#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 */
|
|
|
|
|
|
2019-03-12 10:19:36 -06:00
|
|
|
rsvg_handle_set_dpi (handle, 72.0);
|
2008-08-18 18:50:00 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2008-10-11 18:10:16 +01:00
|
|
|
#else
|
|
|
|
|
static const char *
|
|
|
|
|
svg_convert (char **argv, int fd)
|
|
|
|
|
{
|
|
|
|
|
return "compiled without SVG support.";
|
|
|
|
|
}
|
2008-08-18 18:50:00 +01:00
|
|
|
#endif
|
|
|
|
|
|
2008-10-11 18:10:16 +01:00
|
|
|
#if CAIRO_HAS_SPECTRE
|
2008-10-09 12:11:51 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-18 18:50:00 +01:00
|
|
|
static const char *
|
|
|
|
|
ps_convert (char **argv, int fd)
|
|
|
|
|
{
|
2008-10-09 12:11:51 +01:00
|
|
|
const char *err;
|
|
|
|
|
cairo_surface_t *surface = NULL; /* silence compiler warning */
|
2008-08-18 18:50:00 +01:00
|
|
|
|
2008-10-09 12:11:51 +01:00
|
|
|
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;
|
2008-08-18 18:50:00 +01:00
|
|
|
}
|
2008-10-11 18:10:16 +01:00
|
|
|
#else
|
|
|
|
|
static const char *
|
|
|
|
|
ps_convert (char **argv, int fd)
|
|
|
|
|
{
|
|
|
|
|
return "compiled without PostScript support.";
|
|
|
|
|
}
|
2008-08-18 18:50:00 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
convert (char **argv, int fd)
|
|
|
|
|
{
|
|
|
|
|
static const struct converter {
|
|
|
|
|
const char *type;
|
|
|
|
|
const char *(*func) (char **, int);
|
|
|
|
|
} converters[] = {
|
2008-11-04 10:45:34 +00:00
|
|
|
{ "cs", cs_convert },
|
2008-08-18 18:50:00 +01:00
|
|
|
{ "pdf", pdf_convert },
|
|
|
|
|
{ "ps", ps_convert },
|
|
|
|
|
{ "svg", svg_convert },
|
|
|
|
|
{ NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
const struct converter *converter = converters;
|
|
|
|
|
char *type;
|
|
|
|
|
|
2008-09-24 01:56:44 +01:00
|
|
|
type = strrchr (argv[0], '.');
|
2008-08-18 18:50:00 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2009-05-24 23:46:13 +03:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-08-18 18:50:00 +01:00
|
|
|
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 */
|
2009-05-24 23:46:13 +03:00
|
|
|
if (getenv ("ANY2PPM_NODAEMON") == NULL && daemonize () == -1) {
|
2008-08-18 18:50:00 +01:00
|
|
|
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];
|
|
|
|
|
|
2008-09-25 00:16:45 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-08-18 18:50:00 +01:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
2008-12-23 02:05:32 +02:00
|
|
|
#if CAIRO_CAN_TEST_PDF_SURFACE || CAIRO_CAN_TEST_SVG_SURFACE
|
2014-02-18 20:13:57 -08:00
|
|
|
#if GLIB_MAJOR_VERSION <= 2 && GLIB_MINOR_VERSION <= 34
|
2008-08-18 18:50:00 +01:00
|
|
|
g_type_init ();
|
2008-12-23 02:05:32 +02:00
|
|
|
#endif
|
2014-02-18 20:13:57 -08:00
|
|
|
#endif
|
2008-08-18 18:50:00 +01:00
|
|
|
|
2014-07-23 12:09:17 -04:00
|
|
|
#if defined(_WIN32) && !defined (__CYGWIN__)
|
|
|
|
|
_setmode (1, _O_BINARY);
|
|
|
|
|
#endif
|
|
|
|
|
|
2008-08-18 18:50:00 +01:00
|
|
|
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;
|
|
|
|
|
}
|