PDF Rendering with PDFBox 2.0 and Decrypting - java

I have just upgraded PDFBox version from 1.8 to 2.0.
Migration says that .convertToImage() has been removed and there is no a line in their example code for BufferedImage, but it is used in .writeImage()
Their code:
PDDocument document = PDDocument.load(new File(pdfFilename));
PDFRenderer pdfRenderer = new PDFRenderer(document);
int pageCounter = 0;
for (PDPage page : document.getPages())
{
pdfRenderer.renderImageWithDPI(pageCounter, 300, ImageType.RGB);
// suffix in filename will be used as the file format
ImageIOUtil.writeImage(bim, pdfFilename + "-" + (pageCounter++) + ".png", 300);
}
document.close();
I believe BufferedImage is used in ImageIOUtil.writeImage(bim, pdfFilename + "-" + (pageCounter++) + ".png", 300); as bim. How should I implement BufferedImage if they have removed .convertToImage()?
Second thing is about .decrypt(). They have not mentioned about .decrypt(). What should I use instead of .decrypt()?
My whole code:
try {
String sourceDir = "/home/linux/books/text.pdf";
File sourceFile = new File(sourceDir);
PDDocument document = PDDocument.load(sourceFile);
PDFRenderer pdfRenderer = new PDFRenderer(document);
if (document.isEncrypted()) {
try {
System.out.println("Trying to decrypt it...");
document.decrypt("");
// error says: The method decrypt(String) is undefined for the type PDDocument.
// it was working on pdfbox 1.8.
document.setAllSecurityToBeRemoved(true);
System.out.println("The file has been decrypted in .");
}
catch (Exception e) {
throw new Exception("cannot be decrypted. ", e);
}
}
PDPage firstPage = (PDPage) document.getDocumentCatalog().getPages().get(0);
pdfRenderer.renderImageWithDPI(0, 300, ImageType.RGB);
String fileName = sourceFile.getName().replace(".pdf", "");
BufferedImage image = firstPage.convertToImage(BufferedImage.TYPE_INT_RGB, 300);
ImageIOUtil.writeImage(image , fileName+".jpg",300);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
Getting Started content is under construction. That is why I cannot check my problems.

I believe BufferedImage is used in ImageIOUtil.writeImage(bim, pdfFilename + "-" + (pageCounter++) + ".png", 300); as bim. How should I implement BufferedImage if they have removed .convertToImage()?
Actually there is a tiny bit missing in the migration guide, it should be
BufferedImage bim = pdfRenderer.renderImageWithDPI(pageCounter, 300, ImageType.RGB);
instead of
pdfRenderer.renderImageWithDPI(pageCounter, 300, ImageType.RGB);
Second thing is about .decrypt(). They have not mentioned about .decrypt(). What should I use instead of .decrypt()?
PDDocument now has multiple load overloads which also accept a password, e.g.
/**
* Parses a PDF. Unrestricted main memory will be used for buffering PDF streams.
*
* #param file file to be loaded
* #param password password to be used for decryption
*
* #return loaded document
*
* #throws IOException in case of a file reading or parsing error
*/
public static PDDocument load(File file, String password) throws IOException
or
/**
* Parses a PDF. The given input stream is copied to the memory to enable random access to the pdf.
* Unrestricted main memory will be used for buffering PDF streams.
*
* #param input stream that contains the document.
* #param password password to be used for decryption
*
* #return loaded document
*
* #throws IOException in case of a file reading or parsing error
*/
public static PDDocument load(InputStream input, String password)
throws IOException

Related

Programatically added picture in PDF picture field not being displayed

I have created a PDF with Adobe, which contains an image field called "logo"
Now if i want to add a picture using PDFBox it won't be displayed in the created pdf.
However no error message is thrown and debugging looks completely fine with a correctly created PDImageXObject object.
The used code is mostly adapted from this question:
public static void setImageField(PDDocument pdfDocument, PDAcroForm acroForm, String fieldKey, byte[] imageData)
{
final PDField retrievedField = acroForm.getField(fieldKey);
if (!(retrievedField instanceof PDPushButton)) {
throw new RuntimeException("The field: " + fieldKey + " is not of the correct type");
}
LOGGER.info("Received field: " + retrievedField.getPartialName()); // correct field is being logged
final PDPushButton imageField = (PDPushButton) retrievedField;
final List<PDAnnotationWidget> fieldWidgets = imageField.getWidgets(); // it has exactly one widget, which would be the action to set the image
if (fieldWidgets == null || fieldWidgets.size() <= 0) {
throw new RuntimeException("Misconfiguration for field: " + fieldKey + ", it has no widgets(actions)");
}
final PDAnnotationWidget imageWidget = fieldWidgets.get(0);
PDImageXObject imageForm;
try {
// This test data is resized to be smaller than the bounding box of the image element in the PDF. Just for testing purposes
final String testImage = "iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAARUlEQVR42u3PMREAAAgEIO2fzkRvBlcPGtCVTD3QIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIXC7VGjKHva+IvAAAAAElFTkSuQmCC";
final byte[] testData = Base64.getDecoder().decode(testImage);
imageForm = PDImageXObject.createFromByteArray(pdfDocument, testData, "logo"); // imageForm is being populated with data and no error thrown
}
catch (IOException e) {
throw new RuntimeException("Error creating Image from image data", e);
}
final float imageScaleRatio = (float) (imageForm.getHeight() / imageForm.getWidth());
final PDRectangle imagePosition = getFieldArea(imageField);
LOGGER.info("Received image position: " + imagePosition.toString());
// Retrieve the height and width and position of the rectangle where the picture will be
final float imageHeight = imagePosition.getHeight();
LOGGER.info("Image height: " + imageHeight);
final float imageWidth = imageHeight / imageScaleRatio;
LOGGER.info("Image width: " + imageWidth);
final float imageXPosition = imagePosition.getLowerLeftX();
LOGGER.info("Image X position: " + imageXPosition);
final float imageYPosition = imagePosition.getLowerLeftY();
LOGGER.info("Image Y position: " + imageYPosition);
final PDAppearanceStream documentAppearance = new PDAppearanceStream(pdfDocument);
documentAppearance.setResources(new PDResources()); // not sure why this is done
// Weird "bug" in pdfbox forces to create the contentStream always after the object to add
try (PDPageContentStream documentContentStream = new PDPageContentStream(pdfDocument, documentAppearance)) {
documentContentStream.drawImage(imageForm, imageXPosition, imageYPosition, imageWidth, imageHeight);
}
catch (IOException e) {
throw new RuntimeException("Error drawing the picture in the document", e);
}
// Setting the boundary box is mandatory for the image field! Do not remove or the flatten call on the acroform will NPE
documentAppearance.setBBox(new PDRectangle(imageXPosition, imageYPosition, imageWidth, imageHeight));
// Apply the appearance settings of the document onto the image widget ( No border )
setImageAppearance(imageWidget, documentAppearance);
// This code is normally somewhere else but for SO copied in this method to show how the pdf is being created
acroForm.flatten();
AccessPermission ap = new AccessPermission();
ap.setCanModify(false);
ap.setCanExtractContent(false);
ap.setCanFillInForm(false);
ap.setCanModifyAnnotations(false);
ap.setReadOnly();
StandardProtectionPolicy spp = new StandardProtectionPolicy("", "", ap);
spp.setEncryptionKeyLength(PdfBuildConstants.ENCRYPTION_KEY_LENTGH);
pdfDocument.protect(spp);
pdfDocument.save(pdfFile);
pdfDocument.close();
}
/**
* Applies the appearance settings of the document onto the widget to ensure a consistent look of the document.
*
* #param imageWidget The {#link PDAnnotationWidget Widget} to apply the settings to
* #param documentAppearance The {#link PDAppearanceStream Appearance settings} of the document
*/
private static void setImageAppearance(final PDAnnotationWidget imageWidget,
final PDAppearanceStream documentAppearance)
{
PDAppearanceDictionary widgetAppearance = imageWidget.getAppearance();
if (widgetAppearance == null) {
widgetAppearance = new PDAppearanceDictionary();
imageWidget.setAppearance(widgetAppearance);
}
widgetAppearance.setNormalAppearance(documentAppearance);
}
/**
* Retrieves the dimensions of the given {#link PDField Field} and creates an {#link PDRectangle Rectangle} with the
* same dimensions.
*
* #param field The {#link PDField Field} to create the rectangle for
* #return The created {#link PDRectangle Rectangle} with the dimensions of the field
*/
private static PDRectangle getFieldArea(PDField field) {
final COSDictionary fieldDictionary = field.getCOSObject();
final COSBase fieldAreaValue = fieldDictionary.getDictionaryObject(COSName.RECT);
if (!(fieldAreaValue instanceof COSArray)) {
throw new RuntimeException("The field: " + field.getMappingName() + " has no position values");
}
final COSArray fieldAreaArray = (COSArray) fieldAreaValue;
return new PDRectangle(fieldAreaArray);
}
I also looked at other questions such as this, but I can't use PDJpeg since it is not available in the current version. Additionally the original image to use can be anything from jpeg,png to gif.
I validated that the position and dimension variables being logged have the same value as the image field in the pdf file. (properties of the field)
UPDATE:
Here is an example zip containing the template pdf and the generated pdf which fills in the form fields: file upload or Dropbox
The example picture was a 50x50 png with plain green color generated from online png pixel

Remove space between images added into a single pdf file with iText using java.

I am trying to crate PDF files from a list of images. 4 image should cover a full page with no margin padding or anything. My problem is that the added images are separated by a white line, and I can't figure out a way to remove this separation.
public ByteArrayOutputStream createMultiTicketPdf(List<String> base64Images) {
PDFCreator creator = new PDFCreator();
Document document = creator.getDocument();
creator.setForMulti(true);
float nomargin = 0;
creator.addCustomCSS("common", "/pdf/common.css");
document.setMargins(nomargin, nomargin, nomargin, nomargin);
creator.setTemplateRelativePath("/pdf/multitickettemplate.html");
for(String base64Image : base64Images) {
try {
String parsedString = StringUtils.substringAfter(base64Image, ",");
byte[] decoded = Base64.getDecoder().decode(parsedString);
Image image = Image.getInstance(decoded);
float scaler = ((document.getPageSize().getWidth() - document.leftMargin()
- document.rightMargin()) / image.getWidth()) * 100;
image.scalePercent(scaler);
image.setPaddingTop(nomargin);
creator.addImage(Image.getInstance(image));
} catch (BadElementException | IOException e) {
LOGGER.error("Error occured:", e);
}
}
return creator.create();
}

Put the contents of pdf at the center of canvas in Apache PDFBox

I am working with Apache PDFBox 2.0.8. My Objective is to convert a PDF into Image and enlarge the canvas and put the contents in the center so that i can put some header and footer in the remaining space.
My issue is that the canvas is getting enlarged but the contents are not getting centered, they are stick to the bottom.
public class PDFRescale {
public static void main(String[] args) {
try {
String pdfFilename = "/MuhimbiPOC/Templates/Source_doc_withheaderfooter.pdf";
PDDocument document = PDDocument.load(new File(pdfFilename));
PDFRenderer pdfRenderer = new PDFRenderer(document);
PDPage pge = new PDPage();
PDFRescale ps = new PDFRescale();
int pageCounter = 0;
for (PDPage page : document.getPages())
{
final PDRectangle mediaBox = pge.getMediaBox();
mediaBox.setUpperRightX((float) (mediaBox.getUpperRightX()));
mediaBox.setUpperRightY((float) (mediaBox.getUpperRightY() * 1.5));
mediaBox.setLowerLeftY((float) (mediaBox.getLowerLeftY() * 1.5));
// note that the page number parameter is zero based
page.setMediaBox(mediaBox);
BufferedImage bim = pdfRenderer.renderImageWithDPI(pageCounter, 140, ImageType.RGB);
// suffix in filename will be used as the file format
ImageIOUtil.writeImage(bim, pdfFilename + "-" + (pageCounter++) + ".png", 140);
}
System.out.println("Task Completed ... ");
document.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
My issue is that the canvas is getting enlarged but the contents are not getting centered, they are stick to the bottom.
That is your issue for PDF pages whose mediaBox.getLowerLeftY() is 0. While this is very common, it is not required. If you had worked with a more generic selection of PDFs, you'd have seen that your issue is that the former contents eventually can be anywhere, even off-screen!
The cause is that you do
mediaBox.setUpperRightY((float) (mediaBox.getUpperRightY() * 1.5));
mediaBox.setLowerLeftY((float) (mediaBox.getLowerLeftY() * 1.5));
This would only work if the origin was somewhere on the horizontal mid-screen axis.
Instead use something like
mediaBox.setUpperRightY(mediaBox.getUpperRightY() + mediaBox.getHeight() * 0.5f);
mediaBox.setLowerLeftY(mediaBox.getLowerLeftY() - mediaBox.getHeight() * 0.5f);
Another issue of your code: you only set the MediaBox and ignore the CropBox. pdfRenderer.renderImageWithDPI on the other hand uses the CropBox. Only for PDF pages without explicit CropBox your code enlarges the page area. For a generic solution you should also adapt the CropBox.

Not able to display digital signature related details using PDVisibleSignDesigner using pdfbox v2.0.8 [duplicate]

Digital text with text and background imageI am trying to digitally sign pdf file using PDFBox in Java with visible text to appear on page similar to one that gets created when manually created in Acrobat. As shown in the image (one with only snap shot I am looking for and another with details of digital signature too), this example shows signing using image file. How to do that?
This code will be included among the samples in the upcoming 2.0.9 release of PDFBox, and the current update can be found in the repository. See also the discussion in PDFBOX-3198. It is more flexible and can include both text and images, or only one of the two, or vector graphics, whatever you want.
/**
* This is a second example for visual signing a pdf. It doesn't use the "design pattern" influenced
* PDVisibleSignDesigner, and doesn't create its complex multilevel forms described in the Adobe
* document
* <a href="https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PPKAppearances.pdf">Digital
* Signature Appearances</a>, because this isn't required by the PDF specification. See the
* discussion in December 2017 in PDFBOX-3198.
*
* #author Vakhtang Koroghlishvili
* #author Tilman Hausherr
*/
public class CreateVisibleSignature2 extends CreateSignatureBase
{
private SignatureOptions signatureOptions;
private boolean lateExternalSigning = false;
private File imageFile;
/**
* Initialize the signature creator with a keystore (pkcs12) and pin that
* should be used for the signature.
*
* #param keystore is a pkcs12 keystore.
* #param pin is the pin for the keystore / private key
* #throws KeyStoreException if the keystore has not been initialized (loaded)
* #throws NoSuchAlgorithmException if the algorithm for recovering the key cannot be found
* #throws UnrecoverableKeyException if the given password is wrong
* #throws CertificateException if the certificate is not valid as signing time
* #throws IOException if no certificate could be found
*/
public CreateVisibleSignature2(KeyStore keystore, char[] pin)
throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, IOException, CertificateException
{
super(keystore, pin);
}
public File getImageFile()
{
return imageFile;
}
public void setImageFile(File imageFile)
{
this.imageFile = imageFile;
}
public boolean isLateExternalSigning()
{
return lateExternalSigning;
}
/**
* Set late external signing. Enable this if you want to activate the demo code where the
* signature is kept and added in an extra step without using PDFBox methods. This is disabled
* by default.
*
* #param lateExternalSigning
*/
public void setLateExternalSigning(boolean lateExternalSigning)
{
this.lateExternalSigning = lateExternalSigning;
}
/**
* Sign pdf file and create new file that ends with "_signed.pdf".
*
* #param inputFile The source pdf document file.
* #param signedFile The file to be signed.
* #param humanRect rectangle from a human viewpoint (coordinates start at top left)
* #param tsaUrl optional TSA url
* #throws IOException
*/
public void signPDF(File inputFile, File signedFile, Rectangle2D humanRect, String tsaUrl) throws IOException
{
this.signPDF(inputFile, signedFile, humanRect, tsaUrl, null);
}
/**
* Sign pdf file and create new file that ends with "_signed.pdf".
*
* #param inputFile The source pdf document file.
* #param signedFile The file to be signed.
* #param humanRect rectangle from a human viewpoint (coordinates start at top left)
* #param tsaUrl optional TSA url
* #param signatureFieldName optional name of an existing (unsigned) signature field
* #throws IOException
*/
public void signPDF(File inputFile, File signedFile, Rectangle2D humanRect, String tsaUrl, String signatureFieldName) throws IOException
{
if (inputFile == null || !inputFile.exists())
{
throw new IOException("Document for signing does not exist");
}
setTsaUrl(tsaUrl);
// creating output document and prepare the IO streams.
FileOutputStream fos = new FileOutputStream(signedFile);
try (PDDocument doc = PDDocument.load(inputFile))
{
int accessPermissions = SigUtils.getMDPPermission(doc);
if (accessPermissions == 1)
{
throw new IllegalStateException("No changes to the document are permitted due to DocMDP transform parameters dictionary");
}
// Note that PDFBox has a bug that visual signing on certified files with permission 2
// doesn't work properly, see PDFBOX-3699. As long as this issue is open, you may want to
// be careful with such files.
PDSignature signature = null;
PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
PDRectangle rect = null;
// sign a PDF with an existing empty signature, as created by the CreateEmptySignatureForm example.
if (acroForm != null)
{
signature = findExistingSignature(acroForm, signatureFieldName);
if (signature != null)
{
rect = acroForm.getField(signatureFieldName).getWidgets().get(0).getRectangle();
}
}
if (signature == null)
{
// create signature dictionary
signature = new PDSignature();
}
if (rect == null)
{
rect = createSignatureRectangle(doc, humanRect);
}
// Optional: certify
// can be done only if version is at least 1.5 and if not already set
// doing this on a PDF/A-1b file fails validation by Adobe preflight (PDFBOX-3821)
// PDF/A-1b requires PDF version 1.4 max, so don't increase the version on such files.
if (doc.getVersion() >= 1.5f && accessPermissions == 0)
{
SigUtils.setMDPPermission(doc, signature, 2);
}
if (acroForm != null && acroForm.getNeedAppearances())
{
// PDFBOX-3738 NeedAppearances true results in visible signature becoming invisible
// with Adobe Reader
if (acroForm.getFields().isEmpty())
{
// we can safely delete it if there are no fields
acroForm.getCOSObject().removeItem(COSName.NEED_APPEARANCES);
// note that if you've set MDP permissions, the removal of this item
// may result in Adobe Reader claiming that the document has been changed.
// and/or that field content won't be displayed properly.
// ==> decide what you prefer and adjust your code accordingly.
}
else
{
System.out.println("/NeedAppearances is set, signature may be ignored by Adobe Reader");
}
}
// default filter
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
// subfilter for basic and PAdES Part 2 signatures
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName("Name");
signature.setLocation("Location");
signature.setReason("Reason");
// the signing date, needed for valid signature
signature.setSignDate(Calendar.getInstance());
// do not set SignatureInterface instance, if external signing used
SignatureInterface signatureInterface = isExternalSigning() ? null : this;
// register signature dictionary and sign interface
signatureOptions = new SignatureOptions();
signatureOptions.setVisualSignature(createVisualSignatureTemplate(doc, 0, rect));
signatureOptions.setPage(0);
doc.addSignature(signature, signatureInterface, signatureOptions);
if (isExternalSigning())
{
System.out.println("Signing externally " + signedFile.getName());
ExternalSigningSupport externalSigning = doc.saveIncrementalForExternalSigning(fos);
// invoke external signature service
byte[] cmsSignature = sign(externalSigning.getContent());
// Explanation of late external signing (off by default):
// If you want to add the signature in a separate step, then set an empty byte array
// and call signature.getByteRange() and remember the offset signature.getByteRange()[1]+1.
// you can write the ascii hex signature at a later time even if you don't have this
// PDDocument object anymore, with classic java file random access methods.
// If you can't remember the offset value from ByteRange because your context has changed,
// then open the file with PDFBox, find the field with findExistingSignature() or
// PODDocument.getLastSignatureDictionary() and get the ByteRange from there.
// Close the file and then write the signature as explained earlier in this comment.
if (isLateExternalSigning())
{
// this saves the file with a 0 signature
externalSigning.setSignature(new byte[0]);
// remember the offset (add 1 because of "<")
int offset = signature.getByteRange()[1] + 1;
// now write the signature at the correct offset without any PDFBox methods
try (RandomAccessFile raf = new RandomAccessFile(signedFile, "rw"))
{
raf.seek(offset);
raf.write(Hex.getBytes(cmsSignature));
}
}
else
{
// set signature bytes received from the service and save the file
externalSigning.setSignature(cmsSignature);
}
}
else
{
// write incremental (only for signing purpose)
doc.saveIncremental(fos);
}
}
// Do not close signatureOptions before saving, because some COSStream objects within
// are transferred to the signed document.
// Do not allow signatureOptions get out of scope before saving, because then the COSDocument
// in signature options might by closed by gc, which would close COSStream objects prematurely.
// See https://issues.apache.org/jira/browse/PDFBOX-3743
IOUtils.closeQuietly(signatureOptions);
}
private PDRectangle createSignatureRectangle(PDDocument doc, Rectangle2D humanRect)
{
float x = (float) humanRect.getX();
float y = (float) humanRect.getY();
float width = (float) humanRect.getWidth();
float height = (float) humanRect.getHeight();
PDPage page = doc.getPage(0);
PDRectangle pageRect = page.getCropBox();
PDRectangle rect = new PDRectangle();
// signing should be at the same position regardless of page rotation.
switch (page.getRotation())
{
case 90:
rect.setLowerLeftY(x);
rect.setUpperRightY(x + width);
rect.setLowerLeftX(y);
rect.setUpperRightX(y + height);
break;
case 180:
rect.setUpperRightX(pageRect.getWidth() - x);
rect.setLowerLeftX(pageRect.getWidth() - x - width);
rect.setLowerLeftY(y);
rect.setUpperRightY(y + height);
break;
case 270:
rect.setLowerLeftY(pageRect.getHeight() - x - width);
rect.setUpperRightY(pageRect.getHeight() - x);
rect.setLowerLeftX(pageRect.getWidth() - y - height);
rect.setUpperRightX(pageRect.getWidth() - y);
break;
case 0:
default:
rect.setLowerLeftX(x);
rect.setUpperRightX(x + width);
rect.setLowerLeftY(pageRect.getHeight() - y - height);
rect.setUpperRightY(pageRect.getHeight() - y);
break;
}
return rect;
}
// create a template PDF document with empty signature and return it as a stream.
private InputStream createVisualSignatureTemplate(PDDocument srcDoc, int pageNum, PDRectangle rect) throws IOException
{
try (PDDocument doc = new PDDocument())
{
PDPage page = new PDPage(srcDoc.getPage(pageNum).getMediaBox());
doc.addPage(page);
PDAcroForm acroForm = new PDAcroForm(doc);
doc.getDocumentCatalog().setAcroForm(acroForm);
PDSignatureField signatureField = new PDSignatureField(acroForm);
PDAnnotationWidget widget = signatureField.getWidgets().get(0);
List<PDField> acroFormFields = acroForm.getFields();
acroForm.setSignaturesExist(true);
acroForm.setAppendOnly(true);
acroForm.getCOSObject().setDirect(true);
acroFormFields.add(signatureField);
widget.setRectangle(rect);
// from PDVisualSigBuilder.createHolderForm()
PDStream stream = new PDStream(doc);
PDFormXObject form = new PDFormXObject(stream);
PDResources res = new PDResources();
form.setResources(res);
form.setFormType(1);
PDRectangle bbox = new PDRectangle(rect.getWidth(), rect.getHeight());
float height = bbox.getHeight();
Matrix initialScale = null;
switch (srcDoc.getPage(pageNum).getRotation())
{
case 90:
form.setMatrix(AffineTransform.getQuadrantRotateInstance(1));
initialScale = Matrix.getScaleInstance(bbox.getWidth() / bbox.getHeight(), bbox.getHeight() / bbox.getWidth());
height = bbox.getWidth();
break;
case 180:
form.setMatrix(AffineTransform.getQuadrantRotateInstance(2));
break;
case 270:
form.setMatrix(AffineTransform.getQuadrantRotateInstance(3));
initialScale = Matrix.getScaleInstance(bbox.getWidth() / bbox.getHeight(), bbox.getHeight() / bbox.getWidth());
height = bbox.getWidth();
break;
case 0:
default:
break;
}
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(doc, appearanceStream))
{
// for 90° and 270° scale ratio of width / height
// not really sure about this
// why does scale have no effect when done in the form matrix???
if (initialScale != null)
{
cs.transform(initialScale);
}
// show background (just for debugging, to see the rect size + position)
cs.setNonStrokingColor(Color.yellow);
cs.addRect(-5000, -5000, 10000, 10000);
cs.fill();
// show background image
// save and restore graphics if the image is too large and needs to be scaled
cs.saveGraphicsState();
cs.transform(Matrix.getScaleInstance(0.25f, 0.25f));
PDImageXObject img = PDImageXObject.createFromFileByExtension(imageFile, doc);
cs.drawImage(img, 0, 0);
cs.restoreGraphicsState();
// show text
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 very wide line 1)");
cs.newLine();
cs.showText("(Signature very wide line 2)");
cs.newLine();
cs.showText("(Signature very wide line 3)");
cs.endText();
}
// no need to set annotations and /P entry
ByteArrayOutputStream baos = new ByteArrayOutputStream();
doc.save(baos);
return new ByteArrayInputStream(baos.toByteArray());
}
}
// Find an existing signature (assumed to be empty). You will usually not need this.
private PDSignature findExistingSignature(PDAcroForm acroForm, String sigFieldName)
{
PDSignature signature = null;
PDSignatureField signatureField;
if (acroForm != null)
{
signatureField = (PDSignatureField) acroForm.getField(sigFieldName);
if (signatureField != null)
{
// retrieve signature dictionary
signature = signatureField.getSignature();
if (signature == null)
{
signature = new PDSignature();
// after solving PDFBOX-3524
// signatureField.setValue(signature)
// until then:
signatureField.getCOSObject().setItem(COSName.V, signature);
}
else
{
throw new IllegalStateException("The signature field " + sigFieldName + " is already signed.");
}
}
}
return signature;
}
/**
* Arguments are
* [0] key store
* [1] pin
* [2] document that will be signed
* [3] image of visible signature
*
* #param args
* #throws java.security.KeyStoreException
* #throws java.security.cert.CertificateException
* #throws java.io.IOException
* #throws java.security.NoSuchAlgorithmException
* #throws java.security.UnrecoverableKeyException
*/
public static void main(String[] args) throws KeyStoreException, CertificateException,
IOException, NoSuchAlgorithmException, UnrecoverableKeyException
{
// generate with
// keytool -storepass 123456 -storetype PKCS12 -keystore file.p12 -genkey -alias client -keyalg RSA
if (args.length < 4)
{
usage();
System.exit(1);
}
String tsaUrl = null;
// External signing is needed if you are using an external signing service, e.g. to sign
// several files at once.
boolean externalSig = false;
for (int i = 0; i < args.length; i++)
{
if (args[i].equals("-tsa"))
{
i++;
if (i >= args.length)
{
usage();
System.exit(1);
}
tsaUrl = args[i];
}
if (args[i].equals("-e"))
{
externalSig = true;
}
}
File ksFile = new File(args[0]);
KeyStore keystore = KeyStore.getInstance("PKCS12");
char[] pin = args[1].toCharArray();
keystore.load(new FileInputStream(ksFile), pin);
File documentFile = new File(args[2]);
CreateVisibleSignature2 signing = new CreateVisibleSignature2(keystore, pin.clone());
signing.setImageFile(new File(args[3]));
File signedDocumentFile;
String name = documentFile.getName();
String substring = name.substring(0, name.lastIndexOf('.'));
signedDocumentFile = new File(documentFile.getParent(), substring + "_signed.pdf");
signing.setExternalSigning(externalSig);
// Set the signature rectangle
// Although PDF coordinates start from the bottom, humans start from the top.
// So a human would want to position a signature (x,y) units from the
// top left of the displayed page, and the field has a horizontal width and a vertical height
// regardless of page rotation.
Rectangle2D humanRect = new Rectangle2D.Float(100, 200, 150, 50);
signing.signPDF(documentFile, signedDocumentFile, humanRect, tsaUrl, "Signature1");
}
/**
* This will print the usage for this program.
*/
private static void usage()
{
System.err.println("Usage: java " + CreateVisibleSignature2.class.getName()
+ " <pkcs12-keystore-file> <pin> <input-pdf> <sign-image>\n" + "" +
"options:\n" +
" -tsa <url> sign timestamp using the given TSA server\n"+
" -e sign using external signature creation scenario");
}
}

Convert image to pdf with iText and Java

I succesfully converted image files (gif, png, jpg, bmp) to pdf's using iText 1.3.
I can't change the version since we can't just change versions of a jar obviously in a professional environment.
The problem that I have is that the size of the image in the pdf is larger than the image itself. I am not talking about the file size but about the size of the image when the zoom is set to 100% on both the original image file and the pdf.
The pdf shows the image about a 20% to 30% bigger than the original image.
What am I doing wrong?
public void convertOtherImages2pdf(byte[] in, OutputStream out, String title, String author) throws IOException {
Image image = Image.getInstance(in);
Rectangle imageSize = new Rectangle(image.width() + 1f, image.height() + 1f);
image.scaleAbsolute(image.width(), image.height());
com.lowagie.text.Document document = new com.lowagie.text.Document(imageSize, 0, 0, 0, 0);
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open();
document.add(image);
document.close();
writer.close();
}
Make MultipleImagesToPdf Class
public void imagesToPdf(String destination, String pdfName, String imagFileSource) throws IOException, DocumentException {
Document document = new Document(PageSize.A4, 20.0f, 20.0f, 20.0f, 150.0f);
String desPath = destination;
File destinationDirectory = new File(desPath);
if (!destinationDirectory.exists()){
destinationDirectory.mkdir();
System.out.println("DESTINATION FOLDER CREATED -> " + destinationDirectory.getAbsolutePath());
}else if(destinationDirectory.exists()){
System.out.println("DESTINATION FOLDER ALREADY CREATED!!!");
}else{
System.out.println("DESTINATION FOLDER NOT CREATED!!!");
}
File file = new File(destinationDirectory, pdfName + ".pdf");
FileOutputStream fileOutputStream = new FileOutputStream(file);
PdfWriter pdfWriter = PdfWriter.getInstance(document, fileOutputStream);
document.open();
System.out.println("CONVERTER START.....");
String[] splitImagFiles = imagFileSource.split(",");
for (String singleImage : splitImagFiles) {
Image image = Image.getInstance(singleImage);
document.setPageSize(image);
document.newPage();
image.setAbsolutePosition(0, 0);
document.add(image);
}
document.close();
System.out.println("CONVERTER STOPTED.....");
}
public static void main(String[] args) {
try {
MultipleImagesToPdf converter = new MultipleImagesToPdf();
Scanner sc = new Scanner(System.in);
System.out.print("Enter your destination folder where save PDF \n");
// Destination = D:/Destination/;
String destination = sc.nextLine();
System.out.print("Enter your PDF File Name \n");
// Name = test;
String name = sc.nextLine();
System.out.print("Enter your selected image files name with source folder \n");
String sourcePath = sc.nextLine();
// Source = D:/Source/a.jpg,D:/Source/b.jpg;
if (sourcePath != null || sourcePath != "") {
converter.imagesToPdf(destination, name, sourcePath);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
=================================
Here i use itextpdf-5.4.0 Library
Happy Coding :)
You need to scale the image by the dpi.
float scale = 72 / dpi;
I don't know if such an ancient iText has that image information, more recent iText versions have it.

Categories