Building a document generation system for our web app and am branding the document as required. The document is designed in powerpoint and printed to via NitroPdf. The first page is a large image essentially, with a white area in the image.
I am attempting to place the branding logo in the whitespace allocated. Positioning is ok, however, my branding image is appearing behind the PDF'd document full page image.
Having googled, i can't seem to find a 'z-index' type function... would have thought i wouldn't be the only one with the issue?
Section of code adding the image is as follows:
image.ScaleToFit(width, height);
image.SetDpi(300, 300);
// Position the logo.
image.SetAbsolutePosition(fromLeft, fromBottom);
// Add the image.
document.Add(image);
It is very strange that you would need the following line to add an image to an existing PDF:
document.Add(image);
It's as if you're using PdfWriter instead of PdfStamper, which would be very strange.
Perhaps you overlooked the documentation or maybe you didn't search StackOverflow before you started writing your code: How can I insert an image with iTextSharp in an existing PDF?
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
class Program
{
static void Main(string[] args)
{
using (Stream inputPdfStream = new FileStream("input.pdf", FileMode.Open, FileAccess.Read, FileShare.Read))
using (Stream inputImageStream = new FileStream("some_image.jpg", FileMode.Open, FileAccess.Read, FileShare.Read))
using (Stream outputPdfStream = new FileStream("result.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
var reader = new PdfReader(inputPdfStream);
var stamper = new PdfStamper(reader, outputPdfStream);
var pdfContentByte = stamper.GetOverContent(1);
Image image = Image.GetInstance(inputImageStream);
image.SetAbsolutePosition(100, 100);
pdfContentByte.AddImage(image);
stamper.Close();
}
}
}
You may have found examples where GetUnderContent() is used. This adds content under the existing content. If you want the content to cover the existing content, you need GetOverContent() as is shown in the code sample.
Maybe it's a bit late, but I've faced with the same issue and I've solved with a workaround with Paragraphs (hereunder the code in Visual Basic):
Public Class PDF
Public Doc As Document
Public Writer As PdfWriter
Public Cb As PdfContentByte
Public Sub setFrontImage(ByVal _appendImg As String, align As Integer, x As Integer, y As Integer, ByVal w As Integer, h As Integer, _leading As Integer)
Dim ct As New ColumnText(Cb)
Dim ph As Phrase
Dim ch As Chunk
Dim p As Paragraph = new Paragraph()
Dim image As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(_appendImg)
image.ScaleAbsolute(w, h)
p.Add(new Chunk(image,x,y))
ct.SetSimpleColumn(p,x, y, w, h, _leading, align)
ct.Go()
End Sub
End Class
I saw you used the absolute position to put your logo up your image so am I, consider to modify the usage of Chunk with width and height if you don't need to fit it inside a restricted space.
Related
Consider a 1-page PDF document named in.pdf that looks like this:
We execute the following code in C#:
using (var reader = new PdfReader(#"C:\<path>\in.pdf"))
using (var writer = new PdfWriter(#"C:\<path>\out.pdf"))
using (var pdfDoc = new PdfDocument(reader, writer))
{
var page = pdfDoc.GetFirstPage();
var pdfCanvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc);
using (var canvas = new Canvas(pdfCanvas, new Rectangle(400, 300)))
{
canvas.Add(new Paragraph("new text\r\nnew text")
.SetFontColor(new DeviceRgb(255, 0, 0))
.SetFontSize(50));
}
pdfCanvas.Release();
}
We get new text appearing under the original text, as expected:
Now we execute the same code with one change - we create PdfCanvas as follows:
var pdfCanvas = new PdfCanvas(page);
Result is still as expected - new text is above the original text:
Finally, we execute the same code with PdfCanvas created as follows:
var pdfCanvas = new PdfCanvas(page.NewContentStreamAfter(), page.GetResources(), pdfDoc);
New text is above the original text as expected, but it's flipped!
Is this a bug? Getting the same flipped output creating PdfCanvas like this:
var pdfCanvas = new PdfCanvas(page.GetFirstContentStream(), page.GetResources(), pdfDoc);
//OR
var pdfCanvas = new PdfCanvas(page.GetLastContentStream(), page.GetResources(), pdfDoc);
Using nuget package itext7 v7.1.15.
Is this a bug?
No. It's matching your code and a feature of the PdfCanvas(PdfPage page) constructor.
Each PDF content stream contains a sequence of instructions that change the current graphics state and/or draw something. If the original creator of the respective content stream did not take care to clean up the graphics state, instructions you add to it or to a following content stream of the same page are subject to those graphics state changes.
In your case the original page content stream apparently at the end has a graphics state with the current transformation matrix set to a reflection. Depending on how you add your new content, your additions also are subject to that reflection transformation:
var pdfCanvas = new PdfCanvas(page.NewContentStreamBefore(), page.GetResources(), pdfDoc);
Here you add a new content stream before all existing content streams. Thus, your additions to pdfCanvas are not subject to any graphics state changes and you get upright text.
var pdfCanvas = new PdfCanvas(page);
The constructor you use here, PdfCanvas(PdfPage page), calls another constructor, PdfCanvas(PdfPage page, bool wrapOldContent), which for wrapOldContent == true wraps the existing content in an envelope of a save-graphics-state / restore-graphics-state instruction pair, to restore the original graphics state after the existing content. PdfCanvas(PdfPage page) uses a true value for wrapOldContent under certain conditions, in particular if you are manipulating an existing PDF and the page in question already has a non-empty content stream.
In your case, therefore, the original content is wrapped in such an envelope and the graphics state is restored thereafter. So your additions are not subject to any graphics state changes and you get upright text.
var pdfCanvas = new PdfCanvas(page.NewContentStreamAfter(), page.GetResources(), pdfDoc);
var pdfCanvas = new PdfCanvas(page.GetFirstContentStream(), page.GetResources(), pdfDoc);
var pdfCanvas = new PdfCanvas(page.GetLastContentStream(), page.GetResources(), pdfDoc);
The PdfCanvas constructors you use here do not add any such envelope. Thus, your additions are subject to graphics state changes in the original content and you get mirrored text.
I'm trying to scale the first page of a PDF using iText7 for .NET. The rest of the pages should remain untouched.
The method below works if the PDF contains one page, but if there's multiple pages, the first (supposed to be scaled) page is blank, while the remaining pages is added correctly.
What am I missing here?
public byte[] ScaleFirstPagePdf(byte[] pdf)
{
using (var inputStream = new MemoryStream(pdf))
using (var outputStream = new MemoryStream(pdf))
using (var srcPdf = new PdfDocument(new PdfReader(inputStream)))
using (var destPdf = new PdfDocument(new PdfWriter(outputStream)))
{
for (int pageNum = 1; pageNum <= srcPdf.GetNumberOfPages(); pageNum++)
{
var srcPage = srcPdf.GetPage(pageNum);
var srcPageSize = srcPage.GetPageSizeWithRotation();
if (pageNum == 1)
{
var destPage = destPdf.AddNewPage(new PageSize(srcPageSize));
var canvas = new PdfCanvas(destPage);
var transformMatrix = AffineTransform.GetScaleInstance(0.5f, 0.5f);
canvas.ConcatMatrix(transformMatrix);
var pageCopy = srcPage.CopyAsFormXObject(destPdf);
canvas.AddXObject(pageCopy, 0, 0);
}
else
{
destPdf.AddPage(srcPage.CopyTo(destPdf));
}
}
destPdf.Close();
srcPdf.Close();
return outputStream.ToArray();
}
}
I couldn't reproduce the blank page issue with this code, but definitely the files that are generated in this way can be problematic.
The issue is that you are sharing a byte buffer between two memory streams - one used for reading and another one for writing, simultaneously.
Simply using another buffer or relying on the default MemoryStream implementation solved the issue for me, and should do so for you as well because there doesn't seem to be anything suspicious about your code apart from the problem I mentioned.
Here is how you should create the output stream:
using (var inputStream = new MemoryStream(pdf))
using (var outputStream = new MemoryStream())
If you still experience issues even after this tweak then the problem is definitely file-specific and I doubt you could get any help without sharing the file.
This question already has an answer here:
Why font is not being embedded to the PDF using content stream before in Itext7?
(1 answer)
Closed 4 years ago.
I have an existing PDF that doesn't contain any fonts (image only). I want to stamp some additional text onto the first page using low level canvas operations. When I do this in iText 7, the resulting PDF is missing the Fonts resource dictionary entry (which results in an NPE when parsing the resulting file).
Do I have to do something besides canvas.setFontAndSize() to get the font resource to get added to the output?
Here's a unit test that recreates the issue:
public class CheckFontResourceInclusion {
#Test
public void test() throws Exception {
// create a document to stamp
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try(PdfDocument doc = new PdfDocument(new PdfWriter(baos))){
doc.addNewPage();
}
// stamp it
StampingProperties stampProps = new StampingProperties();
PdfFont font = PdfFontFactory.createFont();
ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
try(PdfDocument doc = new PdfDocument(new PdfReader(new ByteArrayInputStream(baos.toByteArray())), new PdfWriter(resultStream), stampProps)){
PdfPage page = doc.getPage(1);
PdfCanvas canvas = new PdfCanvas(page.newContentStreamAfter(), new PdfResources(), doc);
canvas.beginText();
canvas.setTextRenderingMode(2);
canvas.setFontAndSize(font, 42);
canvas.setTextMatrix(1, 0, 0, -1, 100, 100);
canvas.showText("TEXT TO STAMP");
canvas.endText();
}
// parse text
try(PdfDocument doc = new PdfDocument(new PdfReader(new ByteArrayInputStream(resultStream.toByteArray())))){
LocationTextExtractionStrategy strat = new LocationTextExtractionStrategy();
PdfCanvasProcessor processor = new PdfCanvasProcessor(strat);
processor.processPageContent(doc.getPage(1));
Assert.assertEquals("TEXT TO STAMP", strat.getResultantText());
}
}
}
Here's the resulting failure:
java.lang.NullPointerException
at com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor$SetTextFontOperator.invoke(PdfCanvasProcessor.java:811)
at com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor.invokeOperator(PdfCanvasProcessor.java:456)
at com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor.processContent(PdfCanvasProcessor.java:285)
at com.itextpdf.kernel.pdf.canvas.parser.PdfCanvasProcessor.processPageContent(PdfCanvasProcessor.java:306)
at
The error is the same as in this earlier question: You use a throw-away resources object, so the font resource is missing in the result.
You can fix this by using the actual page resources. Simply replace
PdfCanvas canvas = new PdfCanvas(page.newContentStreamAfter(), new PdfResources(), doc);
by
PdfCanvas canvas = new PdfCanvas(page.newContentStreamAfter(), page.getResources(), doc);
I'm new to working with PdfBox and I'm having a small issue when displaying images. I'm able to import the image, which is sized at 800*900 pixels, and looks fine when viewed in an existing pdf at 100%. However when the resulting PDF is generated using the below code, the image becomes blurry, and the image extends beyond the boundaries of the A4 page.
Is there a different way of sizing/saving images so that they display correctly in pdfbox?
public class PDFtest {
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws IOException, COSVisitorException {
// TODO code application logic here
// Create a document and add a page to it
PDDocument document = new PDDocument();
PDPage page = new PDPage(PDPage.PAGE_SIZE_A4);
document.addPage(page);
// Create a new font object selecting one of the PDF base fonts
PDFont font = PDType1Font.HELVETICA_BOLD;
InputStream in = new FileInputStream(new File("img.jpg"));
PDJpeg img = new PDJpeg(document, in);
// Start a new content stream which will "hold" the to be created content
PDPageContentStream contentStream = new PDPageContentStream(document, page);
// Define a text content stream using the selected font, moving the cursor and drawing the text "Hello World"
contentStream.drawImage(img, 10, 700);
contentStream.beginText();
contentStream.setFont(font, 12);
contentStream.moveTextPositionByAmount(10, 650);
contentStream.drawString("Hello World");
contentStream.endText();
// Make sure that the content stream is closed:
contentStream.close();
// Save the results and ensure that the document is properly closed:
document.save("Hello World.pdf");
document.close();
}
I'd like to point out that as of 2.0 the contentStream.drawXObject function call in Victor's answer is deprecated. If you want to specify a width and height you should use contentStream.drawImage(image, x, y, width, height)
I had the same problem asked in this question, but the given answer is not right.
After some research I found a solution.
Instead of using the function drawImage use the function drawXObject
contentStream.drawXObject( img, 10, 700, 100, 100 );
Where the last two numbers specify the size of the image to be drawn.
For similar situation, for me, with PDF 2.0.11 and a tiff file of dimensions - 1600 x 2100 the following code perfectly fit the image in A4 (portrait) size. Not sure if PDFRectangle is okay with you.
I got this example straight from PDFBOX - Example
The only thing I tweaked/introduced is:
PDRectangle.A4.getWidth(), PDRectangle.A4.getHeight()
Here is the full sample:
public static void main(String[] args) throws IOException
{
// if (args.length != 2)
// {
// System.err.println("usage: " + ImageToPDF.class.getName() + " <image> <output-file>");
// System.exit(1);
// }
String imagePath = "C:/FAX/sample.tiff";
String pdfPath = "C:/FAX/sample.pdf";
if (!pdfPath.endsWith(".pdf"))
{
System.err.println("Last argument must be the destination .pdf file");
System.exit(1);
}
try (PDDocument doc = new PDDocument())
{
PDPage page = new PDPage();
doc.addPage(page);
// createFromFile is the easiest way with an image file
// if you already have the image in a BufferedImage,
// call LosslessFactory.createFromImage() instead
PDImageXObject pdImage = PDImageXObject.createFromFile(imagePath, doc);
// draw the image at full size at (x=20, y=20)
try (PDPageContentStream contents = new PDPageContentStream(doc, page))
{
// draw the image at full size at (x=20, y=20)
contents.drawImage(pdImage, 0, 0, PDRectangle.A4.getWidth(), PDRectangle.A4.getHeight());
// to draw the image at half size at (x=20, y=20) use
// contents.drawImage(pdImage, 20, 20, pdImage.getWidth() / 2, pdImage.getHeight() / 2);
}
doc.save(pdfPath);
System.out.println("Tiff converted to PDF succussfully..!");
}
}
Hope it helps.
If your intention is an A4 sized pic on a PDF, then i guess you find the actual size of typical A4 in pixels.
Also you should be aware of the extension of the picture that you want to view like jpg, gif, or bmp ...
from what I saw in your code, the dimensions of the picture are 10 X 700 which I believe is pretty small size.
contentStream.drawImage(img, 10, 700);
And the extension of the picture is : jpg
InputStream in = new FileInputStream(new File("img.jpg"));
check those and return for more info.
that's all.
good luck'''
As per the new API 2.0.x, one can use the PDRectangle to fetch Pdf page width and height. One can use PDPageContentStream to draw the image in accordance with PDF page.
For reference:
try (PDPageContentStream contents = new PDPageContentStream(pdDocument, pdPage)) {
final PDRectangle mediaBox = pdPage.getMediaBox();
final PDImageXObject pdImage = PDImageXObject.createFromFile(image, pdDocument);
contents.drawImage(pdImage, 0, 0, mediaBox.getWidth(), mediaBox.getHeight());
}
I want to save a image to file and the documentation mentions ImageExportFormat method: Chart1.getExport().getImage().getJPEG().save(javax.imageio.stream.ImageOutputStream ios)
Doco: http://www.steema.com/files/public/teechart/java/v1/docs/JavaDoc/com/steema/teechart/exports/ImageExportFormat.html
This method is not recognised by my code. Has this been removed ? Is there an alternate way I can do this via a stream?
Regards, Clayton
The example below shows how to export to a jpeg file in Swing. A stream could be used natively instead of using ‘File’.
public void save() throws IOException {
Image img = chart1.image(chart1.getWidth(), chart1.getHeight());
RenderedImage rendImage = (RenderedImage) img;
Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
File outfile = new File("c:\\output\\testjavaChart.jpg");
ImageOutputStream ios = ImageIO.createImageOutputStream(outfile);
ImageWriter writer = (ImageWriter) iter.next();
ImageWriteParam format = new javax.imageio.plugins.jpeg.JPEGImageWriteParam(java.util.Locale.getDefault());
writer.setOutput(ios);
// Write the image
writer.write(null, new IIOImage(rendImage, null, null), format);
// Cleanup
ios.flush();
ios.close();
writer.dispose();
}
If you are using SWT, don't hesitate to let us know.