How to add .png images to pdf using Apache PDFBox - java

When I try to draw png images using pdfBox, the pages remain blank. Is there any way to insert png images using pdfBox?
public void createPDFFromImage( String inputFile, String image, String outputFile )
throws IOException, COSVisitorException
{
// the document
PDDocument doc = null;
try
{
doc = PDDocument.load( inputFile );
//we will add the image to the first page.
PDPage page = (PDPage)doc.getDocumentCatalog().getAllPages().get( 0 );
PDXObjectImage ximage = null;
if( image.toLowerCase().endsWith( ".jpg" ) )
{
ximage = new PDJpeg(doc, new FileInputStream( image ) );
}
else if (image.toLowerCase().endsWith(".tif") || image.toLowerCase().endsWith(".tiff"))
{
ximage = new PDCcitt(doc, new RandomAccessFile(new File(image),"r"));
}
else
{
BufferedImage awtImage = ImageIO.read( new File( image ) );
ximage = new PDPixelMap(doc, awtImage);
// throw new IOException( "Image type not supported:" + image );
}
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true);
contentStream.drawImage( ximage, 20, 20 );
contentStream.close();
doc.save( outputFile );
}
finally
{
if( doc != null )
{
doc.close();
}
}
}

There is a pretty nice utility class PDImageXObject to load Images from a java.io.File.
As far as I know, it works well with jpg and png files.
PDImageXObject pdImage = PDImageXObject.createFromFileByContent(imageFile, doc);
contentStream.drawImage(pdImage, 20f, 20f);

Related

AcroForm not visible when merging documents

I'm trying to merge documents side by side with PDFBox, using the following code:
function void generateSideBySidePDF() {
File pdf1File = new File(FILE1_PATH);
File pdf2File = new File(FILE2_PATH);
File outPdfFile = new File(OUTFILE_PATH);
PDDocument pdf1 = null;
PDDocument pdf2 = null;
PDDocument outPdf = null;
try {
pdf1 = PDDocument.load(pdf1File);
pdf2 = PDDocument.load(pdf2File);
outPdf = new PDDocument();
// Create output PDF frame
PDRectangle pdf1Frame = pdf1.getPage(0).getCropBox();
PDRectangle pdf2Frame = pdf2.getPage(0).getCropBox();
PDRectangle outPdfFrame = new PDRectangle(pdf1Frame.getWidth()+pdf2Frame.getWidth(), Math.max(pdf1Frame.getHeight(), pdf2Frame.getHeight()));
// Create output page with calculated frame and add it to the document
COSDictionary dict = new COSDictionary();
dict.setItem(COSName.TYPE, COSName.PAGE);
dict.setItem(COSName.MEDIA_BOX, outPdfFrame);
dict.setItem(COSName.CROP_BOX, outPdfFrame);
dict.setItem(COSName.ART_BOX, outPdfFrame);
PDPage outPdfPage = new PDPage(dict);
outPdf.addPage(outPdfPage);
// Source PDF pages has to be imported as form XObjects to be able to insert them at a specific point in the output page
LayerUtility layerUtility = new LayerUtility(outPdf);
PDFormXObject formPdf1 = layerUtility.importPageAsForm(pdf1, 0);
PDFormXObject formPdf2 = layerUtility.importPageAsForm(pdf2, 0);
// Add form objects to output page
AffineTransform afLeft = new AffineTransform();
layerUtility.appendFormAsLayer(outPdfPage, formPdf1, afLeft, "left");
AffineTransform afRight = AffineTransform.getTranslateInstance(pdf1Frame.getWidth(), 0.0);
layerUtility.appendFormAsLayer(outPdfPage, formPdf2, afRight, "right");
outPdf.save(outPdfFile);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (pdf1 != null) pdf1.close();
if (pdf2 != null) pdf2.close();
if (outPdf != null) outPdf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
However the form fields contained in the original documents are not displayed in the final PDF. I also tried to set the acroform on the final document, doing:
outDoc.getDocumentCatalog().setAcroForm(acroForm);
but it doesn't work.

PDFBox add background when creating document [duplicate]

This question already has answers here:
Watermarking with PDFBox
(7 answers)
Closed 3 years ago.
So I want to not only add text to a pdf when I create it but as well add a background image at the same time. I was wondering if this is possible since I haven't been able to find any example and the only question similar to this (This one) has not given any feedback from the person that made the question and it wasn't marked as solved.
I'm using this very simple example at the moment:
PDDocument doc = null;
PDPage page = null;
try{
doc = new PDDocument();
page = new PDPage();
doc.addPage(page);
PDFont font = PDType1Font.HELVETICA_BOLD;
PDPageContentStream content = new PDPageContentStream(doc, page);
content.beginText();
content.setFont( font, 12 );
content.moveTextPositionByAmount( 100, 700 );
content.drawString("Hello World");
content.endText();
content.close();
doc.save("printme.pdf");
doc.close();
} catch (Exception e){
System.out.println(e);
}
Thanks for your time.
try {
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDPage.PAGE_SIZE_A4);
document.addPage(page);
PDFont font = PDType1Font.HELVETICA_BOLD;
PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true);
addImageToPage(document, 0, 0, 4f, "D:/test.jpg", contentStream);
contentStream.beginText();
contentStream.setFont(font, 12);
contentStream.moveTextPositionByAmount(100, 700);
contentStream.drawString("Hello World");
contentStream.endText();
contentStream.close();
document.save("D:/mydoc.pdf");
} catch (Exception e) {
System.out.println(e);
}
method to add image :
public static void addImageToPage(PDDocument document, int x, int y, float scale, String imageFilePath, PDPageContentStream contentStream)
throws IOException {
BufferedImage tmp_image = ImageIO.read(new File(imageFilePath));
BufferedImage image = new BufferedImage(tmp_image.getWidth(), tmp_image.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR);
image.createGraphics().drawRenderedImage(tmp_image, null);
PDXObjectImage ximage = new PDPixelMap(document, image);
contentStream.drawXObject(ximage, x, y, ximage.getWidth() * scale, ximage.getHeight() * scale);
}

