900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > java 图片格式转化 wmf emf -> svg png

java 图片格式转化 wmf emf -> svg png

时间:2024-07-07 14:08:55

相关推荐

java 图片格式转化 wmf emf -> svg png

在一次调试考试系统bug时遇到的问题,功能是word录入一些题目,解析其中的数学公式转为浏览器可显示的图片。

正常的最新版的word插入的公式是DocumentFormat.OpenXml.Math.OfficeMath类,

这时主要是通过MathML渲染器Jeuclid来将文档中的数学公式xml转换为png。

但是当使用旧版本的word时,插入的公式为objectElement形式,这时上面提到的方法就不能用了,

仔细查看word中包含数学公式的xml片段,发现其中包含一个Element,并且每个标签上都带有一个r:id属性,

<w:object w:dxaOrig="2280" w:dyaOrig="620" w14:anchorId="271EC68A"><v:shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><v:stroke joinstyle="miter"/><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"/><v:f eqn="sum @0 1 0"/><v:f eqn="sum 0 0 @1"/><v:f eqn="prod @2 1 2"/><v:f eqn="prod @3 21600 pixelWidth"/><v:f eqn="prod @3 21600 pixelHeight"/><v:f eqn="sum @0 0 1"/><v:f eqn="prod @6 1 2"/><v:f eqn="prod @7 21600 pixelWidth"/><v:f eqn="sum @8 21600 0"/><v:f eqn="prod @7 21600 pixelHeight"/><v:f eqn="sum @10 21600 0"/></v:formulas><v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"/><o:lock v:ext="edit" aspectratio="t"/></v:shapetype><v:shape id="_x0000_i1025" type="#_x0000_t75" style="width:114pt;height:31.35pt" o:ole=""><v:imagedata r:id="rId6" o:title=""/></v:shape><o:OLEObject Type="Embed" ProgID="Equation.3" ShapeID="_x0000_i1025" DrawAspect="Content" ObjectID="_1560188948" r:id="rId7"/></w:object>

通过查看XWPFDocument(POI提供的word文档解析)的API可以获取文档的所有图片内容,另外还有一个根据ID来获取图片信息的方法,

通过尝试,可以直接通过rid直接获取到对应的图片数据,

XWPFPictureData pictureData = doc.getPictureDataByID(picId);int type = pictureData.getPictureType();

其中大部分是wmf格式,少部分是emf格式,考虑到浏览器不支持显示这两种格式图片,就打算转为png格式。

其中主要用到了Apache提供的jar包batick-codec相关maven依赖如下

<dependency><groupId>org.apache.xmlgraphics</groupId><artifactId>batik-codec</artifactId><version>1.7</version></dependency>

主要用到了其中的WMFTranscoder类和JPEGTranscoder类,

WMFTranscoder负责将wmf转为svg,PNGTranscoder将svg转为jpeg,或者用JPEGTranscoder,示例代码如下

