最近要實作一個使用手寫闆對PDF文檔進行手寫簽名的功能,下面記錄一下關鍵過程。
實作的思路如下:
1、在畫闆中顯示PDF文檔的内容
2、使用者使用簽名版對PDF文檔進行簽名
3、儲存簽名後的畫闆内容到新的PDF中
其中使用pdfbox把PDF文檔轉成圖檔,簽名後又把簽名後的圖檔轉回PDF儲存。
pdfbox(http://pdfbox.apache.org/)是一個處理PDF文檔的JAVA庫。
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.edit.PDPageContentStream;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDJpeg;
import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.PixelGrabber;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
class TestDraw extends Canvas {
Image image;
boolean init = true;
public static final int WIDTH = 1024;
public static final int HEIGHT = 1024;
public Image screen = createImage(WIDTH, HEIGHT, true);// 雙緩沖
private Graphics graphics = screen.getGraphics();
public Image resultImage;
int x1 = -1;
int y1 = -1;
int x2 = -1;
int y2 = -1;
public TestDraw() {
this.setBackground(Color.white);
this.addMouseListener(new MyMouseListener(this));
this.addMouseMotionListener(new MyMouseMotionListener(this));
image = pdfToImg("pdf/tests.pdf");
// 設定初始構造時面闆大小
setPreferredSize(new Dimension(WIDTH, HEIGHT));
// 初始導入一張圖檔
ImageIcon icon = new ImageIcon(image);
resultImage = icon.getImage();
}
public void paint(Graphics g) {
update(g);
}
@Override
public void update(Graphics g) {
BufferedImage bufferedImage= imageToBufferedImage(resultImage);
// Copy image to buffered image
Graphics g2 = bufferedImage.getGraphics();
g2.setColor(Color.black);
if (x1 == -1 || y1 == -1) {
x1 = x2;
y1 = y2;
}
g2.drawLine(x1, y1, x2, y2);
x1 = x2;
y1 = y2;
g2.dispose();
ImageIcon icon = new ImageIcon(bufferedImage);
resultImage = icon.getImage();
graphics.drawImage(resultImage, 0, 0, this);
g.drawImage(screen, 0, 0, null);// 最後個參數一定要用null,這樣可以防止drawImage調用update方法
g.dispose();
}
public static BufferedImage imageToBufferedImage(Image im) {
BufferedImage bi = new BufferedImage
(im.getWidth(null),im.getHeight(null),BufferedImage.TYPE_INT_RGB);
Graphics bg = bi.getGraphics();
bg.drawImage(im, 0, 0, null);
bg.dispose();
return bi;
}
/**
* 生成一個BufferImage
* 生成一個BufferImage BufferImage是Image的子類,左上角坐标都為 (0, 0)
* 第三個參數是代碼Image圖形類型,分為14種,以位數又分為1,2或4位
*
* @param width
* @param height
* @param flag
* @return
*/
final static public BufferedImage createImage(int width, int height,
boolean flag) {
if (flag) {
return new BufferedImage(width, height, 2);
} else {
return new BufferedImage(width, height, 1);
}
}
/**
* 把PDF轉成圖檔
* @param pdfFileName PDF檔案路徑
* @return
*/
public static Image pdfToImg(String pdfFileName) {
ImageIcon imageIcon = null;
try {
PDDocument doc = PDDocument.load(pdfFileName);
int pageCount = doc.getNumberOfPages();
PDPage page = (PDPage) doc.getDocumentCatalog().getAllPages().get(0);
BufferedImage bufferedImage = page.convertToImage();
if (bufferedImage != null) {
imageIcon = new ImageIcon(Toolkit.getDefaultToolkit().createImage(bufferedImage.getSource()));
}
doc.close();
} catch (IOException ex) {
Logger.getLogger(ShowJFrame.class.getName()).log(Level.SEVERE, null, ex);
}
return imageIcon.getImage();
}
}
class MyMouseListener implements MouseListener {
TestDraw draw;
public MyMouseListener(TestDraw draw) {
this.draw = draw;
}
/**
* 點選滑鼠時儲存新的PDF檔案
* @param e
*/
public void mouseClicked(MouseEvent e) {
System.out.println("mouseClicked");
PDDocument doc = null;
PDPage page = null;
try {
doc = new PDDocument();
page = new PDPage();
BufferedImage bufferedImage = toBufferedImage(draw.resultImage);
File outputfile = new File("saved.png");
ImageIO.write(bufferedImage, "png", outputfile);
int w = bufferedImage.getWidth();
int h = bufferedImage.getHeight();
BufferedImage after = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
AffineTransform at = new AffineTransform();
at.scale(0.5, 0.5);
AffineTransformOp scaleOp =
new AffineTransformOp(at, AffineTransformOp.TYPE_BILINEAR);
after = scaleOp.filter(bufferedImage, after);
doc.addPage(page);
PDXObjectImage ximage = new PDJpeg(doc, after);
PDPageContentStream content = new PDPageContentStream(doc, page, true, true);
// content.drawImage(ximage, 0, 0);
content.drawXObject(ximage, 0, 0, 800, 800);
content.close();
doc.save("save.pdf");
doc.close();
} catch (Exception ex) {
System.out.println(ex);
}
}
// This method returns a buffered image with the contents of an image
public static BufferedImage toBufferedImage(Image image) {
if (image instanceof BufferedImage) {
return (BufferedImage) image;
}
// This code ensures that all the pixels in the image are loaded
image = new ImageIcon(image).getImage();
// Determine if the image has transparent pixels; for this method's
// implementation, see e661 Determining If an Image Has Transparent Pixels
boolean hasAlpha = hasAlpha(image);
// Create a buffered image with a format that's compatible with the screen
BufferedImage bimage = null;
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
// Determine the type of transparency of the new buffered image
int transparency = Transparency.OPAQUE;
if (hasAlpha) {
transparency = Transparency.BITMASK;
}
// Create the buffered image
GraphicsDevice gs = ge.getDefaultScreenDevice();
GraphicsConfiguration gc = gs.getDefaultConfiguration();
bimage = gc.createCompatibleImage(
image.getWidth(null), image.getHeight(null), transparency);
} catch (HeadlessException e) {
// The system does not have a screen
}
if (bimage == null) {
// Create a buffered image using the default color model
int type = BufferedImage.TYPE_INT_RGB;
if (hasAlpha) {
type = BufferedImage.TYPE_INT_ARGB;
}
bimage = new BufferedImage(image.getWidth(null), image.getHeight(null), type);
}
// Copy image to buffered image
Graphics g = bimage.createGraphics();
// Paint the image onto the buffered image
g.drawImage(image, 0, 0, null);
g.dispose();
return bimage;
}
//Determining If an Image Has Transparent Pixels
// This method returns true if the specified image has transparent pixels
public static boolean hasAlpha(Image image) {
// If buffered image, the color model is readily available
if (image instanceof BufferedImage) {
BufferedImage bimage = (BufferedImage) image;
return bimage.getColorModel().hasAlpha();
}
// Use a pixel grabber to retrieve the image's color model;
// grabbing a single pixel is usually sufficient
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try {
pg.grabPixels();
} catch (InterruptedException e) {
}
// Get the image's color model
ColorModel cm = pg.getColorModel();
return cm.hasAlpha();
}
public void mouseEntered(MouseEvent e) {
//System.out.println("mouseEntered");
}
public void mouseExited(MouseEvent e) {
//System.out.println("mouseExited");
}
public void mousePressed(MouseEvent e) {
//System.out.println("mousePressed");
draw.x1 = -1;
draw.y1 = -1;
}
public void mouseReleased(MouseEvent e) {
//System.out.println("mouseReleased");
draw.x1 = draw.x2;
draw.y1 = draw.y2;
}
}
class MyMouseMotionListener implements MouseMotionListener {
TestDraw draw;
public MyMouseMotionListener(TestDraw draw) {
this.draw = draw;
}
public void mouseDragged(MouseEvent e) {
//System.out.println("mouseDragged");
draw.x2 = e.getX();
draw.y2 = e.getY();
draw.repaint();
}
public void mouseMoved(MouseEvent e) {
//System.out.println("mouseMoved");
}
}