Save the image with 100% quality. This will still save the image slightly different from the original, because it will also use subsampling to reduce the image size.
img.save('test.jpg', quality=100)
You can also turn off subsampling to make sure you get the exact same as the original image.
img.save('test.jpg', quality=100, subsampling=0)
Answer from Ali Sajjad Rizavi on Stack Overflowpython PIL save image different size original - Stack Overflow
Saving PNG images with PIL is 4 times slower than saving them with OpenCV
selenium - Compress PNG image in Python using PIL - Stack Overflow
python - Is there a way to speed up the Save method with PIL? - Stack Overflow
PNG is a compressed lossless format. The original image was probably saved with different compression settings.
Looking at the documentation you could try:
img.save("photo2.png", "PNG", optimize=True)
or
img.save("photo2.png", "PNG", compress_level=9)
By default, compress_level=6 is used.
Note that the optimize option includes setting the compression level to 9. But it also tries to find optimal encoder settings.
I guess you don't change the image, otherwise the size would be different. If you don't change the image why don't you just copy it?
shutil.copyfile(source, destination)
I see two options which you can both achieve using PIL library given for instance an RGB image.
1 – Reduce the image resolution (and therefore quality – you might not want that). Use the Image.thumbnail() or Image.resize() method provided by PIL.
2 – Reduce the color range of the image (the number of colors will affect file size accordingly). This is what many online converters will do.
img_path = "img.png"
img = Image.open(img_path)
img = img.convert("P", palette=Image.ADAPTIVE, colors=256)
img.save("comp.png", optimize=True)
The PNG format only supports lossless compression, for which the compression ratio is usually limited and not freely adjustable.
If I am right, there is a variable parameter that tells the compressor to spend more or less time finding a better compression scheme. But without a guarantee to succeed.
In PIL.Image.save when saving PNG there is an argument called compression_level with a compression_level=0 we can create faster savings at the cost of no compression. Docs
Compressing image data to PNG takes time - CPU time. There might be a better performant lib to that than PIL, but you'd have to interface it with Python, and it still would take sometime.
"Returning bytes" make no sense - you either want to have image files saved on S3 or don't. And the "bytes" will only represent an image as long as they are properly encoded into an image file, unless you have code to compose back an image from raw bytes.
For speeding this up, you could either create an AWS lambda project that will take the unencoded array, generate the png file and save it to S3 in an async mode, or, easier, you might try saving the image in an uncompressed format, that will spare you from the CPU time to compress PNG: try saving it as a .tga or .bmp file instead of a .png, but expect final files to be 10 to 30 times larger than the equivalent .PNGs.
Also, it is not clear from the code if this is in a web-api view, and you'd like to speedup the API return, and it would be ok if the image would be generated and uploaded in background after the API returns.
In that case, there are ways to improve the responsivity of your app, but we need to have the "web code": i.e. which framework you are using, the view function itself, and the calling to the function presented here.
new_size = (image_width_int,image_height_int)for individual_image in image_files:im = Image.open(r"resize_images/" + individual_image)resized_image = im.resize(new_size)resized_image.save('resized_images/' + individual_image, quality=85, optimize=True)
Even if I change the quality to 10, the files still come out the same size as if I didn't set the quality or optimize at all. Any ideas?
I have a database that stores some information and one of those values has to be an image of a chart I create with matplotlib. I know you can save charts as png files but that would save to my computer and I'd like for it to go directly to the database (SQLite3). I did a bit of research and found you could transform a matplotlib chart to a PIL image using this function:
def fig2img(fig):
"""Convert a Matplotlib figure to a PIL Image and return it"""
import io
buf = io.BytesIO()
fig.savefig(buf)
buf.seek(0)
img = Image.open(buf)
return imgNow that I have the chart transformed to a PIL object, if I print the type of the image I get this:
img = fig2img(fig) print(type(img)) # <class 'PIL.PngImagePlugin.PngImageFile'>
Now, my question is, how can I transform this data format to a raw PNG file without saving it to my hard drive so I can later plug it into the database?
PIL isn't an attribute of newImg1 but newImg1 is an instance of PIL.Image so it has a save method, thus the following should work.
newImg1.save("img1.png","PNG")
Note that just calling a file .png doesn't make it one so you need to specify the file format as a second parameter.
try:
type(newImg1)
dir(newImg1)
and
help(newImg1.save)
As I hate to see questions without a complete answer:
from PIL import Image
newImg1 = Image.new('RGB', (512,512))
for i in range (0,511):
for j in range (0,511):
newImg1.putpixel((i,j),(i+j%256,i,j))
newImg1.save("img1.png")
which yields a test pattern.
To use array style addressing on the image instead of putpixel, convert to a numpy array:
import numpy as np
pixels = np.asarray(newImg1)
pixels.shape, pixels.dtype
-> (512, 512, 3), dtype('uint8')