我正在尝试制作带有视觉签名和pdfbox的PDF。我有两条流,pdfbox似乎只能处理文件。没有三个临时文件,我没能成功。我可以从这里看到API已经改变了,但它仍然处理文件。
public void signPdf(InputStream originalPdf, OutputStream signedPdf,
InputStream image, float x, float y,
String name, String location, String reason) {
File temp = null;
File temp2 = null;
File scratchFile = null;
RandomAccessFile randomAccessFile = null;
OutputStream tempOut = null;
InputStream tempIn = null;
try {
/* Copy original to temporary file */
temp = File.createTempFile("signed1", ".tmp");
tempOut = new FileOutputStream(temp);
copyStream(originalPdf, tempOut);
tempOut.close();
/* Read temporary file to second temporary file and stream */
tempIn = new FileInputStream(temp);
temp2 = File.createTempFile("signed2", ".tmp");
tempOut = new FileOutputStream(temp2);
copyStream(tempIn, tempOut);
tempIn.close();
tempIn = new FileInputStream(temp2);
scratchFile = File.createTempFile("signed3", ".bin");
randomAccessFile = new RandomAccessFile(scratchFile, "rw");
/* Read temporary file */
PDDocument document = PDDocument.load(temp, randomAccessFile);
document.getCurrentAccessPermission().setCanModify(false);
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName(name);
signature.setLocation(location);
signature.setReason(reason);
signature.setSignDate(Calendar.getInstance());
PDVisibleSignDesigner signatureDesigner = new PDVisibleSignDesigner(
document, image, document.getNumberOfPages());
signatureDesigner.xAxis(250).yAxis(60).zoom(-90).signatureFieldName("signature");
PDVisibleSigProperties signatureProperties = new PDVisibleSigProperties();
signatureProperties.signerName(name).signerLocation(location)
.signatureReason(reason).preferredSize(0).page(1)
.visualSignEnabled(true).setPdVisibleSignature(signatureDesigner)
.buildSignature();
SignatureOptions options = new SignatureOptions();
options.setVisualSignature(signatureProperties);
document.addSignature(signature, dataSigner, options);
/* Sign */
document.saveIncremental(tempIn, tempOut);
document.close();
tempIn.close();
/* Copy temporary file to an output stream */
tempIn = new FileInputStream(temp2);
copyStream(tempIn, signedPdf);
} catch (IOException e) {
logger.error("PDF signing failure", e);
} catch (COSVisitorException e) {
logger.error("PDF creation failure", e);
} catch (SignatureException e) {
logger.error("PDF signing failure", e);
} finally {
closeStream(originalPdf);
closeStream(signedPdf);
closeStream(randomAccessFile);
closeStream(tempOut);
deleteTempFile(temp);
deleteTempFile(temp2);
deleteTempFile(scratchFile);
}
}
private void deleteTempFile(File tempFile) {
if (tempFile != null && tempFile.exists() && !tempFile.delete()) {
tempFile.deleteOnExit();
}
}
private void closeStream(Closeable is) {
if (is!= null) {
try {
is.close();
} catch (IOException e) {
logger.error("failure", e);
}
}
}
private void copyStream(InputStream is, OutputStream os) throws IOException {
byte[] buffer = new byte[1024];
int c;
while ((c = is.read(buffer)) != -1) {
os.write(buffer, 0, c);
}
is.close();
}
除了文件疯狂,我在签名上没有看到任何文字。结果是这样的:
当我用itext库做类似的事情时,情况就是这样
为什么视觉签名表示中缺少名称、位置和原因?我该怎么解决?
在签名人身上显示文字有时看起来不太好看。对我来说,我根据想要显示的文本创建新的图像。并将其与签名图像合并。我可以为签名图像添加背景(公司名称水印)
以下是创建带有文本和背景的新签名人图像的代码:
public class ImageSignatory {
public static void main(String[] args) {
DateFormat df = new SimpleDateFormat("MM.dd.yyyy");
Date today = Calendar.getInstance().getTime();
String reportDate = df.format(today);
String text = "Signature eletronic Company AA DUC NGUYEN - Date " + reportDate;
String background = "background.png";
String signImage = "sign.jpg";
String textImage = createImageFromText(text);
String imageResultURL = null ;
try {
String mergedImage = mergeTwoImage(signImage, textImage);
imageResultURL = addBackgroundToImage(background, mergedImage);
} catch (Exception ex) {
}
}
public static String StringDivider(String s) {
StringBuilder sb = new StringBuilder(s);
int i = 0;
while ((i = sb.indexOf(" ", i + 30)) != -1) {
sb.replace(i, i + 1, "\n");
}
return sb.toString();
}
public static BufferedImage toBufferedImage(Image img) {
if (img instanceof BufferedImage) {
return (BufferedImage) img;
}
BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
return bimage;
}
public static String addBackgroundToImage(String backgroundPATH, String imagePath) {
try {
String imageResult = "result.jpg";
Image backgroundImage = ImageIO.read(new File(backgroundPATH));
int width = backgroundImage.getWidth(null);
int height = backgroundImage.getHeight(null);
Image signAndText = ImageIO.read(new File(imagePath));
signAndText = signAndText.getScaledInstance(width, height, Image.SCALE_SMOOTH);
signAndText = toBufferedImage(signAndText);
BufferedImage combined = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g2 = combined.getGraphics();
g2.drawImage(backgroundImage, 0, 0, null);
g2.drawImage(signAndText, 0, 0, null);
g2.dispose();
ImageIO.write(combined, "JPG", new File(imageResult));
return imageResult;
} catch (IOException ex) {
return null;
}
}
public static String mergeTwoImage(String first, String second) {
try {
String tempFileName = "merged_image.png";
Image signatoryImage = ImageIO.read(new File(first));
Image addtionalTextImage = ImageIO.read(new File(second));
float ratio = (float) signatoryImage.getWidth(null) / (float) addtionalTextImage.getWidth(null);
addtionalTextImage = addtionalTextImage.getScaledInstance((int) (ratio * (float) addtionalTextImage.getWidth(null)), (int) (ratio * (float) addtionalTextImage.getHeight(null)), Image.SCALE_SMOOTH);
addtionalTextImage = toBufferedImage(addtionalTextImage);
BufferedImage combinedTemp = new BufferedImage(signatoryImage.getWidth(null), signatoryImage.getHeight(null) + (int) (ratio * (float) addtionalTextImage.getHeight(null)), BufferedImage.TYPE_INT_ARGB);
Graphics g = combinedTemp.getGraphics();
g.drawImage(signatoryImage, 0, 0, null);
g.drawImage(addtionalTextImage, 0, signatoryImage.getHeight(null), null);
g.dispose();
ImageIO.write(combinedTemp, "PNG", new File(tempFileName));
return tempFileName;
} catch (IOException ex) {
return null;
}
}
public static String createImageFromText(String text) {
String tempFileName = "text.png";
text = StringDivider(text);
String[] textParts = text.split("\n");
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
Font font = new Font("Arial", Font.PLAIN, 48);
g2d.setFont(font);
FontMetrics fm = g2d.getFontMetrics();
int width = 0;
for (String textPart : textParts) {
int tempWidth = fm.stringWidth(textPart);
if (tempWidth > width) {
width = tempWidth;
}
}
width += 10;
int oneLineHeight = fm.getHeight();
int height = (oneLineHeight) * textParts.length;
g2d.dispose();
img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
g2d.setFont(font);
fm = g2d.getFontMetrics();
g2d.setColor(Color.BLACK);
int index = 0;
for (String textPart : textParts) {
g2d.drawString(textPart, 5, (oneLineHeight) * index + fm.getAscent());
index++;
}
g2d.dispose();
try {
ImageIO.write(img, "PNG", new File(tempFileName));
} catch (IOException ex) {
return null;
}
return tempFileName;
}
public static void removeFile(String fileName) {
try {
File file = new File(fileName);
file.delete();
} catch (Exception ex) {
}
}
}
它们不在那里,因为它们没有被画出来。
iText表示可视化签名的默认方式是将这些信息添加到可视化中。
PDFBox'PDVisibleSigBuilder
表示可视化签名的默认方式是不包含此类信息。
两者都不是错误或正确,两者都只是默认。
人们寻找此类信息的标准场所毕竟是签名小组。
签名可视化的实际内容由PDVisibleSigBuilder
实例在signatureProperties期间创建。buildSignature()
:
public void buildSignature() throws IOException
{
PDFTemplateBuilder builder = new PDVisibleSigBuilder();
PDFTemplateCreator creator = new PDFTemplateCreator(builder);
setVisibleSignature(creator.buildPDF(getPdVisibleSignature()));
}
因此
signatureProperties.signerName(name).signerLocation(location)
.signatureReason(reason).preferredSize(0).page(1)
.visualSignEnabled(true).setPdVisibleSignature(signatureDesigner)
.buildSignature();
在你的代码中
signatureProperties.signerName(name).signerLocation(location)
.signatureReason(reason).preferredSize(0).page(1)
.visualSignEnabled(true).setPdVisibleSignature(signatureDesigner);
PDFTemplateBuilder builder = new ExtSigBuilder();
PDFTemplateCreator creator = new PDFTemplateCreator(builder);
signatureProperties.setVisibleSignature(creator.buildPDF(signatureProperties.getPdVisibleSignature()));
对于这个PDVisibleSigBuilder
类的自定义版本ExtSigBuilder
,您可以在那里绘制任何您想要的东西,例如:
class ExtSigBuilder extends PDVisibleSigBuilder
{
String fontName;
public void createImageForm(PDResources imageFormResources, PDResources innerFormResource,
PDStream imageFormStream, PDRectangle formrect, AffineTransform affineTransform, PDJpeg img)
throws IOException
{
super.createImageForm(imageFormResources, innerFormResource, imageFormStream, formrect, affineTransform, img);
PDFont font = PDType1Font.HELVETICA;
fontName = getStructure().getImageForm().getResources().addFont(font);
logger.info("Added font to image form: " + fontName);
}
public void injectAppearanceStreams(PDStream holderFormStream, PDStream innterFormStream, PDStream imageFormStream,
String imageObjectName, String imageName, String innerFormName, PDVisibleSignDesigner properties)
throws IOException
{
super.injectAppearanceStreams(holderFormStream, innterFormStream, imageFormStream, imageObjectName, imageName, innerFormName, properties);
String imgFormComment = "q " + 100 + " 0 0 50 0 0 cm /" + imageName + " Do Q\n";
String text = "BT /" + fontName + " 10 Tf (Hello) Tj ET\n";
appendRawCommands(getStructure().getImageFormStream().createOutputStream(), imgFormComment + text);
logger.info("Added text commands to image form: " + text);
}
}
在Helvetica中,在图像表单的左下角(表单实际上显示了一些东西)的大小为10的位置写入Hello。
PS:在我看来,这背后的面向对象结构应该彻底改革。
标题和内容 如上所述,标题可以通过 showNotification 的第一个参数设置。而通知内容可以通过配置项中的 body 进行设置。如下: registration.showNotification('Simple Title', { body: 'Simple piece of body text.\nSecond line of body text :)' }); 在Googl
光环板可以连接 mbuild 的 视觉模块 模块进行编程。 色块识别 1.视觉模块(1)切换到色块识别模式。 指定视觉模块切换到色块识别模式。 示例 按下光环板的按钮,视觉模块(1)切换到色块识别模式。 2. 视觉模块(1)开始学习色块(1)(直到按钮被按下) 指定视觉模块在制定操作执行后开始学习色块。 示例 按下光环板的按钮,视觉模块(1)开始学习色块(1)(直到按钮被按下)。 3. 视觉模块(
视觉模块能够识别条码和线条,也可以学习和识别颜色鲜艳的物体,实现诸如垃圾分类、智慧交通、物体追踪、智能巡线等功能。 连接主控板 通过不同的连线方式,可以将视觉模块作为一个 RJ25 电子模块或 mBuild 电子模块,连接到 mBot 或光环板,然后使用 mBot 或光环板控制视觉模块。 连接到 mBot 与 mBot 连接时,可以使用 3.7V 锂电池或 mBuild 电源模块连接到视觉模块,为
视觉模块能够识别条码和线条,也可以学习和识别颜色鲜艳的物体,实现诸如垃圾分类、智慧交通、物体追踪、智能巡线等功能。 连接主控板 通过不同的连线方式,可以将视觉模块作为一个 RJ25 电子模块或 mBuild 电子模块,连接到 mBot 或光环板,然后使用 mBot 或光环板控制视觉模块。 连接到 mBot 与 mBot 连接时,可以使用 3.7V 锂电池或 mBuild 电源模块连接到视觉模块,为
9.20 维谛一面(共 28min) 对PLC要求很高的公司,问很多杂七杂八的东西,给的少,哪有研究生研究PLC的呢? 自我介绍,项目介绍 PLC会吗?传感器会吗?PLC协议有那些? 热电偶?热电阻? c++ 介绍项目,用到哪些opencv库 做过哪些软硬件的东西? 除了示波器,万用表,电源,还用过那些? 地点要求 未来职业规划 加班看法 薪资要求 深圳说高了,说完就直接下了,不给我反问机会,G
问题内容: 有什么方法可以使用可视化编辑器在Eclipse中制作swing应用程序?我正在使用Ganymede。 问题答案: 我使用Jigloo相当不错。可以为Swing和SWT生成GUI。免费用于非商业用途,以商业用途每位开发人员$ 85美元,相当便宜。适用于3.4(Ganymede)。