import org.apache.batik.transcoder.TranscoderException;import org.apache.batik.transcoder.TranscoderInput;import org.apache.batik.transcoder.TranscoderOutput;import org.apache.batik.transcoder.image.JPEGTranscoder;import org.apache.batik.transcoder.wmf.tosvg.WMFTranscoder;public class BatikWmf{private static final Logger logger = Logger.getLogger(BatikWmf.class);public static final String wmfFilePath = "/tmp/setsWordImg.wmf";public static final String svgFilePath = "/tmp/setsWordImg.svg";public static final String pngFilePath = "/tmp/setsWordImg.png";private byte[] wmfBytes;public BatikWmf() {}public BatikWmf(byte[] wmfBytes) {this.wmfBytes = wmfBytes;}private void transFile(File inFile, File outFile, int type) throws TranscoderException {try {FileInputStream in = new FileInputStream(inFile);FileOutputStream out = new FileOutputStream(outFile);TranscoderInput transIn = new TranscoderInput(in);TranscoderOutput transOut = new TranscoderOutput(out);switch (type) {case 0:WMFTranscoder wmfTranscoder = new WMFTranscoder();System.out.println("wmf开始转svg");wmfTranscoder.transcode(transIn, transOut);System.out.println("svg成功");break;case 1:JPEGTranscoder pngTranscoder = new JPEGTranscoder();pngTranscoder.addTranscodingHint(JPEGTranscoder.KEY_QUALITY,new Float(.8));System.out.println("开始转png");//设置png画质精度0-1之间pngTranscoder.transcode(transIn, transOut);System.out.println("png成功");default:break;}} catch (TranscoderException e) {logger.error("wmf->svg出现异常", e);throw new TranscoderException(e);} catch (FileNotFoundException e) {logger.error("wmf->svg出现异常", e);throw new TranscoderException(e);}}public static void main(String[] args) {try {File wmfFile = new File("/tmp/123.wmf");FileInputStream fis = new FileInputStream(wmfFile);byte[] myBytes = getFisBytes(fis);IWmf wmf = new BatikWmf(myBytes);myBytes = wmf.getPngBytes();System.out.println("结束了");} catch (Exception e) {System.out.println("transcode出错了");}}@Overridepublic byte[] getPngBytes()throws IOException {File wmfFile = new File(wmfFilePath);File svgFile = new File(svgFilePath);File pngFile = new File(pngFilePath);byte[] pngBytes = null;FileOutputStream fos = new FileOutputStream(wmfFile);fos.write(wmfBytes);fos.close();try {transFile(wmfFile, svgFile, 0);} catch (TranscoderException e) {logger.error("wmf转svg异常", e);}try {transFile(svgFile, pngFile, 1);} catch (TranscoderException e) {logger.error("svg转png异常", e);}FileInputStream fis = new FileInputStream(pngFile);pngBytes = getFisBytes(fis);deleteFile(wmfFile);deleteFile(svgFile);deleteFile(pngFile);return pngBytes;}public byte[] getFisBytes(FileInputStream fis) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);byte[] b = new byte[1000];int n;while ((n = fis.read(b)) != -1) {baos.write(b, 0, n);}IOUtils.closeQuietly(fis);IOUtils.closeQuietly(baos);return baos.toByteArray();}private void deleteFile(File file) {if (file.isFile() && file.exists()) {file.delete();}}public static void main(String[] args) {try {File wmfFile = new File("/tmp/123.wmf");FileInputStream fis = new FileInputStream(wmfFile);byte[] myBytes = getFisBytes(fis);IWmf wmf = new BatikWmf(myBytes);myBytes = wmf.getPngBytes();System.out.println("结束了");} catch (Exception e) {System.out.println("transcode出错了");}}}

需要注意的是,在linux服务器上使用该包时会出现一些问题,因为大多linux服务器是不带图形用户界面的,这时候会报一系列和X11 Server相关的错误,其中操作文件流的代码可能不规范,毕竟我只是个前端开发0.0,细节就请忽略吧。

最后我也没解决,主要还是Xserver安装总出错,启动不起来,有时间再研究一下

最后没办法我就只能用另一种方法将wmf转为svg之后,将svg的字节流直接转为base64的字符串在浏览器段显示了,考虑到公式文件不大,也就凑活用了

maven依赖为

<dependency><groupId>net.arnx</groupId><artifactId>wmf2svg</artifactId><version>0.9.5</version></dependency>

import net.arnx.wmf2svg.gdi.svg.SvgGdiException;import net.arnx.wmf2svg.gdi.wmf.WmfParseException;import net.arnx.wmf2svg.gdi.wmf.WmfParser;import net.arnx.wmf2svg.gdi.svg.SvgGdi;import org.w3c.dom.Document;import javax.xml.transform.*;import javax.xml.transform.dom.DOMSource;import javax.xml.transform.stream.StreamResult;import java.io.*;import org.apache.log4j.Logger;import org.apache.poi.util.IOUtils;/*** Created by erry on 17/6/26.*/public class ArnxWmf {private static final Logger logger = Logger.getLogger(ArnxWmf.class);public static final String wmfFilePath = "/tmp/setsWordImg.wmf";public static final String svgFilePath = "/tmp/setsWordImg.svg";private byte[] wmfBytes;public ArnxWmf(byte[] wmfBytes) {this.wmfBytes = wmfBytes;}public ArnxWmf(FileInputStream fis) throws IOException {this.wmfBytes = getFisBytes(fis);}@Overridepublic byte[] getSvgBytes() throws IOException {byte[] svgBytes=null;File svgFile = new File(svgFilePath);File wmfFile = new File(wmfFilePath);FileOutputStream fos = new FileOutputStream(wmfFile);fos.write(wmfBytes);try {transFile(wmfFile, svgFile);} catch (SvgGdiException e) {logger.error(e);} catch (TransformerConfigurationException e) {logger.error(e);}FileInputStream fis = new FileInputStream(svgFile);svgBytes = getFisBytes(fis);deleteFile(svgFile);deleteFile(wmfFile);return svgBytes;}public void transFile(File wmfFile, File svgFile)throws FileNotFoundException, SvgGdiException, TransformerConfigurationException {//wmf转svgboolean compatible = false;FileInputStream fis = new FileInputStream(wmfFile);WmfParser wmfParser = new WmfParser();final SvgGdi gdi = new SvgGdi(compatible);try {wmfParser.parse(fis, gdi);} catch (IOException e) {logger.error(e);} catch (WmfParseException e) {logger.error("wmf转gdi出现异常", e);}Document doc = gdi.getDocument();FileOutputStream fos = new FileOutputStream(svgFile);TransformerFactory factory = TransformerFactory.newInstance();Transformer transformer = factory.newTransformer();transformer.setOutputProperty(OutputKeys.METHOD, "xml");transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");transformer.setOutputProperty(OutputKeys.INDENT, "yes");transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,"-//W3C//DTD SVG 1.0//EN");transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,"/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");try {transformer.transform(new DOMSource(doc), new StreamResult(fos));} catch (TransformerException e) {logger.error("gdi转svg出现异常", e);}IOUtils.closeQuietly(fis);IOUtils.closeQuietly(fos);}public static void main(String[] args) {File wmfFile = new File("/tmp/123.wmf");try {ArnxWmf arnx = new ArnxWmf(new FileInputStream(wmfFile));byte[] bt = arnx.getSvgBytes();ImageUtils.deleteFile(wmfFile);System.out.println(bt.length);} catch (FileNotFoundException e) {logger.error(e);} catch (IOException e) {logger.error(e);}}}

最后通过下面代码转为图片的base64

String base64 = new String(Base64.encodeBase64(svgBytes));String img ="<img src=\"data:image/svg+xml;base64," + base64 + "\"/>";

另外就是将emf图片转为png的问题了,

maven依赖:

<dependency><groupId>org.freehep</groupId><artifactId>freehep-graphicsio-emf</artifactId><version>${freehep.version}</version></dependency>

代码如下:

import java.awt.*;import java.awt.image.BufferedImage;import java.io.*;import org.freehep.graphicsio.emf.EMFInputStream;import org.freehep.graphicsio.emf.EMFRenderer;import org.apache.poi.util.IOUtils;import javax.imageio.ImageIO;/*** Created by erry on 17/6/28.*/public class ImageUtils {public static final String emfFilePath = "/tmp/setsWordImg.emf";public static final String pngFilePath = "/tmp/setsWordImg.png";public static byte[] getFisBytes(FileInputStream fis) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream(1000);byte[] b = new byte[1000];int n;while ((n = fis.read(b)) != -1) {baos.write(b, 0, n);}IOUtils.closeQuietly(fis);IOUtils.closeQuietly(baos);return baos.toByteArray();}public static void deleteFile(File file) {if (file.isFile() && file.exists()) {file.delete();}}public static byte[] emfToPng(byte[] emfBytes) throws IOException {FileInputStream fis = null;FileOutputStream fos = null;EMFInputStream eis = null;byte[] pngBytes = null;File emfFile = new File(emfFilePath);File pngFile = new File(pngFilePath);try {fos = new FileOutputStream(emfFile);fos.write(emfBytes);fis = new FileInputStream(emfFile);eis = new EMFInputStream(fis, EMFInputStream.DEFAULT_VERSION);EMFRenderer emfRender = new EMFRenderer(eis);final int height = (int) eis.readHeader().getBounds().getHeight();final int width = (int) eis.readHeader().getBounds().getWidth();final BufferedImage bufImage = new BufferedImage(width,height, BufferedImage.TYPE_4BYTE_ABGR);Graphics2D g2 = bufImage.createGraphics();emfRender.paint(g2);ImageIO.write(bufImage, "png", pngFile);fis = new FileInputStream(pngFile);pngBytes = getFisBytes(fis);} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {IOUtils.closeQuietly(fos);IOUtils.closeQuietly(eis);deleteFile(emfFile);deleteFile(pngFile);}return pngBytes;}public static void main(String[] args) throws IOException {File emfFile = new File("/tmp/123.emf");byte[] bytes = getFisBytes(new FileInputStream(emfFile));byte[] emfBytes = emfToPng(bytes);}}

其中IOUtils是POI的一个工具类,简化文件的一些操作,看方法名就知道了,具体细节有问题的可以留言或通过其他方式来告知。

需要注意的问题是该类也默认需要GUI,这点可以通过设置java的启动参数来修改,让java不去调用系统硬件,自己来实现其功能:

-Djava.awt.headless=true

本来以为可以一并解决上边transcoder对X11的调用,结果并未如愿,有大神解决过相关问题的希望可以留言指导下,

✧(≖ ◡ ≖✿)嘿嘿

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。