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

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}}

Related

Django Reportlab getKeepWithNext

I am trying to add an image to a PDF generated in Reportlab. I am trying to access the image from a Django field, specifying the full path of the file.
When I run the below code I get: "Exception Value: getKeepWithNext".
Any help as to what I am doing wrong would be greatly appreciated.
def holding_pdf(self, course_slug, holding_slug):
buffer = io.BytesIO()
holding = HoldingDetail.objects.get(identifier=holding_slug)
doc = SimpleDocTemplate(buffer,
rightMargin=72,
leftMargin=72,
topMargin=72,
bottomMargin=72,
pagesize=A4,
title=f"Why the {holding.name} is in the portfolio.pdf")
elements = []
styles = getSampleStyleSheet()
elements.append(Paragraph(str(holding.logo.path), styles['Normal']))
elements.append(Image(holding.logo.path))
print(holding.logo.path)
doc.build(elements)
buffer.seek(0)
return FileResponse(buffer, as_attachment=False, filename=f"Why the {holding.name} is in the portfolio.pdf")
I think that you're using an incorrect Image class. Verify the python imports in your file, and sure you use the Image flowable class provides by reportlab.
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import Paragraph, SimpleDocTemplate, Image

pgmagick image object to blob

Is there a way I can convert the Image() object to blob?
If I want to serve an image which is created by pgmagick to a HTTP request without writing it on the disk, I see converting the image object to blob and then streaming back to the request is the only option.
Let me know if there are any alternatives to achieve this.
Below is the code sample which creates an image.
from flask import Flask
from pgmagick import Image, Geometry, Color, \
DrawableText
app = Flask(__name__)
#app.route("/")
def hello():
image = Image(Geometry(300,300), Color("yellow"))
image.fontPointsize(30)
text = DrawableText(30,200, "hello stackoverflow")
image.draw(text)
#return image.Blob() # is there any similar functions?
if __name__ == "__main__":
app.run()
I am looking for a wrapper on this:
http://www.graphicsmagick.org/api/blob.html#imagetoblob

Django admin upload and image to s3 and then resize the image and save a thumb problem

I am having error after error trying to upload and resize images to s3 with pil and botos3 and the django default_storage. I am trying to do this on save in the admin.
here is the code:
from django.db import models
from django.forms import CheckboxSelectMultiple
import tempfile
from django.conf import settings
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage as s3_storage
from django.core.cache import cache
from datetime import datetime
import Image, os
import PIL.Image as PIL
import re, os, sys, urlparse
class screenshot(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200)
image = models.ImageField(upload_to='screenshots')
thumbnail = models.ImageField(upload_to='screenshots-thumbs', blank=True, null=True, editable=False)
def save(self):
super(screenshot, self).save() # Call the "real" save() method
if self.image:
thumb = Image.open(self.image.path)
thumb.thumbnail(100, 100)
filename = str(self.slug)
temp_image = open(os.path.join('tmp',filename), 'w')
thumb.save(temp_image, 'JPEG')
from django.core.files import File
thumb_data = open(os.path.join('/tmp',filename), 'r')
thumb_file = File(thumb_data)
new_file.thumb.save(str(self.slug) + '.jpg', thumb_file)
def __str__(self):
return self.title
This is just one of the many ways I have tried to get it working, and I either get (2, 'No such file or directory') or some other error.
Please can someone help me to get it working. I want it to use the django backend to get the image uploaded to be resized and saved as the thumbnail and then saved. Let me know if you need to know any information. I would be happy to use the django snippet - http://djangosnippets.org/snippets/224/ but I don't know what data to feed it. I get the same IOErrors and 'no such path/filename' even though the main image is uploading to s3 fine. I have also tried things like:
myimage = open(settings.MEDIA_URL + str(self.image))
myimage_io = StringIO.StringIO()
imageresize = myimage.resize((100,100), Image.ANTIALIAS)
imageresize.save('resize_100_100_aa.jpg', 'JPEG', quality=75)
It's been 3 days of looking now so I am starting to go spare! Thanks
I had a similar problem, but in my case using sorl-thumbnail was not an option. I found that I can open an Image directly from S3BotoStorage by passing in a file descriptor instead of a path.
So instead of
thumb = Image.open(self.image.path)
use
thumb = Image.open(s3_storage.open(self.image.name))
Then you can process and save the new file locally as you were doing before.
Why don't you try sorl-thumbnail. It has the exact same interface as the default ImageField django provides and it seems like it would be a lot nicer to work with than the roll-your-own support.
Storage support
Pluggable Engine support (PIL, pgmagick)
Pluggable Key Value Store support (redis, cached db)
Pluggable Backend support
Admin integration with possibility to delete
Dummy generation
Flexible, simple syntax, generates no html
ImageField for model that deletes thumbnails
CSS style cropping options
Margin calculation for vertical positioning

