How to Get PDF page width and Height? - c#

I have a pdf , and I want to get the width and Height for each page in pdf using iTextSharp?
given this is the pdf I want to work with
string source=#"D:\pdf\test.pdf";
PdfReader reader = new PdfReader(source);

Do you want the MediaBox?
Rectangle mediabox = reader.GetPageSize(page);
Do you want the rotation?
int rotation = reader.GetPageRotation(page);
Do you want the combination of both?
Rectangle pagesize = reader.GetPageSizeWithRotation(page);
Do you want the CropBox?
Rectangle cropbox = reader.GetCropBox(page);
Most of them return an object of type Rectangle that has methods such as getWidth() and getHeight() to get the width and the height of the page.
Other useful methods are getLeft() and getRight() as well as getTop() and getBottom(). These four methods return the x and y coordinates that define the boundaries of your page.
Where did I find most of this documentation?
In chapter 6 of iText in Action.

Related

How to correct obsolete code for creating Canvas

This code using iText7 runs. It copies a PDF file and, on the copy, prints a rectangle on top of page 1 with a red border around a text id or message:
public static void InsertIdPdf(string sourceFilename, string targetFilename, string idText)
{
if (idText.Length > 0)
{
PdfDocument sourcePdf = new PdfDocument(new PdfReader(sourceFilename));
PdfDocument targetPdf = new PdfDocument(new PdfWriter(targetFilename));
sourcePdf.CopyPagesTo(1, sourcePdf.GetNumberOfPages(), targetPdf);
Document document = new Document(targetPdf, new PageSize(PageSize.A4));
PdfPage firstPage = targetPdf.GetFirstPage();
iText.Kernel.Geom.Rectangle pageSize = firstPage.GetCropBox().MoveUp(4);
Canvas canvas = new Canvas(new PdfCanvas(firstPage, true), targetPdf, pageSize);
PdfFont idFont = PdfFontFactory.CreateFont(StandardFonts.HELVETICA);
Style idStyle = new Style()
.SetFont(idFont)
.SetFontSize(8)
.SetPaddingRight(3)
.SetTextAlignment(iText.Layout.Properties.TextAlignment.RIGHT)
.SetBackgroundColor(ColorConstants.WHITE);
Paragraph paragraph = new Paragraph(idText)
.SetBorder(new SolidBorder(ColorConstants.RED, (float)0.7))
.AddStyle(idStyle);
IRenderer renderer = paragraph.CreateRendererSubTree();
renderer.SetParent(document.GetRenderer()).Layout(new LayoutContext(new LayoutArea(1, pageSize)));
canvas.Add(paragraph);
document.Close();
sourcePdf.Close();
targetPdf.Close();
}
}
However, iText7 claims this line to be obsolete because the last argument, the Rectangle, may be removed in a future version:
Canvas canvas = new Canvas(new PdfCanvas(firstPage, true), targetPdf, pageSize);
I've tried to adjust the line, removing pageSize to satisfy iText7, but then the rectangle will print below the normal text on the page and flipped (mirrored) vertically.
So, how to adjust the line to not be obsolete and still print the rectangle at the top?
Also, notice the .MoveUp(4) for pageSize. The value 4 is an empiric value that moves the rectangle to the absolute top of the page. If omitted, the rectangle will be positioned with a small gab to the top of the page. This gab is independent of the font size.
So, why 4? I dislike magic numbers and would prefer a calculated value. What expression could be used to calculate this value?
Reference is the two questions here at SO:
Adding page number text to pdf copy gets flipped/mirrored with iText7
iText7: How to get the real width of a Paragraph
I wasn't able to reproduce this but I am now. I think it was something about the printable area of the document I was trying.
That's aside, the adjustment of the obsolete part is pretty simple. Just change
Canvas canvas = new Canvas(new PdfCanvas(firstPage, true), targetPdf, pageSize);
to
Canvas canvas = new Canvas(new PdfCanvas(firstPage, true), pageSize);
The obsoletion is the pdfDocument parameter.
About the magic number 4. I think it is about the DPI, I really don't know what it is. But the most relevant resource I could find is already in the community: Points -> pixels iText (im)precision

How to scale text within a fixed rectangle with itext7?

