JAVA將Excel中的報表導出為圖片格式(二)實現思路


接上文,一封類似於下方設計的Excel報表,如何將它指定的區域導出為樣式一模一樣的JPG圖片呢?

要實現這個功能沒有現成的解決方案,谷歌度娘了好久也沒有,最終自己想了幾條思路:

 

思路1:將報表中的背景、邊框等截圖下來作為模型圖片,需要定時更新的數據通過JDBC讀取Oracle中的數據繪制到模型圖片上

否定原因:不具可行性,所有數據的坐標點需要有規則方便繪圖時循環繪制,工程量巨大,耦合性巨高,表格數據牽一發而動全身,並且不利於擴展。

 

思路2:不需要報表原型,生成Excel報表后,使用jxl或者poi一個單元一個單元讀取報表內所有單元格,包括單元格的數據和格式,邊框、寬度、高度、字體前景色、背景色都要讀取出來,然后通過JAVA繪圖,最終生成JPG格式的報表。

否定原因:具有一定的可行性,但是代碼量巨大,讀取和繪制費時費力,但是有一定的優點,可以在不忙的時間里編寫一個通用的程序,一勞永逸的解決所有導出問題。

 

思路3:比較奇葩,屬於博主突發奇想的招式,通過WPS或者Office打開Excel,編寫Robot機器人將鼠標移動到兩個指定坐標所覆蓋指定區域,Robot模擬敲擊Ctrl+C,接着將剪貼板上的數據繪圖,導出到JPG文件。

最終實現了思路3,有一定的好處也有弊端,好處是簡單便捷,可操作性高,代碼量低,擴展性強,換其他報表只需要提供另一組坐標參數即可

弊端是完全犧牲了JAVA的跨平台性,甚至如果運行在分辨率較低的服務器上,有可能導致復制操作無法執行

另一個弊端是線程變得不安全了,如果服務器負載較重,無法正確預計Office打開報表的時間,也有可能導致復制操作無法執行

或者多個生成報表截圖的任務同時執行時,顯然使用Robot會導致沖突。

 

下面提供思路3的實現代碼,以后有時間會使用思路2寫一個通用的程序

package com.newflypig.excel;

import java.awt.Graphics;
import java.awt.Image;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.imageio.ImageIO;

public class OpenExcelDemo {

    public static void main(String[] args) throws Exception {
        openExcel("d:\\新增積分月報表.xlsx");

        copyRectByPix(37, 207, 1215, 665); //給定兩個坐標點的數據,圈定截圖范圍

        createImageFileFromClip("d:/" + getTimeStr() + ".jpg");

        closeExcel((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth() - 15, 12);    //需要模擬關閉事件,將Excel關閉,以便下次能正確打開報表    
    }

    private static void closeExcel(int i, int j) throws Exception {
        Robot robot = new Robot();

        robot.delay(500);
        robot.mouseMove(i,j);
        robot.delay(500);
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.delay(500);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);
        robot.delay(500);
        robot.keyPress(KeyEvent.VK_ENTER);
    }

    public static void openExcel(String dir) throws Exception {
        Runtime.getRuntime().exec("cmd /k " + dir + "");
    }

    public static void copyRectByPix(int fromX, int fromY, int toX, int toY)
            throws Exception {
        Robot robot = new Robot();
        robot.delay(3000); // 延時3000毫秒

        robot.mouseMove(fromX, fromY);
        robot.delay(500);
        robot.mousePress(InputEvent.BUTTON1_MASK);
        robot.delay(500);
        robot.mouseMove(toX, toY);
        robot.delay(500);
        robot.mouseRelease(InputEvent.BUTTON1_MASK);

        robot.setAutoDelay(200);
        robot.keyPress(KeyEvent.VK_CONTROL);
        robot.keyPress(KeyEvent.VK_C);
        robot.keyRelease(KeyEvent.VK_CONTROL);
        robot.keyRelease(KeyEvent.VK_C);
    }

    public static void createImageFileFromClip(String dir) throws Exception {
        Transferable t = Toolkit.getDefaultToolkit().getSystemClipboard()
                .getContents(null);
        if (null != t && t.isDataFlavorSupported(DataFlavor.imageFlavor)) {
            Image image = (Image) t.getTransferData(DataFlavor.imageFlavor);
            savePic(image, dir);
        }
    }

    public static String savePic(Image iamge, String dir) throws Exception {
        int w = iamge.getWidth(null);
        int h = iamge.getHeight(null);

        // 首先創建一個BufferedImage變量,因為ImageIO寫圖片用到了BufferedImage變量。
        BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR);

        // 再創建一個Graphics變量,用來畫出來要保持的圖片,及上面傳遞過來的Image變量
        Graphics g = bi.getGraphics();

        g.drawImage(iamge, 0, 0, null);

        // 將BufferedImage變量寫入文件中。
        ImageIO.write(bi, "jpg", new File(dir));
        return dir;
    }

    public static String getTimeStr() {
        String time = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        return time;
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM