insert image in text widget without using imageTK - python

Unfortunately I'm developing under a osx machine where I've been unable to install imageTK...
I need to insert an image taken from a dictionary of images, saved thus:
i = open(filename, 'rb')
i.seek(0)
w = i.read()
i.close()
allicons[d]=w
so at insert time I don't have a filename, just the dict.
with imageTk, this works:
c = cStringIO.StringIO()
c.write(allicons[key])
c.seek(0)
im = Image.open(c)
iconimage=ImageTk.PhotoImage(im)
config.text.image_create(INSERT, image=iconimage)
but I don't know how to do it without imageTk.
Just with "import Image", I tried:
im = Image.open(c)
iconimage = PhotoImage(im)
and iconimage is recognized (TkInter.PhotoImage object ...),
but inserting it I get a "TypeError: str returned non-string (type instance) ... in image_create *self._options(cnf, kw))"
... any help really appreciated, thanks!
alessandro

PhotoImage has a 'data' option. You can supply it with gif data that's been encoded using base64. something like:
dat = base64.encodestring(allicons[key])
pic = PhotoImage(data=dat)
...

Related

Retrieve and show image from MongoDB using PyMongo

I am using PyMongo to retrieve collection data as dictionary and then trying to convert the image key's respective value from the dict to proper base64 encoded string to show the image, but it doesn't just work. When I use mongoengine, it works fine as the string returned from the latter is b64 encoded already, unlike PyMongo.
Following is my sample working Mongoengine code to retrieve a respective image and show as Pillow image:
from mongoengine import connect, Document, fields
import mongoengine
import io
import PIL.Image as Image
print(mongoengine.__version__)
# To save image
connect(db='video_analytics', host='127.0.0.1', port=27017)
class User(Document):
meta = {"collection": "users"}
username = fields.StringField(required=True)
profile_image = fields.ImageField(thumbnail_size=(150, 150, False))
user = User.objects(username='Doggy').first()
# print(user)
img_data = user.profile_image.read()
# Test
print(img_data)
# Ends
bytes = bytearray(img_data)
image = Image.open(io.BytesIO(bytes))
print(image)
# image.show()
And following is my PyMongo code which gives no error but doesn't show the image:
client = MongoClient("mongodb://127.0.0.1:27017/")
# select database
db = client['frame_read']
# select the collection within the database
test = db["random"]
# print("collections count -->" + str(test.count()))
cursor = test.find()
for rec in cursor:
# print(rec['profile_image'])
f = rec['profile_image']
img = Image.open(f)
print(img.size)
img.show()
I tried many ways, but it is just not working. Here I read by default MongoDB stores in BSON bytes format. Is there a way how to retrieve data properly?
I followed this too, but to no avail.
Note: I'm intentionally not using GridFS because my image size is much lesser than 16 MB. If you say GridFS is still better performant for retrieval, then I shall plan using the same.

unotools insert image into document (libreoffice)

