1

我可以渲染文本,但不能渲染 svg 元素。当我保存我试图呈现为 svg 文件的 html 时,Internet Explorer 会以它应该的方式呈现完整的图像,所以我相当确信我的输入数据是好的。

这是我启动启动网络浏览器的线程的地方

Browserinfo bi = new Browserinfo(height, width, rsltPath, stype);
bi.Temphtml = temphtml.Replace("\\", "/");
Thread webBrowseThread = new Thread(new ParameterizedThreadStart(PerformWebBrowseOp));
webBrowseThread.SetApartmentState(ApartmentState.STA);
webBrowseThread.Start(bi);

bi.Temphtml 是我保存输入数据的文件。这是文件的外观(去掉了内脏)

   <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head></head><body><svg xmlns="http://www.w3.org/2000/svg"
    ..svg data...
    </svg></body></html>

这是实际的代码:

private void PerformWebBrowseOp(object obj)
{
    Browserinfo bi = (Browserinfo)obj;
    using (Bitmap bitmap = new Bitmap(bi.Width, bi.Height))
    {
        using (WebBrowser webBrowser = new WebBrowser())
        {
            webBrowser.Navigate("file:///"+bi.Temphtml);
            while (webBrowser.Document.Body == null)
            {
                Application.DoEvents();
            }


            IHTMLDocument2 rawDoc = (IHTMLDocument2)webBrowser.Document.DomDocument;
            //rawDoc.write(sbody);
            IHTMLElement rawBody = rawDoc.body;
            IHTMLElementRender2 render = (IHTMLElementRender2)rawBody;

            Rectangle bitmapRect = new Rectangle(0, 0, bi.Width, bi.Height);
            webBrowser.DrawToBitmap(bitmap, bitmapRect);


            System.Drawing.Imaging.Encoder qualityEncoder = System.Drawing.Imaging.Encoder.Quality;
            var quality = (long)100;
            using (EncoderParameter ratio = new EncoderParameter(qualityEncoder, quality))
            {
                using (EncoderParameters codecParams = new EncoderParameters(1))
                {
                    codecParams.Param[0] = ratio;
                    ImageCodecInfo ici = null;
                    if (bi.ImgType == "jpg")
                    {
                        ici = GetImageEncoder(ImageFormat.Jpeg);
                    }
                    else
                    {
                        ici = GetImageEncoder(ImageFormat.Png);
                    }
                    bitmap.Save(bi.SavePath, ici, codecParams);
                }
            }
        }
    }
    ((AutoResetEvent)waithandle[0]).Set();
}

为了保持讨论的重点,以下注释可能会有所帮助:我最初使用 Batik 并让它工作,但我们的网络服务器上没有安装 Java,老板拒绝安装它。回到绘图板!

我下载了 svg.dll,并让它部分工作。它将渲染部分 svg 元素,但不渲染文本。

我想我缺少一个接口或者应该调用一个 com 对象,但不知道如何或做什么。

4

1 回答 1

1

简单的答案,你不能那样做。但是,您可以使用 librsvg 来完成。我已经复制了下面的代码,该代码适用于 png,但不适用于 jpeg。如果有人能看到 jpeg 部分有什么问题,请告诉我。

您将需要的文件是:

freetype6.dll
intl.dll
libcairo-2.dll
libcroco-0.6-3.dll
libexpat-1.dll
libfontconfig-1.dll
libgdk-win32-2.0-0.dll
libgdk_pixbuf-2.0-0.dll
libgio-2.0-0.dll
libglib-2.0-0.dll
libgmodule-2.0-0.dll
libgobject-2.0-0.dll
libgthread-2.0-0.dll
libgtk-win32-2.0-0.dll
libpango-1.0-0.dll
libpangocairo-1.0-0.dll
libpangoft2-1.0-0.dll
libpangowin32-1.0-0.dll
libpixbufloader-svg.dll
libpng14-14.dll
librsvg-2-2.dll
libxml2-2.dll
zlib1.dll

从您的 html 页面中提取的 svg 代码应如下所示。

<svg xmlns="http://www.w3.org/2000/svg" width="945" height="325"....</svg>

换句话说,去掉除了 svg 标签中的所有 html

这是 C# 例程