I'm trying to make a pdf document with itext7 in c# which should have fixed rectangles containing varying text that should scale within the boundaries of the (invisible) rectangles.
I have tried to find if there's automatic scaling, but so far only found auto-scaling for formfields. Since the pdf will be used for plotting text, formfields are of no use.
Code below is a snippet placing a 'box' with fixed dimensions, where all the text should be shown scaled (on one line)
float fontSize = 22f;
Text lineTxt = new Text("A VERY LONG TEXT SHOULD BE SCALED").SetFont(lineFont).SetFontSize(fontSize);
iText.Kernel.Geom.Rectangle lineTxtRect = new iText.Kernel.Geom.Rectangle(100, posHeight - 200, (float)plotline.producttype_plotmaxwidthpts, (float)plotline.producttype_plotmaxheightpts);
Div lineDiv = new Div();
lineDiv.SetMaxHeight((float)plotline.producttype_plotmaxheightpts);
lineDiv.SetWidth((float)plotline.producttype_plotmaxwidthpts);
lineDiv.SetHeight((float)plotline.producttype_plotmaxheightpts);
lineDiv.SetVerticalAlignment(VerticalAlignment.MIDDLE);
lineDiv.SetBorder(new DashedBorder(1));
Paragraph linePara = new Paragraph().Add(lineTxt).
SetTextAlignment(iText.Layout.Properties.TextAlignment.CENTER).
SetBorder(new DottedBorder(1)).
SetMultipliedLeading(0.7f).
SetMaxHeight((float)plotline.producttype_plotmaxheightpts).
SetHeight((float)plotline.producttype_plotmaxheightpts);
lineDiv.Add(linePara);
new Canvas(PageCanvas, pdf, lineTxtRect).Add(lineDiv).SetBorder(new SolidBorder(1f));
Layout module of iText 7 allows you to simulate rendering of an element (by creating the renderer tree from the element and then using Layout method) and check whether it fits the given area (by checking LayoutResult object). Thus what you can do is check whether the text fits into your fixed rectangle with the given font size. Then you can just do a binary search on the font size.
Here is a sample code:
PdfDocument pdfDocument = new PdfDocument(new PdfWriter(outFileName));
Text lineTxt = new Text("A VERY LONG TEXT SHOULD BE SCALED");
iText.Kernel.Geom.Rectangle lineTxtRect =
new iText.Kernel.Geom.Rectangle(100,200,100,100);
Div lineDiv = new Div();
lineDiv.SetVerticalAlignment(VerticalAlignment.MIDDLE);
lineDiv.SetBorder(new DashedBorder(1));
Paragraph linePara =
new Paragraph()
.Add(lineTxt)
.SetTextAlignment(iText.Layout.Properties.TextAlignment.CENTER)
.SetBorder(new DottedBorder(1))
.SetMultipliedLeading(0.7f);
lineDiv.Add(linePara);
// 1 is the font size that is definitely small enough to draw all the text
float fontSizeL = 1;
// 20 is the maximum value of the font size you want to use
float fontSizeR = 20;
Canvas canvas =
new Canvas(
new PdfCanvas(pdfDocument.AddNewPage()),
pdfDocument,
lineTxtRect);
// Binary search on the font size
while (Math.Abs(fontSizeL - fontSizeR) > 1e-1) {
float curFontSize = (fontSizeL + fontSizeR) / 2;
lineDiv.SetFontSize(curFontSize);
// It is important to set parent for the current element renderer
// to a root renderer.
IRenderer renderer =
lineDiv.CreateRendererSubTree()
.SetParent(canvas.GetRenderer());
LayoutContext context =
new LayoutContext(
new LayoutArea(1, lineTxtRect));
if (renderer.Layout(context).GetStatus() == LayoutResult.FULL) {
// we can fit all the text with curFontSize
fontSizeL = curFontSize;
} else {
fontSizeR = curFontSize;
}
}
// Use the biggest font size that is still small enough to fit all the
// text.
lineDiv.SetFontSize(fontSizeL);
canvas.Add(lineDiv);
pdfDocument.Close();

Merging PDFs with different orientations with iTextSharp

I have two PDF files with different orientations (first document is A4 format and the second A4 landscape).
I want to merge them but I need to preserve the original orientation of each page.
I tried with the rotation with this code:
float width = pdfImportedPage.Width;
float height = pdfImportedPage.Height;
if (width > height)
{
PdfDictionary pageDict = reader.GetPageN(documentPage);
pageDict.Put(PdfName.ROTATE, new PdfNumber(270));
}
After the rotation I call the AddPage method like this:
copy.AddPage(pdfImportedPage);
But the result is an A4 format document with the second part with the text that goes out of the page. For me is good if the text in the second part is horizontal but I need that also the orientation of the page will be as the original document (horizontal).
I'm using iTextSharp version 5.5.13.
I've just discovered that the problem was in another part of the code, after that, when I add the page number.
By the way, a good way to preserve the page orientation is to use the SetPageSize and the NewPage methods, like this piece of code:
for (int page = 1; page <= reader.NumberOfPages; page++)
{
copy.RotateContents = true;
doc.SetPageSize(reader.GetPageSizeWithRotation(page));
doc.NewPage();
importedPage = copy.GetImportedPage(reader, page);
copy.AddPage(importedPage);
}

Barcode i25 using ItextSharp

