nodist_libgvplugin_gdiplus_C_la_SOURCES = GdiPlus*.h
libgvplugin_gdiplus_C_la_SOURCES = \
FileStream.cpp \
+ gvdevice_gdiplus.cpp \
gvloadimage_gdiplus.cpp \
gvplugin_gdiplus.cpp \
gvrender_gdiplus.cpp
# object code is dependent on all the local GDI+ headers
+gvdevice_gdiplus.lo : $(GDIPLUS_HEADS)
+
gvloadimage_gdiplus.lo : $(GDIPLUS_HEADS)
gvrender_gdiplus.lo : $(GDIPLUS_HEADS)
--- /dev/null
+/* $Id$ $Revision$ */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+* This software is part of the graphviz package *
+* http://www.graphviz.org/ *
+* *
+* Copyright (c) 1994-2004 AT&T Corp. *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Corp. *
+* *
+* Information and Software Systems Research *
+* AT&T Research, Florham Park NJ *
+**********************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gvplugin_device.h"
+
+#include "gvplugin_gdiplus.h"
+
+extern "C" size_t gvdevice_write(GVJ_t *job, const unsigned char *s, unsigned int len);
+
+using namespace Gdiplus;
+
+static void gdiplus_format(GVJ_t *job)
+{
+ /* allocate memory and attach stream to it */
+ HGLOBAL buffer = GlobalAlloc(GMEM_MOVEABLE, 0);
+ IStream *stream = NULL;
+ CreateStreamOnHGlobal(buffer, FALSE, &stream); /* FALSE means don't deallocate buffer when releasing stream */
+
+ /* since this is an internal job, start up GDI+ */
+ GraphicsContext context;
+
+ Bitmap bitmap(
+ job->width, /* width in pixels */
+ job->height, /* height in pixels */
+ job->width * BYTES_PER_PIXEL, /* bytes per row: exactly width # of pixels */
+ PixelFormat32bppPARGB, /* pixel format: corresponds to CAIRO_FORMAT_ARGB32 */
+ job->imagedata); /* pixel data from job */
+ SaveBitmapToStream(bitmap, stream, job->device.id);
+
+ /* blast the streamed buffer back to the gvdevice */
+ /* NOTE: this is somewhat inefficient since we should be streaming directly to gvdevice rather than buffering first */
+ /* ... however, GDI+ requires any such direct IStream to implement Seek Read, Write, Stat methods and gvdevice really only offers a write-once model */
+ stream->Release();
+ gvdevice_write(job, (unsigned char*)GlobalLock(buffer), GlobalSize(buffer));
+ GlobalFree(buffer);
+}
+
+static gvdevice_engine_t gdiplus_engine = {
+ NULL, /* gdiplus_initialize */
+ gdiplus_format,
+ NULL, /* gdiplus_finalize */
+};
+
+static gvdevice_features_t device_features_gdiplus = {
+ GVDEVICE_BINARY_FORMAT
+ | GVDEVICE_DOES_TRUECOLOR,/* flags */
+ {0.,0.}, /* default margin - points */
+ {0.,0.}, /* default page width, height - points */
+ {96.,96.}, /* dpi */
+};
+
+gvplugin_installed_t gvdevice_gdiplus_types_for_cairo[] = {
+ {FORMAT_BMP, "bmp:cairo", 8, &gdiplus_engine, &device_features_gdiplus},
+ {FORMAT_GIF, "gif:cairo", 8, &gdiplus_engine, &device_features_gdiplus},
+ {FORMAT_JPEG, "jpe:cairo", 8, &gdiplus_engine, &device_features_gdiplus},
+ {FORMAT_JPEG, "jpeg:cairo", 8, &gdiplus_engine, &device_features_gdiplus},
+ {FORMAT_JPEG, "jpg:cairo", 8, &gdiplus_engine, &device_features_gdiplus},
+ {FORMAT_PNG, "png:cairo", 8, &gdiplus_engine, &device_features_gdiplus},
+ {FORMAT_TIFF, "tif:cairo", 8, &gdiplus_engine, &device_features_gdiplus},
+ {FORMAT_TIFF, "tiff:cairo", 8, &gdiplus_engine, &device_features_gdiplus},
+ {0, NULL, 0, NULL, NULL}
+};
#include "gvplugin.h"
+#include "gvplugin_gdiplus.h"
+
+#include <vector>
+
extern gvplugin_installed_t gvrender_gdiplus_types;
// extern gvplugin_installed_t gvtextlayout_gdiplus_types;
extern gvplugin_installed_t gvloadimage_gdiplus_types;
extern gvplugin_installed_t gvdevice_gdiplus_types;
+extern gvplugin_installed_t gvdevice_gdiplus_types_for_cairo;
+
+using namespace std;
+using namespace Gdiplus;
+
+GraphicsContext::GraphicsContext()
+{
+ GdiplusStartupInput startupInput;
+ GdiplusStartup(&token, &startupInput, NULL);
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ GdiplusShutdown(token);
+}
+
+/* class id corresponding to each format_type */
+static GUID format_id [] = {
+ GUID_NULL,
+ ImageFormatBMP,
+ ImageFormatEMF,
+ ImageFormatEMF,
+ ImageFormatGIF,
+ ImageFormatJPEG,
+ ImageFormatPNG,
+ ImageFormatTIFF
+};
+
+void SaveBitmapToStream(Bitmap &bitmap, IStream *stream, int format)
+{
+ /* search the encoders for one that matches our device id, then save the bitmap there */
+ UINT encoderNum;
+ UINT encoderSize;
+ GetImageEncodersSize(&encoderNum, &encoderSize);
+ vector<char> codec_buffer(encoderSize);
+ ImageCodecInfo *codecs = (ImageCodecInfo *)&codec_buffer.front();
+ GetImageEncoders(encoderNum, encoderSize, codecs);
+ for (UINT i = 0; i < encoderNum; ++i)
+ if (memcmp(&(format_id[format]), &codecs[i].FormatID, sizeof(GUID)) == 0) {
+ bitmap.Save(stream, &codecs[i].Clsid, NULL);
+ break;
+ }
+}
static gvplugin_api_t apis[] = {
{API_render, &gvrender_gdiplus_types},
// {API_textlayout, &gvtextlayout_gdiplus_types},
{API_loadimage, &gvloadimage_gdiplus_types},
{API_device, &gvdevice_gdiplus_types},
+ {API_device, &gvdevice_gdiplus_types_for_cairo},
{(api_t)0, 0},
};
#ifndef GVPLUGIN_GDIPLUS_H
#define GVPLUGIN_GDIPLUS_H
+#include <Windows.h>
+#include <GdiPlus.h>
+
typedef enum {
FORMAT_NONE,
FORMAT_BMP,
FORMAT_TIFF
} format_type;
+struct GraphicsContext
+{
+ ULONG_PTR token;
+
+ GraphicsContext();
+ ~GraphicsContext();
+};
+
+static const int BYTES_PER_PIXEL = 4; /* bytes per pixel */
+
+extern void SaveBitmapToStream(Gdiplus::Bitmap &bitmap, IStream *stream, int format);
+
#endif
#include "graph.h"
#include "gvplugin_gdiplus.h"
-#include <windows.h>
-#include "GdiPlus.h"
-
#include <memory>
#include <vector>
using namespace std;
using namespace Gdiplus;
-/* class id corresponding to each format_type */
-static GUID format_id [] = {
- GUID_NULL,
- ImageFormatBMP,
- ImageFormatEMF,
- ImageFormatEMF,
- ImageFormatGIF,
- ImageFormatJPEG,
- ImageFormatPNG,
- ImageFormatTIFF
-};
-
/* Graphics for internal use, so that we can record image etc. for subsequent retrieval off the job struct */
struct ImageGraphics: public Graphics
{
- ULONG_PTR token;
+ GraphicsContext *context;
Image *image;
IStream *stream;
- ImageGraphics(ULONG_PTR startupToken, Image *newImage, IStream *newStream):
- Graphics(newImage), token(startupToken), image(newImage), stream(newStream)
+ ImageGraphics(GraphicsContext *newContext, Image *newImage, IStream *newStream):
+ Graphics(newImage), context(newContext), image(newImage), stream(newStream)
{
}
};
/* flush and delete the graphics */
ImageGraphics *imageGraphics = static_cast<ImageGraphics *>(context);
- ULONG_PTR startupToken = imageGraphics->token;
+ GraphicsContext *graphicsContext = imageGraphics->context;
Image *image = imageGraphics->image;
IStream *stream = imageGraphics->stream;
delete imageGraphics;
case FORMAT_EMFPLUS:
break;
default:
- /* search the encoders for one that matches our device id, then save the bitmap there */
- Bitmap *bitmap = static_cast<Bitmap *>(image);
- GUID formatId = format_id[job->device.id];
- UINT encoderNum;
- UINT encoderSize;
- GetImageEncodersSize(&encoderNum, &encoderSize);
- vector<char> codec_buffer(encoderSize);
- ImageCodecInfo *codecs = (ImageCodecInfo *)&codec_buffer.front();
- GetImageEncoders(encoderNum, encoderSize, codecs);
- for (UINT i = 0; i < encoderNum; ++i)
- if (memcmp(&(format_id[job->device.id]), &codecs[i].FormatID, sizeof(GUID)) == 0) {
- bitmap->Save(stream, &codecs[i].Clsid, NULL);
- break;
- }
+ SaveBitmapToStream(*static_cast<Bitmap *>(image), stream, job->device.id);
break;
}
GlobalFree(buffer);
/* since this is an internal job, shut down GDI+ */
- GdiplusShutdown(startupToken);
+ delete graphicsContext;
}
}
{
if (!job->external_context && !job->context) {
/* since this is an internal job, start up GDI+ */
- ULONG_PTR startupToken;
- GdiplusStartupInput startupInput;
- GdiplusStartup(&startupToken, &startupInput, NULL);
+ GraphicsContext *context = new GraphicsContext();
/* allocate memory and attach stream to it */
HGLOBAL buffer = GlobalAlloc(GMEM_MOVEABLE, 0);
break;
}
- job->context = new ImageGraphics(startupToken, image, stream);
+ job->context = new ImageGraphics(context, image, stream);
}
/* start graphics state */