Image resize and get data in a buffer using python - python

I want to resize the input image to a fixed size. Then I want to entire content of the resized image file in a buffer for further use like, appending it with other buffer(data).
Currently I am doing it using the following python function,
def get_resize_img(img_file):
img = Image.open(img_file)
img = img.resize((640,960), Image.NEAREST)
img.save("tmp_out.jpg")
fp = open("tmp_out.jpg", "rb")
data = fp.read()
fp.close()
print "img sz:", len(data)
return data
Is there any better way to achieve this without writing into a dummy file (tmp_out.jpg) and reading back from it.
-Mohan

Import StringIO
def get_resize_img(img_file):
buffer = StringIO.StringIO()
img = Image.open(img_file)
img = img.resize((640,960), Image.NEAREST)
format = "YOUR_FORMAT" // JPG,PNG,etc.
img.save(buffer,format)
return buffer.getvalue()

I think you can use the getdata to get the image data, which is in fact the image buffer. Then you can reconstruct the image using frombuffer. Or maybe you can just return the resized Image object and use it later.
You can check out the document here.

if you are using numpy then following can be done
data = numpy.asarray(im)

Related

Streamlit image download button

st.write("Preview")
#openCV image result cropped_image which is an np array
st.image(cropped_image)
#cropped_image converted to PIL image color
result = Image.fromarray(cropped_image.astype('uint8'), 'RGB')
img = Image.open(result)
btn = st.download_button(
label="Download image",
data=img,
file_name="imagename.png",
mime="image/png")
I want to use st.download_button to download the image result. I know I cannot use the cropped_image result since it is an np array. I converted the image array to a PIL image but I don't know how I can get the result image filename from here . Could you please give me some ideas how to solve this issue?
The Streamlit download_button expects the data type to be a certain type. Read more here: https://github.com/streamlit/streamlit/blob/ba46ad297e8816f0d6a3aa910ce67556239f3e6d/lib/streamlit/elements/button.py#L353
You can convert your PIL Image to bytes using the following snippet:
from io import BytesIO
buf = BytesIO()
img.save(buf, format="JPEG")
byte_im = buf.getvalue()
Now you can use the st.download_button
btn = col.download_button(
label="Download Image",
data=byte_im,
file_name="imagename.png",
mime="image/jpeg",
)
If you have the image file in your directory:
st.download_button(label='Download Image',
data= open('yourimage.png', 'rb').read(),
file_name='imagename.png',
mime='image/png')

I want to compress an image in view before saving, but the file size stays the same

