Send PIL image to front without saving it - flask

I'm learning flask and i got stuck in this part.
I want to send a image to a img HTML tag without saving it...
here is where i got so far
PYTHON
def serve_pil_image(pil_img):
img_io = BytesIO()
pil_img.save(img_io, 'JPEG', quality=70)
img_io.seek(0)
return send_file(img_io, mimetype='image/jpeg')
#app.route('/upload', methods=["POST"])
def upload():
target = os.path.join(APP_ROOT, 'static/images')
# create image directory if not found
if not os.path.isdir(target):
os.mkdir(target)
# retrieve file from HTML -- NO SAVING
for upload in request.files.getlist("file"):
print('Getting ', upload)
img = Image.open(upload)
return render_template('processing.html')
#app.route('/static/images')
def serve_img():
img = poster
return serve_pil_image(img)
HTML
<img src="{{ url_for('serve_img', filename=img) }}" class="figure-img img-fluid rounded">

If you know a little JavaScript you could create a url within the window using createObjectURL. Store the blob content that got sent by Flask.send_file in the created object. Get a reference to the image tag, and make it point to the in memory url.

Related

How to include images in xhtml2pdf generated pdf files?

I am running a streamlit app which generates reports containing images and dataframes. I have used jinja2 to generate the html file from a template. Then, I would now like to convert to a pdf file using xhtml2pdf to download.
How to do that?
from jinja2 import Environment, FileSystemLoader
def convert_html_to_pdf(source_html, output_filename="temp/report.pdf"):
result_file = io.BytesIO()
pdf = pisa.CreatePDF(
source_html,
dest=result_file)
return pdf.getvalue()
def load_template():
env = Environment(loader=FileSystemLoader('templates'))
template = env.get_template('catAnalysisTemplate.html')
return template
def render_report(data, filename="report"):
template = load_template()
html = template.render(data)
# with open(f'temp/{filename}.html', 'w') as f:
# f.write(html)
pdf = convert_html_to_pdf(html)
return [html, pdf]
This works fine except the images are not included in the pdf file. My static images are stored in
img/
logo.png
and the charts I may generate it in memory as like
def plot_co_attainment(qp):
img = io.BytesIO()
data = qp.co_attainment()[["Level", "Perc_Attainment"]]
plt.figure(dpi=150)
plt.bar(data["Level"], data["Perc_Attainment"], width=0.5, color=colors)
for i, val in enumerate(data["Perc_Attainment"].values):
plt.text(i, val, str(val) + "%",
horizontalalignment='center',
verticalalignment='bottom',
fontdict={'fontweight': 500, 'size': 20})
plt.xlabel("Course Outcomes")
plt.ylabel("Percentage of Attainment")
plt.ylim((0, 110))
plt.savefig(buf, format='jpg')
return buf
How do I connect the dots and get the images in my pdf file?
I am having the same issue. The way I solved it was to use a link_handler and return the data as a data: uri containing the png image data.
This example will take the src attribute and use it to generate a square image in that color, which will be embedded in the PDF. Sadly this doesn't let you modify the image tag itself so you can't change the sizes/classes or anything else.
Using something like this opens the way to embedding just about anything without having to add them to your template directly.
from base64 import b64encode
from io import BytesIO
from xhtml2pdf import pisa
from PIL import Image
html_src = """
<body>
<div>
<img src="red"/>
<img src="green"/>
<img src="blue"/>
</div>
</body>
"""
def link_callback(src_attr, *args):
"""
Returns the image data for use by the pdf renderer
"""
img_out = BytesIO()
img = Image.new("RGB", (100, 100), src_attr)
img.save(img_out, "png")
return f"data:image/png;base64,{b64encode(img_out.getvalue())}"
def main():
with open("one.pdf", "wb") as f:
pizza = pisa.CreatePDF(
html_src,
dest=f,
link_callback=link_callback,
)
if __name__ == "__main__":
main()

Why are uploaded images via Django admin not showing up in the production server?