I'm trying to insert an image into a libreoffice document that is handled/controlled by unotools.
Therefore I start LibreOffice with this command:
soffice --accept='socket,host=localhost,port=8100;urp;StarOffice.Service'
Inside my python code I can connect to LibreOffice:
from unotools import Socket, connect
from unotools.component.writer import Writer
context = connect(Socket('localhost', 8100))
writer = Writer(context)
(This code is taken from this documentation: https://pypi.org/project/unotools/)
By using writer.set_string_to_end() I can add some text to the document. But I also want to insert an image into the document. So far I couldn't find any resource where this was done. The image is inside of my clipboard, so ideally I want to insert the image directly from there. Alternatively I can save the image temporarily and insert the saved file.
Is there any known way how to insert images by using unotools? Any alternative solution would also be great.
I've found a way to insert images by using uno instead of unotools:
import uno
from com.sun.star.awt import Size
from pythonscript import ScriptContext
def connect_to_office():
if not 'XSCRIPTCONTEXT' in globals():
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext(
'com.sun.star.bridge.UnoUrlResolver', localContext )
client = resolver.resolve("uno:socket,host=localhost,port=8100;urp;StarOffice.ComponentContext" )
global XSCRIPTCONTEXT
XSCRIPTCONTEXT = ScriptContext(client, None, None)
def insert_image(doc):
size = Size()
path = uno.systemPathToFileUrl('/somepath/image.png')
draw_page = self.doc.DrawPage
image = doc.createInstance( 'com.sun.star.drawing.GraphicObjectShape')
image.GraphicURL = path
draw_page.add(image)
size.Width = 7500
size.Height = 5000
image.setSize(size)
image.setPropertyValue('AnchorType', 'AT_FRAME')
connect_to_office()
doc = XSCRIPTCONTEXT.getDocument()
insert_image(doc)
sources:
https://ask.libreoffice.org/en/question/38844/how-do-i-run-python-macro-from-the-command-line/
https://forum.openoffice.org/en/forum/viewtopic.php?f=45&t=80302
I still don't know how to insert an image from my clipboard, I worked around that problem by saving the image first. If someone knows a way to insert the image directly from the clipboard that would still be helpful.

AWS Rekognition detect label Invalid image encoding error

I am using boto3 to make calls to recognition's detect label method which takes an image (in form of base64-encoded bytes) as an input. However I keep getting InvalidImageFormatException and I don't see why. I have read the documentation and looked at some examples but I really can't figure out why I am receiving this error.
Below is my code and what I've tried so far
self.rekog_client = boto3.client('rekognition', 'us-east-1')
with open('abc100.jpg', "rb") as cf:
base64_image=base64.b64encode(cf.read()).decode("ascii")
#also tried this) ==> base64_image=base64.b64encode(cf.read())
resp = self.rekog_client.detect_labels(Image={'Bytes': base64_image})
Output/Exception:
botocore.errorfactory.InvalidImageFormatException: An error occurred(InvalidImageFormatException) when calling the DetectLabels operation: Invalid image encoding
Figured it out, the method actually required base64 encoded binary data, which wasn't really specified in the docs, the doc just said base64-encoded bytes.
self.rekog_client = boto3.client('rekognition', 'us-east-1')
with open('cat_pic600.jpg', "rb") as cf:
base64_image=base64.b64encode(cf.read())
base_64_binary = base64.decodebytes(base64_image)
resp = self.rekog_client.detect_labels(Image={'Bytes': base_64_binary})

How to update an ImageField in Django model with a new Image

In my project a user can upload an image and once it is saved I can run a post_save signal to modify the image using Pillow. And after modifying the image I need to replace the existing image with the new image. Now the issue is if I run the save method in the post_save signal it will lead to maximum recursion error.So instead of this I am thinking of using update method but it throws an error regarding the characters in the file.
Below is the code:
def menuImageLocation(instance,filename):
return "%s/%s"%(instance,filename)
class restaurantMenuImage(models.Model):
restaurant = models.ForeignKey(restaurantCreateUpdate)
title = models.CharField(max_length=100,null=True,blank=True)
menuImage = models.ImageField(upload_to=menuImageLocation,null=True,blank=True,verbose_name="Menu Image")
def __unicode__(self):
return str(self.restaurant)
#receiver(post_save,sender=restaurantMenuImage)
def modifyMenuImage(sender,instance,**kwargs):
getRestaurant = restaurantCreateUpdate.objects.get(restaurantName=instance.restaurant)
image_path = instance.menuImage.path
filename = os.path.basename(image_path)
image_hold = Image.open(image_path)
image = image_hold.resize((300,300),Image.ANTIALIAS)
temp_loc = "%s/%s/%s/tmp"%(settings.MEDIA_ROOT,"menu",getRestaurant.uniqueID)
if not os.path.exists(temp_loc):
os.makedirs(temp_loc)
temp_file_path = os.path.join(temp_loc,filename)
if os.path.exists(temp_file_path):
temp_path = os.path.join(temp_loc,"%s" %(random.random()))
os.makedirs(temp_path)
temp_file_path = os.path.join(temp_path,filename)
temp_image = open(temp_file_path,"w")
image.save(temp_image,quality=80)
temp_data = open(temp_file_path,"r")
image_file = File(temp_data)
instance.menuImage.save(filename, image_file)
So if I run the last line of the code, this will result into maximum recursion error, and instead of using save method I am trying to use update method the file path but for that I am getting the error that the characters exceed the max_length of the "image_file". Will appreciate any help.
Before you run the last line, add a check if the image path of the instance is not the same as the new image path. Then the code will only run once. Your problem occurs, because the code in your post_save signal is always run when you call save on your model, which creates an endless loop. So you need to be careful when you call save in your post_save signal method.
Something like this should help:
if instance.menuImage != image_file:
instance.menuImage.save(filename, image_file)

Django ReportLab: using Drawing object to create PDF and return via Httpresponse

In ReportLab, Drawing object can be written into different renderers, e.g
d = shapes.Drawing(400, 400)
renderPDF.drawToFile(d, 'test.pdf')
and in Django, Canvas object can be sent via httpresponse, e.g.:
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'filename=test.pdf'
c = canvas.Canvas(response)
in my case, my problem is that I have a reportLab script using Drawing object which saves to local file system. I now put it in Django views, and wondering whether there is a way to not save to local file system but instead sent back to client.
I hope I describe this question clearly.
Thanks for any advice!
updates
it turns out there is a function in renderPDF:
renderPDF.draw(drawing, canvas, x, y)
which can render drawing() object in the given canvas.
Using ReportLab in Django without saving to disk is actually pretty easy. There are even examples in the DjangoDocs (https://docs.djangoproject.com/en/dev/howto/outputting-pdf)
The trick basically boils down to using a "file like object" instead of an actual file. Most people use StringIO for this.
You could do it pretty simply with
from cStringIO import StringIO
def some_view(request):
filename = 'test.pdf'
# Make your response and prep to attach
response = HttpResponse(mimetype='application/pdf')
response['Content-Disposition'] = 'attachment; filename=%s.pdf' % (filename)
tmp = StringIO()
# Create a canvas to write on
p = canvas.Canvas(tmp)
# With someone on
p.drawString(100, 100, "Hello world")
# Close the PDF object cleanly.
p.showPage()
p.save()
# Get the data out and close the buffer cleanly
pdf = tmp.getvalue()
tmp.close()
# Get StringIO's body and write it out to the response.
response.write(pdf)
return response
it turns out there is a function in renderPDF:
renderPDF.draw(drawing, canvas, x, y)
which can render drawing() object in the given canvas.
Drawing has a method called asString with a one required attribute that represents the required drawing format such as 'png', 'gif' or 'jpg'.
so instead of calling
renderPDF.drawToFile(d, 'test.pdf')
You could call
binaryStuff = d.asString('gif')
return HttpResponse(binaryStuff, 'image/gif')
Without the need to save your drawing to the disc.
Check https://code.djangoproject.com/wiki/Charts for full example.

Categories

Resources