iTextSharp: table in landscape - c#

I'm using iTextSharp to generate a large document. In this document I want some specific pages in landscape. All the rest is portrait. Does anyone know how I can do this?
Starting a new document is not an option.
Thanks!

You can set the document size and it will affect the next pages. Some snippets:
Set up your document somewhere (you know that already):
var document = new Document();
PdfWriter pdfWriter = PdfWriter.GetInstance(
document, new FileStream(destinationFile, FileMode.Create)
);
pdfWriter.SetFullCompression();
pdfWriter.StrictImageSequence = true;
pdfWriter.SetLinearPageMode();
Now loop over your pages (you probably do that as well already) and decide what page size you want per page:
for (int pageIndex = 1; pageIndex <= pageCount; pageIndex++) {
// Define the page size here, _before_ you start the page.
// You can easily switch from landscape to portrait to whatever
document.SetPageSize(new Rectangle(600, 800));
if (document.IsOpen()) {
document.NewPage();
} else {
document.Open();
}
}

try this code :
using System;
using System.IO;
using iText.Kernel.Events;
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;
namespace iText.Samples.Sandbox.Events
{
public class PageOrientations
{
public static readonly String DEST = "results/sandbox/events/page_orientations.pdf";
public static readonly PdfNumber PORTRAIT = new PdfNumber(0);
public static readonly PdfNumber LANDSCAPE = new PdfNumber(90);
public static readonly PdfNumber INVERTEDPORTRAIT = new PdfNumber(180);
public static readonly PdfNumber SEASCAPE = new PdfNumber(270);
public static void Main(String[] args)
{
FileInfo file = new FileInfo(DEST);
file.Directory.Create();
new PageOrientations().ManipulatePdf(DEST);
}
protected void ManipulatePdf(String dest)
{
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
// The default page orientation is set to portrait in the custom event handler.
PageOrientationsEventHandler eventHandler = new PageOrientationsEventHandler();
pdfDoc.AddEventHandler(PdfDocumentEvent.START_PAGE, eventHandler);
Document doc = new Document(pdfDoc);
doc.Add(new Paragraph("A simple page in portrait orientation"));
eventHandler.SetOrientation(LANDSCAPE);
doc.Add(new AreaBreak());
doc.Add(new Paragraph("A simple page in landscape orientation"));
eventHandler.SetOrientation(INVERTEDPORTRAIT);
doc.Add(new AreaBreak());
doc.Add(new Paragraph("A simple page in inverted portrait orientation"));
eventHandler.SetOrientation(SEASCAPE);
doc.Add(new AreaBreak());
doc.Add(new Paragraph("A simple page in seascape orientation"));
doc.Close();
}
private class PageOrientationsEventHandler : IEventHandler
{
private PdfNumber orientation = PORTRAIT;
public void SetOrientation(PdfNumber orientation)
{
this.orientation = orientation;
}
public void HandleEvent(Event currentEvent)
{
PdfDocumentEvent docEvent = (PdfDocumentEvent) currentEvent;
docEvent.GetPage().Put(PdfName.Rotate, orientation);
}
}
}
}

Related

How can change link type of pdf links by itext7?

I want edit to visible rectangle of links in file pdf:
If i use acrobat ,i can edit link type to "Visible Rectangle"
But with iText7 , How can change this value?
I try setting, but it not working:
string strPage = #"C:\test1.pdf";
string strPageNew = #"C:\result.pdf";
PdfReader reader = new PdfReader(strPage);
using (PdfWriter writer = new PdfWriter(strPageNew))
{
using (PdfDocument pdfDoc = new PdfDocument(reader, writer))
{
PdfPage pdfPage = pdfDoc.GetPage(1);
var annotations = pdfPage.GetAnnotations();
if (annotations != null)
{
foreach (PdfAnnotation a in annotations)
{
if (a.GetSubtype().Equals(PdfName.Link))
{
PdfLinkAnnotation link = (PdfLinkAnnotation)a;
var action = link.GetAction();
if (action != null)
{
if (action.Get(PdfName.S).Equals(PdfName.URI))
{
PdfString destination = action.GetAsString(PdfName.URI);
link.SetFlag(4);
link.SetHighlightMode(PdfAnnotation.HIGHLIGHT_OUTLINE);
link.SetBorderStyle(PdfAnnotation.STYLE_SOLID);
link.SetColor(iText.Kernel.Colors.ColorConstants.RED );
}
}
}
}
}
}
}
reader.Close();

