How to convert Image PIL into Base64 without saving - python

I generate an image with Python, and I need to convert this Pil Image into a Base64, without saving this one into any folder...
I have some data, and I get RGB img with the line below:
img = Image.fromarray(data,'RGB')
What is the simple way to convert this PIL into base64 ?(I can't open a file image because I must not save the img) ?
Thank you for your help
With Node JS, I can get the correct base64 with these lines :
pythonShell= require("python-shell");
app.post('/index/gen/',urlencodedParser, function (req,res){
pythonShell.run('minigen.py', function (err, results) {
if (err) throw err;
var img = base64img.base64Sync('./images/miniature.jpg');
res.send(img); });
})
But I have to save the file if I use NodeJS...
this is the code to generate the matrix from the image, you don't need to know what is in data ;)
image = Image.open("./carte/"+fichier)
image = image.resize((400,400),Image.ANTIALIAS)
w,h = image.size
tab = numpy.array(image)
data = numpy.zeros((h, w, 3), dtype=numpy.uint8)

I found the solution. Hope this helps !
img = Image.fromarray(data, 'RGB') #Crée une image à partir de la matrice
buffer = BytesIO()
img.save(buffer,format="JPEG") #Enregistre l'image dans le buffer
myimage = buffer.getvalue()
print "data:image/jpeg;base64,"+base64.b64encode(myimage)

#florian answer helped me a lot but base64.b64encode(img_byte) returned bytes so I needed to decode it to string before concatenation (using python 3.6):
def img_to_base64_str(self, img):
buffered = BytesIO()
img.save(buffered, format="PNG")
buffered.seek(0)
img_byte = buffered.getvalue()
img_str = "data:image/png;base64," + base64.b64encode(img_byte).decode()

You can use base64 library like this:
import base64
base64.b64encode(img.tobytes())
See tobytes() method of Image object.

Or you can use something like this:
import glob
import random
import base64
from PIL import Image
from io import BytesIO
import io
def get_thumbnail(path):
path = "\\\\?\\"+path # This "\\\\?\\" is used to prevent problems with long Windows paths
i = Image.open(path)
return i
def image_base64(im):
if isinstance(im, str):
im = get_thumbnail(im)
with BytesIO() as buffer:
im.save(buffer, 'jpeg')
return base64.b64encode(buffer.getvalue()).decode()
def image_formatter(im):
return f'<img src="data:image/jpeg;base64,{image_base64(im)}">'
Just pass path of image in get_thumbnail function and image_formatter to display it in HTML.

Related

Rasterio MemoryFile to Pillow image (Or base64 output)

I'm trying to write an AWS Lambda function that takes a TIFF, converts it to JPEG, then outputs it in base64 so that lambda can serve it. But I keep running into malformed response, or issues with reshape_as_image saying axes doesn't match array.
My understanding was that the return of memfile.read() would allow me to use reshape_as_image, however my logic seems faulty.
Without saving to disk, how can I get from memfile to a base64 jpeg representation so that lambda can serve it? I've also tried pillow but I think the necessary step is where I'm failing.
def get_image(self, driver="jpeg"):
data = self.get_image()
with MemoryFile() as memfile:
# Change the driver for output
data[1]['driver'] = driver
with MemoryFile() as memfile:
# Change the driver for output
data[1]['driver'] = driver
with memfile.open(**data[1]) as dataset:
dataset.write(data[0])
image = memfile.read()
image = reshape_as_image(image)
im = Image.open(io.BytesIO(image))
b64data = base64.b64encode(im.tobytes()).decode('utf-8')
return b64data
It seems this isn't necessary for some reason, assuming because memfile.read() gives the actual bytes of the image.
def get_image(self, store=False, driver="GTiff"):
data = self.crop_ortho(store)
with MemoryFile() as memfile:
# Change the driver for output
data[1]['driver'] = driver
with memfile.open(**data[1]) as dataset:
dataset.write(data[0])
image = memfile.read()
im = Image.open(io.BytesIO(image))
im = im.convert('RGB')
# Save bytes to a byte array
imgByteArr = io.BytesIO()
im.save(imgByteArr, format='jpeg')
b64data = base64.b64encode(imgByteArr.getvalue())
return b64data

How to create a zip file in memory with a list of PIL image objects?

I am trying to create a zip file in memory with a list of PIL image objects.
import io
from PIL import Image
def get_images(path):
'''This returns a list of PIL images'''
pass
def file_process_im_memory():
images = get_images('mypath')
file_object = io.BytesIO()
file_object2 = io.BytesIO()
images[0].save(file_object, 'PNG')
images[1].save(file_object2, 'PNG')
file_object.seek(0)
file_object2.seek(0)
The image are written in memory, now I want to create an zip file from the in memory image files, I tried below but it didn't work.
zip_file = ZipFile(zip_file_bytes_io, 'w')
for image in images:
file_object = io.BytesIO()
image.save(file_object, 'PNG')
file_object.seek(0)
zip_file.writestr(file_object.getvlaue())
zip_file_bytes_io.seek(0)
I believe this will do what you want. As I said in a now deleted comment, one issue was that the first argument to zip_file.writestr() should be the filename / member name it will be given in the archive with the second one being the data to be written.
In order to be able to do that the image filenames must be preserved. In the code below get_images() now returns a list of [<image file name>, <PIL image object>] pairs of values so the name will be available when writing the in-memory zip file.
import io
import os
from PIL import Image
from pprint import pprint
from zipfile import ZipFile
def get_images(path):
""" Returns a list of image file base name & PIL image object pairs. """
# Harcoded with two images for testing purposes.
IMAGES = (r"C:\vols\Files\PythonLib\Stack Overflow\cookie_cutter_background.png",
r"C:\vols\Files\PythonLib\Stack Overflow\Flying-Eagle.png")
images = []
for image_path in IMAGES:
# Get image file name without extension.
image_name = os.path.splitext(os.path.os.path.basename(image_path))[0]
pil_image = Image.open(image_path)
images.append([image_name, pil_image])
return images
def file_process_in_memory():
""" Converts PIL image objects into BytesIO in-memory bytes buffers. """
images = get_images('mypath')
for i, (image_name, pil_image) in enumerate(images):
file_object = io.BytesIO()
pil_image.save(file_object, "PNG")
pil_image.close()
images[i][1] = file_object # Replace PIL image object with BytesIO memory buffer.
return images # Return modified list.
images = file_process_in_memory()
# Create an in-memory zip file from the in-memory image file data.
zip_file_bytes_io = io.BytesIO()
with ZipFile(zip_file_bytes_io, 'w') as zip_file:
for image_name, bytes_stream in images:
zip_file.writestr(image_name+".png", bytes_stream.getvalue())
pprint(zip_file.infolist()) # Print final contents of in memory zip file.
print('done')
Sample output:
[<ZipInfo filename='cookie_cutter_background.png' filemode='?rw-------' file_size=727857>,
<ZipInfo filename='Flying-Eagle.png' filemode='?rw-------' file_size=462286>]
done

Regarding Image processing/ or Jpeg format without library

I am trying to write a python code to download and get the detail of image resolution and size and rescale it to (320*568) convert it into base64 string and save it in JSON format.
input : any jpeg image
output : JSON
{ "image64":"encoded string",
"size":"size of image",
"resolution":"resolution of image" }
till now i have done this by this way:
from PIL import Image
a=Image.open("DSC_2561.jpg")
print(a.size)
a=a.resize((320,568))
how to proceed from here?
Here is the solution:
from PIL import Image
import os
def encodeBase64(path):
img= Image.open(path)
img= img.resize((320,568))
data = img.encode("base64")
json = { "image64": data, "size":os.stat(path).st_size, "resolution":img.size[0] + "x" + img.size[1] }
return json

Change color scheme when extracting an image from PDF in Python

I am trying to read an image from a pdf following this post:
Extract images from PDF without resampling, in python?
So far I managed to get the image file from the pdf, but it contains a CWYK color scheme and the picture is becoming messed up.
My code is the following:
import PyPDF2
import struct
pdf_filename = 'document.pdf'
pdf_file = open(pdf_filename, 'rb')
cond_scan_reader = PyPDF2.PdfFileReader(pdf_file)
page = cond_scan_reader.getPage(4)
xObject = page['/Resources']['/XObject'].getObject()
for obj in xObject:
print(xObject[obj])
if xObject[obj]['/Subtype'] == '/Image':
if xObject[obj]['/Filter'] == '/DCTDecode':
data = xObject[obj]._data
img = open("image" + ".jpg", "wb")
img.write(data)
img.close()
pdf_file.close()
The point is that when I save, the colors are all weird, I believe it's because of the colorScheme. I have the following in the console:
{'/Type': '/XObject', '/Subtype': '/Image', '/Width': 1122, '/Height': 502, '/Interpolate': <PyPDF2.generic.BooleanObject object at 0x1061574a8>, '/ColorSpace': '/DeviceCMYK', '/BitsPerComponent': 8, '/Filter': '/DCTDecode'}
As you can see, the ColorSpace is CMYK, and I believe that's why the colors of the image are weird.
That's the image I have:
This is the original image (it is inside a pdf file):
Can anyone help me?
Thanks in advance.
Israel
A CMYK mode JPG image that contained in PDF must be invert.
But in PIL, invert of CMYK mode image is not supported.
Than I solve it using numpy.
Full source is in below link.
https://github.com/Gaia3D/pdfImageExtractor/blob/master/extrectImage.py
imgData = np.frombuffer(img.tobytes(), dtype='B')
invData = np.full(imgData.shape, 255, dtype='B')
invData -= imgData
img = Image.frombytes(img.mode, img.size, invData.tobytes())
img.save(outFileName + ".jpg")

How to change image format without writing it to disk using Python Pillow

I got Pillow image that i got from the Internet:
response= urllib2.urlopen(<url to gif image>)
img = Image.open(cStringIO.StringIO(response.read()))
I want to use it with tesserocr but it wont work with GIF images.
If I save the image as PNG img.save("tmp.png") and load it img = Image.open("tmp.png") everything works.
Is there a way to do this conversion without writing to disk?
import io
from PIL import Image
def convertImageFormat(imgObj, outputFormat=None):
"""Convert image format
Args:
imgObj (Image): the Pillow Image instance
outputFormat (str): Image format, eg: "JPEG"/"PNG"/"BMP"/"TIFF"/...
more refer: https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html
Returns:
bytes, binary data of Image
Raises:
"""
newImgObj = imgObj
if outputFormat and (imgObj.format != outputFormat):
imageBytesIO = io.BytesIO()
imgObj.save(imageBytesIO, outputFormat)
newImgObj = Image.open(imageBytesIO)
return newImgObj
call example:
pngImgFile = "xxx.png"
pngImgObj = Image.open(pngImgFile)
convertToFormat = "JPEG"
convertedJpgImgBytes = convertImageFormat(pngImgObj, convertToFormat)
advanced version convertImageFormat can refer my lib crifanPillow.py
import io
from PIL import Image
def convertImageFormat(imgObj, outputFormat=None, isOptimize=False, isKeepPrevValues=True):
"""Convert image format
Args:
imgObj (Image): the Pillow Image instance
outputFormat (str): Image format, eg: "JPEG"/"PNG"/"BMP"/"TIFF"/...
more refer: https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html
isOptimize (bool): do optimize when using save to convert format
isKeepPrevValues (bool): keep previous property values, such as: filename
Returns:
bytes, binary data of Image
Raises:
"""
newImgObj = imgObj
if outputFormat and (imgObj.format != outputFormat):
imageBytesIO = io.BytesIO()
if isOptimize:
imgObj.save(imageBytesIO, outputFormat, optimize=True)
else:
imgObj.save(imageBytesIO, outputFormat)
newImgObj = Image.open(imageBytesIO)
if isKeepPrevValues:
if imgObj.filename:
newImgObj.filename = imgObj.filename
return newImgObj
The solution was very simple:
response= urllib2.urlopen(<url to gif image>)
img = Image.open(cStringIO.StringIO(response.read()))
img = img.convert("RGB")
Note that you need to remove the alpha channel info to make image compatible with tesserocr

Categories