美文网首页
将pdf转换为jpg

将pdf转换为jpg

作者: xiaojieLu | 来源:发表于2017-09-22 14:52 被阅读447次

    近期遇到一个需求:
    公司的电子税票是以pdf文件格式保存的,这也是统一的标准格式。但是为了方便在手机App上查看,需要将税票转换为jpg格式。

    解决:
    拿到这个题目后,我第一反应就是去找一个Java的第三方库来实现转换。
    尝试了不少的第三方库,比如pdfbox,ImageMagick等,但是效果都不理想。要么是转换出来的中文丢失,要么是表格数据排版混乱,有的甚至连图片都丢失。网上说jpedal效果不错,不过由于是商业版的无法尝试。
    Java的搜索了一圈后发现都不行。想想要不看看C#有没有好的库呢。然后就搜索到了今天的解决方案所用的Adobe Acorbat的Acrobat.dll 来进行转换的办法。
    Java无法直接使用dll,于是还用了jacob来调用dll 来实现。
    不再罗嗦,直接上代码。
    jacob项目地址 https://sourceforge.net/projects/jacob-project/

    以下代码Pdf2Jpg2参考自 http://blog.csdn.net/love_5209/article/details/19162185

    我主要做的修改是:将原来程序的每页pdf转换为一个jpg文件。修改为整个pdf所有页面拼接为一个jpg文件。这样方便存储。
    主要思路是:先用一个循环获取到pdf文件的宽度w和高度h。然后设置一个宽度w,高度h的BufferedImage对象。然后在用一个循环读取每页的pdf内容,再粘贴到BufferedImage上,循环中适当调整粘贴的坐标。最后在循环外将BufferedImage对象输出到jpg文件,就完成了。

    package com.invoicetopdf;
    import java.awt.Graphics;  
    import java.awt.Image;  
    import java.awt.Toolkit;  
    import java.awt.datatransfer.Clipboard;  
    import java.awt.datatransfer.DataFlavor;  
    import java.awt.datatransfer.Transferable;  
    import java.awt.image.BufferedImage;  
    import java.io.File;  
    import java.io.FileOutputStream;  
    import java.io.IOException;  
      
    import java.util.Stack;
    
    import javax.imageio.ImageIO;  
      
    
    import com.jacob.activeX.ActiveXComponent;  
    import com.jacob.com.ComThread;  
    import com.jacob.com.Dispatch;  
    import com.jacob.com.Variant;  
      
    public class Pdf2Jpg2 {  
        /** 
         *  
         * @param filepath 
         *            pdf路径 
         * @param savePath 
         *            img保存路径 
         * @param times 
         *            缩放比例 如:1f为原图比例 
         * @throws IOException  
         */  
        public static void savaPageAsJpgByAcrobat(String filepath, String savePath,  
                float times) throws IOException {  
            ComThread.InitSTA();//初始化com的线程   
            // 输出  
            FileOutputStream out = null;  
            // PDF页数  
            int pageNum = 0;  
            // PDF宽、高  
            int x, y = 0;  
            // PDF控制对象  
            Dispatch pdfObject = null;  
            // PDF坐标对象  
            Dispatch pointxy = null;  
            // pdfActiveX PDDoc对象 主要建立PDF对象  
            ActiveXComponent app = new ActiveXComponent("AcroExch.PDDoc");  
            // pdfActiveX PDF的坐标对象  
            ActiveXComponent point = new ActiveXComponent("AcroExch.Point");  
            try {  
                // 得到控制对象  
                pdfObject = app.getObject();  
                // 得到坐标对象  
                pointxy = point.getObject();  
                // 打开PDF文件,建立PDF操作的开始  
                Dispatch.call(pdfObject, "Open", new Variant(filepath));  
                // 得到当前打开PDF文件的页数  
                pageNum = Dispatch.call(pdfObject, "GetNumPages").toInt();  
                int allimgHeight = 0;
                int allimgWidth = 0;
                
                for (int i = 0; i < pageNum; i++) {  
                    // 根据页码得到单页PDF  
                    Dispatch page = Dispatch.call(pdfObject, "AcquirePage",  
                            new Variant(i)).toDispatch();  
                    // 得到PDF单页大小的Point对象  
                    Dispatch pagePoint = Dispatch.call(page, "GetSize")  
                            .toDispatch(); 
                    if (allimgWidth < (int) (Dispatch.get(pagePoint, "x").toInt() * 2 * times)){  
                        allimgWidth = (int) (Dispatch.get(pagePoint, "x").toInt() * 2 * times);
                    }
                    allimgHeight += (int) (Dispatch.get(pagePoint, "y").toInt() * 2 * times);
                }
                
                BufferedImage tag = new BufferedImage(allimgWidth, allimgHeight, 8);  
                Graphics graphics = tag.getGraphics();  
                
                Stack<Integer> pageHight = new Stack<Integer>();
                
                int tmpHight = 0;
                for (int i = 0; i < pageNum; i++) {  
                    // 根据页码得到单页PDF  
                    Dispatch page = Dispatch.call(pdfObject, "AcquirePage",  
                            new Variant(i)).toDispatch();  
                    // 得到PDF单页大小的Point对象  
                    Dispatch pagePoint = Dispatch.call(page, "GetSize")  
                            .toDispatch();  
                    // 创建PDF位置对象,为拷贝图片到剪贴板做准备  
                    ActiveXComponent pdfRect = new ActiveXComponent("AcroExch.Rect");  
                    // 得到单页PDF的宽  
                    //int imgWidth = (int) (Dispatch.get(pagePoint, "x").toInt() * 2 * times);  
                    //使用最宽的页面作为统一宽度。
                    int imgWidth = allimgWidth; 
                    // 得到单页PDF的高  
                    int imgHeight = (int) (Dispatch.get(pagePoint, "y").toInt() * 2 * times);  
                    
                    // 控制PDF位置对象  
                    Dispatch pdfRectDoc = pdfRect.getObject();  
                    // 设置PDF位置对象的值  
                    Dispatch.put(pdfRectDoc, "Left", new Integer(0));  
                    Dispatch.put(pdfRectDoc, "Right", new Integer(imgWidth));  
                    Dispatch.put(pdfRectDoc, "Top", new Integer(0));  
                    Dispatch.put(pdfRectDoc, "Bottom", new Integer(imgHeight));  
                    // 将设置好位置的PDF拷贝到Windows剪切板,参数:位置对象,宽起点,高起点,分辨率  
                    Dispatch.call(page, "CopyToClipboard", new Object[] {  
                            pdfRectDoc, 0, 0, 200 * times });  
                    Image image = getImageFromClipboard();  
                    
                    if (i==0){
                        graphics.drawImage(image, 0, 0, null); 
                    }
                    else {
                        graphics.drawImage(image, 0, tmpHight, null);
                    }
                    
                    tmpHight += imgHeight;
                    //graphics.dispose();  
                    // 输出图片  
                    //ImageIO.write(tag, "JPEG", new File(savePath + (i+1) + ".jpg"));  
                }  
                graphics.dispose(); 
                ImageIO.write(tag, "JPEG", new File(savePath +  "all.jpg"));  
            } catch (Exception e) {  
                e.printStackTrace();  
            } finally {  
                // 关闭PDF  
                app.invoke("Close", new Variant[] {});  
                ComThread.Release();//关闭com的线程   真正kill进程  
            }  
      
        }  
      
        public static Image getImageFromClipboard() throws Exception {  
            Clipboard sysc = Toolkit.getDefaultToolkit().getSystemClipboard();  
            Transferable cc = sysc.getContents(null);  
            if (cc == null)  
                return null;  
            else if (cc.isDataFlavorSupported(DataFlavor.imageFlavor))  
                return (Image) cc.getTransferData(DataFlavor.imageFlavor);  
            return null;  
        }  
      
        public static void main(String[] args) throws IOException {
            //System.setProperty("java.library.path","d:/test/");
            savaPageAsJpgByAcrobat("d:/test/11.pdf", 
                    "d:/test/", 1f); 
        }
    }  
    

    我在得到jpg文件后,还将jpg文件用二进制的形式回写到了Oracle数据库。具体代码如下:

    package com.invoicetopdf;
    
    import java.io.BufferedInputStream;
    import java.io.BufferedOutputStream;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.sql.Blob;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.zip.GZIPInputStream;
    import java.util.zip.GZIPOutputStream;
    import sun.misc.BASE64Encoder;
    import sun.misc.BASE64Decoder;
    
    public class AutoInvoiceToPDF  {
    
        // base64位编码转成PDF
        public static void base64StringToPdf(String base64Content, String filePath)
                throws IOException {
            BASE64Decoder decoder = new BASE64Decoder();
            BufferedInputStream bis = null;
            FileOutputStream fos = null;
            BufferedOutputStream bos = null;
    
            try {
                byte[] bytes = decoder.decodeBuffer(base64Content);// base64编码内容转换为字节数组
                ByteArrayInputStream byteInputStream = new ByteArrayInputStream(
                        bytes);
                bis = new BufferedInputStream(byteInputStream);
                File file = new File(filePath);
                File path = file.getParentFile();
                if (!path.exists()) {
                    path.mkdirs();
                }
                fos = new FileOutputStream(file);
                bos = new BufferedOutputStream(fos);
    
                byte[] buffer = new byte[1024];
                int length = bis.read(buffer);
                while (length != -1) {
                    bos.write(buffer, 0, length);
                    length = bis.read(buffer);
                }
                bos.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                // closeStream(bis, fos, bos);
                bis.close();
                fos.close();
                bos.close();
                // System.out.println("生成成功");
            }
        }
    
        // pdf转BASE64位编码
        public static String PDFToBase64(File file) {
            BASE64Encoder encoder = new BASE64Encoder();
            FileInputStream fin = null;
            BufferedInputStream bin = null;
            ByteArrayOutputStream baos = null;
            BufferedOutputStream bout = null;
            try {
                fin = new FileInputStream(file);
                bin = new BufferedInputStream(fin);
                baos = new ByteArrayOutputStream();
                bout = new BufferedOutputStream(baos);
                byte[] buffer = new byte[1024];
                int len = bin.read(buffer);
                while (len != -1) {
                    bout.write(buffer, 0, len);
                    len = bin.read(buffer);
                }
                // 刷新此输出流并强制写出所有缓冲的输出字节
                bout.flush();
                byte[] bytes = baos.toByteArray();
                return encoder.encodeBuffer(bytes).trim();
    
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    fin.close();
                    bin.close();
                    bout.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return null;
        }
    
        // GZIP压缩
        public static String gzip(String primStr) {
            if (primStr == null || primStr.length() == 0) {
                return primStr;
            }
    
            ByteArrayOutputStream out = new ByteArrayOutputStream();
    
            GZIPOutputStream gzip = null;
            try {
                gzip = new GZIPOutputStream(out);
                gzip.write(primStr.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (gzip != null) {
                    try {
                        gzip.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return new sun.misc.BASE64Encoder().encode(out.toByteArray());
        }
    
        // GZIP解压
        public static String gunzip(String compressedStr) {
            if (compressedStr == null) {
                return null;
            }
    
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            ByteArrayInputStream in = null;
            GZIPInputStream ginzip = null;
            byte[] compressed = null;
            String decompressed = null;
            try {
                compressed = new sun.misc.BASE64Decoder()
                        .decodeBuffer(compressedStr);
                in = new ByteArrayInputStream(compressed);
                ginzip = new GZIPInputStream(in);
    
                byte[] buffer = new byte[1024];
                int offset = -1;
                while ((offset = ginzip.read(buffer)) != -1) {
                    out.write(buffer, 0, offset);
                }
                decompressed = out.toString();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (ginzip != null) {
                    try {
                        ginzip.close();
                    } catch (IOException e) {
                    }
                }
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {
                    }
                }
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {
                    }
                }
            }
    
            return decompressed;
        }
    
        public static void ReadImgFromDB(Connection conn, int fphm) {
            // 从数据库中读取图片。
            String sql = "select jpgbm from pdfinfo where fphm = '39410355'";
            Statement stmt;
            FileOutputStream fout;
            ResultSet rs;
            try {
                stmt = conn.createStatement();
    
                rs = stmt.executeQuery(sql);
                while (rs.next()) {
                    Blob blob = rs.getBlob(1);
                    byte barr[] = blob.getBytes(1, (int) blob.length());
                    // System.out.println("blob length:" +blob.length());
    
                    fout = new FileOutputStream("d:/dbjpg.jpg");
                    fout.write(barr);
                    fout.flush();
                    fout.close();
                }
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
            }
    
        }
    
        public static void WirteImgToDB(Connection conn, int fphm) {
            // 把图片更新回数据库
            PreparedStatement ps;
            try {
                ps = conn
                        .prepareStatement("update pdfinfo  set  jpgbm = ? where  fphm = ? ");
                FileInputStream fin;
                fin = new FileInputStream("d:\\test\\all.jpg");
                // System.out.println("file size:" + fin.available());
                ps.setBinaryStream(1, fin, fin.available());
                ps.setInt(2, fphm);
                int i = ps.executeUpdate();
                ps.close();
                // System.out.println(i + " records affected");
            } catch (FileNotFoundException e1) {
                e1.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
        public static void AllInOne(Connection conn, int fphm) {
    
            String pdfbm = "";
            try {
                Statement stmt = conn.createStatement();
                String sql = "select pdfbm from pdfinfo where fphm = '" + fphm
                        + "'";
                ResultSet rs = stmt.executeQuery(sql);
                while (rs.next()) {
                    pdfbm = rs.getString("pdfbm");
                }
                rs.close();
                stmt.close();
                pdfbm = gunzip(pdfbm);
                // 生成pdf
                base64StringToPdf(pdfbm, "d:\\test\\11.pdf");
    
                Pdf2Jpg2.savaPageAsJpgByAcrobat("d:\\test\\11.pdf", "d:\\test\\",
                        0.9f);
                WirteImgToDB(conn, fphm);
                System.out.println("fphm:" + fphm + " done!");
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            String url = "jdbc:oracle:thin:@172.xx.x.xx:1521:xxxx";
            String user = "xxxxx";
            String password = "xxxxx";
            Connection conn = null;
            try {
                Class.forName("oracle.jdbc.driver.OracleDriver");
                conn = DriverManager.getConnection(url, user, password);
            } catch (Exception e) {
                e.printStackTrace();
            }
            int fphm = 0;
            String sqlString = " select fphm from pdfinfo where jpgbm is null and rownum<5000 order by indate desc ";
            Statement stmt;
            try {
                stmt = conn.createStatement();
    
                ResultSet rs = stmt.executeQuery(sqlString);
                while (rs.next()) {
                    fphm = rs.getInt("fphm");
                    AllInOne(conn, fphm);
                }
                rs.close();
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            
        }
    
    }
    

    这个文件包含很多方法:
    将数据库中base64编码的pdf编码读出保存为pdf文件 base64StringToPdf
    将图片写入Oracle数据库 WirteImgToDB
    从Oracle读出图片并保存为文件 ReadImgFromDB
    最后通过一个AllInOne将这些方法串联起来。就可以达到读取数据库中的pdf base64编码,然后转换为pdf,再转换为jpg,最后将jpg的二进制写入数据库。
    通过将这两个源代码打包为一个jar,再做一个定时任务,就可以自动去寻找没有转换生成jpg的税票,自动生成了。

    需要注意的是:使用jacob.jar 需要找对版本,并将对应的平台(x86或者x64)的dll放到对应的java.library.path中。一般复制到java运行环境jre对应的bin目录下即可。
    推荐使用jacob 1.18版本。因为1.17版本在Eclispe下面运行没有问题,但是在命令行里面运行的时候总是提示 NoSuchFieldError: m_pDispatch 一切都是对的找不到原因。最后果断换为1.18版本,就ok了。
    jacob 1.18 需要Java7才能支持哦!

    相关文章

      网友评论

          本文标题:将pdf转换为jpg

          本文链接:https://www.haomeiwen.com/subject/fnkfextx.html