Я хотел уменьшить изображение до меньшего размера для облегчения обмена и более быстрой загрузки.

Но я понял, что если я просто уменьшу размер на его h & w, это не поможет, потому что большой файл изображения может иметь меньшее h & w, а маленький файл изображения может иметь большие h & w, поэтому уменьшите размер изображения, уменьшив его высоту & Вес не всегда может уменьшить размер так, как я хотел.

Итак, теперь у меня есть размер байта, используя это:

import os
os.stat('myImage.jpg').st_size

Можно ли уменьшить размер изображения за счет уменьшения его байта? И остаётся своё соотношение?

0
moomoochen 23 Окт 2018 в 05:36

2 ответа

Лучший ответ

Вот функция, которую я написал с помощью PIL. Он выполняет некоторое итеративное изменение размера и сжатие jpeg изображения, чтобы затем посмотреть на полученный размер файла и сравнить его с целевым значением, угадывая следующую лучшую комбинацию ширины / высоты из отношения отклонения размера (в основном, своего рода контроллер P).

Он использует io.BytesIO, который выполняет все изменения размера в памяти, поэтому на самом деле есть только один доступ для чтения и один доступ для записи к файлам на диске. Кроме того, с помощью этого подхода грубой силы вы можете изменить формат целевого файла, скажем, PNG, и он будет работать прямо из коробки.

from PIL import Image
import os
import io

def limit_img_size(img_filename, img_target_filename, target_filesize, tolerance=5):
    img = img_orig = Image.open(img_filename)
    aspect = img.size[0] / img.size[1]

    while True:
        with io.BytesIO() as buffer:
            img.save(buffer, format="JPEG")
            data = buffer.getvalue()
        filesize = len(data)    
        size_deviation = filesize / target_filesize
        print("size: {}; factor: {:.3f}".format(filesize, size_deviation))

        if size_deviation <= (100 + tolerance) / 100:
            # filesize fits
            with open(img_target_filename, "wb") as f:
                f.write(data)
            break
        else:
            # filesize not good enough => adapt width and height
            # use sqrt of deviation since applied both in width and height
            new_width = img.size[0] / size_deviation**0.5    
            new_height = new_width / aspect
            # resize from img_orig to not lose quality
            img = img_orig.resize((int(new_width), int(new_height)))


limit_img_size(
    "test.jpg",   #  input file
    "test_with_limited_size.jpg",     #  target file
    50000,   # bytes    
    tolerance = 5    # percent of what the file may be bigger than target_filesize
)

РЕДАКТИРОВАТЬ:

Под словом "в памяти" я имел в виду, что когда в цикле save находится img к buffer, он сохраняет его в объект BytesIO, который не является файлом на диск но в памяти. И по этому объекту я могу затем определить размер результирующего файла (который является просто длиной этого буфера данных) без фактического сохранения его в файл. В конце концов, возможно, это именно то, как вы ожидали, что это будет работать, но я видел слишком много кодов, которые тратят производительность при сохранении файлов на диск из-за отсутствия знаний о Python io.BytesIO.

В файл будет сохранен только окончательный результат - и это там, где вы хотите. Попробуйте использовать полное имя файла для img_target_filename.

1
Jeronimo 24 Окт 2018 в 07:15

Случилось так, что моему другу нужно было изменить размер / масштаб личного изображения, и требовалось, чтобы изображение было не более 40 КБ. Я написал следующий код для уменьшения / масштабирования изображения с учетом размера на диске. Я предполагаю, что 40 КБ = 40000 Байт, что неточно, но может пригодиться

from skimage.io import imread, imshow
from skimage.transform import rescale, resize, downscale_local_mean
from skimage.io import imsave
import matplotlib.pyplot as plt
import os
import numpy as np

img = imread('original.jpg')
target_size = 40000
size = os.path.getsize('original.jpg')
factor = 0.9
while(size>=40000):
    image_rescaled = rescale(img, factor, anti_aliasing=False)
    imsave('new.jpg', image_rescaled)
    print('factor {} image of size {}'.format(factor,size))
    factor = factor - 0.05
    size = os.path.getsize('new.jpg')

end_size = os.path.getsize('new.jpg')
print(end_size)

Надеюсь, поможет!!!! Вы можете подписаться на меня на GitHub как LeninGF

0
LeninGF 26 Сен 2019 в 04:14
52940369