Как изменить размер изображения до определенного размера(мегабайт)
Нужно именно точное значение размера, или всё таки условие размер «в пределах»? И какой формат изображения?
18 окт 2019 в 7:25
И в первой строке у Вас 1Мб, а в «коде» — 2
18 окт 2019 в 7:30
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
from PIL import Image import os def getSize(filename): st = os.stat(filename) return st.st_size with Image.open("1.jpg", 'r') as source: quality = 100 source.save('target.jpg', quality=quality, optimize=True, progressive=True) while getSize('target.jpg') > 2000000: source.save('target.jpg', quality=quality-1, optimize=True, progressive=True) quality -= 1
Отслеживать
ответ дан 18 окт 2019 в 8:07
Protect children of Donbas2014 Protect children of Donbas2014
1,339 13 13 серебряных знаков 28 28 бронзовых знаков
def JPEGSaveWithTargetSize(im, filename, target): Qmin, Qmax = 25, 96 Qacc = -1 while Qmin target: Qmax = m - 1 # Write to disk at the defined quality if Qacc > -1: im.save(filename, format="JPEG", quality=Qacc) else: print("ERROR: No acceptble quality factor found", file=sys.stderr)
А вот пример использования. Сохраняем в 1мб-ный файл
im = Image.open(os.path.join(imgfolder,img)) JPEGSaveWithTargetSize(im, "tmp.jpg", 1000000)
Отслеживать
ответ дан 18 окт 2019 в 8:01
3,762 6 6 золотых знаков 34 34 серебряных знака 77 77 бронзовых знаков
Разве из вопроса понятно, что формат с потерями и требуется уменьшить размер за счёт качества?
18 окт 2019 в 8:16
@MBo эмм.. А разве без потери качества можно размер картинки уменьшить?
18 окт 2019 в 8:23
Да, изменив физический размер в пикселах. Из исходного вопроса непонятно, что имелось в виду подобрать качество сжатия.
Как сжать изображение в Python
Сегодня мы поговорим про то, как сжать изображение в Python. Вы узнаете, как уменьшить размер файла, сжимая и изменяя размер изображения с помощью библиотеки Pillow.
Сжатие изображения — это процесс уменьшения веса картинки без ухудшения ее качества. Есть много онлайн-инструментов, которые предлагают эту услугу. Большинство из них являются отличным вариантом, если вы хотите быстро и надежно уменьшить вес изображения. Но не всегда это лучшее решение. Поэтому в этой статье мы расскажем, как уменьшать размер файла изображения в Python с помощью библиотеки Pillow.
Кроме того, вы можете свободно использовать код из этого руководства. Например, вы можете создать вокруг него API для пакетного уменьшения размеров изображений вместо использования стороннего API, который будет стоить вам денег.
Мы сделали код для данного урока максимально гибким. Вы можете сжать изображение и изменить его размер с коэффициентом масштабирования или точной шириной и высотой. Более того, вы также можете указать желаемое качество.
Начало работы
Приступим! Для начала нужно установить библиотеку Pillow:
$ pip install Pillow
Теперь откройте новый файл Python и импортируйте нашу библиотеку следующим образом:
import os from PIL import Image
Прежде чем углубиться в сжатие изображений, давайте напишем функцию для получения размера файла в удобном для нас формате:
def get_size_format(b, factor=1024, suffix="B"): """ Scale bytes to its proper byte format e.g: 1253656 => '1.20MB' 1253656678 => '1.17GB' """ for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]: if b < factor: return f"" b /= factor return f"Y"
А теперь создадим нашу основную функцию для сжатия изображений. Выглядеть она будет следующим образом:
def compress_img(image_name, new_size_ratio=0.9, quality=90, width=None, height=None, to_jpg=True): # load the image to memory img = Image.open(image_name) # print the original image shape print("[*] Image shape:", img.size) # get the original image size in bytes image_size = os.path.getsize(image_name) # print the size before compression/resizing print("[*] Size before compression:", get_size_format(image_size)) if new_size_ratio < 1.0: # if resizing ratio is below 1.0, then multiply width & height with this ratio to reduce image size img = img.resize((int(img.size[0] * new_size_ratio), int(img.size[1] * new_size_ratio)), Image.ANTIALIAS) # print new image shape print("[+] New Image shape:", img.size) elif width and height: # if width and height are set, resize with them instead img = img.resize((width, height), Image.ANTIALIAS) # print new image shape print("[+] New Image shape:", img.size) # split the filename and extension filename, ext = os.path.splitext(image_name) # make new filename appending _compressed to the original file name if to_jpg: # change the extension to JPEG new_filename = f"_compressed.jpg" else: # retain the same extension of the original image new_filename = f"_compressed" try: # save the image with the corresponding quality and optimize set to True img.save(new_filename, quality=quality, optimize=True) except OSError: # convert the image to RGB mode first img = img.convert("RGB") # save the image with the corresponding quality and optimize set to True img.save(new_filename, quality=quality, optimize=True) print("[+] New file saved:", new_filename) # get the new image size in bytes new_image_size = os.path.getsize(new_filename) # print the new size in a good format print("[+] Size after compression:", get_size_format(new_image_size)) # calculate the saving bytes saving_diff = new_image_size - image_size # print the saving percentage print(f"[+] Image size change: % of the original image size.")
Какая-то гигантская функция, которая делает много всего. Жуть, не правда ли? Но не переживайте. Сейчас мы рассмотрим ее подробнее и всё станет понятно.
- Мы используем метод Image.open() для загрузки изображения в память. Далее мы получаем размер файла изображения с помощью функции os.path.getsize() . Мы делаем это для того, чтобы позже иметь возможность сравнить этот размер с размером нового сгенерированного файла.
- Если значение new_size_ratio меньше 1.0 , то необходимо изменить размер. Это число находится в диапазоне от 0 до 1 и умножается на ширину и высоту исходного изображения, чтобы получить изображение с более низким разрешением. Это подходящий параметр, если вы хотите еще больше уменьшить размер изображения. Вы также можете установить его на 0,95 или 0,9, чтобы уменьшить размер изображения с минимальными изменениями разрешения.
- Если значение new_size_ratio равно 1.0 , но заданы ширина и высота, мы изменяем размер до этих новых значений ширины и высоты. Убедитесь, что они меньше исходной ширины и высоты!
- Если для to_jpg установлено значение True , мы меняем расширение исходного изображения на JPEG. Это значительно уменьшит размер изображения, особенно для изображений PNG. Если возникнет ошибка OSError , преобразование формата изображения в RGB решит данную проблему.
- И наконец, мы используем метод save() для записи оптимизированного изображения. Мы передаем в качестве параметров имя нового файла, желаемое качество и optimize со значением True . После этого мы получаем размер нового изображения. Его мы сравниваем с размером исходного изображения, который получили в самом начале.
Сжатие изображений на примерах
Теперь, когда у нас есть основная функция, давайте воспользуемся модулем argparse , чтобы интегрировать ее с аргументами командной строки. Сделаем это следующим образом:
if __name__ == "__main__": import argparse parser = argparse.ArgumentParser(description="Simple Python script for compressing and resizing images") parser.add_argument("image", help="Target image to compress and/or resize") parser.add_argument("-j", "--to-jpg", action="store_true", help="Whether to convert the image to the JPEG format") parser.add_argument("-q", "--quality", type=int, help="Quality ranging from a minimum of 0 (worst) to a maximum of 95 (best). Default is 90", default=90) parser.add_argument("-r", "--resize-ratio", type=float, help="Resizing ratio from 0 to 1, setting to 0.5 will multiply width & height of the image by 0.5. Default is 1.0", default=1.0) parser.add_argument("-w", "--width", type=int, help="The new width image, make sure to set it with the `height` parameter") parser.add_argument("-hh", "--height", type=int, help="The new height for the image, make sure to set it with the `width` parameter") args = parser.parse_args() # print the passed arguments print("="*50) print("[*] Image:", args.image) print("[*] To JPEG:", args.to_jpg) print("[*] Quality:", args.quality) print("[*] Resizing ratio:", args.resize_ratio) if args.width and args.height: print("[*] Width:", args.width) print("[*] Height:", args.height) print(" https://github.com/x4nth055/pythoncode-tutorials/blob/master/python-for-multimedia/compress-image/sample-satellite-images.png" target="_blank" rel="noreferrer noopener">этой ссылке.Для начала применим наш скрипт без каких-либо параметров. Это будет выглядеть так:
$ python compress_image.py sample-satellite-images.png
И вот какой результат мы получим:
================================================== [*] Image: sample-satellite-images.png [*] To JPEG: False [*] Quality: 90 [*] Resizing ratio: 1.0 ================================================== [*] Image shape: (953, 496) [*] Size before compression: 425.65KB [+] New file saved: sample-satellite-images_compressed.png [+] Size after compression: 379.25KB [+] Image size change: -10.90% of the original image size.Вес изображения уменьшен с 425,65 КБ до 379,25 КБ. Это примерно 11%. Не много, но всё-таки. Далее попробуем передать -j для преобразования нашего изображения из формата PNG в JPEG:
$ python compress_image.py sample-satellite-images.png -j
Запустим наш код и получим следующий результат:
================================================== [*] Image: sample-satellite-images.png [*] To JPEG: True [*] Quality: 90 [*] Resizing ratio: 1.0 ================================================== [*] Image shape: (953, 496) [*] Size before compression: 425.65KB [+] New file saved: sample-satellite-images_compressed.jpg [+] Size after compression: 100.07KB [+] Image size change: -76.49% of the original image size.Примечание. Получить образец данного изображения вы можете здесь.
Это просто фантастика! Как мы видим, вес уменьшился на 76,5%! Теперь немного уменьшим качество с помощью такой команды:
$ python compress_image.py sample-satellite-images.png -j -q 75
И получим следующий вывод:
================================================== [*] Image: sample-satellite-images.png [*] To JPEG: True [*] Quality: 75 [*] Resizing ratio: 1.0 ================================================== [*] Image shape: (953, 496) [*] Size before compression: 425.65KB [+] New file saved: sample-satellite-images_compressed.jpg [+] Size after compression: 64.95KB [+] Image size change: -84.74% of the original image size.Около 85% уменьшения файла без изменения исходного разрешения изображения! Впечатляет, не правда ли? Что ж, давайте попробуем умножить ширину и высоту изображения на 0,9:
$ python compress_image.py sample-satellite-images.png -j -q 75 -r 0.9
И вот что у нас получится:
================================================== [*] Image: sample-satellite-images.png [*] To JPEG: True [*] Quality: 75 [*] Resizing ratio: 0.9 ================================================== [*] Image shape: (953, 496) [*] Size before compression: 425.65KB [+] New Image shape: (857, 446) [+] New file saved: sample-satellite-images_compressed.jpg [+] Size after compression: 56.94KB [+] Image size change: -86.62% of the original image size.Теперь последний штрих. Давайте установим точные значения ширины и высоты:
$ python compress_image.py sample-satellite-images.png -j -q 75 -w 800 -hh 400
Запустим и получим такой результат:
================================================== [*] Image: sample-satellite-images.png [*] To JPEG: True [*] Quality: 75 [*] Resizing ratio: 1.0 [*] Width: 800 [*] Height: 400 ================================================== [*] Image shape: (953, 496) [*] Size before compression: 425.65KB [+] New Image shape: (800, 400) [+] New file saved: sample-satellite-images_compressed.jpg [+] Size after compression: 49.73KB [+] Image size change: -88.32% of the original image size.Потрясающе! Размер изображения уменьшился на 88%! Это прекрасный результат!
Заключение
Итак, теперь вы знаете, как сжать изображение в Python! Мы рассмотрели примеры и смогли уменьшить вес картинки на 88% без ухудшения разрешения. Невероятно! Что ж, теперь вы можете попробовать настроить параметры в соответствии с вашими потребностями.
Мы надеемся, что эта статья была для вас полезна, а данный скрипт будет удобным в использовании и поможет вам в ваших дальнейших проектах!
Полную версию кода можно получить по следующей ссылке.
Получение и изменение размера изображения в Python
Чтобы получить размер изображения с помощью Pillow в Python, используйте свойство size объекта Image. Свойство size возвращает ширину и высоту изображения.
В этом уроке мы узнаем, как получить размер изображения, другими словами, ширину и высоту изображения, используя библиотеку Pillow.
Синтаксис
Синтаксис для использования свойства size объекта PIL Image приведен ниже.
im = Image.open("sample-image.png") im.sizeПример 1
В следующей программе мы будем читать и изображать, а затем распечатывать его размер, используя свойство size объекта Image.
from PIL import Image #read the image im = Image.open("sample-image.png") #image size print(im.size)(640, 400)Пример 2: доступ к ширине и высоте
Вы можете получить доступ к высоте и ширине из свойства size, используя index. В следующем примере мы получим ширину и высоту изображения.
from PIL import Image #read the image im = Image.open("sample-image.png") #image size width = im.size[0] height = im.size[1] print('Width of the image is:', width) print('Height of the image is:', height)Width of the image is: 640 Height of the image is: 400В этом руководстве на примерах Python мы узнали, как получить размер изображения с помощью библиотеки Python Pillow с помощью хорошо подробных примеров программ.
Изменение размера изображения
Чтобы изменить размер изображения с помощью Pillow, вы можете использовать метод resize() класса PIL.Image.Image. Вы можете передать такие параметры, как размер результирующего изображения, фильтр передискретизации пикселей и область блока источника, которую необходимо учитывать.
Синтаксис
Синтаксис метода resize() показан в следующем фрагменте кода.
Image.resize(size, resample=0, box=None)
- size передается, как кортеж (ширина, высота). Это размер, запрошенный для результирующего выходного изображения после изменения размера.
- resample – это фильтр, который должен использоваться для повторной выборки, это необязательно. Вы можете пройти:
- PIL.Image.NEAREST;
- PIL.Image.BOX;
- PIL.Image.BILINEAR;
- PIL.Image.HAMMING;
- PIL.Image.BICUBIC;
- PIL.Image.LANCZOS.
Если для параметра размера заданы правильные значения, вы можете уменьшить или увеличить входное изображение.
Пример 1: со значениями по умолчанию
В следующем примере мы прочитаем изображение и изменим его размер до (200, 200).
from PIL import Image #read the image im = Image.open("sample-image.png") #image size size=(200,200) #resize image out = im.resize(size) #save resized image out.save('resize-output.png')
Для изменения размера рассматривается все исходное изображение, поскольку мы не предоставили никакого значения для параметра box. В следующем примере мы предоставим параметр box и найдем выходное изображение.
Пример 2: с помощью поля входного изображения
В следующем примере мы предоставим параметр box. При этом мы рассматриваем только область поля входного изображения, а затем изменяем его размер до нужного размера.
from PIL import Image #read the image im = Image.open("sample-image.png") #image size size = (200,200) box = (100,100,500,400) #resize image out = im.resize(size, box=box) #save resized image out.save('resize-output.png')
Если вы заметили, для действия изменения размера учитывается только прямоугольная часть входного изображения.
В этом руководстве на примерах Python мы узнали, как изменить размер изображения с помощью библиотеки PIL.
Pillow — работа с картинками
Pillow — самая популярная библиотека для работы с изображениями в Python. С помощью неё картинки можно открывать, вращать, накладывать фильтры и даже работать с отдельными пикселями.
Обзор
Импортируется библиотека так:
from PIL import Image
Pillow — улучшенная версия библиотеки PIL , поэтому импортируется она таким странным образом. В коде она будет называться PIL .
Далее попробуем что-нибудь сделать с картинкой:
from PIL import Image image = Image.open("example.jpg") rotated_image = image.rotate(45) rotated_image.save("rotated.jpg")
Сначала открываем картинку с названием example.jpg и кладём её в переменную image . На следущей строке поворачиваем картинку на 45 градусов. Метод .rotate() не меняет картинку, а создаёт новую, поэтому положим её в переменную rotated_image . И в конце сохраняем повёрнутую картинку в новый файл rotated.jpg .
Атрибуты картинок
В Pillow есть новые типы данных: JpegImageFile , PngImageFile … Они позволяют хранить картинки прямо в переменных Python. У картинок есть несколько атрибутов, которые понадобятся вам в будущем:
- format — формат данных картинки: jpeg , png …
- mode — цветовая модель картинки: CMYK , RGB , L — для чёрно-белых изображений.
- width — ширина картинки в пикселях.
- height — высота картинки в пикселях.
- size — размер картинки в пикселях. Возвращает tuple : (ширина, высота).
Как их извлечь:
from PIL import Image image = Image.open("example.jpg") print(image.format) # Выведет JPG print(image.mode) # Например, может вывести RGB
Открыть картинку
Для открытия картинки используется функция Image.open() .
В качестве аргументов она принимает на вход путь до файла, который нужно открыть:
from PIL import Image image = Image.open("example.jpg")
Сохранить картинку в файл
Для сохранения картинки есть метод .save() .
В качестве аргументов он принимает:
- Путь до файла, в который сохранить картинку.
- Именованный необязательный параметр format , в котором передаётся формат сохраняемой картинки.
from PIL import Image image = Image.open("example.jpg") image.save("new.jpg") image.save("another.jpg", format="JPEG")
В качестве результата появится 2 копии картинки: new.jpg и another.jpg .
Перевести картинку в другую цветовую модель
О цветовой модели вы можете прочитать в разделе Атрибуты. Чтобы поменять цветовую модель картинки, нужно воспользоваться методом .convert() . Он принимает на вход именной аргумент mode :
from PIL import Image image = Image.open("example.jpg") print(image.mode) # Вывелось RGB cmyk_image = image.convert("CMYK") print(cmyk_image.mode) # Вывелось CMYK print(image.mode) # Вывелось RGB
Заметим, что метод не меняет исходную картинку, а создаёт её копию с цветовой моделью CMYK . Поэтому мы положили её в отдельную переменную.
Обрезать картинку
За обрезание картинки отвечает метод .crop() . Он принимает на вход кортеж из 4 чисел: координат углов новой картинки. Координаты отсчитываются с левого верхнего угла картинки:
Координаты нужно передать в таком порядке: слева, сверху, справа, снизу. Например, вы хотите отрезать 10 пикселей слева и 15 сверху:
from PIL import Image image = Image.open("example.jpg") coordinates = (10, 15, image.width, image.height) cropped = image.crop(coordinates) # Отрежется 10 пикселей слева и 15 сверху
Этот код отрезает 10 пикселей слева и 15 сверху. Самая правая координата — это и есть ширина картинки, а самая нижняя — высота, поэтому мы и использовали эти атрибуты картинки.
Разделить картинку на каналы
Картинки состоят из пикселей разных цветов. Каждый пиксель картинки в RGB состоит из 3 значений: сколько в нём красного, сколько зелёного и сколько синего. А в цветовой схеме CMYK из четырёх: голубой, пурпурный, жёлтый и чёрный. Все значения от 0 до 255. 0 — нет такого цвета, а 255 — его очень-очень много.
На самом деле картинки хранят не по пикселям, а по каналам. RGB картинка хранится как 3 картинки: в первой в каждом пикселе число от 0 до 255, показывающее, сколько в нём красного. Во второй то же, только с зелёным, а в третьем — с синим.
Получается 3 картинки. Но если взять какой-то цветовой канал отдельно от картинки, то она не будет знать, какой цвет ей показывать. У неё в каждом пикселе всего одно значение от 0 до 255. Поэтому она отображается как чёрно-белая. Если в пикселе хранится 0, то пиксель будет чёрный, а если 255 — белый. Чем больше число, тем светлее пиксель.
Метод .split() разбивает картинку на каналы. Работает так:
from PIL import Image image = Image.open("example.jpg") print(image.mode) # Вернуло CMYK, значит канала 4 cyan, magenta, yellow, key_color = image.split() # В переменные запишутся 4 чёрно-белые картинки.
Собрать картинку из каналов
Pillow позволяет разделять картинку на каналы. Но так же позволяет и собирать её обратно. За это отвечает функция Image.merge() . Она принимает на вход 2 аргумента:
- Цветовая модель будущей картинки
- Кортеж из цветовых каналов. Если модель RGB, то первый канал будет покрашен в красный, второй в зелёный, третий в синий.
from PIL import Image image = Image.open("example.jpg") print(image.mode) # Вернуло CMYK, значит канала 4 cyan, magenta, yellow, key_color = image.split() # В переменные запишутся 4 чёрно-белые картинки. new_image = Image.merge("CMYK", (cyan, magenta, yellow, key_color))
new_image ничем не отличается от image , т.к. состоит из тех же каналов в том же порядке.
Покрасить цветовой канал
Pillow позволяет раскрашивать чёрно-белые картинки. За это отвечает функция ImageOps.colorize() .
Она принимает 3 аргумента: Картинка, какой цвет показывать вместо чёрного и какой вместо белого. Пример:
from PIL import Image, ImageOps image = Image.open("example.jpg") colorized = ImageOps.colorize(image, black ="red", white ="yellow")
Код выше сделает из такой картинки:
Изменить размер картинки
Как работает thumbnail
Метод resize приводит картинку к желаемому размеру без сохранения пропорций. Картинка жмётся, становится некрасивой:
Метод thumbnail сохраняет пропорции:
Подробнее о thumbnail
С помощью метода .thumbnail() можно легко сделать миниатюру изображения. Миниатюра — уменьшенная версия картинки, с сохранением пропорций. На вход принимается кортеж с максимальными шириной и высотой. Метод .thumbnail() сам подберёт новые координаты так, чтобы картинка поместилась в заданную область. Например, у вас есть картинка 800x1200 и вы хотите поместить её в рамку 1200x600, то результат метода будет 400x600, т.к. 400x600 как раз помещается в 1200x600:
from PIL import Image image = Image.open("example.jpg") print(image.size) # Вывелось (800, 1200) image.thumbnail((1200, 600)) # Картинка теперь размера 400 на 600 print(image.size) # Вывелось (400, 600)
Наложить картинки друг на друга
Функция Image.blend() создаёт новую картинку, накладывая одно изображение поверх другого. Для работы ему необходимы три аргумента:
- Первая картинка.
- Вторая картинка, того же размера, что и первая.
- Коэффициент прозрачности.
Если прозрачность равна 0.5, то картинки смешаются в равных долях. Если коэффициент равен 1.0, то первая картинка станет полностью прозрачной и останется только вторая. Если 0.0, то наоборот. Прозрачность задаётся дробным числом через точку.
from PIL import Image image1 = Image.open("image1.jpg") image2 = Image.open("image2.jpg") image3 = Image.blend(image1, image2, 0.5) # Получится картинка, сложенная из двух
Наложить со смещением
Отдельного метода для этого нет, но получается за счёт комбинации .crop() и Image.blend().
- Выберите картинку для эффекта. У нас это картинка wave.png с шириной в 1000 пикселей.
- Отрежьте от неё 200 пикселей слева. Получится wave_left.png шириной 800 пикселей.
- Возьмите исходную картинку wave.png и отрежьте от неё по 100 пикселей с обоих сторон: слева и справа. Получится wave_middle.png тоже шириной в 800 пикселей.
- Наложите wave_left.png на wave_middle.png с помощью Image.blend()
- Сохраните в файл то, что получилось. Это картинка смещённая влево.
Попробуйте бесплатные уроки по Python
Получите крутое код-ревью от практикующих программистов с разбором ошибок и рекомендациями, на что обратить внимание — бесплатно.
Переходите на страницу учебных модулей «Девмана» и выбирайте тему.