Im generating a PDF using FPDF which works fine, when certain conditions are met i want to be able to import an existing PDF (sometimes with multiple pages), what im finding though is the FPDI import is overwriting any existing FPDF page generation.
Here is some sample code
if($row['art'] <> '')
{
$datasubject = mysqli_query($link,"SELECT * from documents WHERE subject = 'Art'");
$rowsubject = mysqli_fetch_array($datasubject);
$pdf->AddPage("P","A4");
$pdf->SetY(30);
$pdf->cell(350,20,"Art Page",0,'C',false);
$pdf = new \setasign\Fpdi\Fpdi();
// set the source file
$pageCount = $pdf->setSourceFile("C:\\temp\\sourcedocuments\\Year 7\\art\\KS4 FINE ART KNOWLEDGE ORGANISER higher tier.pdf");
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
$tplIdx = $pdf->importPage($pageNo);
// add a page
$pdf->AddPage();
$pdf->useTemplate($tplIdx, null, null, 210, 300, true);
// font and color selection
$pdf->SetFont('Helvetica');
$pdf->SetTextColor(200, 0, 0);
}
}
Before it hits this "IF " statement FPDF creates a couple of static "Cover" pages but these are also overwritten by the imported document.
Moved $pdf = new \setasign\Fpdi\Fpdi(); from out of the "If" statement and replaced
$pdf = new FPDF(); with $pdf = new \setasign\Fpdi\Fpdi();
Related
We are currently building a proof of concept to generate PDF/UA compliant PDF from from a CSS and html (xhtml) file using xslt. We are able tag the PDF and add the appropriate metadata information.
The last major issue we are unable to solve is embedding a standard PDF font zapfdinbats, which our accessibility assessment tool complains about - using PAC 2.0 along with adobe DC built in checker.
As you can see from the image below the other fonts we are using seems automatically get embedded using the xmlworker from our CSS.
I have also tried finding the font as indicated and found one, however, it doesn't seem to be the correct one.
Here is a sample of our code
private static ReturnValue CreateFromHtml(string html)
{
ReturnValue Result = new ReturnValue();
var stream = new MemoryStream();
using (var doc = new Document(PageSize.LETTER))
{
using (var ms = new MemoryStream())
{
using (var writer = PdfWriter.GetInstance(doc, ms))
{
writer.CloseStream = false;
writer.SetPdfVersion(PdfWriter.PDF_VERSION_1_7);
//TAGGED PDFVERSION_1_7
//Make document tagged
writer.SetTagged();
//===============
//PDF/UA
//Set document metadata
writer.ViewerPreferences = PdfWriter.DisplayDocTitle;
doc.AddLanguage("en-US");
doc.AddTitle("document title");
writer.CreateXmpMetadata();
doc.Open();
var embedfont = HttpContext.Current.Server.MapPath("~/scripts/ZapfDingbats.ttf");
var fontProv = new XMLWorkerFontProvider();
fontProv.DefaultEncoding = "UTF-8";
fontProv.Register(embedfont);
//Testing zapfDingbats font
Font font = FontFactory.GetFont(embedfont, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Paragraph p1 = new Paragraph("Testing of Fonts", font);
doc.Add(p1);
//end font processing
var tagProcessors = (DefaultTagProcessorFactory)Tags.GetHtmlTagProcessorFactory();
tagProcessors.RemoveProcessor(HTML.Tag.IMG);
tagProcessors.AddProcessor(HTML.Tag.IMG, new CustomImageTagProcessor());
var cssFiles = new CssFilesImpl();
cssFiles.Add(XMLWorkerHelper.GetInstance().GetDefaultCSS());
var cssResolver = new StyleAttrCSSResolver(cssFiles);
var charset = Encoding.UTF8;
var context = new HtmlPipelineContext(new CssAppliersImpl(new XMLWorkerFontProvider()));
context.SetAcceptUnknown(true).AutoBookmark(true).SetTagFactory(tagProcessors);
var htmlPipeline = new HtmlPipeline(context, new PdfWriterPipeline(doc, writer));
var cssPipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
var worker = new XMLWorker(cssPipeline, true);
var xmlParser = new XMLParser(true, worker, charset);
using (var sr = new StringReader(html))
{
xmlParser.Parse(sr);
doc.Close();
ms.Position = 0;
ms.CopyTo(stream);
stream.Position = 0;
}
}
}
}
// get bytes from stream
Result.Data = stream.ToArray();
// success
Result.Success = true;
return Result;
}
Maybe there is something in the CSS we need to do (our CSS is quite large f
iText only ships with the Adobe Font Metrics (AFM) file of Zapfdingbats. This means that you can't embed that font unless you provide the corresponding PostScript Font Binary (PFB) file. This PFB file can't be shipped with iText because iText doesn't have a license to do so.
The first step to solve this, is to:
purchase a Zapfdingbats license so that you get the PFB (If I recall correctly, it's a font owned by Adobe), or
use an alternative font when you want to insert special characters (check boxes, phone symbols,...) into your text (e.g. purchase a license for the AdobePiStd font that was used as a substitution font and use that font instead of Zapfdingbats).
In your case, you provided a font ZapfDingbats.ttf which you register with the XMLWorkerFontProvider. When you register this font, it can be recognized through an alias. If ZapfDingbats.ttf isn't picked up by XML Worker, there is probably a mismatch between the name of the font used in the PDF and the alias that was used when ZapfDingbats.ttf was registered.
What is the font name used for ZapfDingbats in the CSS? You should register ZapfDingbats using that name as alias.
I have to insert a an image in a pdf. That is, wherever I see a text 'Signature', I have to insert an signature image there . I can do by saying absolute positions .
But, I am looking for how to find the position of the word 'Signature' in the pdf and insert the image.
Appreciate ur help!
This is the working code:
using (Stream inputImageStream = new FileStream(#"C:\signature.jpeg", FileMode.Open, FileAccess.Read, FileShare.Read))
using (Stream outputPdfStream = new FileStream(#"C:\test\1282011\Result.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
var reader = new PdfReader(#"C:\Test\1282011\Input.pdf");
var stamper = new PdfStamper(reader, outputPdfStream);
var count = reader.NumberOfPages;
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(inputImageStream);
image.SetAbsolutePosition(300, 200); // Absolute position
image.ScaleToFit(200, 30);
PRTokeniser pkt = null;
string strpages = string.Empty;
System.Text.StringBuilder build = new System.Text.StringBuilder();
for (int i = 1; i <= count; i++)
{
var pdfContentByte = stamper.GetOverContent(i);
if (pdfContentByte != null)
{
pkt = new PRTokeniser(stamper.Reader.GetPageContent(i));
while (pkt.NextToken())
{
if (pkt.TokenType == PRTokeniser.TokType.STRING)
{
if (pkt.StringValue == "Signature")
{
pdfContentByte.AddImage(image);
}
}
}
}
}
stamper.Close();
}
}
After some googling, I found out that I could absolute position of text as follows:
extSharp.text.pdf.AcroFields fields = stamper.AcroFields;
IList<iTextSharp.text.pdf.AcroFields.FieldPosition> signatureArea = fields.GetFieldPositions("Signature");
iTextSharp.text.Rectangle rect= signatureArea.First().position;
iTextSharp.text.Rectangle logoRect = new iTextSharp.text.Rectangle(rect);
image.SetAbsolutePosition(logoRect.Width ,logoRect .Height );
But the variable , signatureArea is null all the time even when the pdf contains the word 'Signature'.
Any input..? :)
Jaleel
Check out PdfTextExtractor and specifically the LocationTextExtractionStrategy. Create a class in your project with the exact code for the LocationTextExtractionStrategy and put a breakpoint on the line return sb.ToString(); (line 131 in SVN) and take a look at the contents of the variable locationalResult. You'll see pretty much exactly what you're looking for, a collection of text with start and end locations. If your search word isn't on a line by itself you might have to dig a little deeper but this should point you in the right direction.
That was perfect Chris. I am able to find the text position and insert the signature. What I understood is , there is a list List<TextChunk> LocationalResult in the LocationTextExtractionStrategy class. The RenderText() method in LocationTextExtractionStrategy will add each text to the LocationalResult list.
Actually the list LocationalResult is a private list, I made it public to access it from outside.
I loop through each page of PDF document and call PdfTextExtractor.GetTextFromPage(reader, i, locationStrat); where i is the pagenumber. At this time all text in the page will be added to the LocationalResult with all the position information.
This is what I done . And it works perfect.
I have problems creating a template for my pdf documents in Zend_Pdf. I've followed the guide provided at http://framework.zend.com/manual/en/zend.pdf.pages.html but it doesn't seem to work since no footer text or logo are visible at any page except the first.
This is a sample of my code: (Note; the MTP constant is just the recalculate from mm to points)
//Create pdf object
$pdf = new Zend_Pdf();
//Create the first page
$page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);
/*HEADER*/
//insert logo at the top
$logo = Zend_Pdf_Image::imageWithPath(APPLICATION_PATH . '/../document_root/images/logotype.png');
$page->drawImage($logo, 22*MTP,274*MTP, 62*MTP, 289*MTP);
/*FOOTER*/
$footerStyle->setFont(Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA), 10);
$page->setStyle($footerStyle);
$page->drawText('Footer text', 33*MTP, 20*MTP, 'ISO-8859-1');
//save the page to pdf->pages
$pdf->pages[0] = $page;
//save the page as a template
$template = $pdf->pages[0];
//create the next page from template
$page1 = new Zend_Pdf_Page($template);
//save the next page to pdf->pages
$pdf->pages[] = $page1;
Have I completely misunderstood how this "template function" work in Zend_Pdf? I know that Zend_Pdf lacks quite a number of features compaired to some of the external pdf-generators (like FPDF) but still, there must be some way to make a basic header/footer for all pages right?
Try to use clone instead passing page as argument to a new page.
$page1 = clone $template;
or simply
$pdf->pages[] = clone $pdf->pages[0];
I'm having a problem trying to locate a PdfContentByte directly into an specific page. My problem is: I need to add an Image for each page (That works) and need to add a QRCode to each of the pages at the right bottom corner but this works only for the first Page and I don't know how to repeat it on the other ones.
This is my code:
public string GeneratePDFDocument(Atomic.Development.Montenegro.Data.Entities.Document document, Stamp stamp)
{
string filename = #"C:\Users\Sheldon\Desktop\Pdf.Pdf";
FileStream fs = new FileStream(filename, FileMode.Create);
iTextSharp.text.Document pdfDocument = new iTextSharp.text.Document(PageSize.LETTER, PAGE_LEFT_MARGIN, PAGE_RIGHT_MARGIN, PAGE_TOP_MARGIN, PAGE_BOTTOM_MARGIN);
iTextSharp.text.pdf.PdfWriter writer = iTextSharp.text.pdf.PdfWriter.GetInstance(pdfDocument, fs);
pdfDocument.Open();
int count = document.Pages.Count;
foreach (Page page in document.Pages)
{
Image img = Image.GetInstance(page.Image);
img.ScaleToFit(PageSize.LETTER.Width-(PAGE_LEFT_MARGIN + PAGE_RIGHT_MARGIN), PageSize.LETTER.Height-(PAGE_TOP_MARGIN + PAGE_BOTTOM_MARGIN));
pdfDocument.Add(img);
PlaceCodeBar(writer);
}
pdfDocument.Close();
writer.Close();
fs.Close();
return filename;
}
private static void PlaceCodeBar(iTextSharp.text.pdf.PdfWriter writer)
{
String codeText = "TEXT TO ENCODE";
iTextSharp.text.pdf.BarcodePDF417 pdf417 = new iTextSharp.text.pdf.BarcodePDF417();
pdf417.SetText(codeText);
Image img = pdf417.GetImage();
iTextSharp.text.pdf.BarcodeQRCode qrcode = new iTextSharp.text.pdf.BarcodeQRCode(codeText, 1, 1, null);
img = qrcode.GetImage();
iTextSharp.text.pdf.PdfContentByte cb = writer.DirectContent;
cb.SaveState();
cb.BeginText();
img.SetAbsolutePosition(PageSize.LETTER.Width-PAGE_RIGHT_MARGIN-img.ScaledWidth, PAGE_BOTTOM_MARGIN);
cb.AddImage(img);
cb.EndText();
cb.RestoreState();
}
So add it in your foreach (Page...) loop:
foreach (Page page in document.Pages)
{
Image img = Image.GetInstance(page.Image);
img.ScaleToFit(PageSize.LETTER.Width-(PAGE_LEFT_MARGIN + PAGE_RIGHT_MARGIN), PageSize.LETTER.Height-(PAGE_TOP_MARGIN + PAGE_BOTTOM_MARGIN));
pdfDocument.Add(img);
PlaceCodeBar(writer);
}
If this is a second pass on the same PDF (you've closed it then opened it again), use a PdfStamper rather than a PdfWriter. You can then get the direct content of each page rather than the one direct content that is reused (and reset) for each page.
PS: Drop the BeginText() and EndText() calls. Those operators should only be used when actually drawing text/setting fonts/etc. No line art. No images. The SaveState()/RestoreState() are good though. Definitely keep those.
I just figure out how to solve the problem. Just delete the cb.SaveState() and cb.RestoreState() and it put the image on the page is actually active.
I'm trying to load a existing pdf file, and fill this with database information. Loading the file and everything is working, except for writing data to the loaded page. It doesn't write text to the loaded page. If I add a new page en use a foreach to apply drawing to all pages, all added pages are written, except for the loaded one. Below is the code I'm using:
$pdf = Zend_Pdf::load('./documents/agreements/_root/gegevens.pdf'); // Load pdf
$pdf->pages = array_reverse($pdf->pages); // reverse pages
$pdf->pages[] = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_A4); // Add a page (A4)
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA); // Set font
foreach($pdf->pages as $page) // Apply settings+text to every page (total of 2)
{
$page->setFont($font, 36);
$page->setAlpha(0.25);
$page->drawText('LALALALALALALA', 62, 260, 'UTF-8');
}
$pdf->save('./documents/agreements/Gegevens_'.$this->school_id.'.pdf'); // Save file
I solved the problem: I created a new pdf file with different settings. Creating the pdf with the following settings (I use Acrobat PDFmaker Office COM Addin for word) did the trick. I guess the code was working after all, the pdf itself was causing the problems.
In word select save as PDF
Select the 'Quick and simple PDF' format
Change the settings in 'Adobe PDF conversion options':
Enable -> Convert document information
Enable -> Make PDF/A Compliant
Disable -> Create bookmarks from
Disable -> Convert Comments
Note: This regards saving a file as PDF in word. Other office applications aren't tested.
Try the following:
$pdf = Zend_Pdf::load('./documents/agreements/_root/gegevens.pdf'); // Load pdf
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA); // Set font
foreach($pdf->pages as $pid => $page) // Apply settings+text to every page (total of 2)
{
$myPage = new Zend_Pdf_Page($page);
$myPage->setFont($font, 36);
$myPage->setAlpha(0.25);
$myPage->drawText('LALALALALALALA', 62, 260, 'UTF-8');
$pdf->pages[$pid] = $page;
}
$pdf->save('./documents/agreements/Gegevens_'.$this->school_id.'.pdf'); // Save file
try this one.
$pdf->pages[i]->drawText('LALALALALALALA', 62, 260, 'UTF-8');