優化HighCharts 利用svg導出圖片到Excel,圖片模糊問題 ...
需求:數據統計報表使用到HighCharts顯示各種圖形:柱狀圖,餅圖,點陣圖等等,需要將數據表以及對應的圖像導入到Excel中,方便列印。
解決方法: Excel導出採用NPOI,HighChart圖像利用svg將圖片寫入到Excel中。
遇到的問題:圖片模糊,圖片清晰度與web頁面相比差距很大。
明顯可以看出,差別很大,無法達到要求, 實現此所採用的代碼:
1 var doc = new SvgDocument(); 2 XmlDocument xml = new XmlDocument(); 3 xml.LoadXml(this.chart_Hidden.Value); 4 doc = SvgDocument.Open(xml); 5 Bitmap mapImage = doc.Draw(); 6 byte[] buffer = NPOIExportExcelHelp.BitmapToBytes(mapImage); 7 int pictureIdx = workBook.AddPicture(buffer, PictureType.JPEG); 8 HSSFPatriarch patriarch = (HSSFPatriarch)sheet.CreateDrawingPatriarch(); 9 HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 0, 0, 7, 0, 7, 15); 10 HSSFPicture pict = (HSSFPicture)patriarch.CreatePicture(anchor, pictureIdx); 11 pict.Resize();View Code
優化方案:
1 下載開源的.net導出文件: https://github.com/imclem/Highcharts-export-module-asp.net
利用此項目中的dll文件:itextsharp.dll,sharpPDF.dll,Svg.dll
2 借鑒文章:https://jucelin.com/highcharts_esport_net.html 中針對於CreateSvgDocument()方法的優化改造,優化圖片的格式,1 /// <summary> 2 /// Creates an SvgDocument from the SVG text string. 3 /// </summary> 4 /// <returns>An SvgDocument object.</returns> 5 private SvgDocument CreateSvgDocument() 6 { 7 SvgDocument svgDoc; 8 XmlDocument xml = new XmlDocument(); 9 xml.LoadXml(this.Svg); 10 XmlNodeList nodeListAllg = xml.GetElementsByTagName("g"); 11 Dictionary<int, XmlNode[,]> dic = new Dictionary<int, XmlNode[,]>(); 12 int i = 0; 13 foreach (XmlNode xNod in nodeListAllg) 14 { 15 i++; 16 XmlNode xmlvisibility = xNod.Attributes.GetNamedItem("class"); 17 if (xmlvisibility != null && xmlvisibility.Value == "highcharts-series-group") 18 { 19 foreach (XmlNode xNod2 in xNod.ChildNodes) 20 { 21 i++; 22 XmlNode xmlvisibility1 = xNod2.Attributes.GetNamedItem("visibility"); 23 if (xmlvisibility1 != null && xmlvisibility1.Value == "hidden") 24 { 25 XmlNode[,] xmln = new XmlNode[1, 2]; 26 xmln[0, 0] = xNod; 27 xmln[0, 1] = xNod2; 28 dic.Add(i, xmln); 29 } 30 } 31 } 32 else if (xmlvisibility != null && xmlvisibility.Value == "highcharts-tooltip") 33 { 34 XmlNode[,] xmln = new XmlNode[1, 2]; 35 xmln[0, 0] = xml.FirstChild; 36 xmln[0, 1] = xNod; 37 dic.Add(i, xmln); 38 } 39 } 40 foreach (KeyValuePair<int, XmlNode[,]> a in dic) 41 { 42 a.Value[0, 0].RemoveChild(a.Value[0, 1]); 43 } 44 this.Svg = xml.OuterXml; 45 // Create a MemoryStream from SVG string. 46 using (MemoryStream streamSvg = new MemoryStream( 47 Encoding.UTF8.GetBytes(this.Svg))) 48 { 49 // Create and return SvgDocument from stream. 50 svgDoc = SvgDocument.Open(streamSvg); 51 } 52 // Scale SVG document to requested width. 53 svgDoc.Transforms = new SvgTransformCollection(); 54 float scalar = (float)this.Width / (float)svgDoc.Width; 55 svgDoc.Transforms.Add(new SvgScale(scalar, scalar)); 56 svgDoc.Width = new SvgUnit(svgDoc.Width.Type, svgDoc.Width * scalar); 57 svgDoc.Height = new SvgUnit(svgDoc.Height.Type, svgDoc.Height * scalar); 58 return svgDoc; 59 }View Code 3 利用第二步的方法,基本可以滿足要求,生成的Exce圖片效果如下 4 將以上方法整理封裝成類庫
1 public class HightChartExport 2 { 3 /// <summary> 4 /// 獲取svg圖片buffer,用於excel 5 /// </summary> 6 /// <param name="svgHtml"></param> 7 /// <param name="width"></param> 8 /// <param name="height"></param> 9 /// <returns></returns> 10 public static byte[] GetSvgDocumentByte(string svgHtml, int width, int height) 11 { 12 try 13 { 14 if (string.IsNullOrEmpty(svgHtml)) 15 { 16 return new byte[0]; 17 } 18 if (width == 0 || height == 0) 19 { 20 return new byte[0]; 21 } 22 SvgDocument svgDocument = CreateSvgDocument(svgHtml, width, height); 23 return BitmapToBytes(svgDocument.Draw()); 24 } 25 catch 26 { 27 throw new Exception(); 28 } 29 } 30 private static SvgDocument CreateSvgDocument(string svgHtml, int width, int height) 31 { 32 SvgDocument svgDoc; 33 XmlDocument xml = new XmlDocument(); 34 xml.LoadXml(svgHtml); 35 XmlNodeList nodeListAllg = xml.GetElementsByTagName("g"); 36 Dictionary<int, XmlNode[,]> dic = new Dictionary<int, XmlNode[,]>(); 37 int i = 0; 38 foreach (XmlNode xNod in nodeListAllg) 39 { 40 i++; 41 XmlNode xmlvisibility = xNod.Attributes.GetNamedItem("class"); 42 if (xmlvisibility != null && xmlvisibility.Value == "highcharts-series-group") 43 { 44 foreach (XmlNode xNod2 in xNod.ChildNodes) 45 { 46 i++; 47 XmlNode xmlvisibility1 = xNod2.Attributes.GetNamedItem("visibility"); 48 if (xmlvisibility1 != null && xmlvisibility1.Value == "hidden") 49 { 50 XmlNode[,] xmln = new XmlNode[1, 2]; 51 xmln[0, 0] = xNod; 52 xmln[0, 1] = xNod2; 53 dic.Add(i, xmln); 54 } 55 } 56 } 57 else if (xmlvisibility != null && xmlvisibility.Value == "highcharts-tooltip") 58 { 59 XmlNode[,] xmln = new XmlNode[1, 2]; 60 xmln[0, 0] = xml.FirstChild; 61 xmln[0, 1] = xNod; 62 dic.Add(i, xmln); 63 } 64 } 65 foreach (KeyValuePair<int, XmlNode[,]> a in dic) 66 { 67 a.Value[0, 0].RemoveChild(a.Value[0, 1]); 68 } 69 svgHtml = xml.OuterXml; 70 // Create a MemoryStream from SVG string. 71 using (MemoryStream streamSvg = new MemoryStream( 72 Encoding.UTF8.GetBytes(svgHtml))) 73 { 74 // Create and return SvgDocument from stream. 75 svgDoc = SvgDocument.Open<SvgDocument>(streamSvg); 76 } 77 // Scale SVG document to requested width. 78 svgDoc.Transforms = new SvgTransformCollection(); 79 float scalar = (float)width / (float)svgDoc.Width; 80 svgDoc.Transforms.Add(new SvgScale(scalar, scalar)); 81 svgDoc.Width = new SvgUnit(svgDoc.Width.Type, svgDoc.Width * scalar); 82 svgDoc.Height = new SvgUnit(svgDoc.Height.Type, svgDoc.Height * scalar); 83 return svgDoc; 84 } 85 /// <summary> 86 /// 讀取圖片 87 /// </summary> 88 /// <param name="Bitmap"></param> 89 /// <returns></returns> 90 private static byte[] BitmapToBytes(Bitmap Bitmap) 91 { 92 MemoryStream ms = null; 93 try 94 { 95 ms = new MemoryStream(); 96 Bitmap.Save(ms, ImageFormat.Png); 97 byte[] byteImage = new Byte[ms.Length]; 98 byteImage = ms.ToArray(); 99 return byteImage; 100 } 101 catch (ArgumentNullException ex) 102 { 103 throw ex; 104 } 105 finally 106 { 107 ms.Close(); 108 } 109 } 110 }View Code
5 調用方法如下:
1 byte[] buffer = HightChartExport.GetSvgDocumentByte(this.chart_Pie.Value, Convert.ToInt32(chart_width.Value), Convert.ToInt32(chart_height.Value)); 2 int pictureIdx = workBook.AddPicture(buffer, PictureType.PNG); 3 HSSFPatriarch patriarch = (HSSFPatriarch)sheet.CreateDrawingPatriarch(); 4 HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 0, 0, 0, rowIndex + 1, 0, 15); 5 HSSFPicture pict = (HSSFPicture)patriarch.CreatePicture(anchor, pictureIdx); 6 pict.Resize();View Code
參考文章
https://github.com/imclem/Highcharts-export-module-asp.net
https://jucelin.com/highcharts_esport_net.html