How to fix repeating canvas.toBuffer or canvas.createPdfStream content - node-canvas

I'm using canvas.toBuffer in a loop to generate pdf for different content but all the generated pdf's have the same content. Below is a snippet of the loop I'm using.
for (const d of data) {
context.clearRect(0, 0, imageWidth, imageHeight);
context.drawImage(image, 0, 0, imageWidth, imageHeight);
context.fillText(d.name.toUpperCase(), 1685, 1556);
fs.writeFileSync(`./assets/certs/${d.email}.pdf`,canvas.toBuffer());
}
data is of type, Array<{name:String, email:String}>.
The name is supposed to print the name of each user on an image but It turns out all the pdfs generated have just the name of the first user.
I tried creating a ReadStream from the canvas but I end up with the same issue. Is there something I'm doing wrong or am I missing something ?

This is sort of a bug in node-canvas. It's not possible to reuse a PDF or SVG canvas after calling toBuffer() on it (https://github.com/Automattic/node-canvas/issues/1195).
As a work-around, you can make a new canvas in each iteration of the loop.

Related

Use different image from two PDF for create one PDF with FPDI/TCPDF

I would use two differents pages from two differents PDF for create one PDF with both pages combines.
For that I use FPDF and I have done this :
$finalPDF = new Fpdi();
$secondPDF = new Fpdi();
$personalizationPdfPath = "Path_of_my_first_PDF";
$templatePath = "Path_of_my_second_PDF";
$finalPDF->setSourceFile($templatePath);
$secondPDF->setSourceFile($personalizationPdfPath);
// Import the first page
$page1 = $pdfFinal->importPage(1, PdfReader\PageBoundaries::MEDIA_BOX);
// Import the second page of second PDF
$page2 = $secondPDF->importPage(2, PdfReader\PageBoundaries::MEDIA_BOX);
// Get the size
$dimension = $finalPDF->getTemplateSize($template_page);
// Add the page
$finalPDF->AddPage($dimension["orientation"], array($dimension["width"], $dimension["height"]));
// Apply the page1 on the finalPDF
$finalPDF->useTemplate($page1, 0, 0, $dimension["width"], $dimension["height"]);
// Apply the page2 on the finalPDF
$finalPDF->useTemplate($page2, 20, 28, $dimension["width"]*0.75, $dimension["height"]*0.75); //error
But when I run it, I have Template does not exist error. If I put $page1 instead of $page2 it work, both pages are combine. The first 100% size and second 75% size.
I don't know why the $page2 not working. I have used dd(dump die) to see the difference between both $pages, nothing revelant.
So I use an alternative, transform the $page2 into a picture and use AddImage method :
$imageFromPDF = "Path_of_my_image.jpg";
$finalPdf->Image($imageFromPDF, 35, 35, $dimension["width"]*0.70, $dimension["height"]*0.70, "JPG");
$pdfFinal->Output("F", "nameOfPdf");
It works good, but the quality is bad. I have read this subject but the quality still trash.
On both way, anyone has a good solution ?
Thanks
Just do it step by step. There's no need for 2 FPDI instances.
$pdf = new Fpdi();
// set the first document as the source
$pdf->setSourceFile($templatePath);
// then import the first page of it
$page1 = $pdf->importPage(1, PdfReader\PageBoundaries::MEDIA_BOX);
// now set the second document as the source
$pdf->setSourceFile($personalizationPdfPath);
// and import the second page of it:
$page2 = $pdf->importPage(2, PdfReader\PageBoundaries::MEDIA_BOX);
// to get the size of an imported page, you need to pass the
// value returned by importPage() and not an undefined variable
// such as $template_page!!
$dimensions = $pdf->getTemplateSize($page1); // or $page2?
// Add a page
$pdf->AddPage($dimension["orientation"], $dimension);
// ...now use the imported pages as you want...
// Apply the page1 on the finalPDF
$pdf->useTemplate($page1, 0, 0, $dimension["width"], $dimension["height"]);
// Apply the page2 on the finalPDF
$pdf->useTemplate($page2, 20, 28, $dimension["width"] * 0.75, $dimension["height"] * 0.75);
The values 20 and 28 looks odd to me but it's what you'd used.

Resize pdf document downloaded from API in Swift

