It's my first time using reportlab to generate pdfs, it's VERY hard for me to understand how it works (it took me a day to even put a sized SVG image :D)
I want to achieve a very basic pdf:
As you can see in the images: 1 cover page, then 2 pages with header and footer BUT header with text is only on the first page...
Text is not static at all, it can break up to 4-5 pages, in the future there could be another section with title with different text.
Also I think what is very hard is to set text's Frame.topPadding to be variable based on
header height... I can't even imagine how to do this xD
This is my code right now
I've achieved to do the first page, it was pretty easy, but when it came to Frames, PageTemplates and other, my head blew up...
def _header(self, canvas, doc, title=None):
# Save the state of our canvas so we can draw on it
canvas.saveState()
y_pad = 50
header_height = (y_pad * 2) + (self.styles['heading'].leading if text else 0)
header_frame = Frame(
x1=0,
y1=self.height - header_height,
width=self.width,
height=header_height,
topPadding=y_pad,
bottomPadding=y_pad
)
canvas.setFillColor(DARKGRAY)
canvas.rect(0, self.height - header_height, self.width, header_height, fill=1)
if text:
header_frame.addFromList([
Paragraph(text, self.styles['heading'])
], canvas)
# Release the canvas
canvas.restoreState()
def _dark_page(self, canvas, doc):
canvas.saveState()
canvas.setFillColor(DARKGRAY)
canvas.rect(0, 0, self.width, self.height, fill=1)
canvas.restoreState()
def _create(self):
doc = SimpleDocTemplate(
self.buffer,
topMargin=0,
rightMargin=0,
leftMargin=0,
bottomMargin=0,
pagesize=A4
)
story = []
# cover page template with dark background set by self._dark_page
main_page_template = PageTemplate(id='main', frames=[
Frame(0, 0, self.width, self.height, 0, 100, 0, 100)
], onPage=self._dark_page)
# basic page template for any further text about product
body_page_template = PageTemplate(id='body', frames=[
Frame(0, 0, self.width, self.height, 80, 120, 80, 120, showBoundary=1)
], onPage=lambda c,d: self._header(c, d, title='title title title title')
doc.addPageTemplates([main_page_template, body_page_template])
story.append(NextPageTemplate('main'))
logo = svg2rlg(LOGO_PATH)
logo.width = logo.minWidth() * 0.4
logo.height = logo.height * 0.4
logo.scale(0.4, 0.4)
# logo._showBoundary = 1
logo.hAlign = 'CENTER'
story.append(logo)
story.append(Spacer(width=0, height=80))
# maybe there's a way to position the image in the center between elements,
# like justify-content: between in css...
image = Image(self._get_product_image_path(), 320, 320)
story.append(image)
story.append(Spacer(width=0, height=80))
title = Paragraph(self.product.title, self.styles['heading'])
story.append(title)
if self.product.breed.name_latin:
story += [
Spacer(width=0, height=10),
Paragraph(self.product.breed.name_latin, self.styles['subheading'])
]
story.append(NextPageTemplate('body'))
story.append(PageBreak())
# actual text
story.append(Paragraph(text*4, self.styles['body']))
doc.build(story)
So the question is
How do I set header and footer on the page, and if page breaks, next page with same header and footer, but header without title until the last page of the PageTemplate?
I've tried to get page numbers in self._header doc argument, but it's returning the first page number of the PageTemplate, not every page, maybe there's a way to get a page number from 0(first page used by some template) to the last page used by this template?
THANKS in advance! It already took me 3 days to try to achieve this...
Related
I finally got my html2pdf to work showing my web page just how I want it in the pdf(Any other size was not showing right so I kept adjusting the format size until it all fit properly), and the end result is exactly what I want it to look like... EXCEPT even though my aspect ratio is correct for a landscape, it is still using a very large image and the pdf is not standard letter size (Or a4 for that matter), it is the size I set. This makes for a larger pdf than necessary and does not print well unless we adjust it for the printer. I basically want this exact image just converted to a a4 or letter size to make a smaller pdf. If I don't use the size I set though things are cut off.
Anyway to take this pdf that is generated and resize to be an a4 size(Still fitting the image on it). Everything I try is not working, and I feel like I am missing something simple.
const el = document.getElementById("test);
var opt = {
margin: [10, 10, 10, 10],
filename: label,
image: { type: "jpeg", quality: 0.98 },
//pagebreak: { mode: ["avoid-all", "css"], after: ".newPage" },
pagebreak: {
mode: ["css"],
avoid: ["tr"],
// mode: ["legacy"],
after: ".newPage",
before: ".newPrior"
},
/*pagebreak: {
before: ".newPage",
avoid: ["h2", "tr", "h3", "h4", ".field"]
},*/
html2canvas: {
scale: 2,
logging: true,
dpi: 192,
letterRendering: true
},
jsPDF: {
unit: "mm",
format: [463, 600],
orientation: "landscape"
}
};
var doc = html2pdf()
.from(el)
.set(opt)
.toContainer()
.toCanvas()
.toImg()
.toPdf()
.save()
I have been struggling with this a lot as well. In the end I was able to resolve the issue for me. What did the trick for me was setting the width-property in html2canvas. My application has a fixed width, and setting the width of html2canvas to the width of my application, scaled the PDF to fit on an A4 paper.
html2canvas: { width: element_width},
Try adding the above option to see if it works. Try to find out the width of your print area in pixels and replace element_width with that width.
For completeness: I am using Plotly Dash to create web user interfaces. On my interface I include a button that when clicked generates a PDF report of my dashboard. Below I added the code that I used for this, in case anybody is looking for a Dash solution. To get this working in Dash, download html2pdf.bundlemin.js and copy it to the assets/ folder. The PDF file will be downloaded to the browsers default downloads folder (it might give a download prompt, however that wasn't how it worked for me).
from dash import html, clientside_callback
import dash_bootstrap_components as dbc
# Define your Dash app in the regular way
# In the layout define a component that will trigger the download of the
# PDF report. In this example a button will be responsible.
app.layout = html.Div(
id='main_container',
children = [
dbc.Button(
id='button_download_report',
children='Download PDF report',
className='me-1')
])
# Clientside callbacks allow you to directly insert Javascript code in your
# dashboards. There are also other ways, like including your own js files
# in the assets/ directory.
clientside_callback(
'''
function (button_clicked) {
if (button_clicked > 0) {
// Get the element that you want to print. In this example the
// whole dashboard is printed
var element = document.getElementById("main_container")
// create a date-time string to use for the filename
const d = new Date();
var month = (d.getMonth() + 1).toString()
if (month.length == 1) {
month = "0" + month
}
let text = d.getFullYear().toString() + month + d.getDay() + '-' + d.getHours() + d.getMinutes();
// Set the options to be used when printing the PDF
var main_container_width = element.style.width;
var opt = {
margin: 10,
filename: text + '_my-dashboard.pdf',
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 3, width: main_container_width, dpi: 300 },
jsPDF: { unit: 'mm', format: 'A4', orientation: 'p' },
// Set pagebreaks if you like. It didn't work out well for me.
// pagebreak: { mode: ['avoid-all'] }
};
// Execute the save command.
html2pdf().from(element).set(opt).save();
}
}
''',
Output(component_id='button_download_report', component_property='n_clicks'),
Input(component_id='button_download_report', component_property='n_clicks')
)
Suppose I have a HTML that have some heading & text like:
Heading 1
text......
Heading 2
text.....
Heading 3
text.....
Now I have to print this template in PDF, during print out, I have to add index page which actually refer page number with heading. Means print out should be like this.
Heading 1 ....... 1 [page number]
Heading 2 ....... 2
Heading 3 ....... 3
Heading 1
text......
Heading 2
text.....
Heading 3
text.....
So here I want to know, how to know page number based on text in HTML, like heading 1 belong to which page number & for others.
Any suggestion or idea really appreciated.
pdfConverter.PdfFooterOptions.PageNumberTextFontSize = 10;
pdfConverter.PdfFooterOptions.ShowPageNumber = true;
Its done inside the body of this method :-
private void AddFooter(PdfConverter pdfConverter)
{
string thisPageURL = HttpContext.Current.Request.Url.AbsoluteUri;
string headerAndFooterHtmlUrl = thisPageURL.Substring(0, thisPageURL.LastIndexOf('/')) + "/HeaderAndFooterHtml.htm";
//enable footer
pdfConverter.PdfDocumentOptions.ShowFooter = true;
// set the footer height in points
pdfConverter.PdfFooterOptions.FooterHeight = 60;
//write the page number
pdfConverter.PdfFooterOptions.TextArea = new TextArea(0, 30, "This is page &p; of &P; ",
new System.Drawing.Font(new System.Drawing.FontFamily("Times New Roman"), 10, System.Drawing.GraphicsUnit.Point));
pdfConverter.PdfFooterOptions.TextArea.EmbedTextFont = true;
pdfConverter.PdfFooterOptions.TextArea.TextAlign = HorizontalTextAlign.Right;
// set the footer HTML area
pdfConverter.PdfFooterOptions.HtmlToPdfArea = new HtmlToPdfArea(headerAndFooterHtmlUrl);
pdfConverter.PdfFooterOptions.HtmlToPdfArea.EmbedFonts = cbEmbedFonts.Checked;
}
See this page for more details
http://www.expertpdf.net/expertpdf-html-to-pdf-converter-headers-and-footers/
This is actually a pretty tricky problem which ExpertPDF would have to provide specific functionality to make possible.
My solution (not expertpdf) for this was to calculate the layout of the PDF first, get the text to be used in the index for each page and then calculate the layout of the index page/s. Then I'm able to number the pages (including the index pages) then update the page numbers in the index.. This is the only way to handle template pages which span multiple pages themselves, index text which wraps to take up more than a single line, and indexes which span multiple pages.
Create a TextElement
TextElement te = new TextElement(xPos, yPos, width, ""Page &p; of &P;"", footerFont);
footerTemplate.AddElement(te);
The library will automatically replace the &p; tokens.
Dependency : Win2D
I am trying to generate a Livetile image from background task.
However, the generated PNG file only looks transparent, no single dot is painted at all.
So, I simplified the important code as below to test, yet no result was changed.
I imported Microsoft.Canvas.Graphics(+Effects,+Text),
Dim device As CanvasDevice = New CanvasDevice()
Dim width = 150, height = 150
Using renderTarget = New CanvasRenderTarget(device, width, height, 96)
Dim ds = renderTarget.CreateDrawingSession()
'ds = DrawTile(ds, w, h)
Dim xf As CanvasTextFormat = New CanvasTextFormat()
xf.HorizontalAlignment = CanvasHorizontalAlignment.Left
xf.VerticalAlignment = CanvasVerticalAlignment.Top
xf.FontSize = 12
renderTarget.CreateDrawingSession.Clear(Colors.Red)
ds.Clear(Colors.Blue)
ds.DrawText("hi~", 1, 1, Colors.Black, xf)
renderTarget.CreateDrawingSession.DrawText("hi~", 1, 1, Colors.Black, xf)
Await renderTarget.SaveAsync(Path.Combine(ApplicationData.Current.LocalFolder.Path, "_tile_150x150.png"))
End Using
The file is created, but it's filled with neither Red or Blue. No text at all. It's transparent with only 150x150 pixel canvas.
Is there any problem with the code? or any other reason?
Thanks a lot!
The CanvasDrawingSession ("ds" in your sample) needs to be Closed / Disposed before you call SaveAsync.
You can use "Using ds = renderTarget.CreateDrawingSession()" to do this for you - put the call to SaveAsync after "End Using".
From there you should use the same "ds" rather than call "CreateDrawingSession" multiple times.
We have generated a pdf in landscape mode with header and footer as part of the pdf. The header table and footer display fine in pdf using itextpdf5.1.1 jar. However when we update the jar to 5.5.3, the header table does not show only the footer shows. Below is the code snippet.
document = new Document(PageSize.A4.rotate(), 20, 20, 75, 20);
PdfCopy copy = new PdfCopy(document, new FileOutputStream(strPDFFile));
document.open();
PdfReader pdfReaderIntermediate =
new PdfReader(strIntermediatePDFFile);
numberOfPages = pdfReaderIntermediate.getNumberOfPages();
Font ffont = new Font(Font.FontFamily.UNDEFINED, 7, Font.NORMAL);
System.out.println("###### No. of Pages: " + numberOfPages);
for (int j = 0; j < numberOfPages; ) {
page = copy.getImportedPage(pdfReaderIntermediate, ++j);
stamp = copy.createPageStamp(page);
Phrase footer =
new Phrase(String.format("%d of %d", j, numberOfPages), ffont);
ColumnText.showTextAligned(stamp.getUnderContent(),
Element.ALIGN_CENTER, footer,
(document.right() - document.left()) /
2 + document.leftMargin(),
document.bottom() - 10, 0);
if (j != 1) {
headerTable = new PdfPTable(2);
headerTable.setTotalWidth(700);
headerTable.getDefaultCell().setFixedHeight(10);
headerTable.getDefaultCell().setBorder(Rectangle.NO_BORDER);
headerTable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_LEFT);
headerTable.addCell(new Phrase(String.format(header1), ffont));
headerTable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_RIGHT);
headerTable.addCell(new Phrase(String.format(header2), ffont));
headerTable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_LEFT);
headerTable.addCell(new Phrase(String.format(header3), ffont));
headerTable.getDefaultCell().setHorizontalAlignment(Element.ALIGN_LEFT);
headerTable.addCell(new Phrase(String.format(header5, j),
ffont));
headerTable.completeRow();
headerTable.writeSelectedRows(0, 5, 60.5f, 550,
stamp.getUnderContent());
}
stamp.alterContents();
copy.addPage(page);
}
document.close();
When we change the jar from 5.1.1 to 5.5.3 the header is lost. May be a change is needed in the way we call the header for the new jar.
Any inputs will be well appreciated.
Thanks.
You have cells with default padding (i.e. 2) and height 10, and you try to insert text at height 7. But 2 (top margin) + 7 (text height) + 2 (bottom margin) = 11, i.e. more than fits into your cell height 10. Thus, the text does not fit and is not displayed.
You can fix this by either
using a smaller font, e.g. 6, or
using a heigher cell, e.g. 11, or
using a smaller padding, e.g. 1:
headerTable.getDefaultCell().setPadding(1);
With any of these changes, your header shows.
I don't know in which way iText 5.1.1 handled this differently, but the behavior of current iText versions makes sense.
I have never scripted in photoshop before, so I am wondering if this is possible. The following is currently done manually for over than 300 files. The next time round is for 600 files, therefore I am looking into automating it.
Steps:
Make Image Size to 54pixels Hight and 500px Width -- Found that this is doable.
Align Image Left.
Create a text layer and insert text -- Found that this is doable.
Align Text layer 1px to the right of the image.
Trim empty space.
Would appreciate any help and pointers. Thanks.
This script will get you started: Note that in your request you didn't mention what what the original image was going to be and shrinking it to 500 x 54 is going to stretch it one way or another. Step 2, Align the image left, was omitted as you didn't mention what you are aligning this image to. I suspect you are dealing with a large image and what to shrink it down (as long as it's not smaller than 500 x 54) and work from there. I've also omitted stage 4 as I've hard coded the position of the text to be 1 px from the right hand edge (and it vertically centered with Arial font size 18)
Anhyoo.. you should be able to alter the script to your needs.
// set the source document
srcDoc = app.activeDocument;
//set preference units
var originalRulerPref = app.preferences.rulerUnits;
var originalTypePref = app.preferences.typeUnits;
app.preferences.rulerUnits = Units.POINTS;
app.preferences.typeUnits = TypeUnits.POINTS;
// resize image (ignoring the original aspect ratio)
var w = 500;
var h = 54;
var resizeRes = 72;
var resizeMethod = ResampleMethod.BICUBIC;
srcDoc.resizeImage(w, h, resizeRes, resizeMethod)
//create the text
var textStr = "Some text";
createText("Arial-BoldMT", 18.0, 0,0,0, textStr, w-1, 34)
srcDoc.activeLayer.textItem.justification = Justification.RIGHT
//set preference units back to normal
app.preferences.rulerUnits = originalRulerPref;
app.preferences.typeUnits = originalTypePref;
//trim image to transparent width
app.activeDocument.trim(TrimType.TRANSPARENT, true, true, true, true);
// function CREATE TEXT(typeface, size, R, G, B, text content, text X pos, text Y pos)
// --------------------------------------------------------
function createText(fface, size, colR, colG, colB, content, tX, tY)
{
// Add a new layer in the new document
var artLayerRef = srcDoc.artLayers.add()
// Specify that the layer is a text layer
artLayerRef.kind = LayerKind.TEXT
//This section defines the color of the hello world text
textColor = new SolidColor();
textColor.rgb.red = colR;
textColor.rgb.green = colG;
textColor.rgb.blue = colB;
//Get a reference to the text item so that we can add the text and format it a bit
textItemRef = artLayerRef.textItem
textItemRef.font = fface;
textItemRef.contents = content;
textItemRef.color = textColor;
textItemRef.size = size
textItemRef.position = new Array(tX, tY) //pixels from the left, pixels from the top
}
Everything you listed is doable in a script. I suggest you start by reading 'Adobe Intro To Scripting' in your ExtendScript Toolkit program files directory (e.g. C:\Program Files (x86)\Adobe\Adobe Utilities - CS6\ExtendScript Toolkit CS6\SDK\English)