IText7 PDFHtml generator with header and footer for C#

I am trying to generating a PDF from predefined HTML content. I managed to generate the content, yet without the required HTML Header, HTML Footer, and Arabic language is not supported as well.
My requirements:
Arabic language support.
The ability to generate more than 10 pages.
The footer may differ from one page to another.
There is a web application that sends a request to a WCF service, and the service returns a byte array containing the PDF.
So, I have been searching for a couple of days for a good tool and I found SelectPdf, it is perfect except that it is NOT free, so the only solution is IText7 PDFHtml.
The thing is this library has good documentation for JAVA, and I am really struggling in following the C# examples and converting from JAVA API to C# code.
Anyone has done something similar before with c#?
After a long process of searching and trying, I have got it working and achieved the following features:
Image in the header.
Base64 image in the footer, in addition to the ability to write some text in the other side in the footer.
Generating the same footer for all pages except for the last one.
the number of the generated pages was unlimited.
Page numbering.
All the previous features were free of charge, however, supporting Arabic language needs a license, so I have to pay anyway :)
Kindly find below my C# code and post your improvements if you have any.
public class Pdfgenerator
{
public const string FONT = "Fonts/NotoNaskhArabic-Regular2.ttf";
public static string HEADER_TEXT = "<table width=\"100%\" border=\"0\"><tr><td>Header</td><td align=\"right\">Some title</td></tr></table>";
public static string FOOTER_TEXT = "<table width=\"100%\" border=\"0\"><tr><td>Footer</td><td align=\"right\">Some title</td></tr></table>";
public MemoryStream createPdf()
{
string apPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
MemoryStream file = new MemoryStream();
PdfDocument pdfDocument = null;
PdfDocument pdfDoc = null;
PdfDocument pdfDocument1 = null;
try
{
using (file)
{
PdfFont f = PdfFontFactory.CreateFont(apPath + FONT, PdfEncodings.IDENTITY_H);
string header = "pdfHtml Header and footer example using page-events";
Header headerHandler = new Header(header);
Footer footerHandler = new Footer();
ConverterProperties converterProperties = new ConverterProperties();
PdfWriter writer1 = new PdfWriter(apPath + "test1.pdf");
pdfDocument1 = new PdfDocument(writer1);
pdfDocument1.AddEventHandler(PdfDocumentEvent.START_PAGE, headerHandler);
pdfDocument1.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler);
converterProperties = new ConverterProperties().SetBaseUri(apPath);
HtmlConverter.ConvertToDocument(File.ReadAllText(apPath + "content.html"), pdfDocument1, converterProperties);
footerHandler.lastPage = pdfDocument1.GetLastPage();
pdfDocument1.Close();
}
}
catch (Exception ex)
{
}
finally
{
file.Dispose();
}
return new MemoryStream();
}
}
Generating the header:
class Header : IEventHandler
{
private string header;
private Image image;
public Header(string header)
{
string apPath = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
this.header = header;
image = new Image(ImageDataFactory.Create(apPath + "Images/RANDOM_PHOTO.jpg"));
}
public void HandleEvent(Event #event)
{
PdfDocumentEvent docEvent = (PdfDocumentEvent)#event;
PdfDocument pdf = docEvent.GetDocument();
PdfPage page = docEvent.GetPage();
Rectangle pageSize = page.GetPageSize();
Canvas canvas = new Canvas(new PdfCanvas(page), pdf, pageSize);
canvas.SetFontSize(18);
// Write text at position
canvas.Add(image);
canvas.Close();
}
}
Generating the footer:
class Footer : IEventHandler
{
public PdfPage lastPage = null;
protected PdfFormXObject placeholder;
protected float side = 20;
protected float x = 300;
protected float y = 25;
protected float space = 4.5f;
protected float descent = 3;
public Footer()
{
placeholder = new PdfFormXObject(new Rectangle(0, 0, side, side));
}
public void HandleEvent(Event #event)
{
PdfDocumentEvent docEvent = (PdfDocumentEvent)#event;
PdfDocument pdf = docEvent.GetDocument();
PdfPage page = docEvent.GetPage();
int pageNumber = pdf.GetPageNumber(page);
Rectangle pageSize = page.GetPageSize();
// Creates drawing canvas
PdfCanvas pdfCanvas = new PdfCanvas(page);
Canvas canvas = new Canvas(pdfCanvas, pdf, pageSize);
IList<iText.Layout.Element.IElement> elements = HtmlConverter.ConvertToElements("<table border=\"0\"><tr><td><img src=\"data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==\" alt=\"Italian Trulli\"></td></tr></table>");
Paragraph p = new Paragraph();
foreach (iText.Layout.Element.IElement e in elements)
{
if (e is IBlockElement) {
p.Add((IBlockElement)e);
}
}
if (lastPage == docEvent.GetPage()) {
}
else
{
canvas.ShowTextAligned(p, 25, 75, TextAlignment.LEFT);
}
canvas.Close();
// Create placeholder object to write number of pages
pdfCanvas.AddXObject(placeholder, x + space, y - descent);
pdfCanvas.Release();
}
public void writeTotal(PdfDocument pdf)
{
Canvas canvas = new Canvas(placeholder, pdf);
canvas.ShowTextAligned(pdf.GetNumberOfPages().ToString(),
0, descent, TextAlignment.LEFT);
canvas.Close();
}
}
I was trying to get a stream as an output, so if you want that as well you can use the following in your main service:
public byte[] GetData()
{
MemoryStream stream = new Pdfgenerator().createPdf();
byte[] arr = stream.ToArray();
return stream.ToArray();
}

Extract image from pdf in specific position

I have inserted the image in the pdf using itextsharp as shown below and I tried all the possible solutions to extract it with using the coordinates.
String pathin = pdf.src;
String pathout = "C:\\....";
string signedFile = System.IO.Path.GetTempFileName();
PdfReader reader = new PdfReader(pathin);
FileStream fs = new FileStream(pathout, FileMode.Create);
PdfStamper stamper = new PdfStamper(reader, fs);
PdfContentByte cb = stamper.GetOverContent(1);
iTextSharp.text.Image image1 = iTextSharp.text.Image.GetInstance(imageFileName);
image1.RotationDegrees = 270f;
image1.Alignment = Element.ALIGN_TOP;
image1.SetAbsolutePosition(0,0);
image1.ScalePercent(50f, 50f);
cb.AddImage(image1);
stamper.Close();
fs.Close();
Console.Read();
pdf.src = pathout;
Is there any way to use itextsharp to extract image from position (0,0)?
pseudo-code:
implement IEventListener
parse the page you are interested in, CanvasProcessor takes an IEventListener implementation in its constructor, every time it finishes rendering text, an image, or a path, it will notify the IEventListener
IEventListener has a method called eventOccurred(IEventData data, EventType type). One of the types will be responsible for images
cast IEventData to ImageRenderInfo
derive the coordinates from the ImageRenderInfo object
if the coordinates happen to contain Point(0, 0) then (temporarily) store the image in a variable of your IEventListener
code sample (java, iText7)
disclaimer: the following code does not handle rotation
class MyImageSeek implements IEventListener{
private int pageNr = 0;
private Map<Integer, Map<Rectangle, BufferedImage>> images = new HashMap<>();
public MyImageSeek(PdfDocument pdfDocument){
PdfCanvasProcessor canvasProcessor = new PdfCanvasProcessor(this);
for(int i=1;i<=pdfDocument.getNumberOfPages();i++) {
images.put(i, new HashMap<Rectangle, BufferedImage>());
pageNr = i;
canvasProcessor.processPageContent(pdfDocument.getPage(i));
}
}
#Override
public void eventOccurred(IEventData data, EventType type) {
if(type != EventType.RENDER_IMAGE)
return;
ImageRenderInfo imageRenderInfo = (ImageRenderInfo) data;
int x = (int) imageRenderInfo.getStartPoint().get(0);
int y = (int) imageRenderInfo.getStartPoint().get(1);
int w = (int) imageRenderInfo.getImageCtm().get(Matrix.I11);
int h = (int) imageRenderInfo.getImageCtm().get(Matrix.I22);
try {
images.get(pageNr).put(new Rectangle(x,y,w,h), imageRenderInfo.getImage().getBufferedImage());
} catch (IOException e) {}
}
#Override
public Set<EventType> getSupportedEvents() {
return null;
}
public Map<Rectangle, BufferedImage> getImages(int pageNr){
return images.get(pageNr);
}
}
and this is the main method to call this class
PdfDocument pdfDocument = new PdfDocument(new PdfReader(new File("C:\\Users\\me\\lookAtMe.pdf")));
MyImageSeek meeseek = new MyImageSeek(pdfDocument);
for(Map.Entry<Rectangle, BufferedImage> en : meeseek.getImages(1).entrySet())
System.out.println(en.getKey() + "\t" + en.getValue());

iTextSharp PDF header with HTML string C#

I'm trying to generate PDF reports using iTextSharp with customer information, header and footer etc. All these reports are already generated using EVO APIs. As part of a migration process, we are planning to generate these reports using iTextSharp APIs.
I need to know if there is any possibility to provide a ready to render HTML string to iTextSharp PDF header (Existing EVO design accepts HTML string and build PDF), instead of using PageEvents to design with PDFPTable and PDFPCell (as the number of reports are huge and to avoid rework)
I need to know if there is any possibility to provide a ready to render HTML string to iTextSharp PDF header (Existing EVO design accepts HTML string and build PDF), instead of using PageEvents to design with PDFPTable and PDFPCell
You will have to use page events to draw header or footers but there is no need to use PdfPTable explicitly there. You actually can render html during a page event, e.g. like this:
[Test]
public void CreatePdfWithHtmlHeader()
{
string htmlHeader = "<!DOCTYPE html><html><body><table style=\"width: 100%; border: 1px solid black;\"><tr><td>A</td><td>B</td></tr></table></body></html>";
using (FileStream output = new FileStream(#"C:\Temp\test-results\content\html-header.pdf", FileMode.Create, FileAccess.Write))
using (Document document = new Document(PageSize.A4))
{
PdfWriter writer = PdfWriter.GetInstance(document, output);
writer.PageEvent = new HtmlPageEventHelper(htmlHeader);
document.Open();
document.Add(new Paragraph("1"));
document.NewPage();
document.Add(new Paragraph("2"));
}
}
making use the following two small helper classes.
HtmlPageEventHelper is a page event listener drawing a given html sniplet into the page header. Obviously it can alternatively or additionally write into the page footer, simply use appropriate column coordinates
public class HtmlPageEventHelper : PdfPageEventHelper
{
public HtmlPageEventHelper(string html)
{
this.html = html;
}
public override void OnEndPage(PdfWriter writer, Document document)
{
base.OnEndPage(writer, document);
ColumnText ct = new ColumnText(writer.DirectContent);
XMLWorkerHelper.GetInstance().ParseXHtml(new ColumnTextElementHandler(ct), new StringReader(html));
ct.SetSimpleColumn(document.Left, document.Top, document.Right, document.GetTop(-20), 10, Element.ALIGN_MIDDLE);
ct.Go();
}
string html = null;
}
For more complex HTML sniplets you may want to replace the XMLWorkerHelper.GetInstance().ParseXHtml call by a customized parser call as presented in #Skary's answer.
ColumnTextElementHandler is an IElementHandler implementation that adds content (generated e.g. by parsing HTML) to a ColumnText
public class ColumnTextElementHandler : IElementHandler
{
public ColumnTextElementHandler(ColumnText ct)
{
this.ct = ct;
}
ColumnText ct = null;
public void Add(IWritable w)
{
if (w is WritableElement)
{
foreach (IElement e in ((WritableElement)w).Elements())
{
ct.AddElement(e);
}
}
}
}
By the way, the test above produces a PDF with this content:
...
...
Disclaimer: I predominantly work with Java and have not used the XmlWorker before. Thus, this code may have considerable potential for improvement.
I am not sure to have understand you question right.
If you are asking how to parse HTML to PDF using iTextSharp here is the solutin i found time ago :
using (Document document = new Document(size))
{
var writer = PdfWriter.GetInstance(document, stream);
document.Open();
document.NewPage();
document.Add(new Chunk(""));
var tagProcessors = (DefaultTagProcessorFactory)Tags.GetHtmlTagProcessorFactory();
tagProcessors.RemoveProcessor(HTML.Tag.IMG);
tagProcessors.AddProcessor(HTML.Tag.IMG, new CustomImageTagProcessor());
var charset = Encoding.UTF8;
CssFilesImpl cssFiles = new CssFilesImpl();
cssFiles.Add(XMLWorkerHelper.GetInstance().GetDefaultCSS());
var cssResolver = new StyleAttrCSSResolver(cssFiles);
cssResolver.AddCss(srcCssData, "utf-8", true);
var hpc = new HtmlPipelineContext(new CssAppliersImpl(new XMLWorkerFontProvider()));
hpc.SetAcceptUnknown(true).AutoBookmark(true).SetTagFactory(tagProcessors);
var htmlPipeline = new HtmlPipeline(hpc, new PdfWriterPipeline(document, writer));
var pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
var worker = new XMLWorker(pipeline, true);
var xmlParser = new XMLParser(true, worker, charset);
xmlParser.Parse(new StringReader(srcFileData));
document.Close();
}
To get it work you need to add custom image processor to inline image in the HTML you provide to tha above converte function :
public class CustomImageTagProcessor : iTextSharp.tool.xml.html.Image
{
public override IList<IElement> End(IWorkerContext ctx, Tag tag, IList<IElement> currentContent)
{
IDictionary<string, string> attributes = tag.Attributes;
string src;
if (!attributes.TryGetValue(HTML.Attribute.SRC, out src))
return new List<IElement>(1);
if (string.IsNullOrEmpty(src))
return new List<IElement>(1);
if (src.StartsWith("data:image/", StringComparison.InvariantCultureIgnoreCase))
{
// data:[<MIME-type>][;charset=<encoding>][;base64],<data>
var base64Data = src.Substring(src.IndexOf(",") + 1);
var imagedata = Convert.FromBase64String(base64Data);
var image = iTextSharp.text.Image.GetInstance(imagedata);
var list = new List<IElement>();
var htmlPipelineContext = GetHtmlPipelineContext(ctx);
list.Add(GetCssAppliers().Apply(new Chunk((iTextSharp.text.Image)GetCssAppliers().Apply(image, tag, htmlPipelineContext), 0, 0, true), tag, htmlPipelineContext));
return list;
}
else
{
return base.End(ctx, tag, currentContent);
}
}
}

import named destinations in pdf

I m developing an application in which a word document is converted in pdf. My problem is too complicated please help me out.
My word doc has a toc, bookmarks, endnotes and hyperlinks. when I save this doc as pdf, only bookmarks are converted. After a long research I found that PDF documents does not support bookmark to bookmark hyperlinks, it needs either page number or named destinations.
So I choose named destinations for this purpose, but I am stuck again , because simple "save as" cannot generate named destinations in the pdf doc. So I print the word doc on adobe PDF printer and I got named destination as required, but again this document neither have bookmarks in it nor hyperlinks. so what I decided that I generate two pdf from a word, first by save as option and second one is by printing.
test.pdf (by save as) (contains bookmarks, hyperlinks)
test_p.pdf( by printing) (only contains named destination)
then I research ones again and found a way to extract all named destination from test_p.pdf into XML by a function of itextsharp.but unfortunately I dont get any way to import back this xml in test.pdf.. thats why I came here.
Guide me what to do next if this approach is ok. else suggest me any ohter approach to accomplish this mission.
I wrote a class to replace urls in my PDF files some times ago:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using iTextSharp.text.pdf;
namespace ReplaceLinks
{
public class ReplacePdfLinks
{
Dictionary<string, PdfObject> _namedDestinations;
PdfReader _reader;
public string InputPdf { set; get; }
public string OutputPdf { set; get; }
public Func<Uri, string> UriToNamedDestination { set; get; }
public void Start()
{
updatePdfLinks();
saveChanges();
}
private PdfArray getAnnotationsOfCurrentPage(int pageNumber)
{
var pageDictionary = _reader.GetPageN(pageNumber);
var annotations = pageDictionary.GetAsArray(PdfName.ANNOTS);
return annotations;
}
private static bool hasAction(PdfDictionary annotationDictionary)
{
return annotationDictionary.Get(PdfName.SUBTYPE).Equals(PdfName.LINK);
}
private static bool isUriAction(PdfDictionary annotationAction)
{
return annotationAction.Get(PdfName.S).Equals(PdfName.URI);
}
private void replaceUriWithLocalDestination(PdfDictionary annotationAction)
{
var uri = annotationAction.Get(PdfName.URI) as PdfString;
if (uri == null)
return;
if (string.IsNullOrWhiteSpace(uri.ToString()))
return;
var namedDestination = UriToNamedDestination(new Uri(uri.ToString()));
if (string.IsNullOrWhiteSpace(namedDestination))
return;
PdfObject entry;
if (!_namedDestinations.TryGetValue(namedDestination, out entry))
return;
annotationAction.Remove(PdfName.S);
annotationAction.Remove(PdfName.URI);
var newLocalDestination = new PdfArray();
annotationAction.Put(PdfName.S, PdfName.GOTO);
var xRef = ((PdfArray)entry).First(x => x is PdfIndirectReference);
newLocalDestination.Add(xRef);
newLocalDestination.Add(PdfName.FITH);
annotationAction.Put(PdfName.D, newLocalDestination);
}
private void saveChanges()
{
using (var fileStream = new FileStream(OutputPdf, FileMode.Create, FileAccess.Write, FileShare.None))
using (var stamper = new PdfStamper(_reader, fileStream))
{
stamper.Close();
}
}
private void updatePdfLinks()
{
_reader = new PdfReader(InputPdf);
_namedDestinations = _reader.GetNamedDestinationFromStrings();
var pageCount = _reader.NumberOfPages;
for (var i = 1; i <= pageCount; i++)
{
var annotations = getAnnotationsOfCurrentPage(i);
if (annotations == null || !annotations.Any())
continue;
foreach (var annotation in annotations.ArrayList)
{
var annotationDictionary = (PdfDictionary)PdfReader.GetPdfObject(annotation);
if (!hasAction(annotationDictionary))
continue;
var annotationAction = annotationDictionary.Get(PdfName.A) as PdfDictionary;
if (annotationAction == null)
continue;
if (!isUriAction(annotationAction))
continue;
replaceUriWithLocalDestination(annotationAction);
}
}
}
}
}
To use it:
new ReplacePdfLinks
{
InputPdf = #"test.pdf",
OutputPdf = "mod.pdf",
UriToNamedDestination = uri =>
{
if (uri.Host.ToLowerInvariant().Contains("google.com"))
{
return "entry1";
}
return string.Empty;
}
}.Start();
This sample will modify all of the urls containing google.com to point to a specific named destination "entry1".
And this is the sample file to test the above class:
void WriteFile()
{
using (var doc = new Document(PageSize.LETTER))
{
using (var fs = new FileStream("test.pdf", FileMode.Create))
{
using (var writer = PdfWriter.GetInstance(doc, fs))
{
doc.Open();
var blueFont = FontFactory.GetFont("Arial", 12, Font.NORMAL, BaseColor.BLUE);
doc.Add(new Chunk("Go to URL", blueFont).SetAction(new PdfAction("http://www.google.com/", false)));
doc.NewPage();
doc.Add(new Chunk("Go to Test", blueFont).SetLocalGoto("entry1"));
doc.NewPage();
doc.Add(new Chunk("Test").SetLocalDestination("entry1"));
doc.Close();
}
}
}
}

Categories

Resources