Java轉化PPT爲PNG,實現預覽

1、簡述前端

近來作了一個需求,裏面涉及到了ppt預覽的問題,網上這種case不少,也實驗了一些,可是百度出來的結果然心屬於有始無終的,不能說裏面的內容是胡編亂造的,只是內容不夠準確嚴謹。吐槽完了,說一下總體的方案,對於預覽的方案有:一、PPT轉化爲Flash,前端播放Flash動畫 二、PPT轉化爲圖片,前端輪播圖片,我採用的是第二種方案,使用Apache POI 將PPT轉化爲PNG圖片。java

2、代碼運行環境linux

- JDK 1.8
- Linux/Windowsapache

3、Maven依賴的jarwindows

使用的是Apache POI 的3.16版本,其中具體的jar以下:框架

 <dependency>  
    <groupId>org.apache.poi</groupId>  
    <artifactId>poi</artifactId>  
    <version>3.16</version>  
</dependency>  
<dependency>  
    <groupId>org.apache.poi</groupId>  
    <artifactId>poi-ooxml</artifactId>  
    <version>3.16</version>  
</dependency>  
<dependency>  
    <groupId>org.apache.poi</groupId>  
    <artifactId>poi-scratchpad</artifactId>  
    <version>3.16</version>  
</dependency>

其中poi是核心的jar包,poi-ooxml是處理.pptx格式,poi-scratchpad是處理.ppt格式。jvm

4、核心代碼ide

PPT中英文和圖片是不用作特殊處理的,主要關注在中文如何處理,若是沒有關注到中文等特殊字符,生成的圖片頗有多是亂碼,下面是對亂碼處理的核心代碼:測試

一、pptx帶有中文的文件輸出圖片字體

public void converPPTXtoImage(InputStream pptFileIn, String targetDir) {  
        try(XMLSlideShow oneSlideShow =  new XMLSlideShow(pptFileIn)) {  
            String xmlFontFormat = "<xml-fragment xmlns:a=\\"http://schemas.openxmlformats.org/drawingml/2006/main\\" " +  
                    "xmlns:r=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\\" xmlns:p=\\"http://schemas.openxmlformats.org/presentationml/2006/main\\">" +  
                    "<a:rPr lang=\\"zh-CN\\" altLang=\\"en-US\\" dirty=\\"0\\" smtClean=\\"0\\"> " +  
                    "<a:latin typeface=\\"+mj-ea\\"/> " +  
                    "</a:rPr>" +  
                    "</xml-fragment>";  
            Dimension onePPTPageSize = oneSlideShow.getPageSize();  
            List<XSLFSlide> pptPageXSLFSLiseList = oneSlideShow.getSlides();  
            for(int i = 0; i < pptPageXSLFSLiseList.size(); i ++) {  
                //設置字體,解決中文亂碼問題  
                CTGroupShape oneCTGroupShape = pptPageXSLFSLiseList.get(i).getXmlObject().getCSld().getSpTree();  
                for (CTShape ctShape : oneCTGroupShape.getSpList()) {  
                    CTTextBody oneCTTextBody = ctShape.getTxBody();  
                    if (null == oneCTTextBody) {  
                        continue;  
                    }  
                    CTTextParagraph\[\] oneCTTextParagraph = oneCTTextBody.getPArray();  
                    CTTextFont oneCTTextFont = null;  
                    try {  
                        oneCTTextFont = CTTextFont.Factory.parse(xmlFontFormat);  
                    } catch (XmlException e) {

                    }  
                    if (oneCTTextFont == null) {  
                        continue;  
                    }  
                    for (CTTextParagraph ctTextParagraph : oneCTTextParagraph) {  
                        CTRegularTextRun\[\] onrCTRegularTextRunArray = ctTextParagraph.getRArray();  
                        for (CTRegularTextRun ctRegularTextRun : onrCTRegularTextRunArray) {  
                            CTTextCharacterProperties oneCTTextCharacterProperties = ctRegularTextRun.getRPr();  
                            oneCTTextCharacterProperties.setLatin(oneCTTextFont);  
                        }  
                    }  
                }  
                for(XSLFShape shape : pptPageXSLFSLiseList.get(i).getShapes() ){  
                    if (shape instanceof XSLFTextShape){  
                        XSLFTextShape txtshape = (XSLFTextShape)shape ;  
                        for ( XSLFTextParagraph textPara : txtshape.getTextParagraphs() ){  
                            List<XSLFTextRun> textRunList = textPara.getTextRuns();  
                            for(XSLFTextRun textRun: textRunList) {  
                                textRun.setFontFamily("simsun");  
                            }  
                        }  
                    }  
                }  
                BufferedImage oneBufferedImage = new BufferedImage(onePPTPageSize.width, onePPTPageSize.height, BufferedImage.TYPE\_INT\_RGB);  
                Graphics2D oneGraphics2D = oneBufferedImage.createGraphics();  
                pptPageXSLFSLiseList.get(i).draw(oneGraphics2D);  
                String imgName=(i+1)+ ".png";  
                try(OutputStream imageOut = new FileOutputStream(targetDir + imgName)) {  
                    ImageIO.write(oneBufferedImage, "png", imageOut);  
                } finally {  
                }  
            }  
        } catch (Exception e) {  
        }  
    }

