Преобразование изображений в PDF с помощью Python

Преобразование изображений в PDF с помощью Python

Недавно мне понадобилось преобразовать несколько изображений в PDF-файлы, что привело меня к изучению конвертирования изображений. Присоединяйтесь, если вам интересно!

Растровые и векторные изображения

Во-первых, давайте разберемся, как изображения представлены в данных.

Растровые изображения состоят из пикселей. Пиксель — это наименьший квадрат в растровом изображении, содержащий информацию об изображении. Пиксель может включать цвет и непрозрачность. Чем больше пикселей на изображении, тем лучше качество. Изображения с низким количеством пикселей имеют более низкое разрешение и могут иметь неровные края. Они не могут быть увеличены без потери разрешения. Растровые изображения совместимы со многими устройствами или программными обеспечениями.

Примерами форматов растровых изображений являются JPEG, PNG, TIFF, GIF и BMP.

С другой стороны, векторные изображения состоят из кривых и траекторий, созданных математическими формулами. Благодаря этому они бесконечно масштабируются без потери какого-либо разрешения. Эти изображения обычно не поддерживаются многими устройствами и они часто привязаны к определенному программному обеспечению, такому как Adobe Illustrator.

Из-за того, что они состоят из математических формул, их размеры файлов обычно меньше, чем их растровые аналоги.

Примерами форматов векторных изображений являются SVG, AI (Adobe Illustrator) и EPS (Encapsulated PostScript).

В этой статье я решил сосредоточиться на растровых изображениях.

Что такое пиксель

Пиксель — это наименьшая единица растрового изображения, обычно небольшой квадрат. Размеры изображения обычно представляются в формате [width px x height px], основанном на количестве пикселей в осях x и y. Таким образом, если изображение имеет размер [100px x 200px], оно имеет 100 пикселей на оси x и 200 пикселей на оси y и в общей сложности 20 000 отдельных пикселей.

Группы данных

Изображение может состоять из одной или нескольких полос данных для каждого пикселя. Например, изображение PNG может иметь полосы «R», «G», «B» и «A» для красного, зеленого, синего и альфа значений прозрачности.

Пиксельная или битовая глубина

Этот раздел относится к количеству информации, которая может храниться в каждом пикселе. Например, 1-битная глубина означает, что возможный диапазон значений, которые могут быть сохранены в пикселе, равен 2^1 = 2. Это обычно используется в черно-белых изображениях без изменения непрозрачности. 8-битная глубина означает 2^8 = 256 возможных вариаций в одном пикселе. Изображение JPEG с полосой RGB имеет 3×8 бит, по одному для каждой цветовой полосы.

Теперь, давайте создадим виртуальную среду для нашего проекта:

python3 -m venv image_tutorial
source venv/bin/activate

Я буду использовать это изображение Чарльза Делувио c с сервиса Unsplash:

charles-deluvio-pOUA8Xay514-unsplash.jpg

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

Преобразование изображение в PDF

Если все, что вы хотите — это преобразовать изображение в PDF без значительных изменений изображения, то «img2pdf» — это отличный и эффективный пакет, который делает это за вас с небольшим количеством кода.

Давайте сначала установим его в наше виртуальное окружение, а затем вернемся в оболочку Python:

pip install img2pdf

Во-первых, я определю размер страницы формата А4 [8,3 х 11,7 дюйма] с помощью некоторых включенных утилит калибровки:

import img2pdf

a4_page_size = [img2pdf.in_to_pt(8.3), img2pdf.in_to_pt(11.7)]
layout_function = img2pdf.get_layout_fun(a4_page_size)

Наконец, создаю PDF-файл в памяти и записываю его в файл:

pdf = img2pdf.convert('insert image file name/path', layout_fun=layout_function)
with open('A4_dog.pdf', 'wb') as f:
     f.write(pdf)

Довольно просто, правда?!

Однако результирующий файл довольно большой, это потому, что наше входное изображение было большим. В следующем разделе мы будем использовать Pillow, чтобы уменьшить размер файла, а затем создать PDF-файл.

Использование библиотеки Pillow

Pillow — это популярная и мощная библиотека обработки изображений Python. Я буду использовать её для обработки, а затем для преобразования изображения в PDF.

Во-первых, установите Pillow в нашу виртуальную среду:

pip install Pillow

Давайте откроем оболочку Python и посмотрим, что мы можем узнать о нашем изображении. Введите следующие команды:

from PIL import Image
dog_jpg = Image.open('insert image path here')

Это загрузит наше изображение в память и создаст его экземпляр. Также мы можем узнать некоторые полезные сведения об этом изображении:

dog_jpg.format   # returns the image format
# output: 'JPEG'
dog_jpg.size   # returns the size of the image as (x pixels, y pixels)
# output: (3487, 5230)
dog_jpg.mode   # returns the image bands
# output: 'RGB'
dog_jpg.show()   # opens the image in your default viewer

Наше изображение довольно большое — [3 МБ]. Но мы можем уменьшить размер файла двумя способами:

  • Уменьшить количество пикселей.
  • Ещё больше сжать изображение.

Оба метода уменьшат качество файла и, следовательно, его размер. Я считаю, что сочетание обоих методов дает наилучшие результаты.

Давайте уменьшим количество пикселей, и снизим качество до 85%. Сжатие доступно не для всех форматов изображений, обратитесь к документации для получения информации о том, что возможно для каждого формата.

Я хочу чтобы наш файл помещался на странице формата А4 [8,3 х 11,7 дюйма] с разрешением 200 пикселей на дюйм (PPI или DPI). Давайте определимся с количеством пикселей, которое должна содержать вся страница:

page_size = [int(8.3 * 200), int(11.7 * 200)]
page_size
# output: [1660, 2340]

Наше изображение, конечно, слишком велико, чтобы поместиться на странице с таким разрешением. Нам нужно изменить его размер, чтобы убедиться, что он подходит. Для этого я уменьшу ширину и высоту на один и тот же коэффициент, чтобы сохранить соотношение сторон изображения (отношение ширины к высоте), иначе оно будет выглядеть шатким:

target_width, target_height = page_size
current_width, current_height = dog_jpg.size
scale = max(current_width /target_width, current_height/target_height)

Я устанавливаю масштаб больший из масштабного коэффициента ширины или высоты, чтобы гарантировать, что изображение, безусловно, будет соответствовать обоим размерам страницы.

Разделите оба размера изображения собаки на шкалу, чтобы получить окончательный размер. Мы округляем его в меньшую сторону, потому что значения размера должны быть целыми числами:

final_image_size = [round(current_width / scale), round(current_height / scale)]
final_image_size
# output: [1560, 2340]

Измените размер изображения до его новых размеров. Я пересчитываю изображение с помощью фильтра под названием «LANCZOS», который дает лучшее качество, но работает медленно. Поскольку мы обрабатываем только одно изображение, это не должно быть проблемой. Подробнее о фильтрах вы можете прочитать здесь.

Это приведет к созданию новой измененной копии «dog_jpg» с исходным экземпляром, оставшимся неизменным:

resized_image = dog_jpg.resize(size=final_image_size, resample=Image.LANCZOS)
resized_image.size
# output: (1560, 2340)

В этот момент наше изображение может поместиться на странице формата А4. Однако на оставшейся странице будет 100 пикселей по ширине. Нам нужно заполнить пространство так, чтобы наше изображение точно соответствовало странице формата А4.

Для этого я создам новое изображение, которое будет полностью белым с размерами страницы формата А4, а затем вставлю поверх него изображение нашей собаки:

canvas_image = Image.new(mode='RGB', size=page_size, color='white')
canvas_image.show()

Этот код должен открыть пустое белое изображение размером со страницу формата А4 с разрешением 200 PPI.

Я хочу, чтобы изображение было центрировано на странице, поэтому я помещу 50px пробелов с обеих сторон изображения.

Pillow использует систему координат для отображения изображений сверху слева. Например, [220, 0] относится к 220px справа от верхнего левого края изображения. [100, 50] относится к точке 100px слева и 50px сверху изображения.

Я хочу вставить наше изображение вдоль верхнего края 50px справа от верхнего левого угла холста. Это переводится в положение [50, 0].

Обратите внимание, что функция вставки изменяет вставляемое изображение. Сделайте копию изображения (canvas_image в нашем случае), если это нежелательно:

canvas_image.paste(resized_image, box=(50,0))
canvas_image.show()

Давайте сначала сохраним это изображение в формате JPEG, а затем преобразуем его в PDF. Аргумент качества ниже относится к степени сжатия, применяемой к изображению. Документацию JPEG writer можно посмотреть здесь вместе с другими доступными writers:

canvas_image.save('A4_dog_image.jpeg', format='JPEG', quality=85, optimize=True)

Данное написание кода сохранит новый образ в том же каталоге, что и виртуальное окружение, которое мы создали ранее. Изображение должно выглядеть так:

A4_dog_image.jpeg

Исходное изображение имело размер [3 МБ], а окончательное — около [533 КБ], и оно все еще пригодно для использования.

Наконец, давайте преобразуем это изображение в PDF. Аргумент качества ниже в контексте записи PDF относится к разрешению результирующего PDF в DPI/PPI. Я передаю значение 200, которое мы использовали для масштабирования изображений с самого начала:

canvas_image.save('A4_dog.pdf', format='PDF', quality=200)

И мы закончили! Результирующий PDF-файл будет значительно меньше, чем исходный, который я сгенерировал, потому что я уменьшил масштаб и сжал изображение.

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

Вывод

Эти решения не являются взаимоисключающими, вы можете использовать Pillow для обработки изображений, а затем использовать img2pdf для создания PDF-файлов.

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

Желаю удачи с конвертированием изображений!

Егор Егоров

Программирую на Python с 2017 года. Люблю создавать контент, который помогает людям понять сложные вещи. Не представляю жизнь без непрерывного цикла обучения, спорта и чувства юмора.

Ссылка на мой github есть в шапке. Залетай.

Оцените автора
Егоров Егор
Добавить комментарий

  1. Игорь

    Очень приятная статья.
    Для изменения размера картинки (в меньшую сторону) применяется ещё другой метод:

    from PIL import Image

    image_path = ‘F:/hello.png’

    img = Image.open(image_path)
    # пропорциональное изменение картинки
    img.thumbnail(size=(350,400))

    Ответить
  2. Python

    Автор молодец

    Ответить
    1. Егор Егоров автор

      Спасибо! 🙂

      Ответить
  3. Прокрастинатор

    Автор молодец. Я залипла на картинки. Куча дел, а я разглядываю обложки

    Ответить
    1. Егор Егоров автор

      Вы тоже молодец! 🙂

      Ответить
    2. Егор Егоров автор

      обложки как раз нужны для привлечения внимания)) но все-таки в статьях вся польза)

      Ответить
  4. Asya

    Я ни когда не думала что в одном маленьком фотографии много инфармации можно найти.благодаря вам я узнала как менять размер пикселя и главное что такое пиксель.теперь буду эти навыки выполнять.

    Ответить
    1. Егор Егоров автор

      согласен)

      Ответить