PDFBox locks JPEG input file until application exits

I'm using PDFBox RC2 in a Windows 7 environment, Java 1.8_66. I'm using it to create a PDF from a collection of 200dpi page-sized image files, both JPEG and PNG.
It turns out that when adding JPEG files to a PDF, the PDImageXObject.createFromFile() routine fails to close an internal file handle, thus locking the image file for the lifetime of the application. When adding PNG files to a PDF, there is no problem.
Here's some sample code that reproduces the issue. Using process explorer (from sysinternals), view the open file handles for the java.exe process and run this code. My test uses about 20 full sized JPEG files. Note that after the method exits, several locked files still remain behind.
public Boolean CreateFromImages_Broken(String pdfFilename, String[] imageFilenames) {
PDDocument doc = new PDDocument();
for (String imageFilename : imageFilenames) {
try {
PDPage page = new PDPage();
doc.addPage(page);
PDImageXObject pdImage = PDImageXObject.createFromFile(imageFilename, doc);
// at this point, if the imageFilename is a jpeg, pdImage holds onto a handle for
// the given imageFilename and that file remains locked until the application is closed
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
float scale = (float)72.0 / 200;
page.setMediaBox(new PDRectangle((int)(pdImage.getWidth() * scale), (int)(pdImage.getHeight() * scale)));
contentStream.drawImage(pdImage, 0, 0, pdImage.getWidth()*scale, pdImage.getHeight()*scale);
}
} catch (IOException ioe) {
return false;
}
}
try {
doc.save(pdfFilename);
doc.close();
} catch (IOException ex) {
return false;
}
return true;
}
As a workaround, I reviewed the source code for PNG and JPEG handling, and I've had success by implementing this, which seems to work for both file types:
public Boolean CreateFromImages_FIXED(String pdfFilename, String[] imageFilenames) {
PDDocument doc = new PDDocument();
for (String imageFilename : imageFilenames) {
FileInputStream fis = null;
try {
PDPage page = new PDPage();
doc.addPage(page);
PDImageXObject pdImage = null;
// work around JPEG issue by opening up our own stream, with which
// we can close ourselves instead of PDFBOX leaking it. For PNG
// images, the createFromFile seems to be OK
if (imageFilename.toLowerCase().endsWith(".jpg")) {
fis = new FileInputStream(new File(imageFilename));
pdImage = JPEGFactory.createFromStream(doc, fis);
} else {
pdImage = PDImageXObject.createFromFile(imageFilename, doc);
}
try (PDPageContentStream contentStream = new PDPageContentStream(doc, page)) {
float scale = (float)72.0 / 200;
page.setMediaBox(new PDRectangle((int)(pdImage.getWidth() * scale), (int)(pdImage.getHeight() * scale)));
contentStream.drawImage(pdImage, 0, 0, pdImage.getWidth()*scale, pdImage.getHeight()*scale);
if (fis != null) {
fis.close();
fis = null;
}
}
} catch (IOException ioe) {
return false;
}
}
try {
doc.save(pdfFilename);
doc.close();
} catch (IOException ex) {
return false;
}
return true;
}

