使用ITextSharp将谷歌可视化areacartsvg添加到pdf中
本文关键字:添加 pdf areacartsvg 可视化 ITextSharp 谷歌 使用 | 更新日期: 2023-09-27 18:19:31
Am在创建网页的打印机友好pdf版本的过程中,在尝试添加谷歌区域图时遇到了一些困难。
areacart是使用JavaScript生成的,并在页面上呈现为svg。我尝试了许多不同的方法来添加图表,包括为包含图表的div导入html(到目前为止,我使用这种方法得到的只是图表的标题,而不是实际的图表),我已经研究过将svg转换为图像格式(png、jpeg、gif等),然后保存图像并将其作为图像添加到pdf中。
有人对我如何实现这一点有什么想法吗?
如有任何建议,我们将不胜感激。
使用jQuery和https://github.com/vvvv/SVG我想你使用的是MVC
Javascript:
$("#makePdf").click(function (e) {
$.ajax({
type: 'POST',
url: '/GeneratePdf',
dataType: 'json',
data: JSON.stringify({ svgXml: $("<div />").append($("#chart svg").clone()).html() }),
contentType: 'application/json;charset=utf-8',
success: function (data) {
window.open('/GetPdf?pdfId=' + data.pdfId, '_blank');
}
});
e.preventDefault();
});
需要$("<div />").append($("#chart svg").clone()).html()
,因为无法获取当前元素的xml源,这是我能找到的最优雅的方法,将其附加到新的div
并获取其内容的html。
C#:
using System;
using System.IO;
using System.Drawing.Imaging;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Svg;
// ...
public static MemoryStream PngFromSvg(string svgXml)
{
MemoryStream pngStream = new MemoryStream();
if (!string.IsNullOrWhiteSpace(svgXml))
{
byte[] byteArray = Encoding.ASCII.GetBytes(svgXml);
using (MemoryStream stream = new MemoryStream(byteArray))
{
SvgDocument svgDocument = SvgDocument.Open(stream);
System.Drawing.Bitmap bitmap = svgDocument.Draw();
bitmap.Save(pngStream, System.Drawing.Imaging.ImageFormat.Png);
}
}
}
public static MemoryStream GeneratePdf(MemoryStream pngStream)
{
MemoryStream pdfStream = new MemoryStream();
using (Document document = new Document(PageSize.A4, 20, 20, 20, 20))
{
PdfWriter pdfWriter = PdfWriter.GetInstance(document, pdfStream);
// ...
Image chartImage = Image.GetInstance(System.Drawing.Image.FromStream(pngStream), ImageFormat.Png);
PdfPCell chartCell = new PdfPCell(chartImage, true);
chartCell.Border = Rectangle.NO_BORDER;
//...
document.Close();
pdfWriter.Close();
}
return pdfStream;
}
public class SvgData
{
public string svgXml { get; set; }
}
public class PdfData
{
public string pdfId { get; set; }
}
public JsonResult GeneratePdf(SvgData data)
{
byte[] pdfBytes = GeneratePdf(PngFromSvg(data.svgXml)).ToArray();
// ...
// Either:
// :: Store PDF in database as blob and return unique ID
// :: Store as file and return path to file
return Json(new PdfData{pdfId = pdf.id}, JsonRequestBehavior.AllowGet);
}
public ActionResult GetPdf(Int64 pdfId)
{
// retrieve pdf from database
byte[] pdfBytes = pdf.raw;
return File(pdfBytes, "application/pdf");
}
这个代码很糟糕,但应该是不言自明的。在过去的两周里,这让我头疼,所以我知道你在试图找到"有效"的解决方案时的痛苦。在我看来,发送要解析的svg数据是糟糕的!但除了模仿网络浏览器的渲染引擎,我想不出其他方法了!!
注意:当字体的样式在样式属性中设置时,字体可能会正确呈现,您需要解析这些字体,并使用font-
属性设置字体,例如
$chartSvg.find("text").each(function () {
var $this = $(this);
$this.attr("font-size", $this.css("font-size"));
$this.css("font-size", "");
$this.attr("font-style", $this.css("font-style"));
$this.css("font-style", "");
$this.attr("font-variant", $this.css("font-variant"));
$this.css("font-variant", "");
$this.attr("font-weight", $this.css("font-weight"));
$this.css("font-weight", "");
$this.attr("font-family", $this.css("font-family"));
$this.css("font-family", "");
});
png的质量可能很差,所以我所做的是将svg缩放到两倍的大小,然后将其发送到服务器:
var $chartSvg = $("#chart").find("svg");
var $chartSvgClone = $chartSvg.clone().attr("height", $chartSvg.height() * 2).attr("width", $chartSvg.width() * 2).css("transform", "scale(2)");
var $svgXml = $("<div />").append($chartSvgClone).html();
// ...
另一个警告是,svg库似乎没有正确设置字体系列,所以在您的C#代码中,将SvgDocument传递给
public void SetFonts(SvgElement parent)
{
try
{
SvgText svgText = (SvgText)parent;
svgText.Font = new System.Drawing.Font("Arial", svgText.FontSize.Value);
}
catch
{
}
if(parent.HasChildren())
{
foreach(SvgElement child in parent.Children)
{
SetFonts(child);
}
}
}