Django - Saving thumbnail with different filename

I want to create thumbnails of uploaded image files and save them with "_th" at the end of the filename. Currently, I am using the following code:
def _create_thumbnail(img_path):
image = Image.open(img_path)
if image.mode not in ("L", "RGB"):
image = image.convert("RGB")
image.thumbnail(MEDIA_THUMBNAIL_SIZES, Image.ANTIALIAS)
return image.save(img_path, 'JPEG', quality=MEDIA_THUMBNAIL_QUALITY)
It overwrites the original file. Is there a way to easily change the name of the file to include _th before the file extension and save it in the same place?
Also, I am saving the thumbnail after the post save signal using the following method:
#receiver(post_save, sender=Media, dispatch_uid="media_create_thumb")
def create_media_thumbnail(sender, **kwargs):
thumb = generate_thumbnail(kwargs['instance'].file)
I was wondering if this is an ok (pythonic?) way of using signals? Since I am not using the django admin panel, using the admins post save isn't an option.
This method to create thumbnails will be open to users, so if there is anything about the above code which might cause problems, I'd appreciate the heads up!
I would try the following:
import os
(head, tail) = os.path.split(img_path)
(name,ext)=tail.split('.')
tail=name+'_th.'+ext
img_path=os.path.join(head,tail)
edit:
as i found out recently, you can even shortcut that:
(name,ext)=os.path.splitext(img_path)
img_path = name + '_th.' + ext

Storing Images on App Engine using Django

I'm trying to upload and save a resized image in a db.BlobProperty field on Google App Engine using Django.
the relevant part of my view that process the request looks like this:
image = images.resize(request.POST.get('image'), 100, 100)
recipe.large_image = db.Blob(image)
recipe.put()
Which seems like it would be the logical django equivalent of the example in the docs:
from google.appengine.api import images
class Guestbook(webapp.RequestHandler):
def post(self):
greeting = Greeting()
if users.get_current_user():
greeting.author = users.get_current_user()
greeting.content = self.request.get("content")
avatar = images.resize(self.request.get("img"), 32, 32)
greeting.avatar = db.Blob(avatar)
greeting.put()
self.redirect('/')
(source: http://code.google.com/appengine/docs/python/images/usingimages.html#Transform)
But, I keep getting an error that says: NotImageError / Empty image data.
and refers to this line:
image = images.resize(request.POST.get('image'), 100, 100)
I'm having trouble getting to the image data. Seems like it's not being uploaded but I can't figure out why. My form has the enctype="multipart/form-data" and all that. I think something's wrong with how I'm referring to the image data. "request.POST.get('image')" but I can't figure out how else to reference it. Any ideas?
Thanks in advance.
After some guidance from "hcalves" I figured out the problem. First of all, the default version of Django that comes bundled with App Engine is version 0.96 and how the framework handles uploaded files has changed since then. However in order to maintain compatibility with older apps you have to explicitly tell App Engine to use Django 1.1 like this:
from google.appengine.dist import use_library
use_library('django', '1.1')
You can read more about that in the app engine docs.
Ok, so here's the solution:
from google.appengine.api import images
image = request.FILES['large_image'].read()
recipe.large_image = db.Blob(images.resize(image, 480))
recipe.put()
Then, to serve the dynamic images back again from the datastore, build a handler for images like this:
from django.http import HttpResponse, HttpResponseRedirect
def recipe_image(request,key_name):
recipe = Recipe.get_by_key_name(key_name)
if recipe.large_image:
image = recipe.large_image
else:
return HttpResponseRedirect("/static/image_not_found.png")
#build your response
response = HttpResponse(image)
# set the content type to png because that's what the Google images api
# stores modified images as by default
response['Content-Type'] = 'image/png'
# set some reasonable cache headers unless you want the image pulled on every request
response['Cache-Control'] = 'max-age=7200'
return response
You access uploaded data via request.FILES['field_name'].
http://docs.djangoproject.com/en/dev/topics/http/file-uploads/
Reading more about Google's Image API, seems to me you should be doing something like this:
from google.appengine.api import images
image = Image(request.FILES['image'].read())
image = image.resize(100, 100)
recipe.large_image = db.Blob(image)
recipe.put()
request.FILES['image'].read() should work because it's supposed to be a Django's UploadedFile instance.