PdfBox - PDColorSpaceFactory.createColorSpace(document, iccColorSpace) throws nullpointerexception

I'm trying to create a PDF which has a single image on a single page. The tricky part is to use a custom (defined in a separate file) CMYK color space.
I've tried to call
PDColorSpaceFactory.createColorSpace(document, iccColorSpace)
but keep getting nullpointerexception. I've managed to track the issue up to the constructor:
public PDICCBased( PDDocument doc )
{
array = new COSArray();
array.add( COSName.ICCBASED );
array.add( new PDStream( doc ) );
}
The PDICCBased object has stream field and it's obviously not set. Thus when it's called at:
public static PDColorSpace createColorSpace( PDDocument doc, ColorSpace cs ) throws IOException
{
PDColorSpace retval = null;
if( cs.isCS_sRGB() )
{
retval = PDDeviceRGB.INSTANCE;
}
else if( cs instanceof ICC_ColorSpace )
{
ICC_ColorSpace ics = (ICC_ColorSpace)cs;
PDICCBased pdCS = new PDICCBased( doc );
retval = pdCS;
COSArray ranges = new COSArray();
for( int i=0; i<cs.getNumComponents(); i++ )
{
ranges.add( new COSFloat( ics.getMinValue( i ) ) );
ranges.add( new COSFloat( ics.getMaxValue( i ) ) );
}
PDStream iccData = pdCS.getPDStream();
OutputStream output = null;
try
{
output = iccData.createOutputStream(); <<<<<<<<<-------------
output.write( ics.getProfile().getData() );
}
finally
{
if( output != null )
{
output.close();
}
}
pdCS.setNumberOfComponents( cs.getNumComponents() );
}
else
{
throw new IOException( "Not yet implemented:" + cs );
}
return retval;
}
A NullPointerException is thrown.
Am I missing something? Is there another\ better way to create PDF usinf CMYK color space?
Updated createColorSpace:
public static PDColorSpace createColorSpace( PDDocument doc, ColorSpace cs ) throws IOException
{
PDColorSpace retval = null;
if( cs.isCS_sRGB() )
{
retval = PDDeviceRGB.INSTANCE;
}
else if( cs instanceof ICC_ColorSpace )
{
ICC_ColorSpace ics = (ICC_ColorSpace)cs;
// CREATING MANUALLY THE COS ARR ****************************
COSArray cosArray = new COSArray();
cosArray.add(COSName.ICCBASED);
PDStream pdStream = new PDStream(doc);
cosArray.add(pdStream.getStream());
// USING DIFFERENT CONSTRUTOR *******************************
PDICCBased pdCS = new PDICCBased( cosArray );
retval = pdCS;
COSArray ranges = new COSArray();
for( int i=0; i<cs.getNumComponents(); i++ )
{
ranges.add( new COSFloat( ics.getMinValue( i ) ) );
ranges.add( new COSFloat( ics.getMaxValue( i ) ) );
}
PDStream iccData = pdCS.getPDStream();
OutputStream output = null;
try
{
output = ((COSStream)iccData.getCOSObject()).createFilteredStream();
output.write( ics.getProfile().getData() );
}
finally
{
if( output != null )
{
output.close();
}
}
pdCS.setNumberOfComponents( cs.getNumComponents() );
}
else
{
throw new IOException( "Not yet implemented:" + cs );
}
return retval;
}
That did the trick from creating the colorSpace.
The creation of ColorSpace from a custom icc and applying it to a given image:
ICC_ColorSpace iccColorSpace = new ICC_ColorSpace(ICC_Profile.getInstance("C:\\...\\USWebCoatedSWOP.icc"));
ColorConvertOp op = new ColorConvertOp(image.getColorModel().getColorSpace(), iccColorSpace, null);
image = op.filter(image, null);
The creation of the PDF:
PDDocument document = new PDDocument();
PDColorSpace colorSpace = createColorSpace(document, iccColorSpace);
PDPage blankPage = new PDPage(new PDRectangle(100, 100));
document.addPage(blankPage);
PDPageContentStream pdPageContentStream = new PDPageContentStream(document, blankPage);
PDXObjectImage pdxObjectImage = new PDPixelMap(document, image);
pdxObjectImage.setColorSpace(colorSpace);
pdPageContentStream.drawXObject(pdxObjectImage, 0, 0, imagePostScriptWidth, imagePostScriptHeight);
pdPageContentStream.close();
document.save(byteArrayOutputStream);
document.close();
Hope this helps.
Ok, this seems to be a bug with the first constructor. You could use the second constructor, which uses a COSArray:
The PDF spec explains what to do:
"An ICCBased colour space shall be an array: [/ICCBased stream]"
So you need to create a COSArray, with COSName.ICCBASED as first element, and a COSStream with your ICC data in the second. Create a COSStream and write to it with createFilteredStream(). That COSArray you can use for the second constructor.
Alternatively, just use PDDeviceCMYK.INSTANCE as the colorspace :-)
Update:
I have opened issue PDFBOX-2812 and it has been fixed. You can get a snapshot in a few hours here.

