How to resize base64 encoded image in python - python

I want resize base64 encoded image in python.I searched I could not find. I used Pillow package to do it. However, Pillow has no such kind of feature .

This code does the job (Python 3):
import io
import base64
from PIL import Image
base64_str = 'iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='
buffer = io.BytesIO()
imgdata = base64.b64decode(base64_str)
img = Image.open(io.BytesIO(imgdata))
new_img = img.resize((2, 2)) # x, y
new_img.save(buffer, format="PNG")
img_b64 = base64.b64encode(buffer.getvalue())
print(str(img_b64)[2:-1])
EDIT: Reducing the size of a base64 image does not imply reducing the file size.

Related

Converting Image to Bytearray with Python

I want to convert Image file to Bytearray. I extracted image from pdf file with minecart lib, but I cant find a way to convert it to bytearray. This is my code:
import minecart
from PIL import Image
import io
pdffile = open('sample6.pdf', 'rb')
doc = minecart.Document(pdffile)
for page in doc.iter_pages():
print(page)
img = page.images[0].as_pil()
print(img) # <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=1641x2320 at 0x7FBDF02E6A00>
print(type(img)) # <class 'PIL.JpegImagePlugin.JpegImageFile'>
I have tried to use bytearray(img) but It does not work.
Do you have solution for this (solution that does not consume to much time)?
Create io.BytesIO buffer and write to it using PIL.Image.save. Set appropriate quality and other parameters as per requirement.
import io
from PIL import Image
def convert_pil_image_to_byte_array(img):
img_byte_array = io.BytesIO()
img.save(img_byte_array, format='JPEG', subsampling=0, quality=100)
img_byte_array = img_byte_array.getvalue()
return img_byte_array
References:
Why is the quality of JPEG images produced by PIL so poor?

cv2.imdecode() returns None from image in base64, mimetype image/jpeg received via Websockets

