Меня недавно попросили преобразовать несколько сотен изображений в страницы PDF. Мой друг рисует комиксы, а мой брат хотел прочитать их на планшете. Увы, если у вас есть куча файлов с именем примерно так:
‘Jia_01.Jpg’, ‘Jia_02.Jpg’, ‘Jia_09.Jpg’, ‘Jia_10.Jpg’, ‘Jia_11.Jpg’, ‘Jia_101.Jpg’
планшет Android переупорядочит их примерно так:
‘Jia_01.Jpg’, ‘Jia_02.Jpg’, ‘Jia_09.Jpg’, ‘Jia_10.Jpg’, ‘Jia_101.Jpg’, ‘Jia_11.Jpg’
И это сбивало с толку все больше файлов, которые у вас были не в порядке. К сожалению, даже Python сортирует файлы таким образом. Я попытался использовать модуль glob непосредственно на них, а затем отсортировал результат и получил точно такую же проблему. Поэтому первое, что мне нужно было сделать, — это найти какой-то алгоритм сортировки, который мог бы правильно их сортировать. Следует отметить, что Windows 7 может правильно сортировать файлы в своей файловой системе, хотя Python не может.
После небольшого поиска в Google я нашел следующий скрипт в StackOverflow :
import re
#----------------------------------------------------------------------
def sorted_nicely( l ):
"""
Sort the given iterable in the way that humans expect.
"""
convert = lambda text: int(text) if text.isdigit() else text
alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ]
return sorted(l, key = alphanum_key)
Это сработало отлично! Теперь мне просто нужно было найти способ разместить каждую комическую страницу на своей собственной странице PDF. К счастью, библиотека reportlab позволяет сделать это довольно легко. Вам просто нужно перебирать изображения и вставлять их по одной на страницу. Проще взглянуть на код, поэтому давайте сделаем это:
import glob
import os
import re
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Image, PageBreak
from reportlab.lib.units import inch
#----------------------------------------------------------------------
def sorted_nicely( l ):
"""
# http://stackoverflow.com/questions/2669059/how-to-sort-alpha-numeric-set-in-python
Sort the given iterable in the way that humans expect.
"""
convert = lambda text: int(text) if text.isdigit() else text
alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ]
return sorted(l, key = alphanum_key)
#----------------------------------------------------------------------
def create_comic(fname, front_cover, back_cover, path):
""""""
filename = os.path.join(path, fname + ".pdf")
doc = SimpleDocTemplate(filename,pagesize=letter,
rightMargin=72,leftMargin=72,
topMargin=72,bottomMargin=18)
Story=[]
width = 7.5*inch
height = 9.5*inch
pictures = sorted_nicely(glob.glob(path + "\\%s*" % fname))
Story.append(Image(front_cover, width, height))
Story.append(PageBreak())
x = 0
page_nums = {100:'%s_101-200.pdf', 200:'%s_201-300.pdf',
300:'%s_301-400.pdf', 400:'%s_401-500.pdf',
500:'%s_end.pdf'}
for pic in pictures:
parts = pic.split("\\")
p = parts[-1].split("%s" % fname)
page_num = int(p[-1].split(".")[0])
print "page_num => ", page_num
im = Image(pic, width, height)
Story.append(im)
Story.append(PageBreak())
if page_num in page_nums.keys():
print "%s created" % filename
doc.build(Story)
filename = os.path.join(path, page_nums[page_num] % fname)
doc = SimpleDocTemplate(filename,
pagesize=letter,
rightMargin=72,leftMargin=72,
topMargin=72,bottomMargin=18)
Story=[]
print pic
x += 1
Story.append(Image(back_cover, width, height))
doc.build(Story)
print "%s created" % filename
#----------------------------------------------------------------------
if __name__ == "__main__":
path = r"C:\Users\Mike\Desktop\Sam's Comics"
front_cover = os.path.join(path, "FrontCover.jpg")
back_cover = os.path.join(path, "BackCover2.jpg")
create_comic("Jia_", front_cover, back_cover, path)
Давайте разберемся с этим немного. Как обычно, у вас есть некоторые необходимые импорты, необходимые для работы этого кода. Вы заметите, что у нас также есть та функция sorted_nicely, о которой мы говорили ранее, также в этом коде. Основная функция называется create_comic и принимает четыре аргумента: fname, front_cover, back_cover, path. Если вы ранее использовали инструментарий reportlab, то вы узнаете SimpleDocTemplate и список Story, так как они прямо из учебника reportlab.
В любом случае, вы перебираете отсортированные изображения и добавляете изображение в Story вместе с объектом PageBreak. Причина в том, что в цикле есть условие, состоит в том, что я обнаружил, что если я попытаюсь создать PDF со всеми 400+ изображениями, у меня возникнет ошибка памяти. Поэтому я разбил его на серию документов в формате PDF объемом не более 100 страниц. В конце документа вы должны вызвать метод build объекта doc , чтобы фактически создать документ PDF.
Теперь вы знаете, как я закончил писать целую кучу изображений в нескольких документах PDF. Теоретически, вы можете использовать PyPdf, чтобы объединить все полученные PDF-файлы в один PDF-файл, но я не пробовал. Вы можете закончить с другой ошибкой памяти. Я оставлю это как упражнение для читателя.
Исходный код