I have to combine multiple pages from several files into new one PDF. The page orientation of all the pages must be portrait.
After this work is done, I am using a couple of programs to reset the rotation to zero without really rotate the page.
I want to use itext to remove the rotation value.
Taked from itext examples, I've tried something like this:
protected void manipulatePdf(String dest) throws Exception {
PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(DEST));
int n = pdfDoc.getNumberOfPages();
PdfPage page;
PdfNumber rotate;
for (int p = 1; p <= n; p++) {
page = pdfDoc.getPage(p);
rotate = page.getPdfObject().getAsNumber(PdfName.Rotate);
page.setRotation(0);
pdfDoc.close();
}
}
This:
PdfDictionary diccionario = page.getPdfObject();
diccionario.Remove(iText.Kernel.Pdf.PdfName.Rotate);
And the function CopyPagesTo with the same result: The pages orientation has been altered.
Here there is an example file with 0, 90, 180 y 270 degrees.
The goal is set rotate value of all pages to zero keeping portrait mode:
https://filebin.ca/4vep0uuU1p2s/1.pdf
Any advice would be greatly appreciated.
I have found a solution using the SetIgnorePageRotationForContent function.
VB.NET example:
Dim srcPdf As iText.Kernel.Pdf.PdfDocument = New iText.Kernel.Pdf.PdfDocument(New iText.Kernel.Pdf.PdfReader(srcFile))
Dim destPDF As New iText.Kernel.Pdf.PdfDocument(New iText.Kernel.Pdf.PdfWriter(destFile))
For contador = 1 To srcPdf.GetNumberOfPages
Dim srcPage = srcPdf.GetPage(contador)
Dim rotacion As iText.Kernel.Pdf.PdfNumber = srcPage.GetPdfObject().GetAsNumber(iText.Kernel.Pdf.PdfName.Rotate)
If IsNothing(rotacion) OrElse rotacion.IntValue = 0 Then
srcPdf.CopyPagesTo(contador, contador, destPDF)
Continue For
End If
Dim destPage As iText.Kernel.Pdf.PdfPage = destPDF.AddNewPage(New iText.Kernel.Geom.PageSize(srcPage.GetPageSizeWithRotation))
If rotacion.IntValue = 180 Then
destPage.GetPdfObject().Put(iText.Kernel.Pdf.PdfName.Rotate, New iText.Kernel.Pdf.PdfNumber(180))
Else
destPage.GetPdfObject().Put(iText.Kernel.Pdf.PdfName.Rotate, New iText.Kernel.Pdf.PdfNumber(rotacion.IntValue + 180))
End If
destPage.SetIgnorePageRotationForContent(True)
Dim canvas As New iText.Kernel.Pdf.Canvas.PdfCanvas(destPage)
Dim pageCopy As iText.Kernel.Pdf.Xobject.PdfFormXObject = srcPage.CopyAsFormXObject(destPDF)
canvas.AddXObject(pageCopy, 0, 0)
destPage.GetPdfObject().Remove(iText.Kernel.Pdf.PdfName.Rotate)
Next
destPDF.Close()
srcPdf.Close()
Related
I have masked an existing pdf document with images, as described into this question: iText7 Image Transparency
My issue is that somebody using Acrobat Reader DC Pro can still edit the document and remove the images, making the masking ineffective.
I have been thinking of flattening the pdDocument, but it seems the API applies to form, and not to the entire document.
I have tried the code below, but it is still possible to edit the pdf and remove the masking images.
Do you have any advice for this?
// Read the pdf input
PdfReader pdfReader = new PdfReader(value);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PdfWriter pdfWriter = new PdfWriter(outputStream);
PdfDocument pdfDoc = new PdfDocument(pdfReader, pdfWriter);
Document document = new Document(pdfDoc);
// Creating an ImageData object
ImageData data = ImageDataFactory.create(fileName);
for (int x = 1; x < 800; ) {
for (int y = 1; y < 1000; ) {
Image image = new Image(data);
image.setFixedPosition(x , y);
document.add(image);
y = y + y1 + 40;
}
x = x + x1 + 40;
}
PdfAcroForm.getAcroForm(pdfDoc, true).flattenFields();
// The content has now been modified, return it as a stream
document.close();
I expect: the image cannot be removed, or the document cannot be edited
I am unable to put stamp using itext7 using Java language on only skia generated pdf (skia is pdf library used by google; if someone has worked on google docs-> Clicks on Print -> Save as Pdf ). It Stamps incorrectly; if I stamp at top left position of pdf page then it would stamp at bottom left and show (inverted mirror) image and (inverted mirror) text. For all other pdfs it gives correct stamping.
It seems pdf generated by skia has missing meta -data.
Since you didn't share any code, nor any document, I created a PDF document from Google docs, and I used the code I wrote in answer to the Itextsharp 7 - Scaled and Centered Image as watermark question to add a Watermark in the center.
The result looked like this:
As you can see in the Document Properties, the original document was created using Skia/PDF m67; modified using iText® 7.1.3.
You need a Watermark in the top left, so I adapted the code like this:
public void createPdf(String src, String dest) throws IOException {
PdfDocument pdfDoc = new PdfDocument(
new PdfReader(src), new PdfWriter(dest));
Document document = new Document(pdfDoc);
PdfCanvas over;
PdfExtGState gs1 = new PdfExtGState();
gs1.setFillOpacity(0.5f);
int n = pdfDoc.getNumberOfPages();
Rectangle pagesize;
ImageData img = ImageDataFactory.create(IMG);
float iW = img.getWidth();
float iH = img.getHeight();
float x, y;
for (int i = 1; i <= n; i++)
{
PdfPage pdfPage = pdfDoc.getPage(i);
pagesize = pdfPage.getPageSize();
x = pagesize.getLeft();
y = pagesize.getTop() - iH;
over = new PdfCanvas(pdfDoc.getPage(i));
over.saveState();
over.setExtGState(gs1);
over.addImage(img, iW, 0, 0, iH, x, y);
over.restoreState();
}
document.close();
pdfDoc.close();
}
The result looks like this:
The image isn't mirrored; it's at the top-left position of the page. In short: there doesn't seem to be any problem with PDF's created with Skia/PDF m67.
I'm trying to implement a invisible watermarking function using itext 7 in java. So far I've managed to implement the embedding of watermark to all pages using the following code:
PdfDocument pdfdoc = new PdfDocument(new PdfReader(source),new PdfWriter(dest));
Document doc = new Document(pdfdoc);
PdfCanvas canvas;
Rectangle pagesize;
PdfExtGState qrcode = new PdfExtGState();
qrcode.setFillOpacity(0); // sets opacity of watermark.
byte[] bytearray = convertBI(watermark);
ImageData imgd = ImageDataFactory.create(bytearray);
float w = imgd.getWidth() , h = imgd.getHeight();
float x,y;
for(int i = 1;i<=pdfdoc.getNumberOfPages();i++)
{
PdfPage page = pdfdoc.getPage(i);
pagesize = page.getPageSizeWithRotation();
page.setIgnorePageRotationForContent(true);
x = (pagesize.getLeft() + pagesize.getRight())/ 2;
y = (pagesize.getTop() + pagesize.getBottom())/ 2;
canvas = new PdfCanvas(pdfdoc.getPage(i));
canvas.saveState();
canvas.setExtGState(qrcode);
canvas.addImage(imgd,w,0,0,h,x-(w/2),y-(h/2),true);
canvas.restoreState();
}
doc.close();
However I'm having troubles retrieving the watermark. So far I've tried redrawing the page on another canvas and setting the fill opacity but to no avail. The only way I've managed to make the watermark visible through the use of itext-rups and manually changing the value of the extGS as seen here
Would anyone be able to advise me on whether it is possible to change the value of the extGState dictionary from code or any alternative methods to achieving the same result?
Update: So I've tried to access the dictionary in code but it just return nulls.
PdfDocument pdfdoc = new PdfDocument(new PdfReader(source),new PdfWriter(dest));
Document doc = new Document(pdfdoc);
for(int pageNo = 1; pageNo<= pdfdoc.getNumberOfPages();pageNo++)
{
PdfPage pdfpage = pdfdoc.getPage(pageNo);
PdfResources rsrc = pdfpage.getResources();
PdfDictionary pExtGSD = rsrc.getResource(PdfName.ExtGState);
if(!pExtGSD.isEmpty())
{
System.out.println(pExtGSD.getAsFloat(new PdfName("/Gs1")));
}
}
doc.close();
I am generating barcodes using iText API, everything looks good when it is linear barcodes when it is 2D barcodes then barcodes are placed into pdf document as images, hence reducing the quality of the barcode on low resolution printers and unable to scan the barcode. Below is the code
BarcodePDF417 pdf417 = new BarcodePDF417();
String text = "BarcodePDF417 barcode";
pdf417.setText(text);
Image img = pdf417.getImage();
document.add(img);
Now i am look for an alternative to draw barcode and i found palceBarcode method which might favor to the requirement.
I have seen the below code in BarcodePDF417 class in itext source and could not able to find out the way how to use it
public void placeBarcode(PdfContentByte cb, BaseColor foreground, float moduleHeight, float moduleWidth) {
paintCode();
int stride = (bitColumns + 7) / 8;
cb.setColorFill(foreground);
for (int k = 0; k < codeRows; ++k) {
int p = k * stride;
for (int j = 0; j < bitColumns; ++j) {
int b = outBits[p + j / 8] & 0xff;
b <<= j % 8;
if ((b & 0x80) != 0) {
cb.rectangle(j * moduleWidth, (codeRows - k - 1) * moduleHeight, moduleWidth, moduleHeight);
}
}
}
cb.fill();
}
Can anyone suggest the way to use the above method?
I have written code like below but getting dark page as a whole.
Rectangle pageSize = new Rectangle(w * 72, h * 72);
Document doc = new Document(pageSize, 1f, 1f, 1f, 1f);
PdfWriter writer = PdfWriter.getInstance(doc, getOutputStream());
doc.open();
PdfContentByte cb = writer.getDirectContent();
BarcodePDF417 pf = new BarcodePDF417();
pf.setText("BarcodePDF417 barcode");
pf.getImage();
Rectangle rc = pf.getBarcodeSize();
pf.placeBarcode(cb, BaseColor.BLACK, rc.getHeight(), rc.getWidth());
doc.close();
Please take a look at the BarcodePlacement example. In this example, we create three PDF417 barcodes:
PdfContentByte cb = writer.getDirectContent();
Image img = createBarcode(cb, "This is a 2D barcode", 1, 1);
document.add(new Paragraph(
String.format("This barcode measures %s by %s user units",
img.getScaledWidth(), img.getScaledHeight())));
document.add(img);
img = createBarcode(cb, "This is NOT a raster image", 3, 3);
document.add(new Paragraph(
String.format("This barcode measures %s by %s user units",
img.getScaledWidth(), img.getScaledHeight())));
document.add(img);
img = createBarcode(cb, "This is vector data drawn on a PDF page", 1, 3);
document.add(new Paragraph(
String.format("This barcode measures %s by %s user units",
img.getScaledWidth(), img.getScaledHeight())));
The result looks like this on the outside:
One particular barcode looks like this on the inside:
I'm adding this inside view to show that the 2D barcode is not added as a raster image (as was the case with the initial approach you've tried). It is a vector image consisting of a series of small rectangles. You can check this for yourself by taking a look at the barcode_placement.pdf file.
Please don't be confused because I use an Image object. If you look at the createBarcode() method, you can see that the Image is, in fact, a vector image:
public Image createBarcode(PdfContentByte cb, String text,
float mh, float mw) throws BadElementException {
BarcodePDF417 pf = new BarcodePDF417();
pf.setText("BarcodePDF417 barcode");
Rectangle size = pf.getBarcodeSize();
PdfTemplate template = cb.createTemplate(
mw * size.getWidth(), mh * size.getHeight());
pf.placeBarcode(template, BaseColor.BLACK, mh, mw);
return Image.getInstance(template);
}
The height and the width passed to the placeBarcode() method, define the height and the width of the small rectangles that are drawn. If you look at the inside view, you can see for instance:
0 21 3 1 re
This is a rectangle with x = 0, y = 21, width 3 and height 1.
When you ask the barcode for its size, you get the number of rectangles that will be drawn. Hence the dimensions of the barcode is:
Rectangle size = pf.getBarcodeSize();
float width = mw * size.getWidth();
float height = mh * size.getHeight();
Your assumption that size is a size in user units is only correct if mw and mh are equal to 1.
I use these values to create a PdfTemplate instance and I draw the barcode to this Form XObject. Most of the times, it's easier to work with the Image class than working with PdfTemplate, so I wrap the PdfTemplate inside an Image.
I can then add this Image to the document just like any other image. The main difference with ordinary images, is that this image is a vector image.
I am trying to add a header to existing pdf documents in Java with iText. I can add the header at a fixed place on the document, but all the documents are different page sizes, so it is not always at the top of the page. I have tried getting the page size so that I could calculate the position of the header, but it seems as if the page size is not actually what I want. On some documents, calling reader.getPageSize(i).getTop(20) will place the text in the right place at the top of the page, however, on some different documents it will place it half way down the page. Most of the pages have been scanned be a Xerox copier, if that makes a difference. Here is the code I am using:
PdfReader reader = new PdfReader(readFilePath);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(writeFilePath));
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
PdfContentByte cb = stamper.getOverContent(i);
cb.beginText();
cb.setFontAndSize(bf, 14);
float x = reader.getPageSize(i).getWidth() / 2;
float y = reader.getPageSize(i).getTop(20);
cb.showTextAligned(PdfContentByte.ALIGN_CENTER, "Copy", x, y, 0);
cb.endText();
}
stamper.close();
PDF that works correctly
PDF that works incorrectly
Take a look at the StampHeader1 example. I adapted your code, introducing ColumnText.showTextAligned() and using a Phrase for the sake of simplicity (maybe you can change that part of your code too):
public void manipulatePdf(String src, String dest) throws IOException, DocumentException {
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
Phrase header = new Phrase("Copy", new Font(FontFamily.HELVETICA, 14));
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
float x = reader.getPageSize(i).getWidth() / 2;
float y = reader.getPageSize(i).getTop(20);
ColumnText.showTextAligned(
stamper.getOverContent(i), Element.ALIGN_CENTER,
header, x, y, 0);
}
stamper.close();
reader.close();
}
As you have found out, this code assumes that no rotation was defined.
Now take a look at the StampHeader2 example. I'm using your "Wrong" file and I've added one extra line:
stamper.setRotateContents(false);
By telling the stamper not to rotate the content I'm adding, I'm adding the content using the coordinates as if the page isn't rotated. Please take a look at the result: stamped_header2.pdf. We added "Copy" at the top of the page, but as the page is rotated, we see the word appear on the side. The word is rotated because the page is rotated.
Maybe that's what you want, maybe it isn't. If it isn't, please take a look at StampHeader3 in which I calculate x and y differently, based on the rotation of the page:
if (reader.getPageRotation(i) % 180 == 0) {
x = reader.getPageSize(i).getWidth() / 2;
y = reader.getPageSize(i).getTop(20);
}
else {
x = reader.getPageSize(i).getHeight() / 2;
y = reader.getPageSize(i).getRight(20);
}
Now the word "Copy" appears on what is perceived as the "top of the page" (but in reality, it could be the side of the page): stamped_header3.pdf