Share This
Связаться со мной
Крути в низ
Categories
//Как сжать изображение в Python

Как сжать изображение в Python

15.05.2022Category : 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:.2f}{unit}{suffix}"         b /= factor     return f"{b:.2f}Y{suffix}"

А теперь создадим нашу основную функцию для сжатия изображений. Выглядеть она будет следующим образом:

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"{filename}_compressed.jpg"     else:         # retain the same extension of the original image         new_filename = f"{filename}_compressed{ext}"     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: {saving_diff/image_size*100:.2f}% of the original image size.")

Какая-то гигантская функция, которая делает много всего. Жуть, не правда ли? Но не переживайте. Сейчас мы рассмотрим ее подробнее и всё станет понятно. 

kak szhat izobrazhenie v python d08034c - Как сжать изображение в Python

Английский для программистов

Наш телеграм канал с тестами по английскому языку для программистов. Английский это часть карьеры программиста. Поэтому полезно заняться им уже сейчас

Подробнее ×

Итак:

  1. Мы используем метод Image.open() для загрузки изображения в память. Далее мы получаем размер файла изображения с помощью функции os.path.getsize(). Мы делаем это для того, чтобы позже иметь возможность сравнить этот размер с размером нового сгенерированного файла.
  2. Если значение new_size_ratio меньше 1.0, то необходимо изменить размер. Это число находится в диапазоне от 0 до 1 и умножается на ширину и высоту исходного изображения, чтобы получить изображение с более низким разрешением. Это подходящий параметр, если вы хотите еще больше уменьшить размер изображения. Вы также можете установить его на 0,95 или 0,9, чтобы уменьшить размер изображения с минимальными изменениями разрешения.
  3. Если значение new_size_ratio равно 1.0, но заданы ширина и высота, мы изменяем размер до этих новых значений ширины и высоты. Убедитесь, что они меньше исходной ширины и высоты!
  4. Если для to_jpg установлено значение True, мы меняем расширение исходного изображения на JPEG. Это значительно уменьшит размер изображения, особенно для изображений PNG. Если возникнет ошибка OSError, преобразование формата изображения в RGB решит данную проблему.
  5. И наконец, мы используем метод 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("="*50)     # compress the image     compress_img(args.image, args.resize_ratio, args.quality, args.width, args.height, args.to_jpg)

Здесь мы создали парсер аргументов командной строки и добавили параметры, которые уже обсуждали выше.

Теперь воспользуемся нашим скриптом. Вы можете получить пример изображения по этой ссылке.

Для начала применим наш скрипт без каких-либо параметров. Это будет выглядеть так:

$ 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% без ухудшения разрешения. Невероятно! Что ж, теперь вы можете попробовать настроить параметры в соответствии с вашими потребностями. 

Мы надеемся, что эта статья была для вас полезна, а данный скрипт будет удобным в использовании и поможет вам в ваших дальнейших проектах!

Полную версию кода можно получить по следующей ссылке.

Перевод статьи «How to Compress Images in Python».

  • 3 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Свежие комментарии

    Рубрики

    About Author 01.

    blank
    Roman Spiridonov

    Моя специальность - Back-end Developer, Software Engineer Python. Мне 39 лет, я работаю в области информационных технологий более 5 лет. Опыт программирования на Python более 3 лет. На Django более 2 лет.

    Categories 05.

    © Speccy 2022 / All rights reserved

    Связаться со мной
    Close