After a week, I'm pretty sure this can't be done, but I thought I'd give it one last ditch effort.
I have an API that I call that returns a Data object in the response.result.value. That data is a full fledged PDF file. For instance if I call the API with Postman, and then click on save the result, I can open that saved file with any PDF viewer.
Now, that I the data object in my viewController, I can call
data.write(to: pdfURL) and it writes the file to the URL I specified.
At this point the PDF is still good, I can print that URL, and then in finder locate that file and again view it with any PDF viewer, no problem.
Here's where the problem happens. Lastly, I want to send that PDF file to a small label printer, the labels in the printer are 2" wide, and 1" high. The PDF file that I am getting from the API, creates the PDF in 8.5" x 11" size.
So when it is printed on the label, it shrinks the file to fit on the label making the text and images on the label so small that it can't be read.
I can't change the PDF coming from the API.
I can't change any more settings on the printer.
The only chance I have to "zoom in" on this is to change the document or page size of the PDF file.
I have tried getting a handle to the file that is written to disk, then getting its page and then setting its bounds.
But not the page is just blank. I know that PDF cord start with x=0,y=0 in the bottom left corner, so I've used both of these as my page size:
let page = CGRect(x: 0, y: 0, width: 85, height: 40)
let page = CGRect(x: 472, y: 707, width: 85, height: 40)
guard let data = response.result.value else {
print("Did not get PDF data from API")
return
}
let page = CGRect(x: 472, y: 707, width: 85, height: 40)
let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileName = "shelfTag.pdf"
let pdfURL = documentURL.appendingPathComponent("\(fileName)")
do {
print(pdfURL)
try data.write(to: pdfURL)
} catch {
print("Couldn't write PDF to file.)
}
if #available(iOS 11.0, *) {
let pdfDocument = PDFDocument(url: pdfURL)
let pdfPage = pdfDocument?.page(at: 0)
pdfPage?.setBounds(page, for: .mediaBox)
pdfDocument?.write(toFile: pdfURL.path)
} else {
// Fallback on earlier versions
}
Either the image and text is too small to read
or
The printed label is just blank.
PDF functionality in iOS is limited. You could use these classes to recreate a PDF of the desired size if you have access to the data on the PDF. https://developer.apple.com/documentation/uikit/1623915-uigraphicsbeginpdfpagewithinfo?language=objc
The other option is to use a 3rd party app like Foxit. There may be a free versions you could use.
Unfortunately, there is no easy answer!
This looks very promising to me: https://github.com/prachigauriar/ResizePDF
The author describes it this way:
"resizepdf is a tool for macOS that resizes PDFs! It’s written in Swift and is very simple. It has no external dependencies."
In my brief experimentation with it I found that although it's a Mac app intended as a command line tool I think it can be easily migrated to iOS.
I found that the app works but trivial bugs keep it from running right off the bat. (The test that runs on startup looks for a filename that is different from the one the asset has. Match that name on the asset to achieve success. It is not necessary to run the app as a command line tool -- it'll kick off a test task when run in Xcode.)

itext 7 c# how to clip an existing pdf

let's say I have a bunch of pdf files that I want to migrate into a new pdf. BUT the new pdf file is a table-structured file. And the content of the pdf files should fit in the first cell of a two-column-table.
I am not sure if the approach of working with tables is correct. I am open to any other solutions. All I want is at the end some custom text at the top, followed by pdf content and a checkbox on the right side. (One per pdf content)
What I have so far:
`
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
Document doc = new Document(pdfDoc, PageSize.A4);
doc.SetMargins(0f, 0f, 18f, 18f);
PdfReader reader = new PdfReader(src);
PdfDocument srcDoc = new PdfDocument(reader);
Table table = new Table(new float[] { 2f, 1f });
PdfFormXObject imagePage = srcDoc.GetFirstPage().CopyAsFormXObject(pdfDoc);
var image = new Image(imagePage);
Cell cell = new Cell().Add(image);
cell.SetHorizontalAlignment(HorizontalAlignment.LEFT);
cell.SetVerticalAlignment(VerticalAlignment.TOP);
table.AddCell(cell);
Table checkTable = new Table(2);
Cell cellCheck1 = new Cell();
cellCheck1.SetNextRenderer(new CheckboxCellRenderer(cellCheck1, "cb1", 0));
cellCheck1.SetHeight(50);
checkTable.AddCell(cellCheck1);
Cell cellCheck2 = new Cell();
cellCheck2.SetNextRenderer(new CheckboxCellRenderer(cellCheck2, "cb2", 1));
cellCheck2.SetHeight(50);
checkTable.AddCell(cellCheck2);
table.AddCell(checkTable);
doc.Add(table);
doc.Close();`
My Problem here is that the pdf content has still its margin. Which completely spoils the design. It is so frustrating, I appreciate any help.
You say
My Problem here is that the pdf content has still its margin. Which completely spoils the design.
PDFs (usually) don't know anything about margins. Thus, you have to detect the margins of the page to import first. You can do this by parsing the page content into an event listener that keeps track of the bounding box of drawing instructions, like the TextMarginFinder. Then you can reduce the source page to those dimensions. This can be done by means of the following method:
PdfPage restrictToText(PdfPage page)
{
TextMarginFinder finder = new TextMarginFinder();
new PdfCanvasProcessor(finder).ProcessPageContent(page);
Rectangle textRect = finder.GetTextRectangle();
page.SetMediaBox(textRect);
page.SetCropBox(textRect);
return page;
}
You apply this method in your code right before you copy the page as form XObject, i.e. you replace
PdfFormXObject imagePage = srcDoc.GetFirstPage().CopyAsFormXObject(pdfDoc);
by
PdfFormXObject imagePage = restrictToText(srcDoc.GetFirstPage()).CopyAsFormXObject(pdfDoc);
This causes the Image this XObject will be embedded in to have the correct size. Unfortunately it will be somewhat mispositioned because the restricted page still has the same coordinate system as the original one, merely its crop box defines a smaller section than before. To fix this, one has to apply an offset, one has to subtract the coordinates of the lower left corner of the page crop box which has become the XObject bounding box. Thus, add after instantiating the Image the following code:
Rectangle bbox = imagePage.GetBBox().ToRectangle();
image.SetProperty(Property.LEFT, -bbox.GetLeft());
image.SetProperty(Property.BOTTOM, -bbox.GetBottom());
image.SetProperty(Property.POSITION, LayoutPosition.RELATIVE);
Now the restricted page is properly positioned in your table cell.
Beware: The TextMarginFinder (as its name indicates) determines the margins by text alone. Thus, if the page contains other contents, too, e.g. decorations like a logo, this logo is ignored and might eventually be cut out. If you want such decorations, too, in your overviews, you have to use a different margin finder class.

IText PDFImage seems to shrink or disappear during new pages after upgrade from 2.1.7 to 5.5.5 (Java .jars)

I seem to have an issue after upgrading iText from 2.1.7 where the PDF seems to be missing or the image has shrunk between pages.
I'm wondering if this is a known issue or if there is something that I need to set in order to fix it.
Some context:
no real calculations have been changed when switching libraries.
the general structure is that we have a Document which has a pdfTable which holds a bunch of pdfImages.
changing between landscape and portrait produces different results.
the images are scaled down so that it will fit the page.
Edit: Sorry, my application was pretty big and does a bunch of work. I had to make a simple mock version before posting the problem
Sample Code (So the numbers are just examples that I used. I basically added a 800*600 Image 5 times using landscape position. I end up seeing only 3 pages when I am expecting 5.)
Note: Using portrait page size shows all 5 but it seems that the sizes vary for some reason.
ByteArrayOutputStream baos = createTemporaryOutputStream();
Document doc = newDocument();
PdfWriter writer = newWriter(doc, baos);
writer.setViewerPreferences(PdfWriter.ALLOW_PRINTING | PdfWriter.PageLayoutSinglePage);
//create page rectangle landscape
Rectangle page = new Rectangle(PageSize.A4.rotate());
doc.setPageSize(page);
doc.setMargins((float)36.0, (float)36.0, (float)36.0, (float)36.0);
doc.open();
//create element pdf table.
PdfPTable table = new PdfPTable(new float[]{(float) 770.0});
table.setWidthPercentage(100);
table.setSplitRows(true);
table.setSplitLate(false);
table.setHeaderRows(0);
// in my case I used 5 800*600 images (same picture)
//then I loop through them and create pdfcell
//and then add it to table which then gets added to the document
List<Image> hi = (List<Image>) model.get("images");
for (Image image : hi) {
com.itextpdf.text.Image pdfImage = com.itextpdf.text.Image.getInstance(image.getBytes());
pdfImage.scalePercent((float) (0.8642384 * 100));
PdfPCell cell = new PdfPCell(pdfImage, false);
table.addCell(cell);
}
doc.add(table);
doc.close();

How to move text written in Type 3 Font from one pdf to other pdf?

I have a pdf which include text written in Type 3 Font.
I want to get some text from it and write it into other pdf in exactly same shape.
I am using itext. Please give me a tip.
edit: I attached my code.
DocumentFont f = renderInfo.getFont();
String str = renderInfo.getText();
x = renderInfo.getBaseline().getStartPoint().get(Vector.I1);
In this code, I want to write str into x value position.
In Type 3 Font, is it work?
You can copy parts of one page to a new one using code like this:
InputStream resourceStream = getClass().getResourceAsStream("from.pdf");
PdfReader reader = new PdfReader(new FileOutputStream("from.pdf"));
Rectangle pagesize = reader.getPageSizeWithRotation(1);
Document document = new Document(pagesize);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("areaOfFrom.pdf"));
document.open();
PdfContentByte content = writer.getDirectContent();
PdfImportedPage page = writer.getImportedPage(reader, 1);
content.saveState();
content.rectangle(0, 350, 360, 475);
content.clip();
content.newPath();
content.addTemplate(page, 0, 0);
content.restoreState();
document.close();
reader.close();
This turns your
into
Unfortunately, though, that hidden content is merely... hidden... but it is still there. You can especially mark the lines with that hidden text and try to copy&paste them.
If you want to completely remove that hidden text (or start out by merely copying the desired text), you have to inspect the content of the imported page and filter it. I'm afraid iText does not yet explicitly support something like that. It can be done using the iText lowlevel API but it is quite some work.