我试图在压模上的单个pdf中添加多个签名。我可以添加多个母模。在我的一个案例中,我得到了错误
至少有一个签名无效。还需要使所有签名有效。
我想在一个PDF中添加多个有效符号。请帮帮我。在图中,只有一个符号是有效的,其他符号是无效的,所以让我看看我做错了什么
下面是我的代码快照
public void getSignOnPdf(Map<Integer, byte[]> PdfSigneture1, List<Long> documentIds, List<String> calTimeStamp,
String originalPdfReadServerPath, String tickImagePath, int serverTime, int pageNumberToInsertStamp,
String name, String location, String reasonForSign, int xCo_ordinates, int yCo_ordinates,
int signatureWidth, int signatureHeight, String pdfPassword, String internal_outputFinalPdfPath)
throws Exception {
String pdfReadServerPath = null;
String l_slash = new String();
String originalPDFPath = new String(originalPdfReadServerPath.trim());
boolean isCorrectPDFOutputPath = false;
String aspOutputPdfServerPath = null;
synchronized (this) {
if ((internal_outputFinalPdfPath != null) && (!internal_outputFinalPdfPath.trim().isEmpty())) {
System.out.println("[" + EsignCommonFuntion.generateTimeStampForLog()
+ "] :1--> outputFinalPdfPath is: " + internal_outputFinalPdfPath);
if (!(new File(internal_outputFinalPdfPath)).isFile()) {
isCorrectPDFOutputPath = true;
aspOutputPdfServerPath = internal_outputFinalPdfPath;
} else {
System.out.println("1--> Please provide directory path for outputFinalPdfPath: "
.concat(String.valueOf(internal_outputFinalPdfPath)));
}
} else {
System.out.println(" 1--> outputFinalPdfPath is empty or null: "
.concat(String.valueOf(internal_outputFinalPdfPath)));
}
}
boolean isPasswordPresent = false;
String pdfPasswordForEncryption;
synchronized (this) {
if ((pdfPassword != null) && (!pdfPassword.trim().isEmpty())) {
pdfPasswordForEncryption = pdfPassword.trim();
isPasswordPresent = true;
} else {
pdfPasswordForEncryption = null;
}
String pdfOriginalName = (new File(originalPDFPath)).getName();
String pdfAbsolutePath = originalPDFPath.substring(0, originalPDFPath.lastIndexOf(l_slash));
if (isPasswordPresent) {
pdfAbsolutePath = getEncryptedPdfName(originalPDFPath, pdfAbsolutePath + l_slash,
pdfPasswordForEncryption, pdfOriginalName);
pdfReadServerPath = new String(pdfAbsolutePath);
} else {
pdfReadServerPath = originalPDFPath;
}
}
ArrayList<String> unSignedFilesList = new ArrayList<String>();
Map<Integer, byte[]> l_PdfSigneture = PdfSigneture1;
int actual_pageNumForStamp = 1;
String pdfFileName = (new File(pdfReadServerPath)).getName();
FileOutputStream fos = null;
String nameToShowInSignature = name;
String locationToShowInSignature = location;
String reasonForSignatureSign = reasonForSign;
PDDocument documentFinal = null;
try {
pdfReadServerPath = pdfReadServerPath.substring(0, pdfReadServerPath.lastIndexOf(l_slash));
System.out.println("inside getSignOnMethod pdfAbsolutePath:".concat(String.valueOf(pdfReadServerPath)));
unSignedFilesList.add(pdfFileName);
System.out.println("inside getSignOnMethod pdfFileName:".concat(String.valueOf(pdfFileName)));
String PDFpath = pdfReadServerPath + l_slash + (String) (unSignedFilesList).get(0);
System.out.println("Inside for PDFpath: ".concat(String.valueOf(PDFpath)));
String finalOutputPdfName = ((String) (unSignedFilesList).get(0)).substring(0,
((String) (unSignedFilesList).get(0)).lastIndexOf(".")) + "_signedFinal.pdf";
File outFile2 = null;
if (isCorrectPDFOutputPath) {
System.out.println("if condition Final signed PDF ouptut Path: " + aspOutputPdfServerPath + l_slash
+ finalOutputPdfName);
outFile2 = new File(aspOutputPdfServerPath + l_slash + finalOutputPdfName);
fos = new FileOutputStream(outFile2);
} else {
outFile2 = new File(pdfReadServerPath + l_slash + outFile2);
fos = new FileOutputStream(outFile2);
}
documentFinal = PDDocument.load(new File(PDFpath));
for (int i = 1; i < 4; i++) {
FileInputStream image2 = new FileInputStream(tickImagePath);
PDSignature pdsignature = new PDSignature();
pdsignature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
pdsignature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
Calendar cal = GregorianCalendar.getInstance();
SimpleDateFormat l_simpleDateFormater = new SimpleDateFormat("yyyyMMdd_HHmmss");
String timeStamp = (String) calTimeStamp.get(i - 1);
try {
cal.setTime(l_simpleDateFormater.parse(timeStamp));
} catch (ParseException ex) {
ex.printStackTrace();
}
cal.add(12, serverTime);
pdsignature.setSignDate(cal);
documentFinal.setDocumentId((Long) documentIds.get(i - 1));
String dateToShowInSignature = cal.getTime().toString();
Float saveIncrementalObj1 = null;
saveIncrementalObj1 = new Float((float) xCo_ordinates, (float) yCo_ordinates, (float) signatureWidth,
(float) signatureHeight);
PDRectangle rect = getPDRectangle(documentFinal, saveIncrementalObj1, i);
PDVisibleSignDesigner visibleSig;
(visibleSig = new PDVisibleSignDesigner(documentFinal, image2, i)).xAxis(xCo_ordinates)
.yAxis(yCo_ordinates).zoom(-95.0F).signatureFieldName("signature");
PDVisibleSigProperties visibleSignatureProp = new PDVisibleSigProperties();
visibleSignatureProp.signerName("name").signerLocation("location").signatureReason("Security")
.preferredSize(0).page(i - 1).visualSignEnabled(true).setPdVisibleSignature(visibleSig)
.buildSignature();
try {
PdfSigneture = new TreeMap<>();
// PdfSigneture.clear();
PdfSigneture = l_PdfSigneture;
if (visibleSignatureProp.isVisualSignEnabled()) {
this.options = new SignatureOptions();
this.options.setVisualSignature(visibleSignatureProp);
this.options.setPage(visibleSignatureProp.getPage());
this.options.setVisualSignature(
getInputStream(documentFinal, i, rect, tickImagePath, nameToShowInSignature,
locationToShowInSignature, dateToShowInSignature, reasonForSignatureSign));
documentFinal.addSignature(pdsignature, this, this.options);
} else {
documentFinal.addSignature(pdsignature, this);
}
} catch (Exception e) {
e.printStackTrace();
}
}
synchronized (this) {
SaveIncrementalSignObject saveIncrementalSignObject;
(saveIncrementalSignObject = new SaveIncrementalSignObject()).setFos(fos);
saveIncrementalSignObject.setPDDocumentFromFile(documentFinal);
saveIncrementalForSign(saveIncrementalSignObject);
}
} catch (Exception localException2) {
System.out.println("Insidemethod -- Exception block" + localException2.getMessage());
return;
} finally {
fos.flush();
if (fos != null) {
fos.close();
}
documentFinal.close();
}
}
public static synchronized void saveIncrementalForSign(SaveIncrementalSignObject p_SaveIncrementalObj) {
PDDocument documentFinal = null;
try {
(documentFinal = p_SaveIncrementalObj.getPDDocumentFromFile())
.saveIncremental(p_SaveIncrementalObj.getFos());
} catch (Exception e) {
e.printStackTrace();
try {
// documentFinal.close();
return;
} catch (Exception eX) {
eX.printStackTrace();
return;
}
}
}
在评论中,您澄清了您想要实现的目标:
我试图将一个签名应用到多个地方。
正如下面第一节所讨论的,这并不是您的代码所做的:您的代码试图在单个修订版中的每个地方应用多个签名,这是不可能的,这里也解释了这一点。
另一方面,PDF规范团队不希望在单个修订版中将单个签名应用于多个位置,并且一些实现这一点的方法已被规范无效,但正如下面第二部分所解释的那样,这是可能的。
您似乎试图在一次传递中应用多个签名:
if (isPasswordPresent) {
documentFinal = PDDocument.load(new File(PDFpath), pdfPasswordForEncryption);
} else {
documentFinal = PDDocument.load(new File(PDFpath));
}
for (int i = 1; i < 4; i++) {
FileInputStream image2 = new FileInputStream(tickImagePath);
PDSignature pdsignature = new PDSignature();
[...]
try {
[...]
if (visibleSignatureProp.isVisualSignEnabled()) {
[...]
documentFinal.addSignature(pdsignature, this, this.options);
} else {
documentFinal.addSignature(pdsignature, this);
}
} catch (Exception e) {
System.out.println("Inside getSignOnPdf sub exception block at addSignature:" + e + "error :" + e.getMessage());
e.printStackTrace();
}
}
synchronized (this) {
[...]
saveIncrementalForSign(saveIncrementalSignObject);
}
这是行不通的。
在PDF中,在单独的PDF版本中一个接一个地应用多个签名,而不是在同一版本中并行应用:
您可以在这个答案中找到一些背景和从那里引用的文档。
因此,在伪代码中,您必须做的是:
for (int i = 1; i < 4; i++) {
load current version of the PDF;
apply the i'th signature;
save and sign as new current version of the PDF;
}
方法名称<代码>PDDocument。addSignature在这里可能有点误导,因为它可能被认为意味着可能会添加多个签名。事实并非如此;所有签名都将使用其小部件创建为签名字段,但实际上只有最后添加的PDSignature的字段才会被签名,因此只有最后添加的签名字段才会具有合理的值。
@Tilman-可能应该在PDDocument中进行测试。如果加载文档后已添加签名,则addSignature会引发异常。
PDF对象从PDF页面上的签名可视化到实际签名(基于CMS的子过滤器中的CMS签名容器)的路径不是即时的。相反,我们有
为了执行你的实际任务,
将一个签名应用于多个位置,
因此,从具有签名外观的多个页面到单个签名容器似乎有许多选项:
现在让我们看看PDF规范ISO 32000-2。首先,它警告不要使用具有多个可视化的单个签名:
签名在文件中的位置可能影响其法律含义。[…]
如果签名与多个位置相关联,则含义可能会变得模糊不清。
(ISO 32000-2,第12.7.5.5节“签名字段”)
因此,规范试图禁止具有多个可视化的单个签名:
给定的注释字典只能从一页的Annots数组中引用。
(ISO 32000-2,第12.5.2节“注释词典”)
这禁止上述备选案文1。
签名字段不得引用多个注释
(ISO 32000-2,第12.7.5.5节“签名字段”)
这禁止了选项2。
显然,选项3并没有被明确禁止。对于通用表单字段,值对象共享甚至被明确允许,因为表单字段值是可继承的!
因此,严格来说,使用选项3可以创建具有多种可视化效果的签名。
不过,请注意,PDF规范团队显然无意允许他们这样做,很可能是疏忽。因此,您必须考虑到一些即将到来的规范勘误表最终也会禁止选项3。
如果您仍然想尝试,应该可以使用选项3的方法调整或修补PDFBox以创建具有多个可视化的单个签名。
例如,iText,cf.这个答案已经被证明是可能的。
此外,您共享的示例文档使用了此选项。
事实证明,使用PDFBox沿着选项3创建多可视化PDF签名非常容易。尤其是,这比使用iText执行此操作要容易,请参阅上面提到的答案,因为这里的签名值字典是一个用户自己创建和处理的对象,而在iText中,它是在后台创建的,并且是及时的。
人们所要做的就是创建一个PDSignature
对象并正常地用它生成一个签名(使用PDDocument.addSignature
),然后添加任意数量的其他签名字段,将这些字段的签名值属性设置为在开始时创建的单个PDSignature
对象。
E、 g.您可以使用这样的方法添加其他签名字段:
void addSignatureField(PDDocument pdDocument, PDPage pdPage, PDRectangle rectangle, PDSignature signature) throws IOException {
PDAcroForm acroForm = pdDocument.getDocumentCatalog().getAcroForm();
List<PDField> acroFormFields = acroForm.getFields();
PDSignatureField signatureField = new PDSignatureField(acroForm);
signatureField.setSignature(signature);
PDAnnotationWidget widget = signatureField.getWidgets().get(0);
acroFormFields.add(signatureField);
widget.setRectangle(rectangle);
widget.setPage(pdPage);
// from PDVisualSigBuilder.createHolderForm()
PDStream stream = new PDStream(pdDocument);
PDFormXObject form = new PDFormXObject(stream);
PDResources res = new PDResources();
form.setResources(res);
form.setFormType(1);
PDRectangle bbox = new PDRectangle(rectangle.getWidth(), rectangle.getHeight());
float height = bbox.getHeight();
form.setBBox(bbox);
PDFont font = PDType1Font.HELVETICA_BOLD;
// from PDVisualSigBuilder.createAppearanceDictionary()
PDAppearanceDictionary appearance = new PDAppearanceDictionary();
appearance.getCOSObject().setDirect(true);
PDAppearanceStream appearanceStream = new PDAppearanceStream(form.getCOSObject());
appearance.setNormalAppearance(appearanceStream);
widget.setAppearance(appearance);
try (PDPageContentStream cs = new PDPageContentStream(pdDocument, appearanceStream))
{
// show background (just for debugging, to see the rect size + position)
cs.setNonStrokingColor(Color.yellow);
cs.addRect(-5000, -5000, 10000, 10000);
cs.fill();
float fontSize = 10;
float leading = fontSize * 1.5f;
cs.beginText();
cs.setFont(font, fontSize);
cs.setNonStrokingColor(Color.black);
cs.newLineAtOffset(fontSize, height - leading);
cs.setLeading(leading);
cs.showText("Signature text");
cs.newLine();
cs.showText("some additional Information");
cs.newLine();
cs.showText("let's keep talking");
cs.endText();
}
pdPage.getAnnotations().add(widget);
COSDictionary pageTreeObject = pdPage.getCOSObject();
while (pageTreeObject != null) {
pageTreeObject.setNeedToBeUpdated(true);
pageTreeObject = (COSDictionary) pageTreeObject.getDictionaryObject(COSName.PARENT);
}
}
(CreateMultipleVisualizations助手方法)
(此方法实际上基于pdfbox examples工件中的CreateVisibleSignature2.createVisualSignatureTemplate方法,但经过了严格简化,现在用于创建实际签名字段,而不仅仅是复制模板。)
像这样使用
try ( InputStream resource = PDF_SOURCE_STREAM;
OutputStream result = PDF_TARGET_STREAM;
PDDocument pdDocument = PDDocument.load(resource) )
{
PDAcroForm acroForm = pdDocument.getDocumentCatalog().getAcroForm();
if (acroForm == null) {
pdDocument.getDocumentCatalog().setAcroForm(acroForm = new PDAcroForm(pdDocument));
}
acroForm.setSignaturesExist(true);
acroForm.setAppendOnly(true);
acroForm.getCOSObject().setDirect(true);
PDRectangle rectangle = new PDRectangle(100, 600, 300, 100);
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName("Example User");
signature.setLocation("Los Angeles, CA");
signature.setReason("Testing");
signature.setSignDate(Calendar.getInstance());
pdDocument.addSignature(signature, this);
for (PDPage pdPage : pdDocument.getPages()) {
addSignatureField(pdDocument, pdPage, rectangle, signature);
}
pdDocument.saveIncremental(result);
}
(CreateMultipleVisualizations testtestCreateSignatureSusMultipleVisualizations
)
我们检索一个PDF,在结果文档的每个页面上都有一个签名可视化(还有一个额外的不可见的,因为我有点懒),但只有一个实际的签名值(假设此使用byte[]sign(InputStream)方法实现SignatureInterface)。
不过要小心:
Python 3.4和Pandas 0.15.0 df是一个数据帧,col1是一列。使用下面的代码,我正在检查值10的存在,并将这些值替换为1000。 这是另一个例子。这一次,我将根据索引更改col2中的值。 这两种情况都会产生以下警告: 最后 这将产生一个类似的警告,并附带一个建议: 我不确定我是否理解警告中指出的讨论。编写这三行代码的更好方法是什么? 请注意,这些操作是有效的。
我在重新分解旧代码时遇到了一些麻烦,这是学校的作业,所以...我打算使用工厂设计模式或策略,但我不确定如何在这个特定的场景中使用它们: 我一直在继续,因为我有很多if-else语句,所以我正在考虑使用上面的模式。帮助
如何用vscode选择多行? 在Visual Studio上,您可以按左alt键并选择多行,但它不适用于vscode。
我已经阅读了一些关于如何模拟或模拟HttpClient的文档,但是我不能成功地为我的单元测试复制。到目前为止,我还不能接口HttpClient,所以我选择注入HttpMessageHandler,其想法是设置它,以便返回对客户机的任何调用的响应。
Exception:二进制XML文件第30行:二进制XML文件第30行:inflating类Android.support.design.widget.textInputLayout由:Android.view.filflateException:二进制XML文件第30行:inflating类Android.support.design.widget.textInputLayout由:java.l