核心處理亂碼的是:

    //設置字體,解決中文亂碼問題  
    CTGroupShape oneCTGroupShape = pptPageXSLFSLiseList.get(i).getXmlObject().getCSld().getSpTree();  
                for (CTShape ctShape : oneCTGroupShape.getSpList()) {  
        CTTextBody oneCTTextBody = ctShape.getTxBody();  
        if (null == oneCTTextBody) {  
            continue;  
        }  
        CTTextParagraph\[\] oneCTTextParagraph = oneCTTextBody.getPArray();  
        CTTextFont oneCTTextFont = null;  
        try {  
            oneCTTextFont = CTTextFont.Factory.parse(xmlFontFormat);  
        } catch (XmlException e) {

        }  
        if (oneCTTextFont == null) {  
            continue;  
        }  
        for (CTTextParagraph ctTextParagraph : oneCTTextParagraph) {  
            CTRegularTextRun\[\] onrCTRegularTextRunArray = ctTextParagraph.getRArray();  
            for (CTRegularTextRun ctRegularTextRun : onrCTRegularTextRunArray) {  
                CTTextCharacterProperties oneCTTextCharacterProperties = ctRegularTextRun.getRPr();  
                oneCTTextCharacterProperties.setLatin(oneCTTextFont);  
            }  
        }  
    }  
    for(XSLFShape shape : pptPageXSLFSLiseList.get(i).getShapes() ){  
        if (shape instanceof XSLFTextShape){  
            XSLFTextShape txtshape = (XSLFTextShape)shape ;  
            for ( XSLFTextParagraph textPara : txtshape.getTextParagraphs() ){  
                List<XSLFTextRun> textRunList = textPara.getTextRuns();  
                for(XSLFTextRun textRun: textRunList) {  
                    textRun.setFontFamily("simsun");  
                }  
            }  
        }  
    }

二、ppt格式的帶有中文的文件輸出爲圖片

   public void converPPTtoImage(InputStream pptStream, String targetImageFileDir) {  
        try (HSLFSlideShow oneSlideShow = new HSLFSlideShow(pptStream)) {  
            List<HSLFSlide> pptPageXSLFSLiseList = oneSlideShow.getSlides();  
            for (int i = 0; i < pptPageXSLFSLiseList.size(); i++) {  
                //設置字體,解決中文亂碼問題  
                for (List<HSLFTextParagraph> list : pptPageXSLFSLiseList.get(i).getTextParagraphs()) {  
                    for (HSLFTextParagraph hslfTextParagraph : list) {  
                        for (HSLFTextRun textRun : hslfTextParagraph.getTextRuns()) {  
                            Double size = textRun.getFontSize();  
                            if ((size <= 0) || (size >= 26040)) {  
                                textRun.setFontSize(20.0);  
                            }  
                            textRun.setFontFamily("simsun");  
                        }  
                    }  
                }  
                String imgName =  (i + 1) + ".png";  
                BufferedImage oneBufferedImage = new BufferedImage(oneSlideShow.getPageSize().width, oneSlideShow.getPageSize().height, BufferedImage.TYPE\_INT\_RGB);  
                Graphics2D oneGraphics2D = oneBufferedImage.createGraphics();  
                pptPageXSLFSLiseList.get(i).draw(oneGraphics2D);  
                try( OutputStream imageOut = new FileOutputStream(targetImageFileDir+imgName)) {  
                    ImageIO.write(oneBufferedImage, "png", imageOut);  
                } finally {

                }  
            }  
        } catch (Exception e) {  
            logger.error("converPPTtoImage eror", e);  
        }  
    }

