最近要实现一个使用手写板对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"); } }
相关推荐
在IT行业中,手写签名是一种常见的交互方式,特别是在电子文档签署、在线交易验证等领域。...通过这样的技术,用户可以在数字环境中获得类似纸笔签名的体验,这对于现代无纸化办公和电子商务环境具有重要意义。
在IT行业中,手写签名是一种重要的身份验证和文档认可方式,尤其在电子文档和无纸化办公环境中。本文将深入探讨“手写签名,可保存为图片或到数据库”这一技术概念及其应用。 首先,手写签名是个人身份的直观表示,...
"前端实现canvas手机端手写签名"这一技术就是为了解决这个问题,它允许用户在手机等移动设备上通过触摸屏幕实现手写签名,为无纸化办公提供了便利。本文将深入探讨如何使用HTML5的Canvas API来构建一个手机端的手写...
在现代Web开发中,HTML5提供了许多增强的功能,其中之一就是支持手写签名并将其提交到服务器端进行存储。这个功能通常用于需要...这一技术在电子签名、合同签署等领域有着广泛的应用,极大地提高了无纸化办公的效率。
执法终端通过蓝牙或Wi-Fi连接打印机,可即时打印签名确认单,或者将电子签名通过网络传输至后台系统,实现无纸化办公。 总结,WPF手写签名功能的实现依赖于Windows Ink技术,通过InkCanvas控件和事件处理,我们可以...
例如,电商平台的订单确认、银行的远程开户、无纸化办公系统的文件审批等,都离不开电子签名的功能。 总的来说,基于HTML5和Mui的电子签名方案,不仅降低了开发成本,还提升了用户体验,是现代Web应用中不可或缺的...
OA无纸化办公系统电子签章插件是现代企业信息化管理中的重要组成部分,它旨在提升工作效率,确保文档安全,减少纸质文件的使用,实现环保的办公环境。在数字化办公时代,电子签章作为合法有效的签名形式,对于合同、...
这种技术为无纸化办公、在线合同签署、电子商务等领域提供了便利,减少了实体签名的必要性,同时也提升了用户体验,因为用户无需打印、签字、扫描或传真文件。 【标签】: 1. HTML:HTML(超文本标记语言)是构建...
汉王科技是一家知名的电子签名设备和解决方案提供商,其签名板产品广泛应用于银行、保险、电信等行业,提供无纸化办公的解决方案。 描述中提到的“汉王签名板,调用汉王签批控件接口dll”,揭示了这个DEMO程序的...
政府机构也可以用它来进行无纸化办公,提高效率的同时保证信息安全。 总之,加密签名手写装置及方法是现代信息安全体系中不可或缺的一部分,它提供了安全、便捷的电子签名解决方案,促进了数字化时代的交易和沟通。...
Sanasa是一款致力于实现无纸化办公的解决方案,它旨在通过数字化技术提高工作效率,减少对纸质文档的依赖,同时促进环保。无纸化办公是当前信息化社会中一个重要的发展趋势,尤其在企业、政府机构以及教育等领域得到...
在IT行业中,电子签名是一种重要的技术,特别是在数字化和无纸化办公的趋势下,它扮演着不可或缺的角色。本文将深入探讨“电子签名(仿毛笔字)”这一主题,结合使用ActionScript 3(AS3)实现的系统,来阐述相关的...
在IT领域,表单手写签章控件是一种常见的软件组件,主要应用于电子文档和在线表单中,允许用户以手写方式添加签名,从而实现无纸化办公和远程签署。这种控件通常具备高度的交互性和灵活性,可以集成到各种应用程序中...
无纸化办公,这是老板对我的要求,然而有人现场执法文件全部电子化,只有签字部分让一个搞web的人有点儿头疼,不能为了这个找个人来开发app吧于是想到了小程序,对于一个新接触小程序的人来说还是有挑战性的,因为我...
"H5手写签字"是指利用HTML5技术实现的在线手写签名功能,允许用户通过触控设备或者鼠标模拟手写,进行电子签名,这种功能在电子商务、法律文档签署、远程办公等场景中有着广泛的应用。 一、HTML5 Canvas API 手写...
随着科技的进步,无纸化办公和数字化签名已经成为趋势,电子装置上的手写文档处理技术也随之发展。这篇文档将深入探讨这一领域的关键知识点。 一、电子政务与无纸化办公 电子政务,简称e-Government,是指政府利用...
纸质文件的存储、运输和管理都需要投入大量的人力物力,而电子签名的应用可以实现无纸化办公,减少纸质文件的使用,节约资源,同时也减少了与纸质文件相关的管理费用。 此外,电子签名还能促进跨机构协作。在医联体...
这个控件适用于各种基于Web的应用场景,如企业办公自动化系统、电子合同平台等,大大提高了无纸化办公的效率和安全性。 在Websign 4.0.4.2版本中,开发者可能已经优化了签名的稳定性和用户体验。手写签章功能让用户...
在现代信息化社会,电子签名已经成为了商业活动中不可或缺的一部分,特别是在远程协作和无纸化办公的背景下。本技术分享将深入探讨如何使用HTML5中的Canvas API实现手机电子签字功能,即canvas_sign,它允许用户在...
该系统提供了手写签章功能,让用户可以如同在纸上一样自由地在电子文档上进行签名,大大提高了工作效率,同时也符合了现代信息化社会对无纸化办公的需求。 "完美注册版"通常指的是该软件已经成功激活,用户可以...