I use websockets to receive video frames. Image is encoded in base64 mimetype image/jpeg. I'm trying to convert image to np.ndarray. When I read image file code works correct. But when I'm trying to read image from socket stream, issue is occured.
image_data = base64.b64decode(part.encoded_image)
np_array = np.frombuffer(image_data, np.uint8)
image = cv2.imdecode(np_array, cv2.IMREAD_UNCHANGED)
In docs cv2.imdecode() returns None in case when image is short or corrupted. My image is in HD format, 1280/720. Data isn't corrupted as I could successfully decode it using online converter.
This is the beginning of received data:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0KSEiMEExNDk7Pj4+JS5ESUM8SDc9Pjv/
You have to skip data:image/jpeg;base64, to get only base64 data which will give you correct image data and cv2 will decode and display it.
In example I use split(',', 1) for this - it gives me data:image/jpeg;base64, in variable header and image data in data.
I use full image in code.
import base64
import numpy as np
import cv2
encoded_image = 'data:image/jpeg;base64,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'
header, data = encoded_image.split(',', 1)
#print('header:', header)
#print(' data:', data[:20])
image_data = base64.b64decode(data)
#print('result:', image_data[:20])
np_array = np.frombuffer(image_data, np.uint8)
#print(' array:', np_array[:2])
image = cv2.imdecode(np_array, cv2.IMREAD_UNCHANGED)
#print(' image:', image[:2])
cv2.imshow('image', image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Result:
(face image with size 7x7)

Convert numpy array to base64

I want to convert frame from a video file to base64 without save in directory.
I use: img = frame.copy() to take a frame from my video and it return a numpy array.
How can i convert it into base64 to store in database and display it into web.
Thanks for your help.
The following code should work - note you'll have to switch around the format as needed, and the corresponding base64 string. In this example I've used PNG.
from PIL import Image
from io import BytesIO
import base64
data = frame.copy()
image_out = Image.fromarray(data)
buffer = BytesIO()
image_out.save(buffer, format="PNG")
base64_str = "data:image/png;base64," + base64.b64encode(buffer.getvalue()).decode("utf-8")
Output:
>>> base64_str
`data:image/png;base64,iVBORw...`

Read a base 64 encoded image from memory using OpenCv python library

I'm working on an app that to do some facial recognition from a webcam stream. I get base64 encoded data uri's of the canvas and want to use it to do something like this:
cv2.imshow('image',img)
The data URI looks something like this:
data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7
So, for clarity I've shown what the image looks like so the base64 string is not broken.
<img src="data:image/gif;base64,R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7">
The official doc says, that imread accepts a file path as the argument. From this SO answer, if I do something like:
import base64
imgdata = base64.b64decode(imgstring) #I use imgdata as this variable itself in references below
filename = 'some_image.jpg'
with open(filename, 'wb') as f:
f.write(imgdata)
The above code snippet works and the image file gets generated properly. However I don't think so many File IO operations are feasible considering I'd be doing this for every frame of the stream. I want to be able to read the image into the memory directly creating the img object.
I have tried two solutions that seem to be working for some people.
Using PIL reference:
pilImage = Image.open(StringIO(imgdata))
npImage = np.array(pilImage)
matImage = cv.fromarray(npImage)
I get cv not defined as I have openCV3 installed which is available to me as cv2 module. I tried img = cv2.imdecode(npImage,0), this returns nothing.
Getting the bytes from decoded string and converting it into an numpy array of sorts
file_bytes = numpy.asarray(bytearray(imgdata), dtype=numpy.uint8)
img = cv2.imdecode(file_bytes, 0) #Here as well I get returned nothing
The documentation doesn't really mention what the imdecode function returns. However, from the errors that I encountered, I guess it is expecting a numpy array or a scalar as the first argument. How do I get a handle on that image in memory so that I can do cv2.imshow('image',img) and all kinds of cool stuff thereafter.
I hope I was able to make myself clear.
This is my solution for python 3.7 and without using PIL
import base64
def readb64(uri):
encoded_data = uri.split(',')[1]
nparr = np.fromstring(base64.b64decode(encoded_data), np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
return img
i hope that this solutions works for all
This worked for me on python 2, and doesn't require PIL/pillow or any other dependencies (except cv2):
Edit: for python3 use base64.b64decode(encoded_data) to decode instead.
import cv2
import numpy as np
def data_uri_to_cv2_img(uri):
encoded_data = uri.split(',')[1]
nparr = np.fromstring(encoded_data.decode('base64'), np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
return img
data_uri = "data:image/jpeg;base64,/9j/4AAQ..."
img = data_uri_to_cv2_img(data_uri)
cv2.imshow(img)
You can just use both cv2 and pillow like this:
import base64
from PIL import Image
import cv2
from StringIO import StringIO
import numpy as np
def readb64(base64_string):
sbuf = StringIO()
sbuf.write(base64.b64decode(base64_string))
pimg = Image.open(sbuf)
return cv2.cvtColor(np.array(pimg), cv2.COLOR_RGB2BGR)
cvimg = readb64('R0lGODlhEAAQAMQAAORHHOVSKudfOulrSOp3WOyDZu6QdvCchPGolfO0o/XBs/fNwfjZ0frl3/zy7////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAkAABAALAAAAAAQABAAAAVVICSOZGlCQAosJ6mu7fiyZeKqNKToQGDsM8hBADgUXoGAiqhSvp5QAnQKGIgUhwFUYLCVDFCrKUE1lBavAViFIDlTImbKC5Gm2hB0SlBCBMQiB0UjIQA7')
cv2.imshow(cvimg)
I found this simple solution.
import cv2
import numpy as np
import base64
image = "" # raw data with base64 encoding
decoded_data = base64.b64decode(image)
np_data = np.fromstring(decoded_data,np.uint8)
img = cv2.imdecode(np_data,cv2.IMREAD_UNCHANGED)
cv2.imshow("test", img)
cv2.waitKey(0)
Source : https://gist.github.com/HoweChen/7cdd09b08147133d8e1fbe9b52c24768

Upload Image To Imgur After Resizeing In PIL

I am writing a script which will get an image from a link. Then the image will be resized using the PIL module and the uploaded to Imgur using pyimgur. I dont want to save the image on disk, instead manipulate the image in memory and then upload it from memory to Imgur.
The Script:
from pyimgur import Imgur
import cStringIO
import requests
from PIL import Image
LINK = "http://pngimg.com/upload/cat_PNG106.png"
CLIENT_ID = '29619ae5d125ae6'
im = Imgur(CLIENT_ID)
def _upload_image(img, title):
uploaded_image = im.upload_image(img, title=title)
return uploaded_image.link
def _resize_image(width, height, link):
#Retrieve our source image from a URL
fp = requests.get(link)
#Load the URL data into an image
img = cStringIO.StringIO(fp.content)
im = Image.open(img)
#Resize the image
im2 = im.resize((width, height), Image.NEAREST)
#saving the image into a cStringIO object to avoid writing to disk
out_im2 = cStringIO.StringIO()
im2.save(out_im2, 'png')
return out_im2.getvalue()
When I run this script I get this error: TypeError: file() argument 1 must be encoded string without NULL bytes, not str
Anyone has a solution in mind?
It looks like the same problem as this, and the solution is to use StringIO.
A common tip for searching such issues is to search using the generic part of the error message/string.

Categories