I want to get the image in the clipboard and convert its data into a base64 encoded string so that I can put that into a HTML img tag.
I've tried the following:
from PIL import ImageGrab
from base64 import encodestring
img = ImageGrab.grabclipboard()
imgStr = encodestring(img.fp.read())
Plus some other combinations, all of which give me incorrect representations of the image.
I'm struggling with the docs on this one; does anyone have an idea on how to accomplish this?
ImageGrab.grabclipboard() returns an Image object. You need to convert it to a known image format, like jpeg or png, then to encode the resulting string in base64 to be able to
use it within an HTML img tag:
import cStringIO
jpeg_image_buffer = cStringIO.StringIO()
image.save(jpeg_image_buffer, format="JPEG")
imgStr = base64.b64encode(jpeg_image_buffer.getvalue())
(answer has been edited to fix the typo).
Related
How can I open an image in pillow that I already opened using open('image','r')
I have an image that I opened using the open() function, but i want to use the image in pillow.
Actually, I encoded it using base64, then the program decodes it,then gives you a variable that is in the same format as the open() function has. Then I just want to show the image, if there is another way to show the image without saving it, please let me know.
Here is the code that I use to decode it, just so you know:
import base64
image_64_encode = 'this-string-is-big-so'
image_64_decode = base64.decodebytes(image_64_encode)
I just want to show the image.
Like this:
from base64 import b64decode
from PIL import Image
import io
# Load useful-looking base64 string of a PNG
b64 = 'iVBORw0KGgoAAAANSUhEUgAAAEAAAABAEAIAAAB1mzrKAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0T///////8JWPfcAAAAB3RJTUUH5QsDDgY2fEahewAAANhJREFUeNrt3LENg0AQRcFFOue4/yIhN9K5jAl4UwHS02flAB977z1h1sxzr1M/xnsVAFszz7W++jHeqwVgBcAKgHUDsBaAFQArANYNwFoAVgCsAFg3AFszv/tz6sd4r15BWAGwbgDWArACYAXACoB1hLEWgBUAKwDWDcBaAFYArADYmvldn24A0wKwAmAFwPodgLUArABYAbBuANYCsAJgBcAKgHWEsRaAFQDr+wCsG4D1CsIKgBUA6wZgLQArAFYArBuAtQCsAFgBsG4A1gKwY++Z/sDe+QP/bITzNFwkpgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMS0xMS0wM1QxNDowNjo1NCswMDowMGz+3A4AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjEtMTEtMDNUMTQ6MDY6NTQrMDA6MDAdo2SyAAAAAElFTkSuQmCC'
# Open it with PIL - no disk access required
im = Image.open(io.BytesIO(b64decode(b64)))
print(im)
# prints: <PIL.PngImagePlugin.PngImageFile image mode=RGB size=64x64 at 0x7FF3B90251C0>
The clue is here in the Pillow documentation where it says:
fp – A filename (string), pathlib.Path object or a file object.
As the question says, i need a way to decode a base64 image into the pixel values of that image. I tried using opencv for imdecode, and that's pretty much all i found about this.
The reason i want to do it is because i am writing a backend api, which receives a base64 encoded image from a web application (written in TypeScript if that's needed, from a object) and then in python i want to parse it's pixel values to do some computation, like see what's the average color of the image.
The problem is that the data isn't sent just as pixels probably, it's a strange format and i don't know how to decode it.
Here is an example base64 image:
EDIT
iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAh0lEQVQ4T+3TMQ6AIAwF0PZIbIxwcljZuFENJhiDrX4imzKT109bWESEFh7+wdfdvO0hM18KPM0QAhtyxu/Q6Sl32EKnwForOecohEApJbXfMLjsyeNglgzF2iUNV5/cUllJSinkvT9qjPemwSblnCnGuKMwiH4ZCOxYT2GtiFYUXhs08QfBDdNTgsUZ/lOUAAAAAElFTkSuQmCC==
It can be decoded in browser decoders and it also shows the image properly, i just can't decode it so that i can iterate through the pixel values.
import base64
import numpy as np
import cv2
base64_string = "INSERT BASE64 HERE"
decoded = base64.b64decode(base64_string)
buffer = np.fromstring(decoded, np.float32)
image_array = cv2.imdecode(buffer, cv2.IMREAD_COLOR)
cv2.imshow("img", image_array)
cv2.waitKey(0)
The base64 string is decoded and then np.fromstring converts the decoded string to an array. Finally cv2.imdecode decodes the NumPy array to convert to image format.
I'm trying to send json dict that should contain Pillow image as one of his fields, to do that I have to convert the image to string.
I tried to use pillow function:
image.toString()
but still got it as bytes, so I tried to encode it:
buff = BytesIO()
image.save(buff, format="JPEG")
img_str = base64.b64encode(buff.getvalue())
but still got it as bytes.
How can I convert Pillow images to format that can be saved in json file?
In the comments, Mark Setchell suggests calling .decode('ascii') on the result of your b64encode call. I agree that this will work, but I think base64encoding to begin with is introducing an unnecessary extra step that complicates your code.*
Instead, I suggest directly decoding the bytes returned by image.tostring. The only complication is that the bytes object can contain values larger than 128, so you can't decode it with ascii. Try using an encoding that can handle values up to 256, such as latin1.
from PIL import Image
import json
#create sample file. You don't have to do this in your real code.
img = Image.new("RGB", (10,10), "red")
#decode.
s = img.tobytes().decode("latin1")
#serialize.
with open("outputfile.json", "w") as file:
json.dump(s, file)
(*but, to my surprise, the resulting json file is still smaller than one made with a latin1 encoding, at least for my sample file. Use your own judgement to determine whether file size or program clarity is more important.)
I use the following to exchange Pillow images via json.
import json
from PIL import Image
import numpy as np
filename = "filename.jpeg"
image = Image.open(filename)
json_data = json.dumps(np.array(image).tolist())
new_image = Image.fromarray(np.array(json.loads(json_data), dtype='uint8'))
1) I have an image that I converted to a string. It looks like this:
bytesimage = b'iVBORw0KGgoAAAANSUhEUgA.... etc etc
2) I can convert it to an 'bytesimage.png' using:
def StringToImage(self, stringname, imageoutput):
imgdata = base64.b64decode(stringname)
imagename = imageoutput
with open(imagename, 'wb') as f:
f.write(imgdata)
3) But then I want to save that image or string to memory to use in wxpython interface without needing to save the file. I have seen several related questions where the solution is using io.BytesIO, but I just cant connect the steps and both wxpython or PIL don't seem to read the bytes properly.
So to clarify:
I have a image stored in a string DONE
I can convert that to an image (if needed) but dont want to save it DONE
I need that string OR image (whichever is best) saved to memory NEEDS SOLVING
Then I want to be able to use that image in wxpython (I can open in PIL first if required)
Any help would be fantastic!
StringIO seems to be the way to go. It allows you to pass the decoded string directly to PIL.
import base64
from PIL import Image
import StringIO
# Banana emoji (JPG) as a b64 string.
b64_img_str = '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'
# Decode back to the original bytes
new_img_str = base64.b64decode(b64_img_str)
# Use StringIO to provide an in-memory buffer that we can use
# to pass the image string to PIL.
sio = StringIO.StringIO(new_img_str)
img = Image.open(sio)
# Display the image
img.show()
When importing an image I receive a different value than when I create an image. If I import the image
img = open('16x9.gif','rb')
img.read().encode('base64')
# 'R0lGODlhEAAJAIAAAAAAAAAAACH5BAEAAAAALAAAAAAQAAkAAAIKhI+py+0Po5yUFQA7\n'
But, If I create the image in cStringIO:
import cStringIO
import base64
import Image
tmp = cStringIO.StringIO()
img = Image.new('RGB', (16,9))
img.save(tmp, format='GIF', transparency=0)
base64.b64encode(tmp.getvalue())
# Response truncated for readability
# 'R0lGODdhEAAJAIcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADMAAGYAAJkAAMwAAP8AA...
The value returned by this second snippet is different and much longer than the first.
Why are my return values different and how do i get the shorter (see first) base64 value?
The difference is between those images representations is format, as your first string is a gif in 89a format, while your tmp is 87a.
>>> 'R0lGODlh'.decode('base64')
'GIF89a'
>>> 'R0lGODdh'.decode('base64')
'GIF87a'
The only related discussion on the topic I found is this: GIF89A and PIL, so it seems that PIL can load 89a format, but can't create it on his own.
As #delnan pointed out, I was not using the equivalent image.
But, in my search I found that png images return shorter base64 strings than gif images.
Closer to what was retuned from a gif that was made in photoshop.