PdfBox: issues when creating pdf from bmp

When generating a PDF form BMP the result is allways curios.
Input "hellowworld.bmp"
Output (only the relevant part)
why is there a loss of quality
why is it repeated three times
why is there a black square ( green Frame)
Heres how i test it:
#Test
public final void testWriteSingleBMPtoPDF() throws IOException {
Assert.assertTrue("File existst", TestFileHelper.getBMP(BMPS.HELLOWORLD).exists());
Assert.assertTrue("File readable", TestFileHelper.getBMP(BMPS.HELLOWORLD).canRead());
ArrayList<File> doc = new ArrayList<EncodedPage>();
doc.add(createPage(BMPS.HELLOWORLD));
File result = null;
try {
result = ConvertPDF.bmpToPDF(doc);
} catch (COSVisitorException e) {
e.printStackTrace();
}
Assert.assertTrue("File existst", result.exists());
Assert.assertTrue("File readable", result.canRead());
System.out.println("Please Check >"+result+"<");
}
Heres the part of my java implementation
public static File bmpToPDF(ArrayList<File> inputDoc)
PDDocument document = new PDDocument();
String saveTo = "C:\\temp\\" + System.currentTimeMillis() + ".pdf";
for (File bmpPage : inputDoc) {
PDPage page = null;
PDXObjectImage ximage = null;
page = new PDPage();
document.addPage(page);
BufferedImage awtImage = ImageIO.read(bmpPage);
ximage = new PDPixelMap(document, awtImage);
PDPageContentStream content = new PDPageContentStream(document, page);
content.drawImage(ximage, 0, 0);
content.close();
}
document.save(saveTo);
document.close();
return new File(saveTo) ;
Version of Apache PDFBox is 1.7.1

Categories

Resources