Problem with table of contents after page resize - c#

I have doc and change page size
builder.PageSetup.PageWidth = ConvertUtil.MillimeterToPoint(219.1);
builder.PageSetup.PageHeight = ConvertUtil.MillimeterToPoint(285.7);
Doc has Table of content, but after changed size it placed wrong
wrong sized TOC
Any suggestions how to place normal TOC full page width?
Tried with different docs. Same problem.

Width of the TOC is defined by tab stops in the TOC styles. So, after increasing width of the page, you have also increase size of the TOC styles tab stops accordingly. Please see the following code:
Document doc = new Document(#"C:\Temp\in.docx");
doc.FirstSection.PageSetup.PageWidth = doc.FirstSection.PageSetup.PageWidth + 200;
UpdateTocStyles(doc);
// Update fields to rebuild the TOC.
doc.UpdateFields();
doc.Save(#"C:\Temp\out.docx");
private void UpdateTocStyles(Document doc)
{
// List of all TOC styles.
StyleIdentifier[] tocStyles = new StyleIdentifier[]
{
StyleIdentifier.Toc1,
StyleIdentifier.Toc2,
StyleIdentifier.Toc3,
StyleIdentifier.Toc4,
StyleIdentifier.Toc5,
StyleIdentifier.Toc6,
StyleIdentifier.Toc7,
StyleIdentifier.Toc8,
StyleIdentifier.Toc9
};
// Calculate width of the page without left and right margins.
double pageWidth = doc.FirstSection.PageSetup.PageWidth - doc.FirstSection.PageSetup.RightMargin - doc.FirstSection.PageSetup.LeftMargin;
// Reset tab stops in TOC styles.
foreach (StyleIdentifier tocStyleIdentifier in tocStyles)
{
Style tocStyle = doc.Styles[tocStyleIdentifier];
tocStyle.ParagraphFormat.TabStops.Clear();
tocStyle.ParagraphFormat.TabStops.Add(new TabStop(pageWidth, TabAlignment.Right, TabLeader.Dots));
}
}

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

Remove page numbers from PDFsharp page merge when merging with another document

I used PDFsharp to merge 2 PDF files. My code adds page numbering to the bottom of each page. Now I need to merge the created document with another PDF the same way. The issue I get is the page numbers on the part created from the last document are fine. The document created from the first merge has the new page number added over the top of the first set so there are now two page numbers on top of each other in the first set of pages. So in one spot I have both of these "Page 1 of 40" and Page "1 of 110" on top of each other.
Here is the code I used to merge the PDFs
using PdfSharp.Drawing;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
namespace SomeProject.Helpers
{
public static class PDFHelper
{
public static void MergePDFFiles(string[] pdfFiles, string outputFilePath)
{
PdfDocument document = new PdfDocument();
foreach (string pdfFile in pdfFiles)
{
PdfDocument inputPDFDocument = PdfReader.Open(pdfFile, PdfDocumentOpenMode.Import);
document.Version = inputPDFDocument.Version;
foreach (PdfPage page in inputPDFDocument.Pages)
{
document.AddPage(page);
}
}
// Set font for paging
XFont font = new XFont("Verdana", 9);
XBrush brush = XBrushes.Black;
// Create variable that store page count
string noPages = document.Pages.Count.ToString();
// Set for loop of document page count and set page number using DrawString function of PdfSharp
for (int i = 0; i < document.Pages.Count; ++i)
{
PdfPage page = document.Pages[i];
// Make a layout rectangle.
XRect layoutRectangle = new XRect(240 /*X*/ , page.Height - font.Height - 10 /*Y*/ , page.Width /*Width*/ , font.Height /*Height*/ );
using (XGraphics gfx = XGraphics.FromPdfPage(page))
{
gfx.DrawString("Page " + (i + 1).ToString() + " of " + noPages, font, brush, layoutRectangle, XStringFormats.Center);
}
}
document.Save(outputFilePath);
}
}
}
A clean solution: only add the page numbers to the final documents. Keep copies of intermediate files without page numbers or create the files twice as needed.
A hack: draw a white rectangle below the new page numbers to hide anything that is already in that area. The PDF will have both page numbers, but only the most recent and current page number will be visible.
Removing page numbers is a bit complicated.

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);
}

Where does bottom and right border come from in abcPdf

