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
Related
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
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}}
I'm trying to convert a pdf file uploaded in Django to a jpg file. I would like to use the file directly in the InMemoryUploadedFile state.
I tried to use wand but without any success.
Here is the code I wrote:
from django.shortcuts import render
from wand.image import Image as wi
# Create your views here.
def readPDF(request):
context = {}
if request.method == 'POST':
uploaded_file = request.FILES['document']
if uploaded_file.content_type == 'application/pdf':
pdf = wi(filename=uploaded_file.name, resolution=300)
pdfImage = pdf.convert("jpeg")
return render(request, 'readPDF.html', {"pdf": pdfImage})
I tried different things like using uploaded_file.file or uploaded_file.name as the first argument for the wand image but without any success.`
I thank you in advance for your help!
Should be able to pass InMemoryUploadedFile directly to Wand's constructor.
uploaded_file = request.FILES['document']
if uploaded_file.content_type == 'application/pdf':
with wi(file=uploaded_file, resolution=300) as pdf:
# ...
However, I wouldn't recommend attempting to convert PDF pages to JPEGs in a HTTP request. Best to write the document to storage, and have a background worker manage the slow / unsafe tasks.
I think the correct way to have instance variables in Flask is by adding users and sessions, but I'm trying to test a concept and I don't want to go through all of that just yet. I'm trying to have a web app load an image into a variable that can then have different image operations performed on it. Obviously you don't want to have to keep performing a list of operations on the image on each new request because that would be horribly inefficient.
Is there a way of having an app.var in Flask that I can access from different routes? I've tried using the global context and Flask's current_app, but I get the impression that's not what they're for.
The code for my blueprint is:
import os
from flask import Flask, url_for, render_template, \
g, send_file, Blueprint
from io import BytesIO
from PIL import Image, ImageDraw, ImageOps
home = Blueprint('home', __name__)
#home.before_request
def before_request():
g.img = None
g.user = None
#home.route('/')
def index():
return render_template('home/index.html')
#home.route('/image')
def image():
if g.img is None:
root = os.path.dirname(os.path.abspath(__file__))
filename = os.path.join(root, '../static/images/lena.jpg')
g.img = Image.open(filename)
img_bytes = BytesIO()
g.img.save(img_bytes, 'jpeg')
img_bytes.seek(0)
return send_file(img_bytes, mimetype='image/jpg')
#home.route('/grayscale', methods=['POST'])
def grayscale():
if g.img:
print('POST grayscale request')
g.img = ImageOps.grayscale(img)
return "Grayscale operation successful"
else:
print('Grayscale called with no image loaded')
return "Grayscale operation failed"
The /image route returns the image correctly, but I'd like to be able to call /grayscale, perform the operation, and be able to make another call to /image and have it return the image from memory without loading it.
You could save a key in your session variable and use that to identify the image in a global dictionary. However this might lead to some trouble if you use multiple Flask application instances. But with one it would be fine. Otherwise you could use Redis when working with multiple workers. I haven't tried the following code but it should show the concept.
from flask import session
import uuid
app.config['SECRET_KEY'] = 'your secret key'
img_dict = {}
#route('/image')
def image():
key = session.get('key')
if key is None:
session['key'] = key = uuid.uuid1()
img_dict[key] = yourimagedata
#home.route('/grayscale', methods=['POST'])
def grayscale():
key = session.get('key')
if key is None:
print('Grayscale called with no image loaded')
return "Grayscale operation failed"
else:
img = img_dict[key]
print('POST grayscale request')
g.img = ImageOps.grayscale(img)
return "Grayscale operation successful"
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.