SVG2PNG(前台个后台将SVG转换为PNG,完美支持IE8下载)--amcharts导出png

Posted Qiao_Zhi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SVG2PNG(前台个后台将SVG转换为PNG,完美支持IE8下载)--amcharts导出png相关的知识,希望对你有一定的参考价值。

  在项目中用到了amcharts,amcharts图标统计插件是利用SVG实现的,其自带下载png功能,但是不支持IE以下浏览器。因此研究了SVG转换为png,最终实现的效果是将amcharts生成一张png写入一个excel并提供下载。(只支持IE9以上)

1.SVG简介:

SVG 意为可缩放矢量图形(Scalable Vector Graphics)。说白了就是利用xml定义图形。

SVG 使用 XML 格式定义图像。

例如一个简单的圆形:

<html>
<body>
<h1>My first SVG</h1>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black"
  stroke-width="2" fill="red" />
</svg>
</body>
</html>

 

结果:

 

 

注意:如果将SVG的父标签去掉也是正常使用的,比如:(用浏览器打开后缀为下面后缀为SVG的文件)

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black"
  stroke-width="2" fill="red" />
</svg>

 

结果:

 

 

 但是如果将SVG根标签的xmlns属性去掉是不会显示为图形的,比如:

<svg version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black"
  stroke-width="2" fill="red" />
</svg>

 

 总结:SVG如果正常显示为图形,需要在SVG根标签引入   xmlns="http://www.w3.org/2000/svg"  

更多的关于SVG的使用参考菜鸟教程:http://www.runoob.com/svg/svg-tutorial.html

 

2.SVG转换为PNG

  会研究前台JS生成和后台利用batik生成png。所有用到的JS以及lib或者其他会在最后提供github连接。

2.1前台转换(不支持IE)

 需要的JS:saveSvgAsPng.js   ,前台下载也比较简单。支持chrome、firefox等主流浏览器(Ie就不主流了。。。。。)

 简单的测试:

<html>
    <body>
        <h1>My first SVG</h1>
        <div>
            <svg xmlns="http://www.w3.org/2000/svg" version="1.1" id="testSvg">
                  <circle cx="100" cy="50" r="40" stroke="black"
                  stroke-width="2" fill="red" />
            </svg>
        </div>
        <button onclick="downloadSvg()">download</button>
    </body>
    <script src="saveSvgAsPng.js" type="text/javascript" charset="utf-8"></script>
    <script type="text/javascript">
        function downloadSvg(){
            //下载的方法--第一个参数是SVG的顶级元素,第二个参数是文件名字
            saveSvgAsPng(document.getElementById("testSvg"), "diagram.png");
        }
    </script>
</html>

 

 

 2.2后台将SVG转换为PNG

  (后台转换的时候svgCode的第一个元素必须是svg,而且必须有xmlns属性,而且有一个坑是SVG自带的clippath是小写,导致在裁剪转换的时候识别不了,所以必须将clippath转换为clipPath)

   后台转换也就是将SVGCODE转换为PNG,注意SVGCODE是需要xmlns属性的,否则会转换失败。

  采用的是batik1.7+JDK7(刚开始采用JDK8+batik1.8的时候转换pdf报错)。

  batik官网下载地址:https://xmlgraphics.apache.org/batik/download.html

1.依赖的jar包:(commons-io包是为了读取svgcode)

 

 

 2.工程结构

 

 

3. 需要转换的SVGCODE:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black"
  stroke-width="2" fill="red" />
</svg>

 

直接浏览器打开效果:

 

 4.转换的代码以及测试:

package cn.qlq.svg2png;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.ImageTranscoder;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.io.FileUtils;

/**
 * 将svg转换为png格式的图片
 * 
 * 
 */
public abstract class SVG2PNGUtils {

