How to know if text exceeds the fill box in itextSharp - c#

I am using the following code:
PdfReader PDFReader = new PdfReader("c:\\file.pdf");
FileStream Stream = new FileStream("c:\\new.pdf", FileMode.Create, FileAccess.Write);
PdfStamper PDFStamper = new PdfStamper(PDFReader, Stream);
for (int iCount = 0; iCount < PDFStamper.Reader.NumberOfPages; iCount++)
{
iTextSharp.text.Rectangle PageSize = PDFReader.GetCropBox(iCount + 1);
PdfContentByte PDFData = PDFStamper.GetOverContent(iCount + 1);
BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED);
PDFData.BeginText();
PDFData.SetColorFill(CMYKColor.RED);
PDFData.SetFontAndSize(baseFont, 20);
PDFData.ShowTextAligned(PdfContentByte.ALIGN, SAMPLE DOCUMENT", (PageSize.Right + PageSize.Left) / 2, (PageSize.Top + PageSize.Bottom) / 2, 45);
PDFData.EndText();
}
PDFStamper.Close();
PDFReader.Close();
But sometimes the overlaid text exceeds the page size because I have hard coded the font as 20. So, is there any way to know if the overlaid text will exceed the page size? Because I want to use code like I will then use:
if(pagesize exceeds)
reduce font size by 1 point and check again .....
If the above doesn't work, then my next step is to use a PNG image that has the overlaid text in it and its background as transparent. then resize the image according to the pagesize and then overlay it.
however, I will prefer the first part. if not, then I will go for the second option.

After doing some minor calculations, this method should calculate the maximum font size to use for such a vertical text and apply it:
void Stamp(PdfContentByte cb, Rectangle rect, BaseFont bf, string text)
{
int altitude = Math.Max(bf.GetAscent(text), bf.GetDescent(text));
int width = bf.GetWidth(text);
double horizontalFit = Math.Sqrt(2.0) * 1000 * (rect.Left + rect.Right) / (width + 2 * altitude);
double verticalFit = Math.Sqrt(2.0) * 1000 * (rect.Bottom + rect.Top) / (width + 2 * altitude);
double fit = Math.Min(horizontalFit, verticalFit);
cb.BeginText();
cb.SetColorFill(CMYKColor.RED);
cb.SetFontAndSize(bf, (float) fit);
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, text, (rect.Right + rect.Left) / 2, (rect.Top + rect.Bottom) / 2, 45);
cb.EndText();
}
You can call it like this:
using (PdfReader reader = new PdfReader(source))
using (PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create, FileAccess.Write)))
{
for (int iCount = 0; iCount < reader.NumberOfPages; iCount++)
{
Rectangle PageSize = reader.GetCropBox(iCount + 1);
PdfContentByte PDFData = stamper.GetOverContent(iCount + 1);
BaseFont baseFont = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED);
Stamp(PDFData, PageSize, baseFont, "SAMPLE DOCUMENT");
}
}
(By the way, I used your BaseFont but you should be aware that iText(Sharp) will ignore BaseFont.EMBEDDED for standard 14 fonts like BaseFont.HELVETICA.)
The result looks like this:
PS: If you (as expressed in your question) really don't want to use a font size above 20, you have to Min the fit value again with 20.

Related

Getting past the 200 inch adobe error with iTextSharp