I have a functional update view that I am trying to compress uploaded images before saving them. However, when I try to compress the image, nothing happens and instead just saves the image with the exact same size.
I think I might be saving it wrong, but I am unsure of how to save it correctly. Please let me know. Thank you!
import io
from PIL import Image
def get_compressed_image(file):
image = Image.open(file)
with io.BytesIO() as output:
image.save(output, format=image.format, quality=20, optimize=True)
contents = output.getvalue()
return contents
def updated_form_view(request)
...
if initial_form.is_valid():
initial_form.clean()
updated_form = initial_form.save(commit=False)
updated_form.username = request.user.username
# compressing image here
updated_form.form_image.file.image = get_compressed_image(updated_form.form_image)
updated_form.save()```
we must reduce the resolution of picture, like this:
from PIL import Image
img = Image.open("logo.jpg")
amount = 1.5 # higher amount: more reduction. lower: less reduction
width, height = img.size
new_size = int(width // amount), int(height // amount)
compressed = img.resize(new_size,Image.ANTIALIAS)
compressed.save("compressed.jpg")
less resolution + no exif info = less size
and take note ur code worked but ur code dont change the resolution of picture but it pixelize image like this:
just click it

Cannot convert string to float (reading image file as bytes) [duplicate]

I'm trying to load image from string like as PHP function imagecreatefromstring
How can I do that?
I have MySQL blob field image. I'm using MySQLdb and don't want create temporary file for working with images in PyOpenCV.
NOTE: need cv (not cv2) wrapper function
This is what I normally use to convert images stored in database to OpenCV images in Python.
import numpy as np
import cv2
from cv2 import cv
# Load image as string from file/database
fd = open('foo.jpg')
img_str = fd.read()
fd.close()
# CV2
nparr = np.fromstring(img_str, np.uint8)
img_np = cv2.imdecode(nparr, cv2.CV_LOAD_IMAGE_COLOR) # cv2.IMREAD_COLOR in OpenCV 3.1
# CV
img_ipl = cv.CreateImageHeader((img_np.shape[1], img_np.shape[0]), cv.IPL_DEPTH_8U, 3)
cv.SetData(img_ipl, img_np.tostring(), img_np.dtype.itemsize * 3 * img_np.shape[1])
# check types
print type(img_str)
print type(img_np)
print type(img_ipl)
I have added the conversion from numpy.ndarray to cv2.cv.iplimage, so the script above will print:
<type 'str'>
<type 'numpy.ndarray'>
<type 'cv2.cv.iplimage'>
EDIT:
As of latest numpy 1.18.5 +, the np.fromstring raise a warning, hence np.frombuffer shall be used in that place.
I think this answer provided on this stackoverflow question is a better answer for this question.
Quoting details (borrowed from #lamhoangtung from above linked answer)
import base64
import json
import cv2
import numpy as np
response = json.loads(open('./0.json', 'r').read())
string = response['img']
jpg_original = base64.b64decode(string)
jpg_as_np = np.frombuffer(jpg_original, dtype=np.uint8)
img = cv2.imdecode(jpg_as_np, flags=1)
cv2.imwrite('./0.jpg', img)
I've try to use this code to create an opencv from a string containing a raw buffer (plain pixel data) and it doesn't work in that peculiar case.
So here's how to do that for this kind of data:
image = np.fromstring(im_str, np.uint8).reshape( h, w, nb_planes )
(but yes you need to know your image properties)
if your B and G channel is permuted, here's how to fix it:
image = cv2.cvtColor(image, cv2.cv.CV_BGR2RGB)
I was following the solution from #jabaldonedo but it seems it's a bit old and need some adjustments.
I am using OpenCV 3.4.8.29 by the way.
im_path = 'path/to/foo.jpg'
with open(im_path, 'rb') as fp:
im_b = fp.read()
image_np = np.frombuffer(im_b, np.uint8)
img_np = cv2.imdecode(image_np, cv2.IMREAD_COLOR)
im_cv = cv2.imread(im_path)
print('Same image: {}'.format(np.all(im_cv == img_np)))
Same image: True
One gotcha of imdecode:
If the buffer is too short or contains invalid data, the function returns [None]
This feels uncharacteristically lenient from OpenCV. Here's a function that accommodates for this:
import numpy as np
import cv2 as cv
def read_image(content: bytes) -> np.ndarray:
"""
Image bytes to OpenCV image
:param content: Image bytes
:returns OpenCV image
:raises TypeError: If content is not bytes
:raises ValueError: If content does not represent an image
"""
if not isinstance(content, bytes):
raise TypeError(f"Expected 'content' to be bytes, received: {type(content)}")
image = cv.imdecode(np.frombuffer(content, dtype=np.uint8), cv.IMREAD_COLOR)
if image is None:
raise ValueError(f"Expected 'content' to be image bytes")
return image

how to convert a PIL image to string and then convert it back to PIL image? The convsersion is to be done without saving it to a new file

I am currently doing this for bytestring conversion but I need to convert to string.
img=Image.fromarray(img)
output = io.BytesIO()
img.save(output, format="png")
image_as_string = output.getvalue()
img=Image.open(io.BytesIO(image_as_string))
img.save('strimg.png')
Here is my solution with base64.
import base64
img = Image.open("test.png")
output = io.BytesIO()
img.save(output, format="png")
image_as_string = base64.b64encode(output.getvalue())
#encrypting/decrypting
img=Image.open(io.BytesIO(base64.b64decode(image_as_string)))
img.save('string.png')

Extract an image from a PDF in python

I'm trying to extract images from a pdf using PyPDF2, but when my code gets it, the image is very different from what it should actually look like, look at the example below:
But this is how it should really look like:
Here's the pdf I'm using:
https://www.hbp.com/resources/SAMPLE%20PDF.pdf
Here's my code:
pdf_filename = "SAMPLE.pdf"
pdf_file = open(pdf_filename, 'rb')
cond_scan_reader = PyPDF2.PdfFileReader(pdf_file)
page = cond_scan_reader.getPage(0)
xObject = page['/Resources']['/XObject'].getObject()
i = 0
for obj in xObject:
# print(xObject[obj])
if xObject[obj]['/Subtype'] == '/Image':
if xObject[obj]['/Filter'] == '/DCTDecode':
data = xObject[obj]._data
img = open("{}".format(i) + ".jpg", "wb")
img.write(data)
img.close()
i += 1
And since I need to keep the image in it's colour mode, I can't just convert it to RBG if it was CMYK because I need that information.
Also, I'm trying to get dpi from images I get from a pdf, is that information always stored in the image?
Thanks in advance
I used pdfreader to extract the image from your example.
The image uses ICCBased colorspace with the value of N=4 and Intent value of RelativeColorimetric. This means that the "closest" PDF colorspace is DeviceCMYK.
All you need is to convert the image to RGB and invert the colors.
Here is the code:
from pdfreader import SimplePDFViewer
import PIL.ImageOps
fd = open("SAMPLE PDF.pdf", "rb")
viewer = SimplePDFViewer(fd)
viewer.render()
img = viewer.canvas.images['Im0']
# this displays ICCBased 4 RelativeColorimetric
print(img.ColorSpace[0], img.ColorSpace[1].N, img.Intent)
pil_image = img.to_Pillow()
pil_image = pil_image.convert("RGB")
inverted = PIL.ImageOps.invert(pil_image)
inverted.save("sample.png")
Read more on PDF objects: Image (sec. 8.9.5), InlineImage (sec. 8.9.7)
Hope this works: you probably need to use another library such as Pillow:
Here is an example:
from PIL import Image
image = Image.open("path_to_image")
if image.mode == 'CMYK':
image = image.convert('RGB')
image.write("path_to_image.jpg")
Reference: Convert from CMYK to RGB

Categories