    /**
     * 将svg字符串转换为png
     * 
     * @param svgCode
     *            svg代码
     * @param pngFilePath
     *            保存的路径
     * @throws TranscoderException
     *             svg代码异常
     * @throws IOException
     *             io错误
     */
    public static void convertToPng(String svgCode, String pngFilePath) throws IOException, TranscoderException {

        File file = new File(pngFilePath);

        FileOutputStream outputStream = null;
        try {
            file.createNewFile();
            outputStream = new FileOutputStream(file);
            convertToPng(svgCode, outputStream);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 将svgCode转换成png文件,直接输出到流中
     * 
     * @param svgCode
     *            svg代码
     * @param outputStream
     *            输出流
     * @throws TranscoderException
     *             异常
     * @throws IOException
     *             io异常
     */
    public static void convertToPng(String svgCode, OutputStream outputStream) throws TranscoderException, IOException {
        try {
            byte[] bytes = svgCode.getBytes("utf-8");
            PNGTranscoder t = new PNGTranscoder();
            TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(bytes));
            TranscoderOutput output = new TranscoderOutput(outputStream);
            // 增加图片的属性设置(单位是像素)---下面是写死了,实际应该是根据SVG的大小动态设置,默认宽高都是400
            t.addTranscodingHint(ImageTranscoder.KEY_WIDTH, new Float(941));
            t.addTranscodingHint(ImageTranscoder.KEY_HEIGHT, new Float(800));
            t.transcode(input, output);
            outputStream.flush();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws IOException, TranscoderException {
        ClassLoader classLoader = SVG2PNGUtils.class.getClassLoader();
        String filePath = classLoader.getResource("cn/qlq/svg2png/svgtest.svg").getPath();
        String svgCode = FileUtils.readFileToString(new File(filePath), "UTF-8");
        convertToPng(svgCode, "e:/test.png");
    }
}

 

 结果会生成PNG。(再次强调SVG文件的xmlns一定要写)

 

SVG也可以转换为pdf与jpeg,下面是写的一个通用方法:

package cn.qlq.svg2png;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.batik.transcoder.Transcoder;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.ImageTranscoder;
import org.apache.batik.transcoder.image.JPEGTranscoder;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.io.FileUtils;
import org.apache.fop.svg.PDFTranscoder;

/**
 * 通用的转换工具类,可以转换PDF、JPG、PNG
 * 
 * @author Administrator
 *
 */
public class SVGConvertUtils {

    /**
     * 
     * @param svgCode
     *            svgcode
     * @param pngFilePath
     *            文件名称
     * @param convertType
     *            转换类型
     * @throws IOException
     * @throws TranscoderException
     */
    public static void convertToPng(String svgCode, String pngFilePath, String convertType)
            throws IOException, TranscoderException {

        File file = new File(pngFilePath);
        FileOutputStream outputStream = null;
        try {
            file.createNewFile();
            outputStream = new FileOutputStream(file);
            convertToPng(svgCode, outputStream, convertType);
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 
     * @param svgCode
     * @param outputStream
     * @param convertType
     *            转换类型
     * @throws TranscoderException
     * @throws IOException
     */
    public static void convertToPng(String svgCode, OutputStream outputStream, String convertType)
            throws TranscoderException, IOException {
        try {
            byte[] bytes = svgCode.getBytes("utf-8");
            Transcoder t = null;
            if ("png".equals(convertType)) {
                t = new PNGTranscoder();
            } else if ("pdf".equals(convertType)) {
                t = new PDFTranscoder();
            } else if ("jpeg".equals(convertType)) {
                t = new JPEGTranscoder();
            }

            TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(bytes));
            TranscoderOutput output = new TranscoderOutput(outputStream);
            // 增加图片的属性设置(单位是像素)---下面是写死了,实际应该是根据SVG的大小动态设置,默认宽高都是400
            t.addTranscodingHint(ImageTranscoder.KEY_WIDTH, new Float(941));
            t.addTranscodingHint(ImageTranscoder.KEY_HEIGHT, new Float(800));
            t.transcode(input, output);
            outputStream.flush();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static void main(String[] args) throws IOException, TranscoderException {
        ClassLoader classLoader = SVG2PNGUtils.class.getClassLoader();
        String filePath = classLoader.getResource("cn/qlq/svg2png/svgtest.svg").getPath();
        String svgCode = FileUtils.readFileToString(new File(filePath), "UTF-8");
        convertToPng(svgCode, "e:/test.png", "png");
        convertToPng(svgCode, "e:/test.pdf", "pdf");
        convertToPng(svgCode, "e:/test.jpeg", "jpeg");
    }
}

 

至此就实现了SVG转换为PNG、PDF、JPEG,在web应用中我们可以将SVGCODE传到后台处理之后生成一个PNG并提供下载,再深入一点可以将图片再写入excel中提供下载。

 

 

3.amcharts生成图片(后台将SVG生成图片到Excel提供下载)

  其实amcharts自带JS下载功能,但是对于IE8却不兼容,在这里研究也主要是为了IE8浏览器的兼容性问题。

  前提需要明白amcharts使用的是SVG方式生成的图形,所以在有了上面的基础之后我们可以将SVG生成图片写入Excel提供下载。先理清自己的思路:

     1.接受前台的SVGCode参数
     2.采用JSoup处理code(加上xmlns属性,并且获取宽度和高度属性)
    3.后台生成图片
    4.图片写入Excel
    5.excel提供下载

  接下来我们按照上面的思路开始编写代码。

 

3.1前台界面的SVG预览图:

    

 

  右键查看元素我们发现amcharts生成的SVG的根元素不带xmlns属性,如下:

    

 

  我们将上面代码保存下来并且在SVG的根元素加    xmlns="http://www.w3.org/2000/svg"  即可正常显示为图形,如下:(也可以自己保存下来通过网页打开)

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="position: absolute; width: 500px; height: 552px;"><desc>JavaScript chart by amCharts 3.4.2</desc><g><path cs="100,100" d="M0.5,0.5 L499.5,0.5 L499.5,551.5 L0.5,551.5 Z" fill="#FFFFFF" stroke="#000000" fill-opacity="0" stroke-width="1" stroke-opacity="0"></path><path cs="100,100" d="M0.5,0.5 L424.5,0.5 L424.5,476.5 L0.5,476.5 Z" fill="#FFFFFF" stroke="#000000" fill-opacity="0" stroke-width="1" stroke-opacity="0" transform="translate(55,55)" class="amChartsPlotArea"></path></g><g><g transform="translate(55,55)"><g><path cs="100,100" d="M0.5,48.5 L5.5,48.5" fill="none" stroke-width="1" stroke-opacity="1" stroke="#DADADA" transform="translate(-6,0)"></path><path cs="100,100" d="M0.5,0.5 L0.5,0.5 L424.5,0.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.15" stroke="#000000"></path></g><g><path cs="100,100" d="M0.5,143.5 L5.5,143.5" fill="none" stroke-width="1" stroke-opacity="1" stroke="#DADADA" transform="translate(-6,0)"></path><path cs="100,100" d="M0.5,95.5 L0.5,95.5 L424.5,95.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.15" stroke="#000000"></path></g><g><path cs="100,100" d="M0.5,238.5 L5.5,238.5" fill="none" stroke-width="1" stroke-opacity="1" stroke="#DADADA" transform="translate(-6,0)"></path><path cs="100,100" d="M0.5,190.5 L0.5,190.5 L424.5,190.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.15" stroke="#000000"></path></g><g><path cs="100,100" d="M0.5,333.5 L5.5,333.5" fill="none" stroke-width="1" stroke-opacity="1" stroke="#DADADA" transform="translate(-6,0)"></path><path cs="100,100" d="M0.5,285.5 L0.5,285.5 L424.5,285.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.15" stroke="#000000"></path></g><g><path cs="100,100" d="M0.5,428.5 L5.5,428.5" fill="none" stroke-width="1" stroke-opacity="1" stroke="#DADADA" transform="translate(-6,0)"></path><path cs="100,100" d="M0.5,380.5 L0.5,380.5 L424.5,380.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.15" stroke="#000000"></path></g><g><path cs="100,100" d="M0.5,476.5 L0.5,476.5 L424.5,476.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.15" stroke="#000000"></path></g></g><g transform="translate(55,55)" visibility="visible"><g><path cs="100,100" d="M0.5,0.5 L0.5,5.5" fill="none" stroke-width="1" stroke-opacity="0.2" stroke="#000000" transform="translate(0,-5)"></path><path cs="100,100" d="M0.5,476.5 L0.5,476.5 L0.5,0.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.15" stroke="#000000"></path></g><g><path cs="100,100" d="M21.5,476.5 L21.5,476.5 L21.5,0.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.08" stroke="#000000"></path></g><g><path cs="100,100" d="M42.5,476.5 L42.5,476.5 L42.5,0.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.08" stroke="#000000"></path></g><g><path cs="100,100" d="M64.5,476.5 L64.5,476.5 L64.5,0.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.08" stroke="#000000"></path></g><g><path cs="100,100" d="M85.5,476.5 L85.5,476.5 L85.5,0.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.08" stroke="#000000"></path></g><g><path cs="100,100" d="M106.5,0.5 L106.5,5.5" fill="none" stroke-width="1" stroke-opacity="0.2" stroke="#000000" transform="translate(0,-5)"></path><path cs="100,100" d="M106.5,476.5 L106.5,476.5 L106.5,0.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.15" stroke="#000000"></path></g><g><path cs="100,100" d="M127.5,476.5 L127.5,476.5 L127.5,0.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.08" stroke="#000000"></path></g><g><path cs="100,100" d="M148.5,476.5 L148.5,476.5 L148.5,0.5" fill="none" stroke-width="1" stroke-dasharray="3" stroke-opacity="0.08" stroke="#000000"></path></g><g><path cs="100,100" d="M170.5,476.5 L170.5,476.5 L170.5,0.5" fill="none" stroke-width="1" stroke-dasharray以上是关于SVG2PNG(前台个后台将SVG转换为PNG,完美支持IE8下载)--amcharts导出png的主要内容,如果未能解决你的问题,请参考以下文章

Java端使用Batik将SVG转为PNG

将 SVG 转换为 PNG,并将应用的图像作为 svg 元素的背景

使用 C# 将 SVG 转换为 PNG [关闭]

如何将 PNG 图像转换为 SVG? [关闭]

将svg转换为png时如何包含CSS样式

使用 PHP 将 SVG 图像转换为 PNG