Here is my code:
import Image
import sys
import json
if __name__ == '__main__':
args = json.loads(sys.argv[1])
srcPath = args.get('srcPath')
image = Image.open(srcPath)
sizes = {}
for variant_name, dimensions in args.get('sizes').items():
if '%' in dimensions:
sizes[variant_name] = image.size
else:
width = int(dimensions.split('x')[0])
height = int(dimensions.split('x')[1])
widthAndHeight = (width, height)
sizes[variant_name] = widthAndHeight
for key, val in sizes.items():
imageName = key + '.' + srcPath.split('.')[1]
convertedImage = image.resize(val, Image.ANTIALIAS)
image.save(imageName)
print 'done'
And I'm calling it with:
python image.py '{"sizes":{"large":"200x150","orig":"100%x100%"},"srcPath":"/Users/bobcobb/Desktop/avocado.png"}'
If the argument 100%x100% is passed in, then I want to resize to the original size, otherwise, I want to resize to the passed in size. So the above code would generate 2 images (one original, the other 200x150).
Right now, it just saves the image as the original size for both. How can I fix this?
Your problem is that the resized image is assigned to convertedImage, but you save the original image (at the new filename).
So changing this line
image.save(imageName)
into
convertedImage.save(imageName)
solves this problem.
Related
Use-case: I make a presentation in python-pptx and then manually go in and add some slide and then remember that I need to change one or more of the pictures. Then I want to be able to run the program again and have it replace the picture with the same name.
My problem is that sometimes it works, usually the first time, and the picture is replaced with the same descr but more often then not, it is replaced with image.png and because of this i am unable to find that picture the next time I try to replace. Does any one has any ideas? Here is my replace function:
def replace(self, newPic):
for slide in self.pres.slides:
for shape in slide.shapes:
try:
if shape._pic.nvPicPr.cNvPr.get('descr') == newPic:
top, left, width, height = shape.top, shape.left, shape.width, shape.height
self.deleteShape(shape)
img = slide.shapes.add_picture(self.inDir + "/" + newPic, left, top, width, height)
imgDescr = img._pic.nvPicPr.cNvPr.get('descr')
except AttributeError:
pass
I also tried the following,
def replace(self, newPic):
#If in list with every figure
for slide in self.pres.slides:
for shape in slide.shapes:
try:
if shape._pic.nvPicPr.cNvPr.get('descr') == newPic:
imgPic = shape._pic
imgRID = imgPic.xpath('./p:blipFill/a:blip/#r:embed')[0]
imgPart = shape.part.relatedpart(imgRID)
with open(self.inDir + "/" + newPic, 'rb') as f:
rImgBlob = f.read()
# replace
imgPart._blob = rImgBlob
except AttributeError:
pass
However here i got an attribute error
imgPart = shape.part.relatedpart(imgRID)
AttributeError: 'SlidePart' object has no attribute 'relatedpart'
I have created a PowerPoint master slide and I have a template where I'd like to replace the logo through code based on the client.
The thing is that whenever I insert the image through code, the image gets resized but does not respect the correct ratio, so it gets distorted in some cases. I have found a good answer from #scanny in this link here, which helped me a bit but not fully since I can now upload the images, but they still get distorted.
Here is my code
import collections.abc
from datetime import datetime
from logging import PlaceHolder
from pptx import Presentation
from pptx.util import *
from PIL import Image
import win32com.client as win32
import os
TEXT_PLACEHOLDER_TYPE = 2
OBJECT_PLACEHOLDER_TYPE = 7
PICTURE_PLACEHOLDER_TYPE = 18
# ------------- FUNCTIONS -------------
def _add_image(slide, placeholder_id, image_url):
placeholder = slide.placeholders[placeholder_id]
# Calculate the image size of the image
im = Image.open(image_url)
width, height = im.size
# Make sure the placeholder doesn't zoom in
placeholder.height = height
placeholder.width = width
# Insert the picture
placeholder = placeholder.insert_picture(image_url)
available_width = placeholder.width
available_height = placeholder.height
image_width, image_height = placeholder.image.size
placeholder_aspect_ratio = float(available_width) / float(available_height)
image_aspect_ratio = float(image_width) / float(image_height)
if placeholder_aspect_ratio > image_aspect_ratio:
available_width = int(image_aspect_ratio * available_height)
# ---otherwise shrink the height
else:
available_height = int(available_width/image_aspect_ratio)**
# ----------- PROGRAM START -----------
print("\n----PROGRAM STARTS HERE ----\n")
result_ppt = Presentation("data/TEMPLATE.pptx")
slide = result_ppt.slides[0]
for _ph in slide.placeholders:
print(f"NAME: {_ph.name}\n"
f"PLACEHOLDER TYPE: {_ph.placeholder_format.type}\n"
f"PLACEHODER ID: {_ph.placeholder_format.idx}\n"
f"ID: {_ph.shape_id}\n"
f"TYPE: {_ph.shape_type}\n")
# Handles IMAGE - Replacing company logo
if _ph.placeholder_format.type == PICTURE_PLACEHOLDER_TYPE:
# Makes sure we are only changing logos tagged with client_logo id
if _ph.name == "client_logo":
_add_image(slide=slide, placeholder_id=_ph.placeholder_format.idx, image_url="data/client_logo.png")
result_ppt.save("data/new_template.pptx")
And there it is! I can't make my images be not distorted no matter what I do.
One last thing is that inside the function that handles that I changed the
placeholder.width = int(image_aspect_ratio * available_height)
available_width = int(image_aspect_ratio * available_height)
Because for some reason using the placeholder.width was placing the images squished to the corner so I couldn't see it.
I am trying to generate a image which produces gif like effect by flushing the response continuously to the browser, I am relatively new to django/python and tried with following code testing for both text and image. The generator for text works fine but in case of image only first version of image is being generated.
I tried searching but can't find anything on this. I am confused how to proceed with this or if this is at all possible with django or If the idea is conceptually wrong.
Image Generator :
def refreshx():
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
size = (1000,500)
im = Image.new('RGB', size)
draw = ImageDraw.Draw(im)
red = (255,255,255)
text_pos = (10,30)
draw.text(text_pos, str(datetime.datetime.today()), fill=red)
buffer = StringIO.StringIO()
im.save(buffer, 'PNG')
yield buffer.getvalue()
time.sleep(5)
buffers = StringIO.StringIO()
ims = Image.new('RGB', size)
draws = ImageDraw.Draw(ims)
text_poss = (30,80)
draws.text(text_poss, 'dasdasdsa', fill=red)
print 'been there'
ims.save(buffers, 'PNG')
yield buffers.getvalue()
Text Generator :
def testgenerator():
yield str(datetime.datetime.today())
time.sleep(5)
yield str(datetime.datetime.today())
View Function :
def test(request):
#return HttpResponse(testgenerator());
return HttpResponse(refreshx(), mimetype="image/png")
EDIT :
I learned while researching that there's a concept called gifsocket, I'm looking into it..please suggest if anyone has experience with these
I'm learning Python and Django.
An image is provided by the user using forms.ImageField(). Then I have to process it in order to create two different sized images.
When I submit the form, Django returns the following error:
IOError at /add_event/
cannot identify image file
I call the resize function:
def create_event(owner_id, name, image):
image_thumb = image_resizer(image, name, '_t', 'events', 180, 120)
image_medium = image_resizer(image, name, '_m', 'events', 300, 200)
I get en error when image_resizer is called for the second time:
def image_resizer(image, name, size, app_name, length, height):
im = Image.open(image)
if im.mode != "RGB":
im = im.convert("RGB")
im = create_thumb(im, length, height)
posit = str(MEDIA_ROOT)+'/'+app_name+'/'
image_2 = im
image_name = name + size +'.jpg'
imageurl = posit + image_name
image_2.save(imageurl,'JPEG',quality=80)
url_image='/'+app_name+'/'+image_name
return url_image
Versions:
Django 1.3.1
Python 2.7.1
PIL 1.1.7
I'm trying to find the problem, but i don't know what to do. Thank you in advanced!
EDIT
I solved rewriting the function; now it creates the different images in batch:
I call the resize function:
url_array = image_resizer.resize_batch(image, image_name, [[180,120,'_t'], [300,200,'_m']], '/events/')
so:
image_thumb = url_array[0]
image_medium = url_array[1]
and the resize function:
def resize_batch(image, name, size_array, position):
im = Image.open(image)
if im.mode != "RGB":
im = im.convert("RGB")
url_array = []
for size in size_array:
new_im = create_thumb(im, size[0], size[1])
posit = str(MEDIA_ROOT) + position
image_name = name + size[2] +'.jpg'
imageurl = posit + image_name
new_im.save(imageurl,'JPEG',quality=90)
new_url_array = position + image_name
url_array.append(new_url_array)
return url_array
Thanks to all!
As ilvar asks in the comments, what kind of object is image? I'm going to assume for the purposes of this answer that it's the file property of a Django ImageField that comes from a file uploaded by a remote user.
After a file upload, the object you get in the ImageField.file property is a TemporaryUploadedFile object that might represent a file on disk or in memory, depending on how large the upload was. This object behaves much like a normal Python file object, so after you have read it once (to make the first thumbnail), you have reached the end of the file, so that when you try to read it again (to make the second thumbnail), there's nothing there, hence the IOError. To make a second thumbnail, you need to seek back to the beginning of the file. So you could add the line
image.seek(0)
to the start of your image_resizer function.
But this is unnecessary! You have this problem because you are asking the Python Imaging Library to re-read the image for each new thumbnail you want to create. This is a waste of time: better to read the image just once and then create all the thumbnails you want.
I'm guessing that is a TemporaryUploadedFile ... find this with type(image).
import cStringIO
if isinstance(image, TemporaryUploadedFile):
temp_file = open(image.temporary_file_path(), 'rb+')
content = cStringIO.StringIO(temp_file.read())
image = Image.open(content)
temp_file.close()
I'm not 100% sure of the code above ... comes from 2 classes I've got for image manipulation ... but give it a try.
If is a InMemoryUploadedFile your code should work!
i have a problem when converting some Qimages to thumbnails using PIL.
to be used in a list widget , check the image below
where the image should look like :
please note that i use horizontal flow and the text of item is an empty text
one more thing : this only happens when i put more than 1 image
for i in listOfImages:
picture = Image.open(i)
picture.thumbnail((50,50), Image.ANTIALIAS )
qimage = QtGui.QImage(ImageQt.ImageQt(picture))
icon = QtGui.QIcon(QtGui.QPixmap.fromImage(qimage))
item = QtGui.QListWidgetItem(str(path))
item.setIcon(icon)
self.listWidget.addItem(item)
any idea what is going on ? and why images are being pixlated ?.. any better solutions
EDIT : using
pix = QtGui.QPixmap(path)
pix = pix.scaled(50,50,QtCore.Qt.KeepAspectRatio)
icon = QtGui.QIcon(pix)
will be very problematic (needed 10 seconds to run) while the code above needed 1 second.
thanks
from io import BytesIO
qimage = QtGui.QImage()
fp = BytesIO()
picture.save(fp, "BMP")
qimage.loadFromData(fp.getvalue(), "BMP")
icon ...
I had tried ImageQt, but the performance is not good.
I reference http://doloopwhile.hatenablog.com/entry/20100305/1267782841
Because I use python 3.3, cStringIO is replaced by BytesIO
I've not used PIL with PyQt. Have you tried using a QImageReader?
item = QListWidgetItem(image_path)
imageReader = QImageReader()
imageReader.setFileName(image_path)
size = imageReader.size()
size.scale(50, 50, Qt.KeepAspectRatio)
imageReader.setScaledSize(size)
image = imageReader.read()
pix = QPixmap.fromImage(image)
icon = QIcon(pix)
item.setIcon(icon)
self.listWidget.addItem(item)