I am converting a multi-paged (paginated) pdf document into a single page (non-paginated) pdf document.
I am looking to overcome the 200 inch limitation in adobe reader.
With iTextSharp.PdfReader each page is read to create a total height of the target document and find the maximum width.
The code to create the document works ok reading directly from the paginated pdf into the non-paginated pdf. Utilizing Chrome or Foxit the file opens fine. Adobe gives the 200 inch truncation when the page exceeds 200 inchs. In my test file the page height is 8.25 x 814 inches.
Changing the UserUnits to 4.07 (814/200) has Adobe show the page height as 814in but still truncates the page as well as showing the width as 33.
If the width of the target file is set to width/userunits (8.25/4.07) the only left 2 inches are shown in the target file.
The copy part of the code:
RandomAccessFileOrArray ra = new RandomAccessFileOrArray(fn);
SizeF pageSize = new SizeF(pageWidth, pageHeight);
float USERUnitNewValue = ComputeUserUnit(pageSize);
if (pageHeight > 14400f)
{
USERUnitNewValue = pageHeight / 14400f;
}
float NewPageWidth = (pageWidth <= 14400f) ? pageWidth : pageWidth* USERUnitNewValue;
float NewPageHeight = pageHeight * USERUnitNewValue;
FileInfo file1 = new FileInfo(newfn);
DirectoryInfo directory1 = file1.Directory;
if (!directory1.Exists)
directory1.Create();
iTextSharp.text.Rectangle newPagesize = new iTextSharp.text.Rectangle(pageWidth, pageHeight);
Document newPdf = new Document(newPagesize);
PdfWriter writer = PdfWriter.GetInstance(newPdf, new FileStream(newfn, FileMode.Create));
writer.PdfVersion = PdfWriter.VERSION_1_6;
if (pageHeight > 14400)
{
writer.Userunit = USERUnitNewValue;
}
newPdf.SetMargins(0f, 0f, 0f, 0f);
newPdf.Open();
PdfContentByte cb = writer.DirectContent;
float verticalPosition = pageHeight;
for (int pagenumber = 1; pagenumber <= n1; pagenumber++)
{
if (pdfReader.NumberOfPages >= pagenumber)
{
verticalPosition = verticalPosition - pdfReader.GetPageSize(pagenumber).Height;
cb.AddTemplate(writer.GetImportedPage(pdfReader, pagenumber), 0, verticalPosition);
}
else
{
break;
}
}
newPdf.Close();
How can the original file be copied into the target where both files would keep the same size if someone sends it to a printer?
Yes there is some redundancy in this code as I have been troubleshooting this for a little while now.
The key question here is a setting that would maintain the 8.25 x 814in and still allow adobe to open the file.
Thanks,
Mike
Thank you David.
After looking through Mr Lowagie's document and brief note about addTemplate.
cb.addTemplate(page, scale, 0, 0, scale, 0, 0)
The code was updated to utilize the new userunit and scaling.
Opening ok in Adobe now and reporting page length as expected
Once again the code is a little ugly still
RandomAccessFileOrArray ra = new RandomAccessFileOrArray(fn);
SizeF pageSize = GetPageSize(fn);
PdfReader pdfReader = new PdfReader(fn);
float USERUnitNewValue = ComputeUserUnit(pageSize);
int n1 = pdfReader.NumberOfPages;
if (pageSize.Height > 14400f) //14400 value is 72 pixels per inch over 200 inches. 200 inches seems to be adobe limit to a page
{ //determine the userunit to be used
USERUnitNewValue = pageSize.Height / 14400f;
}
float NewPageWidth = (pageSize.Width <= 14400f) ? pageSize.Width / USERUnitNewValue : pageSize.Width / USERUnitNewValue;
float NewPageHeight = pageSize.Height / USERUnitNewValue;
FileInfo file1 = new FileInfo(newfn);
DirectoryInfo directory1 = file1.Directory;
if (!directory1.Exists)
directory1.Create();
iTextSharp.text.Rectangle newPagesize = new iTextSharp.text.Rectangle(NewPageWidth, NewPageHeight);
Document newPdf = new Document(newPagesize);
PdfWriter writer = PdfWriter.GetInstance(newPdf, new FileStream(newfn, FileMode.Create));
writer.PdfVersion = PdfWriter.VERSION_1_6;
if (pageSize.Height > 14400)
{
writer.Userunit = USERUnitNewValue;
}
newPdf.SetMargins(0f, 0f, 0f, 0f);
newPdf.Open();
PdfContentByte cb = writer.DirectContent;
float verticalPosition = NewPageHeight;
for (int pagenumber = 1; pagenumber <= n1; pagenumber++)
{
if (pdfReader.NumberOfPages >= pagenumber)
{
/*convoluted page position. First position should be 0,0
unlike other counters this starts as page 1 so we need to subtract the
first page height away so that we start at the bottom of the previous image
* hmm seems that ths AddTemplate feature adds the pages in reverse order or
* at least the coordinate system sets 0,0 at the bottom left of the page
*/
float widthfactor = 1 / USERUnitNewValue; //Page scaling (width)
float heightfactor = 1 / USERUnitNewValue; //Page scaling (height)
//vertical position needs to take into account the new page height taking new UserUnit in affect
verticalPosition = verticalPosition - (pdfReader.GetPageSize(pagenumber).Height / USERUnitNewValue);
cb.AddTemplate(writer.GetImportedPage(pdfReader, pagenumber), heightfactor, 0, 0, widthfactor, 0, verticalPosition);
}
else
{
break;
}
}
newPdf.Close();
Thank you again for your help,
Mike

