java 图片格式转化 wmf,emf 您所在的位置:网站首页 goodgame是什么意思啊 java 图片格式转化 wmf,emf

java 图片格式转化 wmf,emf

2024-01-14 03:18| 来源: 网络整理| 查看: 265

在一次调试考试系统bug时遇到的问题,功能是word录入一些题目,解析其中的数学公式转为浏览器可显示的图片。 正常的最新版的word插入的公式是DocumentFormat.OpenXml.Math.OfficeMath类, 这时主要是通过MathML渲染器Jeuclid来将文档中的数学公式xml转换为png。 但是当使用旧版本的word时,插入的公式为objectElement形式,这时上面提到的方法就不能用了, 仔细查看word中包含数学公式的xml片段,发现其中包含一个Element,并且每个标签上都带有一个r:id属性,

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

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

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

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

org.apache.xmlgraphics batik-codec 1.7

主要用到了其中的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出错了"); } } @Override public 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依赖为

net.arnx wmf2svg 0.9.5

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); } @Override public 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转svg boolean 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, "http://www.w3.org/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 ="";

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

org.freehep freehep-graphicsio-emf ${freehep.version}

代码如下:

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的调用,结果并未如愿,有大神解决过相关问题的希望可以留言指导下, ✧(≖ ◡ ≖✿)嘿嘿



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有