核心處理亂碼的是:

    for (List<HSLFTextParagraph> list : pptPageXSLFSLiseList.get(i).getTextParagraphs()) {  
        for (HSLFTextParagraph hslfTextParagraph : list) {  
            for (HSLFTextRun textRun : hslfTextParagraph.getTextRuns()) {  
                Double size = textRun.getFontSize();  
                if ((size <= 0) || (size >= 26040)) {  
                    textRun.setFontSize(20.0);  
                }  
                textRun.setFontFamily("simsun");  
            }  
        }  
    }

上面都有這個:

textRun.setFontFamily("simsun");

這裏是設置字體爲宋體,若是你的程序運行環境已經有宋體的字體了,那麼這裏就應該是:

textRun.setFontFamily("宋體");

其實不必定用宋體,用其餘字體也是能夠的,只要該字體支持漢字的渲染便可,jvm自帶的字體是不支持漢字的渲染的。剛開始我本地是windows,自帶宋體,因此是textRun.setFontFamily("宋體"),自測的時候上傳一個pptx文件生成的圖片沒有中文亂碼。可是部署到測試環境後,帶有中文的pptx文件就出現了亂碼,緣由是測試環境是linux,自己是不帶宋體等渲染漢字的字體,解決的方案一個是測試環境jvm的字體庫裏面把宋體加上,加上後重啓java應用,textRun.setFontFamily("宋體")就生效了。另一個就是在應用啓動的時候,把宋體文件註冊到JVM中,這個時候textRun設置的字體應該是你註冊的時候的文件名,好比simsun,註冊代碼以下:

try(InputStream fontFile = Application.class.getClassLoader().getResourceAsStream("static/fonts/simsun.ttf")) {  
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();  
    Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, fontFile);  
    ge.registerFont(dynamicFont);  
} catch (Exception e) {  
}

這段代碼就是讀入simsun.ttf文件,生成字體,註冊到GraphicsEnvironment中。這段代碼能夠放在系統啓動過程當中,我用了Spring的框架,實現了接口InitializingBean,放在了實現的方法中。完整的一個Help類的代碼以下:

public class POIPowerPointHelper implements InitializingBean {  
    private static GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();

