最近要实现一个使用手写板对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");
- }
- }