private void RasterizeSvg(string tempsvg, string rsltPath, int _width, int _height, string formattype)
{
    string slib = ConfigurationManager.AppSettings["LibrSvgPath"];
    if (slib == null)
    {
        slib = @"C:\Librsvg";
    }
    bool callSuccessful = SetDllDirectory(slib); 
    if (!callSuccessful)
    {
        throw new Exception("Could not set DLL directory");
    }

    // g_type_init is critical for the png to save correctly
    g_type_init();
    rsvg_init();

    IntPtr error = IntPtr.Zero;
    IntPtr rsvghandle = rsvg_handle_new_from_file(tempsvg, out error);

    if (error != IntPtr.Zero)
    {
        throw new Exception(Marshal.ReadInt32(error).ToString());
    }
    rsvg_handle_close(rsvghandle, out error);
    if (error != IntPtr.Zero)
    {
        throw new Exception(Marshal.ReadInt32(error).ToString());
    }
    IntPtr cairosurface = cairo_image_surface_create(cairo_format_t.CAIRO_FORMAT_RGB24, _width, _height);
    IntPtr cairocontext = cairo_create(cairosurface);
    bool brslt = rsvg_handle_render_cairo(rsvghandle, cairocontext);

    cairo_destroy(cairocontext);

    if (formattype == "png")
    {
        cairo_surface_write_to_png(cairosurface, rsltPath);
        cairo_surface_destroy(cairosurface);
    }
    else
    {
        //jpeg not working.  the problem is how to convert from a cairo surface to a pixbuf
        // once we figure that out, we can implement the jpeg conversion

        /*option 1*/
        //IntPtr pixbuf = cairo_create(cairosurface);
        //cairo_set_source_surface(pixbuf, cairosurface, 0, 0);
        //cairo_rectangle(pixbuf, 0, 0, _width, _height);
        //cairo_fill(pixbuf);
        //error = IntPtr.Zero;                

        /*option 2*/
        IntPtr pixbuf = rsvg_handle_get_pixbuf(rsvghandle);
        rsvg_handle_close(rsvghandle, out error);

        cairo_surface_destroy(cairosurface);
        gdk_init(0, "");
        callSuccessful = gdk_pixbuf_save(pixbuf, rsltPath, formattype, out error);
        gdk_exit(out error);

        if (!callSuccessful)
        {
            throw new Exception(error.ToInt32().ToString());
        }
        /* need to release pixbuf memory*/
    }
    g_object_unref(rsvghandle);
}

正如我在顶部所说,jpeg 还没有工作。但它会渲染为png。

最后这里有一些你需要的声明

enum cairo_format_t
{
    CAIRO_FORMAT_INVALID = -1,
    CAIRO_FORMAT_ARGB32 = 0,
    CAIRO_FORMAT_RGB24 = 1,
    CAIRO_FORMAT_A8 = 2,
    CAIRO_FORMAT_A1 = 3,
    CAIRO_FORMAT_RGB16_565 = 4,
    CAIRO_FORMAT_RGB30 = 5
}

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern bool SetDllDirectory(string pathname);

[DllImport("libgobject-2.0-0.dll", SetLastError = true)]
static extern void g_type_init();

[DllImport("libgobject-2.0-0.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void g_object_unref(IntPtr obj);

[DllImport("librsvg-2-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern bool rsvg_handle_render_cairo(IntPtr handle, IntPtr cairorenderer);

[DllImport("librsvg-2-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr rsvg_handle_get_pixbuf(IntPtr _rsvghandle);

[DllImport("librsvg-2-2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr rsvg_handle_new_from_file(string file_name, out IntPtr error);

[DllImport("librsvg-2-2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern bool rsvg_handle_close(IntPtr _rsvghandle, out IntPtr error);

[DllImport("librsvg-2-2.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void rsvg_init();

[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr cairo_create(IntPtr cairo_surface_t);

[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr cairo_image_surface_create(cairo_format_t _pixformat, int width, int height);

[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_surface_write_to_png(IntPtr cairo_surface_t, string filename);

[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_set_source_surface(IntPtr destbuf, IntPtr srcsuface, double x, double y);

[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_rectangle(IntPtr buf, double x, double y, double width, double height);

[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_fill(IntPtr destbuf);

[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_destroy(IntPtr buf);

[DllImport("libcairo-2.dll", SetLastError = true, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void cairo_surface_destroy(IntPtr buf);

[DllImport("libgdk_pixbuf-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern bool gdk_pixbuf_save(IntPtr pixbuf, string filename, string type, out IntPtr error);

[DllImport("libgdk_pixbuf-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern IntPtr gdk_pixbuf_get_from_drawable(IntPtr dest, IntPtr src, IntPtr cmap, int srcx, int srcy, int destx, int desty, int width, int height);

[DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void gdk_init(int argcnt, string args);

[DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern void gdk_exit(out IntPtr error);
于 2012-10-02T14:23:53.160 回答