    @Override  
    public void afterPropertiesSet() throws Exception {  
        try (InputStream fontFile = POIPowerPointHelper .class.getClassLoader().getResourceAsStream("fonts/simsun.ttf")) {  
            Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, fontFile);  
            ge.registerFont(dynamicFont);  
        } catch (Exception e) {  
        }  
    }

    public void converPPTXtoImage(InputStream pptFileIn, String targetDir) {  
        try (XMLSlideShow oneSlideShow = new XMLSlideShow(pptFileIn)) {  
            String xmlFontFormat = "<xml-fragment xmlns:a=\\"http://schemas.openxmlformats.org/drawingml/2006/main\\" " +  
                    "xmlns:r=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\\" xmlns:p=\\"http://schemas.openxmlformats.org/presentationml/2006/main\\">" +  
                    "<a:rPr lang=\\"zh-CN\\" altLang=\\"en-US\\" dirty=\\"0\\" smtClean=\\"0\\"> " +  
                    "<a:latin typeface=\\"+mj-ea\\"/> " +  
                    "</a:rPr>" +  
                    "</xml-fragment>";  
            Dimension onePPTPageSize = oneSlideShow.getPageSize();  
            List<XSLFSlide> pptPageXSLFSLiseList = oneSlideShow.getSlides();  
            for (int i = 0; i < pptPageXSLFSLiseList.size(); i++) {  
                //設置字體,解決中文亂碼問題  
                CTGroupShape oneCTGroupShape = pptPageXSLFSLiseList.get(i).getXmlObject().getCSld().getSpTree();  
                for (CTShape ctShape : oneCTGroupShape.getSpList()) {  
                    CTTextBody oneCTTextBody = ctShape.getTxBody();  
                    if (null == oneCTTextBody) {  
                        continue;  
                    }  
                    CTTextParagraph\[\] oneCTTextParagraph = oneCTTextBody.getPArray();  
                    CTTextFont oneCTTextFont = null;  
                    try {  
                        oneCTTextFont = CTTextFont.Factory.parse(xmlFontFormat);  
                    } catch (XmlException e) {

                    }  
                    if (oneCTTextFont == null) {  
                        continue;  
                    }  
                    for (CTTextParagraph ctTextParagraph : oneCTTextParagraph) {  
                        CTRegularTextRun\[\] onrCTRegularTextRunArray = ctTextParagraph.getRArray();  
                        for (CTRegularTextRun ctRegularTextRun : onrCTRegularTextRunArray) {  
                            CTTextCharacterProperties oneCTTextCharacterProperties = ctRegularTextRun.getRPr();  
                            oneCTTextCharacterProperties.setLatin(oneCTTextFont);  
                        }  
                    }  
                }  
                for (XSLFShape shape : pptPageXSLFSLiseList.get(i).getShapes()) {  
                    if (shape instanceof XSLFTextShape) {  
                        XSLFTextShape txtshape = (XSLFTextShape) shape;  
                        for (XSLFTextParagraph textPara : txtshape.getTextParagraphs()) {  
                            List<XSLFTextRun> textRunList = textPara.getTextRuns();  
                            for (XSLFTextRun textRun : textRunList) {  
                                textRun.setFontFamily("simsun");  
                            }  
                        }  
                    }  
                }  
                BufferedImage oneBufferedImage = new BufferedImage(onePPTPageSize.width, onePPTPageSize.height, BufferedImage.TYPE\_INT\_RGB);  
                Graphics2D oneGraphics2D = oneBufferedImage.createGraphics();  
                pptPageXSLFSLiseList.get(i).draw(oneGraphics2D);  
                String imgName = (i + 1) + ".png";  
                try (OutputStream imageOut = new FileOutputStream(targetDir + imgName)) {  
                    ImageIO.write(oneBufferedImage, "png", imageOut);  
                } finally {  
                }  
            }  
        } catch (Exception e) {  
        }  
    }

    public void converPPTtoImage(InputStream pptStream, String targetImageFileDir) {  
        try (HSLFSlideShow oneSlideShow = new HSLFSlideShow(pptStream);) {  
            List<HSLFSlide> pptPageXSLFSLiseList = oneSlideShow.getSlides();  
            for (int i = 0; i < pptPageXSLFSLiseList.size(); i++) {  
                //設置字體,解決中文亂碼問題  
                for (List<HSLFTextParagraph> list : pptPageXSLFSLiseList.get(i).getTextParagraphs()) {  
                    for (HSLFTextParagraph hslfTextParagraph : list) {  
                        for (HSLFTextRun textRun : hslfTextParagraph.getTextRuns()) {  
                            Double size = textRun.getFontSize();  
                            if ((size <= 0) || (size >= 26040)) {  
                                textRun.setFontSize(20.0);  
                            }  
                            textRun.setFontFamily("simsun");  
                        }  
                    }  
                }  
                String imgName = (i + 1) + ".png";  
                BufferedImage oneBufferedImage = new BufferedImage(oneSlideShow.getPageSize().width, oneSlideShow.getPageSize().height, BufferedImage.TYPE\_INT\_RGB);  
                Graphics2D oneGraphics2D = oneBufferedImage.createGraphics();  
                pptPageXSLFSLiseList.get(i).draw(oneGraphics2D);  
                try (OutputStream imageOut = new FileOutputStream(targetImageFileDir + imgName)) {  
                    ImageIO.write(oneBufferedImage, "png", imageOut);  
                } finally {  
                }  
            }  
        } catch (Exception e) {  
        }  
    }  
}

PS: 上面的類沒有import相應的包,使用時請自行導包。上面代碼,略有簡陋,若有問題敬請斧正。參考https://blog.csdn.net/yushuai_it/article/details/65445898

PS:簡書上不太適合寫技術類的文章,本篇是做者從本身的簡書帳號搬過來的,非抄襲

相關文章
相關標籤/搜索