Since google vision has some restrictions on input image size, I want to first resize input image and then use the detect_labels() function.
Here's their sample code
def detect_labels(path):
"""Detects labels in the file."""
vision_client = vision.Client()
with io.open(path, 'rb') as image_file:
content = image_file.read()
image = vision_client.image(content=content)
labels = image.detect_labels()
print('Labels:')
for label in labels:
print(label.description)
they use io to open the image file. I wonder in this way, how to resize the image in memory and then call detect_labels() ?
You can resize the image via PIL/Pillow and then pass it to the client:
replace
with io.open(path, 'rb') as image_file:
content = image_file.read()
with
# Warning: untested code, may require some fiddling
import Image, StringIO
img = Image.open(path)
img.thumbnail((512, 512))
buffer = StringIO.StringIO()
img.save(buffer, "PNG")
content = buffer.getvalue()
Code for python3:
Credits : #kristaps
import io
from PIL import Image
img = Image.open(path)
img.thumbnail((512, 512))
buffer = io.BytesIO()
img.save(buffer, "JPEG")
content = buffer.getvalue()
Related
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()
I'm developing a GUI in Python using Tkinter to learn image processing. GUI's process flow would be as
Load image (jpg|png|...) => Resize/ thumbnail image (240 * 240) => Preview image
from Tkinter import *
import PIL
class Window:
def __init__(self, master):
master.title("Image Processing test")
master.minsize(800, 400)
from PIL import Image
im = Image.open("IMG_0562.png")
size = 240, 240
im.thumbnail(size)
p = im.tobytes()
# photo = PhotoImage(file="IMG_0562.gif")
# photo = BitmapImage(data=p)
w = Label(root, image=photo, width=240, height=240).grid(row=20, column=2)
self.photo = photo
root = Tk()
window = Window(root)
root.mainloop()
My problem is I couldn't get the image in a proper format to use it in Label. As Label only accepts PhotoImage and BitmapImage. PhotoImage doesn't support png or jpg file. So I used Image from PIL to load and resize my colored image. I've tried Image.tobitmap() and Image.tobytes() too but not useful in this case.
Solved the problem by saving the image in memory using io.BytesIO()
from Tkinter import *
from PIL import Image
import io
class Window:
def __init__(self, master):
master.title("Image Processing test")
master.minsize(800, 400)
im = Image.open("IMG_0562.png")
size = 240, 240
im.thumbnail(size)
b = io.BytesIO()
im.save(b, 'gif')
p = b.getvalue()
photo = BitmapImage(data=p)
w = Label(root, image=photo, width=240, height=240).grid(row=20, column=2)
self.photo = photo
root = Tk()
window = Window(root)
root.mainloop()
import shopify
from base64 import b64encode
#omitted the shopify key
shopify.ShopifyResource.set_site(shop_url)
path = "product.jpg"
new_product = shopify.Product()
new_product.title = "title"
new_product.body_html = "This is a test"
image = shopify.Image()
with open(path, "rb") as f:
filename = path.split("/")[-1:][0]
#encoded = b64encode(f.read()) (I tried this one as well)
encoded = f.read()
image.attach_image(encoded, filename=filename)
new_product.images = image
new_product.save()
I tested both methods:
encoded = b64encode(f.read())
encoded = f.read()
In both tests, the output was the same:
The product was successfully created, however, with no image.
I also noticed that the image returns image(None) and new_products.images returns image(None) as well.
You were so close- the new_product.images attribute must be a list of Image instances, not an Image instance. Also, if you look at the source of attach_image(), you can see they do the base64 encoding for you.
import shopify
#omitted the shopify key
shopify.ShopifyResource.set_site(shop_url)
path = "product.jpg"
new_product = shopify.Product()
new_product.title = "title"
new_product.body_html = "This is a test"
image = shopify.Image()
with open(path, "rb") as f:
filename = path.split("/")[-1:][0]
encoded = f.read()
image.attach_image(encoded, filename=filename)
new_product.images = [image] # Here's the change
new_product.save()
self.fake("products/632910392/images", method='POST', body=self.load_fixture('image'), headers={'Content-type': 'application/json'})
image = shopify.Image({'product_id':632910392})
image.position = 1
binary_in=base64.b64decode("R0lGODlhbgCMAPf/APbr48VySrxTO7IgKt2qmKQdJeK8lsFjROG5p/nz7Zg3MNmnd7Q1MLNVS9GId71hSJMZIuzTu4UtKbeEeakhKMl8U8WYjfr18YQaIbAf==")
image.attach_image(data=binary_in, filename='ipod-nano.png')
image.save()
I want to display an image produced by matplotlib in django.
I have a working solution but want to do it without writing to the disk.
Here is the code:
def __get_img_data1(): # not working - returns a white blank image
fig = plt.figure()
imgdata = StringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0)
content = imgdata.getvalue()
imgdata.close()
return content
def __get_img_data2(): # not working - returns a broken image
fig = plt.figure()
imgdata = StringIO.StringIO()
fig.savefig(imgdata, format='png')
imgdata.seek(0)
from PIL import Image
return Image.open(imgdata)
def __get_img_data3(): # working!
img_file = NamedTemporaryFile(delete=False)
plt.savefig(img_file.name, dpi=600)
img_data = open(img_file.name + '.png', 'rb').read()
os.remove(img_file.name)
os.remove(img_file.name + '.png')
return img_data
I have taken 3 approaches shown above.
How to make it work without writing to the disk?
It is supposed to work according to the documentation:
http://matplotlib.org/faq/howto_faq.html
but it displays an empty white image.
uh, I figured out.
The problem is that I needed to get the figure object before doing my plotting.
This works:
def __get_png_img_buff(fig):
buff = StringIO.StringIO()
fig.savefig(buff, format='png')
buff.seek(0)
return buff
In order to resize images upon upload (using PIL), I'm overriding the save method for my Article model like so:
def save(self):
super(Article, self).save()
if self.image:
size = (160, 160)
image = Image.open(self.image)
image.thumbnail(size, Image.ANTIALIAS)
image.save(self.image.path)
This works locally but in production I get an error:
NotImplementedError: This backend doesn't support absolute paths.
I tried replacing the image.save line with
image.save(self.image.url)
but then I get an IOError:
[Errno 2] No such file or directory: 'https://my_bucket_name.s3.amazonaws.com/article/article_images/2.jpg'
That is the correct location of the image though. If I put that address in the browser, the image is there. I tried a number of other things but so far, no luck.
You should try and avoid saving to absolute paths; there is a File Storage API which abstracts these types of operations for you.
Looking at the PIL Documentation, it appears that the save() function supports passing a file-like object instead of a path.
I'm not in an environment where I can test this code, but I believe you would need to do something like this instead of your last line:
from django.core.files.storage import default_storage as storage
fh = storage.open(self.image.name, "w")
format = 'png' # You need to set the correct image format here
image.save(fh, format)
fh.close()
For me default.storage.write() did not work, image.save() did not work, this one worked. See this code if anyone is still interested. I apologize for the indentation. My project was using Cloudinary and Django small project.
from io import BytesIO
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage as storage
def save(self, *args, **kargs):
super(User, self).save(*args, **kargs)
# After save, read the file
image_read = storage.open(self.profile_image.name, "r")
image = Image.open(image_read)
if image.height > 200 or image.width > 200:
size = 200, 200
# Create a buffer to hold the bytes
imageBuffer = BytesIO()
# Resize
image.thumbnail(size, Image.ANTIALIAS)
# Save the image as jpeg to the buffer
image.save(imageBuffer, image.format)
# Check whether it is resized
image.show()
# Save the modified image
user = User.objects.get(pk=self.pk)
user.profile_image.save(self.profile_image.name, ContentFile(imageBuffer.getvalue()))
image_read = storage.open(user.profile_image.name, "r")
image = Image.open(image_read)
image.show()
image_read.close()
If you are working with cloud storages for files in Django
NotImplementedError: This backend doesn't support absolute paths
To fix it you need to replace file.path with file.name
For code in the the question: image.save(self.image.path) with image.save(self.image.name)
Here how it looks like in the console
>>> c = ContactImport.objects.last()
>>> c.json_file.name
'protected/json_files/data_SbLN1MpVGetUiN_uodPnd9yE2prgeTVTYKZ.json'
>>> c.json_file
<FieldFile: protected/json_files/data_SbLN1MpVGetUiN_uodPnd9yE2prgeTVTYKZ.json>
>>> c.json_file.url
'https://storage.googleapis.com/super-secret/media/api/protected/json_files/data_SbLN1MpVGetUiN_uodPnd9yE2prgeTVTYKZ.json?Expires=1631378947&GoogleAccessId=secret&Signature=ga7...'