I have the following model field
logo = models.ImageField(upload_to=municipality_logo_file_name)
and function that uploads the image to the desired location.
def municipality_logo_file_name(instance, filename):
name, extension = os.path.splitext(filename)
return os.path.join('municipality', 'logo', str(uuid.uuid4()) + extension.lower())
In the development mode, a file uploads correctly to for example /media/municipality/logo/1e3cc24a-841b-4577-aa59-b53e5b10420b.png and then displays correctly in the template using
<img src="{{ municipality.logo.url }}" alt="Logo obce" style="max-height: 8rem; width: auto">
In the production, file uploads well, but does not display in the template and the url cannot be followed to display image, the response is
Not Found
The requested resource was not found on this server.
Using IIS and wfastcgi.py.
Any hint as to why this might be happening would be much appreciated.
Try this:
from django.conf import settings
from django.db import models
class Image(models.Model)
image = models.ImageField('Image', upload_to='video-image/')
#property
def image_url(self):
return '%s%s' % (settings.HOST, self.image.url) if self.image else ''

Flask app -how to display an image generated from within the app?

so I have some python code that generates an image inside my Flask app (can do it in JPG,PNG,etc..) and I want to display that image on my Flask app. the problem is that it needs to live in the 'static' folder,
and it is 'read only' - so I can't create the image inside it.
can I make the 'url_for' look inside other directories? or somehow write my image file into the 'static' folder in runtime?
I had a similar issue on one of my pet projects. I'm not sure if there's a better way to do it but I managed to get around it by encoding the image in base64 and passing the image tag to the html file directly via render_template(). Essentially:
import io
def serve_pil_image(pil_img):
img_io = io.BytesIO()
pil_img.save(img_io, 'jpeg', quality=100)
img_io.seek(0)
img = base64.b64encode(img_io.getvalue()).decode('ascii')
img_tag = f'<img src="data:image/jpg;base64,{img}" class="img-fluid"/>'
return img_tag
And in your flask app:
from PIL import Image
#app.route('/')
def index():
my_image = Image.open(image_file)
img_tag=serve_pil_image(my_image)
return render_template('index.html', image=img_tag)
And in your html:
{{image|safe}}

How can I serve an image in django?

I have a binary field to save images
photograph = models.BinaryField(default=None)
In my form, I save the image
photograph = cd['photograph'].file.getvalue(),
)
In My view
f = open('my.jpeg', 'bw')
myfile = File(f)
myfile.write(student.photograph)
filepath = os.path.abspath(os.path.realpath('my.jpeg'))
context['urls'] = filepath
return render(request, 'dashboard.html', context)
The image is saved to the database, it is being retrieved successfully.
Screenshot of the image being saved successfully
My template
The HTML in the template renders well.
If I copy the HTML into a local file, the image appears well and good.
However, the image doesn't load properly when I use django.
Right click > copy image address gives me this: about:blank#blocked
Is it a security or a permissions issue?
After much research, this is what I found.
in HTML
<img src = "data/image:jpeg;base64, {{base64_string}}/>
in view
from django.http import urlsafe_b64encode
return render(request, 'template.html', {'base64_string' : urlsafe_b64encode(myobject.photograph)
This works for development. For production, I guess static files could be served the django way.

Saving JPG format with PIL

I'm using PIL to make thumbnails of images I upload and everything is fine with PNGs or GIFs. However, uploading JPGs is giving me a headache. I kept getting a invalid format type for a while, and then I found this at the bottom of the JPG page on the PIL website...
Note: To enable JPEG support, you need to build and install the IJG
JPEG library before building the Python Imaging Library. See the
distribution README for details.
Anyway, so I deployed to Heroku and for some reason it seems to be no longer giving me the invalid format error that I had been getting on my local... except even though there is now a photo object living in the db, I can't seem to access them. I drop their location into into an image tag but I keep getting a broken image link symbol.
Here is what my override save looks like in models:
def save(self, force_update=False, force_insert=False, thumb_size=(90,150)):
image = Image.open(self.image)
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
# save the original size
self.image_width, self.image_height = image.size
image.thumbnail(thumb_size, Image.ANTIALIAS)
# save the thumbnail to memory
temp_handle = StringIO()
image.save(temp_handle, format='JPEG')
temp_handle.seek(0) # rewind the file
# save to the thumbnail field
suf = SimpleUploadedFile(os.path.split(self.image.name)[-1],
temp_handle.read(),
content_type='image/jpg')
self.thumbnail.save(suf.name, suf, save=False)
self.thumbnail_width, self.thumbnail_height = image.size
#save the image object
super(Photo, self).save(force_update, force_insert)