gvdevice plugin to output cairo bitmaps; encapsulated graphics context and modularize...
authorglenlow <devnull@localhost>
Sat, 5 Jul 2008 06:43:09 +0000 (06:43 +0000)
committerglenlow <devnull@localhost>
Sat, 5 Jul 2008 06:43:09 +0000 (06:43 +0000)
plugin/gdiplus/Makefile.am
plugin/gdiplus/gvdevice_gdiplus.cpp [new file with mode: 0755]
plugin/gdiplus/gvplugin_gdiplus.cpp
plugin/gdiplus/gvplugin_gdiplus.h
plugin/gdiplus/gvrender_gdiplus.cpp

index 2765f17bc5812bb43a2861aa6ce981694107af3d..8f934e94a355fc36395e632c8389ec3d490415c7 100644 (file)
@@ -26,6 +26,7 @@ noinst_HEADERS = FileStream.h gvplugin_gdiplus.h
 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
@@ -46,6 +47,8 @@ endif
 
 # 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)
diff --git a/plugin/gdiplus/gvdevice_gdiplus.cpp b/plugin/gdiplus/gvdevice_gdiplus.cpp
new file mode 100755 (executable)
index 0000000..673575d
--- /dev/null
@@ -0,0 +1,79 @@
+/* $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}
+};
index 0301de1b724eca13543a4708e3a06feae90dff68..df773f35e5e5dd3f1582829b1f4bc96ea9fe8b34 100755 (executable)
 
 #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},
 };
 
index 6ddc0fc9bfbe7c61bb81ff9ffe70e3af4062910c..19eb14085ea8124cb2a78795b12258c16644f818 100755 (executable)
@@ -17,6 +17,9 @@
 #ifndef GVPLUGIN_GDIPLUS_H
 #define GVPLUGIN_GDIPLUS_H
 
+#include <Windows.h>
+#include <GdiPlus.h>
+
 typedef enum {
        FORMAT_NONE,
        FORMAT_BMP,
@@ -28,4 +31,16 @@ typedef enum {
        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
index 26b40380b37266a40f8c1ed245b2662dc5d43e46..3fcc7ed18da8df5fc95e7f2c7a59eeb70d282eb9 100755 (executable)
@@ -26,9 +26,6 @@
 #include "graph.h"
 #include "gvplugin_gdiplus.h"
 
-#include <windows.h>
-#include "GdiPlus.h"
-
 #include <memory>
 #include <vector>
 
@@ -37,27 +34,15 @@ extern "C" size_t gvdevice_write(GVJ_t *job, const unsigned char *s, unsigned in
 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)
        {
        }
 };
@@ -92,7 +77,7 @@ static void gdiplusgen_end_job(GVJ_t *job)
                
                /* 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;
@@ -102,20 +87,7 @@ static void gdiplusgen_end_job(GVJ_t *job)
                        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;
                }
                
@@ -131,7 +103,7 @@ static void gdiplusgen_end_job(GVJ_t *job)
                GlobalFree(buffer);
                        
                /* since this is an internal job, shut down GDI+ */
-               GdiplusShutdown(startupToken);
+               delete graphicsContext;
        }
 }
 
@@ -139,9 +111,7 @@ static void gdiplusgen_begin_page(GVJ_t *job)
 {
        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);
@@ -168,7 +138,7 @@ static void gdiplusgen_begin_page(GVJ_t *job)
                        break;
                }
                
-               job->context = new ImageGraphics(startupToken, image, stream);
+               job->context = new ImageGraphics(context, image, stream);
        }
        
        /* start graphics state */