Reputation: 674
I am using render_to_string in django for parse an HTML and export to PDF.
html = render_to_string("etiquetaTNT.html", {
'context': context,
'barcode': b,
'barcodeimg': barcodeimg,
})
font_config = FontConfiguration()
HTML(string=html).write_pdf(response, font_config=font_config)
return response
I am trying to insert a barcode in PDF. I generate this barcode in a PNG.
br = barcode.get('code128', b, writer=ImageWriter())
filename = br.save(b)
barcodeimg = filename
But the PDF in template, not show the image.
<img class="logo" src="{{barcodeimg}}" alt="Barcode" />
I do not know the way to save the filename in the template that I want, and I do not know to show in the PDF, because any image is showed. For example, the logo, it is showed in HTML template but not in the PDF.
<img class="logo" src="{{logo}}" alt="TNT Logo" />
The libraries that I am using:
import barcode
from barcode.writer import ImageWriter
from django.http import HttpResponse
from django.template.loader import render_to_string
from weasyprint import HTML
from weasyprint.fonts import FontConfiguration
I do not want to use Reportlab, because I need to render a HTML, not a Canvas.
Upvotes: 0
Views: 2177
Reputation: 2015
Enhancing the solution provided by @tim-mccurrach, I have created a templatetag for it.
/app/templatetags/barcode_tags.py
from django import template
from io import BytesIO
import barcode
register = template.Library()
@register.simple_tag
def barcode_generate(uid):
rv = BytesIO()
# code = barcode.get('code128', b, writer=SVGWriter())
code = barcode.get('code128', uid,
writer=barcode.writer.SVGWriter())
code.write(rv)
rv.seek(0)
# get rid of the first bit of boilerplate
rv.readline()
rv.readline()
rv.readline()
rv.readline()
# read the svg tag into a string
svg = rv.read()
return svg.decode("utf-8")
And then In the template.html:
{% load barcode_tags %}
{% barcode_generate object.uid as barcode_svg %}
{{barcode_svg | safe}}
Upvotes: 0
Reputation: 6845
Think about what happens when you load a webpage. There is the initial request where the document is loaded, and then subsequent requests are made to fetch the images / other assets.
When you want to print some HTML to PDF using weasyprint
, weasyprint has to fetch all of the other images. Checking out the python-barcode
docs, br.save(b)
is just going to return literally just the filename, (which will be saved in your current working directory). So your html will look something like this:
<img class="logo" src="some_filename.svg" alt="Barcode" />
Quite how it fetches this will depend on how you have weasyprint
set up. You can check out django-weasyprint
which has a custom URL fetcher. But as things stand, weasyprint can't fetch this file.
There are a few ways you can fix this. But it depends alot on how you are deploying this. For example, heroku (as I understand it) doesn't have a local file system you can write to, so you would need to write the file to an external service like s3, and then insert the url for that into your template, which weasyprint
will then be able to fetch. However, I think there is probably a simpler solution we can use in this case.
Taking a look at the python-barcode
docs it looks like you can write using SVG.
This is good because we can insert SVG straight into our HTML template (and avoid having to fetch any other assets). I would suggest something like the following
from io import BytesIO
from barcode.writer import SVGWriter
# Write the barcode to a binary stream
rv = BytesIO()
code = barcode.get('code128', b, writer=SVGWriter())
code.write(rv)
rv.seek(0)
# get rid of the first bit of boilerplate
rv.readline()
rv.readline()
rv.readline()
rv.readline()
# read the svg tag into a string
svg = rv.read()
Now you'll just need to insert that string into your template. Just add it to your context, and render it as follows:
{{svg}}
Upvotes: 2