Why I am getting border on bottom and right when rendering html using abcAdf.
PS I got professional license using (ABCpdf9-64.dll)
My process is to create page:
I use master / child layout template in mvc (works)
I point to this html using abcPdf to convert into pdf
Html rendered
When my html gets rendered (plain) format : each originating from its respective location.
<h1>Layout</h1>
<p>
content
</p>
C# code to render pdf
My code is as follows:
using (var pdf = new Doc())
{
pdf.HtmlOptions.Timeout = 600000;
pdf.HtmlOptions.AddTags = true;
pdf.Page = pdf.AddPage();
var id = pdf.AddImageUrl(url, true, 1024, true);
if (allowPaging)
{
while (true)
{
if (!pdf.Chainable(id))
{
break;
}
pdf.Page = pdf.AddPage();
id = pdf.AddImageToChain(id);
}
for (int i = 1; i <= pdf.PageCount; i++)
{
pdf.PageNumber = i;
pdf.Flatten();
}
////reset back to page 1 so the pdf starts displaying there
if (pdf.PageCount > 0)
{
pdf.PageNumber = 1;
}
}
return store(pdf);
}
Output
My text/html gets rendered ok but I get borders that I have not asked for.
Rendered output:
Please note the hairline in bottom of the image.
After hours of googling about setting margin in abcpdf, I found nothing and took it as a challenge to find it myself.
I tried experimenting with everything I found relevant in the abcpdf documentation and finally made a chart myself
for setting the margins. I have successfully implemented this in many situations. Hope this helps others.
Here is a code snippet that shows how to set margins-
string html; // my html content that should be shown in the pdf page
Doc pdf = new Doc();
// adjust the default rotation and save
double w = pdf.MediaBox.Width;
double h = pdf.MediaBox.Height;
double l = pdf.MediaBox.Left;
double b = pdf.MediaBox.Bottom;
// explicitly giving page size
pdf.MediaBox.String = "A4";
pdf.Transform.Rotate(90, l, b);
pdf.Transform.Translate(w, 0);
pdf.Rect.Width = h;
pdf.Rect.Height = w;
int theID1 = pdf.GetInfoInt(pdf.Root, "Pages");
pdf.SetInfo(theID1, "/Rotate", "90");
int theID;
pdf.Rect.String = "17 55 823 423";
theID = pdf.AddImageHtml(html.ToString()); //Writes the HTML image to PDF
Here is a picture that describes margin layout for some junk values. Here
20 suggests that your content starts 20 pixels away from left of your pdf page
770 suggests that your content ends 770 pixels away from left of your pdf page
75 suggests that your content starts 55 pixels above the bottom of your pdf page
600 suggests that your content ends 600 pixels above the bottom of your pdf page
In your case you have to add
pdf.Rect.String = "20 75 770 600"; // giving junk values
right before
var id = pdf.AddImageUrl(url, true, 1024, true);
NOTE: In this example I explicitly set landscape mode instead of portrait mode. But orientation doesn't matter for setting
margins.

Change the inset of a specific page with abcpdf

I use abcpdf to create a pdf from a html string. The following snippet shows the way I do it:
var pdfDocument = new Doc();
pdfDocument.Page = pdfDocument.AddPage();
pdfDocument.Font = pdfDocument.AddFont("Times-Roman");
pdfDocument.FontSize = 12;
var documentId = pdfDocument.AddImageHtml(innerHtml);
var counter = 0;
while (true)
{
counter++;
if (!pdfDocument.Chainable(documentId))
{
break;
}
pdfDocument.Page = pdfDocument.AddPage();
// how to add a inset of 20, 0 on every page after the second? The following 2lines don't affect the pdf pages
if (counter >= 3)
pdfDocument.Rect.Inset(20, 0);
documentId = pdfDocument.AddImageToChain(documentId);
}
After the AddPage I want to add a new inset for every page with pagenumber > 2
Thanks in advance
I can assure you that your inset call will be having an effect. Try calling FrameRect on each page and you shuld be able to see this.
So why is it that you are not seeing the effect you are expecting?
Well your HTML has a fixed width at the point you call AddImageUrl/HTML. Each subsequent call to AddImageToChain utilizes this fixed width.
If in your 'inset' pages you reduce the height of the area on the page you will get the next chunk of the page truncated to that height.
If in your 'inset' pages you reduce the width of the area then things become more difficult. The width is fixed so it can't be changed. Instead ABCpdf will scale the page down so that it does fit.
So if you reduce the width from say 600 points to 580 points then the scale factor for this content would be 580/600 = 97%.
Most likely this is what is happening but because the scale factor is small you are not noticing it.
I work on ABCpdf and my replies may contain concepts based around ABCpdf. It's what I know. :-)
Comment #1 from SwissCoder was right. AddImageHtml already adds the first page. After also contacting the WebSuperGoo support, they recommend me to use PageCountof class Doc.
while (true)
{
if (!pdfDocument.Chainable(documentId))
{
break;
}
pdfDocument.Page = pdfDocument.AddPage();
if (pdfDocument.PageCount >= 3)
pdfDocument.Rect.Inset(0, 20);
documentId = pdfDocument.AddImageToChain(documentId);
}
The other solution would be to adjust the index to count unto required pagenumber - 1 as ÀddImageHtml already adds the first page to the document.

Categories