i am using BarcodeInter25 class to make barcode. I am able to make it but its just blur how can it become more sharp ??
also its background white colour is not completely white
My Code:
BarcodeInter25 code25 = new BarcodeInter25();
Rectangle r = new iTextSharp.text.Rectangle(38, 152);
code25.ChecksumText = false;
code25.Code = "some digits";
code25.BarHeight = 2
System.Drawing.Image i = code25.CreateDrawingImage(System.Drawing.Color.Black, System.Drawing.Color.White);
MemoryStream ms = new MemoryStream();
i.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
Image img = Image.GetInstance(ms.ToArray());
ms.Dispose();
Looking at your code, it should be obvious why the barcode is blurry. You convert it to a System.Drawing.Image (making it a raster image) and then you convert it to an iTextSharp.text.Image (but by then the image is already blurry).
The correct way to achieve what you want, is to create an iTextSharp.text.Image straight from the barcode (do not pass through System.Drawing.Image). This can be done like this:
BarcodeInter25 code25 = new BarcodeInter25();
Rectangle r = new iTextSharp.text.Rectangle(38, 152);
code25.ChecksumText = false;
code25.Code = "some digits";
code25.BarHeight = 2;
PdfContentByte cb = writer.DirectContent;
Image img = code25.CreateImageWithBarcode(cb, null, null);
Now the Image object won't be a raster image (with pixels that make the lines blurry), but it will be a true vector image (no pixels, but instructions such as moveTo(), lineTo() and stroke()). Vector data has the advantage that it is resolution independent: you can zoom in and zoom out as much as you want, it will always be sharp.
This is explained in Chapter 10 of my book where you'll find the Barcodes example. In that chapter, you'll also discover the setFont() (or in iTextSharp the Font property). I quote from the API documentation:
public void setFont(BaseFont font)
Sets the text font.
Parameters:
font - the text font. Set to null to suppress any text
So if you don't want to see any text, you can add the following line to the above code snippet:
code25.Font = null;
You should avoid re-sizing by any means. The output is most likely pixel-perfect but when you scale it up/down a bilinear filter will smooth it rendering it blurry.
I had the same exact problem by embedding a QRC code in a PDF and solved it by avoiding a resize.
If you really need a different size apply it programmatically in code by using the correct interpolation algorithm.

PdfSmartCopy is copying the contents at the bottom (footer) of the new PDF file

I have a function which is cropping the specific part of the pdf file and adding it into the new Pdf file but the main problem that i am getting is that it is showing the cropped part of the page into the bottom (footer) of the newly created pdf file.
Here is the code..
public static void CropPdfFile(string sourceFilePath, string outputFilePath)
{
// Allows PdfReader to read a pdf document without the owner's password
PdfReader.unethicalreading = true;
// Reads the PDF document
using (PdfReader pdfReader = new PdfReader(sourceFilePath))
{
// Set which part of the source document will be copied.
// PdfRectangel(bottom-left-x, bottom-left-y, upper-right-x, upper-right-y)
PdfRectangle rect = new PdfRectangle(0f, 9049.172f, 594.0195f, 700.3f);
using (var output = new FileStream(outputFilePath, FileMode.CreateNew, FileAccess.Write))
{
// Create a new document
using (Document doc = new Document())
{
// Make a copy of the document
PdfSmartCopy smartCopy = new PdfSmartCopy(doc, output);
// Open the newly created document
doc.Open();
// Loop through all pages of the source document
for (int i = 4; i <= pdfReader.NumberOfPages; i++)
{
// Get a page
var page = pdfReader.GetPageN(i);
// Apply the rectangle filter we created
page.Put(PdfName.CROPBOX, rect);
page.Put(PdfName.MEDIABOX, rect);
// Copy the content and insert into the new document
smartCopy.SetLinearPageMode();
var copiedPage = smartCopy.GetImportedPage(pdfReader, i);
smartCopy.AddPage(copiedPage);
}
// Close the output document
doc.Close();
}
}
}
Please help me to solve this..
The size of a PDF page (expressed in user units) depends on the value of the mediabox. For instance: The media box of an A4 page is usually defined like this [0 0 595 842]
In this case, the origin of the coordinate system (0, 0) coincides with the lower-left corner. The coordinate of the upper right corner is (595, 842).
Another possible value for an A4 page would be [0 842 595 1684]. Same width (595 user units), same height (1684 - 842 = 842 user units), but the lower-left corner now has the coordinate (0, 842) and the coordinate of the upper-right corner is (595, 1684).
You write that you create a PdfRectangle using these parameters: (bottom-left-x, bottom-left-y, upper-right-x, upper-right-y). However, you're using these hard-coded values: 0f, 9049.172f, 594.0195f, 700.3f.
Your lower-left-y (9049.172) is at a higher position than your upper-right-y (700.3). This doesn't really make sense. Hence: you should consider changing that value to something that does make sense. What value that should be, is a question only you can answer since only you know the value of the MediaBox of the file you want to crop.
In your comment, you explain that your PDF is an A4 page. You can check this by using the PdfReader method named getPageSize(). If you want to crop the page so that you only see the header of your document, you need to use something like this:
PdfRectangle rect = new PdfRectangle(0f, 842 - x, 595, 842);
Where x is the height of the header. For instance, if the header is 100 user units, then you'd need:
PdfRectangle rect = new PdfRectangle(0f, 742, 595, 842);
It is unclear why you're always talking about 100px. If you want to convert pixels to points, please read Convert Pixels to Points
Using the formula mentioned there 100 pixels equals 75 points.

Categories