Replacing image in PDF using PDFBox - pdfbox

I have a PDF document which has a blank image (with grey background). I need to replace this blank image with another image which I have as a byte array.
I replace the image using PDFBox as below:
// Convert byte array to BufferedImage
BufferedImage imgFromBytes = ImageIO.read(new ByteArrayInputStream(imgBytes));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(imgFromBytes, "jpg", baos);
// Replace empty image in pdf with the image generated from byte array
PDXObjectImage newImage = new PDJpeg(doc, new ByteArrayInputStream(baos.toByteArray()));
blankImg.getCOSStream().replaceWithStream(newImage.getCOSStream());
This replaces the blank image in the pdf. But the problem is, the image generated from the byte array is not the same size as compared to the blank image. I guess it does some auto-scaling, because of which there is some blank space at the bottom which is grey in color (due to the background of the blank image).
So I tried re-scaling the image as below:
// Convert byte array to BufferedImage
BufferedImage imgFromBytes = ImageIO.read(new ByteArrayInputStream(imgBytes));
//Re-size the image
BufferedImage resizedImage = new BufferedImage(blankImg.getWidth(), blankImg.getHeight(), BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = resizedImage.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2d.drawImage(imgFromBytes, 0, 0, blankImg.getWidth(), blankImg.getHeight(), Color.WHITE, null);
g2d.dispose();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(resizedImage, "jpg", baos);
// Replace empty image in pdf with the image generated from byte array
PDXObjectImage newImage = new PDJpeg(doc, new ByteArrayInputStream(baos.toByteArray()));
blankImg.getCOSStream().replaceWithStream(newImage.getCOSStream());
But this doesn't help me either. I still see the grey background at the bottom. Moreover, this reduces the quality of the image and also chops a bit from the top and bottom of the image generated from the bytes.
What would be the best way to replace the blank image with the image I get from the byte array, so that it fits the size of the blank image perfectly?
Thanks.

Related

How to rotate an Image using Itex7 and C#?

I am using the C#SDK for iText . As a simple test I'm creating a PDF with an Image in it. What I want to do is to rotate this Image in the PDF. This is the code I'm using
PdfWriter writer = new PdfWriter("./test.pdf", new WriterProperties().SetPdfVersion(PdfVersion.PDF_2_0));
PdfDocument pdfDocument = new PdfDocument(writer);
pdfDocument.SetTagged();
Document document = new Document(pdfDocument);
Image image = new Image(ImageDataFactory.Create("google-logo.png")).SetRotationAngle(90).SetAutoScale(true);
document.Add(image);
document.Close();
However, in the generated file, the Image shows like this
So how can I rotate the Image by 90 degrees?
The documentation of Image#SetRotationAngle says that the value must be passed in radians, not in angles.
So just replacing image.SetRotationAngle(90) with image.SetRotationAngle(Math.PI / 2) should do the trick

PDF generated using PDFBox is magnified when printing / saving via Safari

I generated a pdf using PDFBox which is then sent to the front-end. When I print / save this pdf in Chrome / Firefox, it looks good. However, when I try to do the same using Safari, the pdf is magnified.
Not sure if this is a browser issue or whether it has something to do with Safari not able to read the pdf properly. Any ideas?
This is the pdf generated from Chrome, and this is the one from Safari (I've redacted few details).
This is my code:
PDXObjectImage blankImg = (PDXObjectImage) object;
if(blankImg.getHeight() > 460){
BufferedImage img = ImageIO.read(new ByteArrayInputStream(shippingLabel));
BufferedImage resizedImage = Scalr.resize(img, Scalr.Method.BALANCED, Scalr.Mode.FIT_EXACT, img.getWidth(), img.getHeight());
// Convert images to jpg format
BufferedImage jpegImage = new BufferedImage(resizedImage.getWidth(),resizedImage.getHeight(), BufferedImage.TYPE_INT_RGB);
jpegImage.createGraphics().drawImage(resizedImage, 0, 0, Color.WHITE, null);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(jpegImage, "jpg", baos);
// Replace empty image in template with the image generated from shipping label byte array
PDXObjectImage carrierLabel = new PDJpeg(doc, new ByteArrayInputStream(baos.toByteArray()));
blankImg.getCOSStream().replaceWithStream(carrierLabel.getCOSStream());
break;
}
PDStream updatedStream = new PDStream(doc);
OutputStream out = updatedStream.createOutputStream();
ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
tokenWriter.writeTokens(tokens);
page.setContents(updatedStream);
// Convert PDDoc to byte[]
ByteArrayOutputStream outUpdated = new ByteArrayOutputStream();
doc.save(outUpdated);
return outUpdated.toByteArray();
This is what I'm doing. I have a pdf with a blank image. I read this image, and replace this with another existing image which is available as byte array, and finally return the updated pdf as a byte array as ResponseEntity from Spring boot server running in the backend.
Thanks.

write lines on PDF

I want to write line by line on a pdf document
the code I have is writing the text in the center of the page
how can I write line by line?
// Create a new PDF document
PdfDocument document = new PdfDocument();
document.Info.Title = "Created with PDFsharp";
// Create an empty page
PdfPage page = document.AddPage();
// Get an XGraphics object for drawing
XGraphics gfx = XGraphics.FromPdfPage(page);
// Create a font
XFont font = new XFont("Verdana", 20, XFontStyle.BoldItalic);
// Draw the text
gfx.DrawString("Hello, World!", font, XBrushes.Black,
new XRect(0, 0, page.Width, page.Height),
XStringFormats.TopCenter);
With new XRect(0, 0, page.Width, page.Height) you specify where text will be drawn.
Use a smaller rectangle and increase the second value from line to line.
PDFsharp includes several examples:
http://pdfsharp.net/wiki/PDFsharpSamples.ashx
Especially check Text Layout. Sample code included with the source package of PDFsharp.
Also check out MigraDoc as it adds pagebreaks automatically.
http://pdfsharp.net/wiki/MigraDocSamples.ashx

Image Opacity in PdfSharp.NET

I'm using PDFSharp.NET library to watermark a list of PDFs file. Everything works fine, the website has a lot of samples.
http://www.pdfsharp.net/wiki/Graphics-sample.ashx
The last thing I need is to add the Company Logo, which is big, in the middle of the PDF Page.
I can use a PNG, so that areas which are set as transparent do not "cover" the PDF page".
The pdf is not generated using PDFSharp, but is an "Image" PDF.
For this reason, what I need, is, in addition to the transparency, which works, be able some how to set the Image Opacity!
The code to place the image is this one:
XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Append);
XImage image = XImage.FromFile(mypath);
gfx.DrawImage(image, pwidth/2-image.PixelWidth/2, pheight/2 image.PixelHeight/2);
gfx.Dispose();
Anyone has already faced with that?
I don't know how to alter the opacity of an image while drawing it using PDFsharp (and I'm afraid this can't be done).
So instead I would just open the logo (PNG) with an image processor and set the opacity there.
I was looking in to this aswell now for making a watermark (companyLogo) to place over pdf sheets. The code below lets you change the opacity.
PDFSharp can not change the image opacity. What you can do is change the image you feed to PDF sharp. This has already been answered so I am just sharing my code of doing so.
private void DrawGraphics()
{
XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Append);
Image myTransparenImage = SetImageOpacity(Image.FromFile("MyPath"), (float)opacityYouwant); // opacityYouWant has to be a value between 0.0 and 1.0
XImage image = XImage.FromBitmapSource(Convert(myTransparenImage));
gfx.DrawImage(image, pwidth / 2 - image.PixelWidth / 2, pheight / 2 image.PixelHeight / 2);
gfx.Dispose();
}
public Image SetImageOpacity(Image image, float opacity)
{
try
{
//create a Bitmap the size of the image provided
Bitmap bmp = new Bitmap(image.Width, image.Height);
//create a graphics object from the image
using (Graphics gfx = Graphics.FromImage(bmp))
{
//create a color matrix object
ColorMatrix matrix = new ColorMatrix();
//set the opacity
matrix.Matrix33 = opacity;
//create image attributes
ImageAttributes attributes = new ImageAttributes();
//set the color(opacity) of the image
attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
//now draw the image
gfx.DrawImage(image, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);
}
return bmp;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
}
public BitmapImage Convert(Image img)
{
using (var memory = new MemoryStream())
{
img.Save(memory, ImageFormat.Png);
memory.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
return bitmapImage;
}
}

How to exactly position an Image inside an existing PDF page using PDFBox?

I am able to insert an Image inside an existing pdf document, but the problem is,
The image is placed at the bottom of the page
The page becomes white with the newly added text showing on it.
I am using following code.
List<PDPage> pages = pdDoc.getDocumentCatalog().getAllPages();
if(pages.size() > 0){
PDJpeg img = new PDJpeg(pdDoc, in);
PDPageContentStream stream = new PDPageContentStream(pdDoc,pages.get(0));
stream.drawImage(img, 60, 60);
stream.close();
}
I want the image on the first page.
PDFBox is a low-level library to work with PDF files. You are responsible for more high-level features. So in this example, you are placing your image at (60, 60) starting from lower-left corner of your document. That is what stream.drawImage(img, 60, 60); does.
If you want to move your image somewhere else, you have to calculate and provide the wanted location (perhaps from dimensions obtained with page.findCropBox(), or manually input your location).
As for the text, PDF document elements are absolutely positioned. There are no low-level capabilities for re-flowing text, floating or something similar. If you write your text on top of your image, it will be written on top of your image.
Finally, for your page becoming white -- you are creating a new content stream and so overwriting the original one for your page. You should be appending to the already available stream.
The relevant line is:
PDPageContentStream stream = new PDPageContentStream( pdDoc, pages.get(0));
What you should do is call it like this:
PDPageContentStream stream = new PDPageContentStream( pdDoc, pages.get(0), true, true);
The first true is whether to append content, and the final true (not critical here) is whether to compress the stream.
Take a look at AddImageToPDF sample available from PDFBox sources.
Try this
doc = PDDocument.load( inputFileName );
PDXObjectImage ximage = null;
ximage = new PDJpeg(doc, new FileInputStream( image )
PDPage page = (PDPage)doc.getDocumentCatalog().getAllPages().get(0);
PDPageContentStream contentStream = new PDPageContentStream(doc, page, true, true);
contentStream.drawImage( ximage, 425, 675 );
contentStream.close();
This prints the image in first page. If u want to print in all pages just put on a for loop with a condition of number of pages as the limit.
This worked for me well!
So late answer but this is for who works on it in 2020 with Kotlin: drawImage() is getting float values inside itself so try this:
val file = File(getPdfFile(FILE_NAME))
val document = PDDocument.load(file)
val page = document.getPage(0)
val contentStream: PDPageContentStream
contentStream = PDPageContentStream(document, page, true, true)
// Define a content stream for adding to the PDF
val bitmap: Bitmap? = ImageSaver(this).setFileName("sign.png").setDirectoryName("signature").load()
val mediaBox: PDRectangle = page.mediaBox
val ximage: PDImageXObject = JPEGFactory.createFromImage(document, bitmap)
contentStream.drawImage(ximage, mediaBox.width - 4 * 65, 26f)
// Make sure that the content stream is closed:
contentStream.close()
// Save the final pdf document to a file
pdfSaveLocation = "$directoryPDF/$UPDATED_FILE_NAME"
val pathSave = pdfSaveLocation
document.save(pathSave)
document.close()
I am creating a new PDF and running below code in a loop - to add one image per page and below co-ordinates and height and width values work well for me.
where out is BufferedImage reference variable
PDPage page = new PDPage();
outputdocument.addPage(page);
PDPageContentStream contentStream = new PDPageContentStream(outputdocument, page, AppendMode.APPEND, true);
PDImageXObject pdImageXObject = JPEGFactory.createFromImage(outputdocument, out);
contentStream.drawImage(pdImageXObject, 5, 2, 600, 750);
contentStream.close();
This link gives you details about Class PrintImageLocations.
This PrintImageLocations will give you the x and y coordinates of the images.
Usage: java org.apache.pdfbox.examples.util.PrintImageLocations input-pdf