Insert text in Red Color at the bottom of existing pdf file with itextsharp

I have an existing PDF file, I want to insert a text at the bottom of PDF file in Red color, but the existing pdf file color must remain the same.
Thank You #mkl below code, I used which is specific for Stamp.
public static void ManipulatePdf(string src, string dest)
{
src = #"C:\CCPR Temp\TempFiles\PayStub_000106488_12282019_20200117112403.pdf";
dest = #"C:\CCPR Temp\TempFiles\PayStub_WithStamper.pdf";
PdfReader reader = new PdfReader(src);
PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create)); // create?
int numberOfPages = reader.NumberOfPages;
Rectangle pagesize;
for (int i = 1; i <= numberOfPages; i++)
{
PdfContentByte under = stamper.GetUnderContent(i);
pagesize = reader.GetPageSize(i);
float x =40;// (pagesize.Left + pagesize.Right) / 2;
float y = pagesize.Top/4;// (pagesize.Bottom + pagesize.Top) / 2;
PdfGState gs = new PdfGState();
gs.FillOpacity = 1.0f;
under.SaveState();
under.SetGState(gs);
under.SetRGBColorFill(255,0,0);
ColumnText.ShowTextAligned(under, Element.ALIGN_BOTTOM,
new Phrase("Watermark", new Font(Font.FontFamily.HELVETICA, 20)),
x, y, 1);
under.RestoreState();
}
stamper.Close();
reader.Close();
}
Adding content to an existing PDF document without changing the existing content, is sometimes referred to as stamping. Examples are adding page numbers, adding a watermark, and adding a running head.
For your specific case:
Create a PdfDocument instance from a PdfReader (to read the input PDF) and a PdfWriter (to write the output PDF). The PdfDocument instance will be in stamping mode.
Set the red text color on a Paragraph with the footer text.
Position the text with the ShowTextAligned convenience method, based on the page size.
You may also want to take into account page rotation.
PdfDocument pdfDoc = new PdfDocument(new PdfReader("input.pdf"), new PdfWriter("output.pdf"));
Document doc = new Document(pdfDoc);
Paragraph footer = new Paragraph("This is a footer").SetFontColor(ColorConstants.RED);
for (int i = 1; i <= pdfDoc.GetNumberOfPages(); i++)
{
Rectangle pageSize = pdfDoc.GetPage(i).GetPageSize();
float x = pageSize.GetLeft() + pageSize.GetWidth() / 2;
float y = pageSize.GetBottom() + 20;
doc.ShowTextAligned(footer, x, y, i, TextAlignment.CENTER, VerticalAlignment.BOTTOM, 0);
}
doc.Close();
This will set the Font of your Paragraph. I am not sure about the Position.
BaseFont btnRedFooter = BaseFont.CreateFont(BaseFont.TIMES_ROMAN, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
iTextSharp.text.Font fntRedFooter = FontFactory.GetFont(iTextSharp.text.Font.FontFamily.TIMES_ROMAN.ToString(), 16,
iTextSharp.text.Font.BOLD, iTextSharp.text.BaseColor.RED);
pProtocoll.Add(new Paragraph("Text in Footer", fntRedFooter));
I used the below steps and finally, got the required output. I was struggling for the font color, to apply to the newly added text.
public static void StampPdfFile(string oldFile, string newFile)
{
// open the reader
PdfReader reader = new PdfReader(oldFile);
Rectangle size = reader.GetPageSizeWithRotation(1);
Document document = new Document(size);
// open the writer
FileStream fs = new FileStream(newFile, FileMode.Create, FileAccess.Write);
PdfWriter writer = PdfWriter.GetInstance(document, fs);
document.Open();
// the pdf content
PdfContentByte cb = writer.DirectContent;
// select the font properties
BaseFont bf = BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
cb.SetFontAndSize(bf, 8);
// write the text in the pdf content
cb.BeginText();
string text = $"Voided On - {DateTime.Now.Date.ToString("MM/dd/yyyy")}";
// put the alignment and coordinates here
cb.SetColorFill(BaseColor.RED); //Give Red color to the newly added Text only
cb.ShowTextAligned(2, text, 120, 250, 0);
cb.SetColorFill(BaseColor.BLACK); //Give Red color to the exisitng file content only
cb.EndText();
// create the new page and add it to the pdf
PdfImportedPage page = writer.GetImportedPage(reader, 1);
cb.AddTemplate(page, 0, 0);
document.Close();
fs.Close();
writer.Close();
reader.Close();
}

Set margin for content in a pdf itext7

I'm working with pdfs, I'm merging them first and then creating a heading and a footer for every page of the merged pdf. I'm using one method to merge and a different one to set the header and footer.
For certain documents the header and footer overlaps with the content. I've tried to set margin for the document but it doesn't change anything.
public byte[] HeaderAndFooter(byte[] inputPdf)
{
var dest = new MemoryStream();
PdfDocument pdfDoc = new PdfDocument(new PdfReader(inputPdf.ToMemoryStream()),
new PdfWriter(dest));
Document doc = new Document(pdfDoc);
doc.SetMargins(200,200, 200, 200); /* It doesn't matter the
numbers I set in here the document remains the same...*/
numberOfPages = pdfDoc.GetNumberOfPages();
Paragraph header = new Paragraph("This is a header for every page...")
.SetFont(PdfFontFactory.CreateFont(FontConstants.HELVETICA))
.SetFontSize(10)
.SetFontColor(Color.BLACK);
for (int i = 1; i <= numberOfPages; i++)
{
var pageSize = pdfDoc.GetPage(i).GetPageSize();
float LeftMargin = 36;
float BottomMargin = 24;
float y = pageSize.GetTop() - 72;
float center = pageSize.GetWidth() / 2;
doc.ShowTextAligned(header, LeftMargin, y, i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0);
doc.ShowTextAligned(footerL, LeftMargin, BottomMargin, i, TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0);
doc.ShowTextAligned(footerC, center, BottomMargin, i, TextAlignment.CENTER, VerticalAlignment.BOTTOM, 0);
}
doc.Close();
return dest.ToArray();
}
How could I avoid the header and footer from overlapping with the content?

ItextSharp add image on center of page with the text under it

I'm trying add picture on centre(middle) of page PDF file with text, but I can't do it right. I use for image SetAbsolutePosition, but text don't stand under picture.
I need in my Pdf file next format of page:
I use next code:
PdfWriter writer = PdfWriter.GetInstance(doc, fs);
ITextEvents ev = new ITextEvents();
writer.PageEvent = ev;
doc.Open();
var paragraph = new Paragraph();
var paragraph1 = new Paragraph();
var chunk = new Chunk("Text under picture", f14nb);
var chunk1 = new Chunk("Code of picture", f14);
img = ScaleImg(Image.GetInstance(imgNane_2));
img.SetAbsolutePosition((PageSize.A4.Width - img.ScaledWidth) / 2,
((PageSize.A4.Height - img.ScaledHeight) / 2));
paragraph.Add(img);
paragraph1.Add(chunk);
paragraph1.Add(chunk1);
doc.Add(paragraph);
doc.Add(paragraph1);
doc.Close();
private Image ScaleImg(Image img)
{
if (img.Height > img.Width)
{
//Maximum height is 800 pixels.
float percentage = 0.0f;
percentage = 640 / img.Height;
img.ScalePercent(percentage * 100);
}
else
{
//Maximum width is 600 pixels.
float percentage = 0.0f;
percentage = 500 / img.Width;
img.ScalePercent(percentage * 100);
}
return img;
}
I think, that I should use another way for solve my problem, but I don't know which.
Thank you.
I understood how do it.
This is for image with text:
public Image getWatermarkedImage(Document Doc, Image img, String watermarkText)
{
float width = img.ScaledWidth;
float height = img.ScaledHeight;
PdfTemplate template = cb.CreateTemplate(width, height);
template.AddImage(img, width, 0, 0, height, 0, 0);
ColumnText.ShowTextAligned(template, Element.ALIGN_RIGHT,
new Phrase(watermarkText, fontBold_14), width - 10, 10, 0);
return Image.GetInstance(template);
}
This is for adding text under image(main code):
var codeOfPicture = "*Code of picture* - *Код картинки*";
var chunk = new Chunk("Text under picture", font_14);
img = ScaleImg(Image.GetInstance(imgNane_1));//imgNane_2));
var tmpImg = getWatermarkedImage(doc, img, codeOfPicture);
var textY = ((PageSize.A4.Height - img.ScaledHeight) / 2) - 15;
var textX = PageSize.A4.Width / 2;
tmpImg.SetAbsolutePosition((PageSize.A4.Width - img.ScaledWidth) / 2,
((PageSize.A4.Height - img.ScaledHeight) / 2));
doc.Add(tmpImg);
ColumnText.ShowTextAligned(cb, Element.ALIGN_CENTER, new Phrase(chunk), textX, textY, 0);

itextsharp how to add a full line break

I use itextsharp and i need to draw a dotted linebreak from left to right of the page(100% width) but don't know how. The doc always has a margin left right. Please help
var pageSize = PageSize.A4;
if (_pdfSettings.LetterPageSizeEnabled)
{
pageSize = PageSize.LETTER;
}
var doc = new Document(pageSize);
PdfWriter.GetInstance(doc, stream);
doc.Open();
//fonts
var titleFont = GetFont();
titleFont.SetStyle(Font.BOLD);
titleFont.Color = BaseColor.BLACK;
titleFont.Size = 16;
var largeFont = GetFont();
largeFont.SetStyle(Font.BOLD);
largeFont.Color = BaseColor.BLACK;
largeFont.Size = 18;
int ordCount = orders.Count;
int ordNum = 0;
foreach (var order in orders)
{
var addressTable = new PdfPTable(3);
addressTable.WidthPercentage = 100f;
addressTable.SetWidths(new[] { 25, 37, 37 });
// sender address
cell = new PdfPCell();
//cell.Border = Rectangle.NO_BORDER;
cell.AddElement(new Paragraph("Người Gửi", titleFont));
cell.AddElement(new Paragraph(_localizationService.GetResource("admin.orders.pdfinvoice.sender", lang.Id), smallFont));
cell.AddElement(new Paragraph(_localizationService.GetResource("admin.orders.pdfinvoice.senderaddress", lang.Id), smallFont));
cell.AddElement(new Paragraph(_localizationService.GetResource("PDFInvoice.Hotline", lang.Id), smallFont));
cell.AddElement(new Paragraph("TAKARA.VN", largeFont));
addressTable.AddCell(cell);
......
Chunk linebreak = new Chunk(new DottedLineSeparator());
doc.Add(linebreak);
doc.Add(new Paragraph(""));
....
}
Please take a look at the example FullDottedLine.
You're creating a DottedLineSeparator of which the width percentage is 100% by default. This 100% is the full available width withing the margins of the page. If you want the line to exceed the available width, you need a percentage that is higher than 100%.
In the example, the default page size (A4) and the default margins (36) are used. This means that the width of the page is 595 user units and the available width equals 595 - (2 x 36) user units. The percentage needed to span the complete width of the page equals 100 x (595 / 523).
Take a look at the resulting PDF file full_dotted_line.pdf and you'll see that the line now runs through the margins.

Categories