123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- /*************************************************************************
- * Copyright (c) 2011 AT&T Intellectual Property
- * All rights reserved. This program and the accompanying materials
- * are made available under the terms of the Eclipse Public License v1.0
- * which accompanies this distribution, and is available at
- * https://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors: Details at https://graphviz.org
- *************************************************************************/
- #include "config.h"
- #include "gdioctx_wrapper.h"
- #include <assert.h>
- #include <gvc/gvplugin_device.h>
- #include <gvc/gvio.h>
- #include <limits.h>
- #include <gd.h>
- #include <stdbool.h>
- #include <stddef.h>
- #include <string.h>
- int gvdevice_gd_putBuf (gdIOCtx *context, const void *buffer, int len)
- {
- gd_context_t *gd_context = get_containing_context(context);
- assert(len >= 0);
- const size_t result = gvwrite(gd_context->job, buffer, (size_t)len);
- assert(result <= (size_t)len);
- return (int)result;
- }
- void gvdevice_gd_putC (gdIOCtx *context, int C)
- {
- gd_context_t *gd_context = get_containing_context(context);
- char c = (char)C;
- gvwrite(gd_context->job, &c, 1);
- }
- #ifdef HAVE_PANGOCAIRO
- typedef enum {
- FORMAT_GIF,
- FORMAT_JPEG,
- FORMAT_PNG,
- FORMAT_WBMP,
- FORMAT_GD,
- FORMAT_GD2,
- FORMAT_XBM,
- } format_type;
- static void gd_format(GVJ_t * job)
- {
- gdImagePtr im;
- unsigned int x, y;
- const unsigned char *data = (unsigned char *)job->imagedata;
- unsigned int width = job->width;
- unsigned int height = job->height;
- gd_context_t gd_context;
- memset(&gd_context, 0, sizeof(gd_context));
- gd_context.ctx.putBuf = gvdevice_gd_putBuf;
- gd_context.ctx.putC = gvdevice_gd_putC;
- gd_context.job = job;
- assert(width <= INT_MAX);
- assert(height <= INT_MAX);
- im = gdImageCreateTrueColor((int)width, (int)height);
- switch (job->device.id) {
- #ifdef HAVE_GD_PNG
- case FORMAT_PNG:
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- const int r = *data++;
- const int g = *data++;
- const int b = *data++;
- // gd’s alpha is 7-bit, so scale down ÷2 from our 8-bit
- const int alpha = *data++ >> 1;
- const int color = r | (g << 8) | (b << 16) | ((0x7f - alpha) << 24);
- im->tpixels[y][x] = color;
- }
- }
- break;
- #endif
- default:
- /* pick an off-white color, so that transparent backgrounds look white in jpgs */
- #define TRANSPARENT 0x7ffffffe
- gdImageColorTransparent(im, TRANSPARENT);
- gdImageAlphaBlending(im, false);
- for (y = 0; y < height; y++) {
- for (x = 0; x < width; x++) {
- const int r = *data++;
- const int g = *data++;
- const int b = *data++;
- // gd’s alpha is 7-bit, so scale down ÷2 from our 8-bit
- const int alpha = *data++ >> 1;
- const int color = r | (g << 8) | (b << 16) | ((0x7f - alpha) << 24);
- if (alpha >= 0x20)
- /* if not > 75% transparent */
- im->tpixels[y][x] = color;
- else
- im->tpixels[y][x] = TRANSPARENT;
- }
- }
- break;
- }
- switch (job->device.id) {
- #ifdef HAVE_GD_GIF
- case FORMAT_GIF:
- gdImageTrueColorToPalette(im, 0, 256);
- gdImageGifCtx(im, &gd_context.ctx);
- break;
- #endif
- #ifdef HAVE_GD_JPEG
- case FORMAT_JPEG:
- /*
- * Write IM to OUTFILE as a JFIF-formatted JPEG image, using
- * quality JPEG_QUALITY. If JPEG_QUALITY is in the range
- * 0-100, increasing values represent higher quality but also
- * larger image size. If JPEG_QUALITY is negative, the
- * IJG JPEG library's default quality is used (which should
- * be near optimal for many applications). See the IJG JPEG
- * library documentation for more details.
- */
- #define JPEG_QUALITY -1
- gdImageJpegCtx(im, &gd_context.ctx, JPEG_QUALITY);
- break;
- #endif
- #ifdef HAVE_GD_PNG
- case FORMAT_PNG:
- gdImageTrueColorToPalette(im, 0, 256);
- gdImagePngCtx(im, &gd_context.ctx);
- break;
- #endif
- case FORMAT_GD:
- gdImageGd(im, job->output_file);
- break;
- case FORMAT_GD2:
- #define GD2_CHUNKSIZE 128
- #define GD2_RAW 1
- #define GD2_COMPRESSED 2
- gdImageGd2(im, job->output_file, GD2_CHUNKSIZE, GD2_COMPRESSED);
- break;
- #ifdef HAVE_GD_GIF
- case FORMAT_WBMP:
- {
- /* Use black for the foreground color for the B&W wbmp image. */
- int black = gdImageColorResolveAlpha(im, 0, 0, 0, gdAlphaOpaque);
- gdImageWBMPCtx(im, black, &gd_context.ctx);
- }
- break;
- #endif
- break;
- default:
- break;
- }
- gdImageDestroy(im);
- }
- static gvdevice_engine_t gd_engine = {
- NULL, /* gd_initialize */
- gd_format,
- NULL, /* gd_finalize */
- };
- static gvdevice_features_t device_features_gd = {
- GVDEVICE_BINARY_FORMAT
- | GVDEVICE_DOES_TRUECOLOR,/* flags */
- {0.,0.}, /* default margin - points */
- {0.,0.}, /* default page width, height - points */
- {96.,96.}, /* dpi */
- };
- static gvdevice_features_t device_features_gd_no_writer = {
- GVDEVICE_BINARY_FORMAT
- | GVDEVICE_NO_WRITER
- | GVDEVICE_DOES_TRUECOLOR,/* flags */
- {0.,0.}, /* default margin - points */
- {0.,0.}, /* default page width, height - points */
- {96.,96.}, /* dpi */
- };
- #endif
- gvplugin_installed_t gvdevice_gd_types[] = {
- #ifdef HAVE_PANGOCAIRO
- #ifdef HAVE_GD_GIF
- {FORMAT_GIF, "gif:cairo", 10, &gd_engine, &device_features_gd},
- {FORMAT_WBMP, "wbmp:cairo", 5, &gd_engine, &device_features_gd},
- #endif
- #ifdef HAVE_GD_JPEG
- {FORMAT_JPEG, "jpe:cairo", 5, &gd_engine, &device_features_gd},
- {FORMAT_JPEG, "jpeg:cairo", 5, &gd_engine, &device_features_gd},
- {FORMAT_JPEG, "jpg:cairo", 5, &gd_engine, &device_features_gd},
- #endif
- #ifdef HAVE_GD_PNG
- {FORMAT_PNG, "png:cairo", 5, &gd_engine, &device_features_gd},
- #endif
- {FORMAT_GD, "gd:cairo", 5, &gd_engine, &device_features_gd_no_writer},
- {FORMAT_GD2, "gd2:cairo", 5, &gd_engine, &device_features_gd_no_writer},
- #endif
- {0, NULL, 0, NULL, NULL}
- };
|