{"id":2699,"date":"2024-10-02T19:57:59","date_gmt":"2024-10-02T10:57:59","guid":{"rendered":"https:\/\/secondlife.lol\/?p=2699"},"modified":"2024-09-29T21:43:39","modified_gmt":"2024-09-29T12:43:39","slug":"converting-multiple-images-to-pdf-python","status":"publish","type":"post","link":"https:\/\/secondlife.lol\/en\/converting-multiple-images-to-pdf-python\/","title":{"rendered":"Repeating multiple image to PDF conversions: Easily automate with Python code"},"content":{"rendered":"<p><a href=\"https:\/\/secondlife.lol\/en\/python-pdf-image-processing-pillow-reportlab\/\" data-type=\"link\" data-id=\"https:\/\/secondlife.lol\/python-pdf-image-processing-pillow-reportlab\/\">Previous Post<\/a>on how to convert multiple images to PDF? Today, we're going to take it a step further: what if you've created a multi-image PDF file from a subfolder (A) in a specific folder, and that specific folder has other images in another subfolder (B)? What if a folder contains a mix of folders where you've already created PDF files and folders where you haven't, and you want to convert each folder to PDF? It's a bit more complicated than it sounds when I write it down, so take a look below to see what I mean. <\/p>\n\n\n<style>.kb-image2699_6099ec-df .kb-image-has-overlay:after{opacity:0.3;}<\/style>\n<div class=\"wp-block-kadence-image kb-image2699_6099ec-df\"><figure class=\"aligncenter size-full\"><img decoding=\"async\" width=\"506\" height=\"217\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2024\/09\/image-6.png\" alt=\"\uc5ec\ub7ec \uc774\ubbf8\uc9c0 PDF \ubcc0\ud658 \ud3ec\uc2a4\ud2b8 \uadf8\ub9bc\" class=\"kb-img wp-image-2700\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2024\/09\/image-6.png 506w, https:\/\/secondlife.lol\/wp-content\/uploads\/2024\/09\/image-6-300x129.png 300w\" sizes=\"(max-width: 506px) 100vw, 506px\" \/><\/figure><\/div>\n\n\n<style>.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-content-wrap{padding-top:var(--global-kb-spacing-sm, 1.5rem);padding-right:var(--global-kb-spacing-sm, 1.5rem);padding-bottom:var(--global-kb-spacing-sm, 1.5rem);padding-left:var(--global-kb-spacing-sm, 1.5rem);border-top:3px solid var(--global-palette2, #2B6CB0);border-right:3px solid var(--global-palette2, #2B6CB0);border-bottom:3px solid var(--global-palette2, #2B6CB0);border-left:3px solid var(--global-palette2, #2B6CB0);border-top-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px;border-bottom-left-radius:5px;box-shadow:0px 0px 14px 0px rgba(0, 0, 0, 0.2);}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-contents-title-wrap{padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-contents-title-wrap{color:var(--global-palette2, #2B6CB0);}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-contents-title{color:var(--global-palette2, #2B6CB0);font-size:28px;font-weight:regular;font-style:normal;}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-content-wrap .kb-table-of-content-list{color:var(--global-palette1, #3182CE);line-height:2em;font-weight:regular;font-style:normal;margin-top:var(--global-kb-spacing-sm, 1.5rem);margin-right:0px;margin-bottom:0px;margin-left:0px;}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-content-wrap .kb-table-of-content-list .kb-table-of-contents__entry:hover{color:var(--global-palette6, #718096);}@media all and (max-width: 1024px){.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-content-wrap{border-top:3px solid var(--global-palette2, #2B6CB0);border-right:3px solid var(--global-palette2, #2B6CB0);border-bottom:3px solid var(--global-palette2, #2B6CB0);border-left:3px solid var(--global-palette2, #2B6CB0);}}@media all and (max-width: 1024px){.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-contents-title{font-size:28px;}}@media all and (max-width: 767px){.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-content-wrap{border-top:3px solid var(--global-palette2, #2B6CB0);border-right:3px solid var(--global-palette2, #2B6CB0);border-bottom:3px solid var(--global-palette2, #2B6CB0);border-left:3px solid var(--global-palette2, #2B6CB0);}.kb-table-of-content-nav.kb-table-of-content-id83_5f28a6-34 .kb-table-of-contents-title{font-size:28px;}}<\/style>\n\n\n<h2 class=\"wp-block-heading\">Code description: Convert multiple images to PDF with Python<\/h2>\n\n\n\n<p>In this code, the <strong><a href=\"https:\/\/python-pillow.org\/\" target=\"_blank\" rel=\"noopener\">Pillow<\/a><\/strong>and <strong><a href=\"https:\/\/docs.reportlab.com\/\" data-type=\"link\" data-id=\"https:\/\/docs.reportlab.com\/\" target=\"_blank\" rel=\"noopener\">ReportLab<\/a><\/strong> Use libraries to automate multiple image to PDF conversions. During image processing and PDF creation, you can navigate through a directory structure to convert multiple images to PDFs individually.<\/p>\n\n\n<style>.kb-image2699_863a93-4f .kb-image-has-overlay:after{opacity:0.3;}.kb-image2699_863a93-4f img.kb-img, .kb-image2699_863a93-4f .kb-img img{box-shadow:0px 0px 14px 0px rgba(0, 0, 0, 0.2);}<\/style>\n<div class=\"wp-block-kadence-image kb-image2699_863a93-4f\"><figure class=\"aligncenter size-medium_large\"><img decoding=\"async\" width=\"768\" height=\"520\" src=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2024\/09\/image-7-7-768x520.jpg\" alt=\"\uc5ec\ub7ec \uc774\ubbf8\uc9c0 PDF \ubcc0\ud658 \ud3ec\uc2a4\ud2b8 \uadf8\ub9bc\" class=\"kb-img wp-image-2714\" srcset=\"https:\/\/secondlife.lol\/wp-content\/uploads\/2024\/09\/image-7-7-768x520.jpg 768w, https:\/\/secondlife.lol\/wp-content\/uploads\/2024\/09\/image-7-7-300x203.jpg 300w, https:\/\/secondlife.lol\/wp-content\/uploads\/2024\/09\/image-7-7-600x406.jpg 600w, https:\/\/secondlife.lol\/wp-content\/uploads\/2024\/09\/image-7-7.jpg 1200w\" sizes=\"(max-width: 768px) 100vw, 768px\" \/><\/figure><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">1. load the required Python libraries<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>import os\nfrom PIL import Image\nfrom reportlab.pdfgen import canvas\nfrom reportlab.lib.pagesizes import portrait<\/code><\/pre>\n\n\n\n<p>The first step is to load the necessary libraries, in this case the <strong>os, PIL<\/strong>The <strong>Image<\/strong>and <strong>ReportLab<\/strong>The <strong>canvas<\/strong> and <strong>portrait<\/strong> Use the Page Size option.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>os<\/code>: Browse files in a directory and create paths.<\/li>\n\n\n\n<li><code>Pillow (PIL)<\/code>: Open and process an image file.<\/li>\n\n\n\n<li><code>ReportLab<\/code>: Create a PDF file and insert an image.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">2. Write an image processing function<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>def process_images(c, dir_path):\n    img_list = sorted([img_name for img_name in os.listdir(dir_path) if img_name.endswith(\".png\")])\n    if img_list:\n        for img_name in img_list[1:]:\n            img_path = os.path.join(dir_path, img_name)\n            img = Image.open(img_path)\n            img_width, img_height = img.size\n            c.setPageSize((img_width, img_height))\n            c.showPage()\n            c.drawInlineImage(img_path, 0, 0, width=img_width, height=img_height)<\/code><\/pre>\n\n\n\n<p>This function is a key part of processing image files and converting them to PDFs.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>img_list<\/strong>: Get only \".png\" files from the given directory and sort them.<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>os.listdir(dir_path)<\/code>will get all files in the directory, <code>if img_name.endswith(\".png\")<\/code> The condition selects only PNG files.<\/li>\n\n\n\n<li><strong>Open an image file<\/strong>: After creating the image path <code>Image.open()<\/code>to open the image.<\/li>\n\n\n\n<li><strong>Setting the page size<\/strong>: <code>setPageSize()<\/code>to set the page size to fit the image size.<\/li>\n\n\n\n<li><strong>Add an image<\/strong>: <code>drawInlineImage()<\/code>to insert an image into a PDF page.<\/li>\n\n\n\n<li><strong>showPage()<\/strong>: Finish the page and prepare a new page.<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\"><\/ol>\n\n\n\n<p>This process converts each PNG file into one PDF page.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">3. Handle subdirectories within a directory<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>def process_subdirs(main_dir, output_dir):\n    for subdir in os.listdir(main_dir):\n        subdir_path = os.path.join(main_dir, subdir)\n        if os.path.isdir(subdir_path):\n            for second_subdir in os.listdir(subdir_path):\n                second_subdir_path = os.path.join(subdir_path, second_subdir)\n                if os.path.isdir(second_subdir_path):\n                    pdf_path = os.path.join(output_dir, subdir, f\"{second_subdir}.pdf\")\n                    if not os.path.exists(pdf_path):\n                        os.makedirs(os.path.dirname(pdf_path), exist_ok=True)\n                        c = canvas.Canvas(pdf_path, pagesize=None)\n                        process_images(c, second_subdir_path)\n                        c.save()\n                        print(f\"Generated PDF file: {pdf_path}\")<\/code><\/pre>\n\n\n\n<p>This function is responsible for processing all subdirectories within a given main directory, generating a PDF file for each directory.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>os.listdir()<\/strong>: Gets a list of files in the main directory and subdirectories.<\/li>\n<\/ol>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>os.path.isdir()<\/code> Condition to determine if it's a directory.<\/li>\n\n\n\n<li><strong>Create a path to a PDF file<\/strong>: <code>os.path.join()<\/code>to create the path to the PDF file, and will only create the PDF file if it doesn't already exist.<\/li>\n\n\n\n<li><strong>Create and save PDFs<\/strong>: by creating a Canvas object, <code>process_images()<\/code> function to process the image and save the PDF file.<\/li>\n\n\n\n<li><strong>os.makedirs()<\/strong>: Create a folder to store the PDF file if it doesn't already exist.<\/li>\n<\/ul>\n\n\n\n<ol class=\"wp-block-list\"><\/ol>\n\n\n\n<p>This function traverses the directory structure and automatically converts the PNG files in each subdirectory to PDF.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4. call the main function<\/h3>\n\n\n\n<pre class=\"wp-block-code\"><code>main_dir = \"C:\\\\Users\\\\user\\\\Documents\\\\Book\"\noutput_dir = \"C:\\\\Users\\\\user\\\\Documents\\\\Book_pdf\"\nprocess_subdirs(main_dir, output_dir)<\/code><\/pre>\n\n\n\n<p>Finally, run the PDF conversion job on the given path.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>main_dir<\/strong>: Path to the main directory, including images.<\/li>\n\n\n\n<li><strong>output_dir<\/strong>Path where the PDF file will be saved.<\/li>\n\n\n\n<li><strong>process_subdirs()<\/strong> function is called, which converts all images in the main directory and saves them as PDFs.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Full Python code<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>import os\nfrom PIL import Image\nfrom reportlab.pdfgen import canvas\nfrom reportlab.lib.pagesizes import portrait\n\ndef process_images(c, dir_path):\n    img_list = sorted([img_name for img_name in os.listdir(dir_path) if img_name.endswith(\".png\")])\n    if img_list:\n        for img_name in img_list[1:]:\n            img_path = os.path.join(dir_path, img_name)\n            img = Image.open(img_path)\n            img_width, img_height = img.size\n            c.setPageSize((img_width, img_height))\n            c.showPage()\n            c.drawInlineImage(img_path, 0, 0, width=img_width, height=img_height)\n\ndef process_subdirs(main_dir, output_dir):\n    for subdir in os.listdir(main_dir):\n        subdir_path = os.path.join(main_dir, subdir)\n        if os.path.isdir(subdir_path):\n            for second_subdir in os.listdir(subdir_path):\n                second_subdir_path = os.path.join(subdir_path, second_subdir)\n                if os.path.isdir(second_subdir_path):\n                    pdf_path = os.path.join(output_dir, subdir, f\"{second_subdir}.pdf\")\n                    if not os.path.exists(pdf_path):  <strong># Run only if no PDF file has already been created<\/strong>\n                        os.makedirs(os.path.dirname(pdf_path), exist_ok=True)\n                        c = canvas.Canvas(pdf_path, pagesize=None)\n                        process_images(c, second_subdir_path)\n                        c.save()\n                        print(f\"Generated PDF file: {pdf_path}\")\n\n# starting point\nmain_dir = \"C:\\\\Users\\\\user\\\\Documents\\\\Book\"\noutput_dir = \"C:\\\\Users\\\\user\\\\Documents\\\\Book_pdf\"\nprocess_subdirs(main_dir, output_dir)<\/code><\/pre>\n\n\n\n<p>This code automates the process of finding PNG image files in multiple directories and converting them to PDF. Now you too can use Python to efficiently handle multiple image to PDF conversion tasks!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"># Additional description<\/h3>\n\n\n\n<p>I'm going to try to explain what I want to do in Python code, which might make it more difficult, so I'm going to write some additional details. For example, let's say I have 1, 2, 3... subfolders under folder A, and the same 1, 2, 3... subfolders under folder B. Each subfolder in folder A contains png image files, so after doing the above, you'll have multiple images in folder B, each with the same folder name, in a single pdf file. <\/p>\n\n\n\n<p>However, if we want to leave the images in folder A, where the pdf file was already created in folder B, undeleted, we need to code the Python so that the subfolder of folder A, where the pdf file was created, should be skipped when the above operation is performed. In the full code above, you can see the '#<strong>Run only if no PDF file has already been created<\/strong>' will do the job. Now you should be able to easily convert multiple images to PDF per folder.<\/p>","protected":false},"excerpt":{"rendered":"<p>\uc774\uc804 \ud3ec\uc2a4\ud2b8\uc5d0\uc11c \uc5ec\ub7ec \uc774\ubbf8\uc9c0 PDF \ubcc0\ud658 \ubc29\ubc95\uc744 \ud655\uc778\ud574 \ubcf4\uc168\ub098\uc694? \uc624\ub298\uc740&#8230;<\/p>","protected":false},"author":3,"featured_media":2717,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"categories":[3],"tags":[291,297,293,295,298,299],"class_list":{"0":"post-2699","1":"post","2":"type-post","3":"status-publish","4":"format-standard","5":"has-post-thumbnail","6":"hentry","7":"category-python-coding","8":"tag-python-pdf","9":"tag---pdf-","10":"tag--pdf-","11":"tag-295","13":"tag-299"},"taxonomy_info":{"category":[{"value":3,"label":"\ud30c\uc774\uc36c(Python)"}],"post_tag":[{"value":291,"label":"Python PDF"},{"value":297,"label":"\uc5ec\ub7ec \uc774\ubbf8\uc9c0 PDF \ubcc0\ud658"},{"value":293,"label":"\uc774\ubbf8\uc9c0 PDF \ubcc0\ud658"},{"value":295,"label":"\uc774\ubbf8\uc9c0 \ucc98\ub9ac"},{"value":298,"label":"\ud30c\uc774\uc36c PDF \uc0dd\uc131"},{"value":299,"label":"\ud30c\uc774\uc36c \uc790\ub3d9\ud654"}]},"featured_image_src_large":["https:\/\/secondlife.lol\/wp-content\/uploads\/2024\/10\/\uc5ec\ub7ec-\uc774\ubbf8\uc9c0-PDF-\ubcc0\ud658-\ud3ec\uc2a4\ud2b8-\uc378\ub124\uc77c-600x600.webp",600,600,true],"author_info":{"display_name":"TERE","author_link":"https:\/\/secondlife.lol\/en\/author\/tere\/"},"comment_info":0,"category_info":[{"term_id":3,"name":"\ud30c\uc774\uc36c(Python)","slug":"python-coding","term_group":0,"term_taxonomy_id":3,"taxonomy":"category","description":"","parent":20,"count":116,"filter":"raw","cat_ID":3,"category_count":116,"category_description":"","cat_name":"\ud30c\uc774\uc36c(Python)","category_nicename":"python-coding","category_parent":20}],"tag_info":[{"term_id":291,"name":"Python PDF","slug":"python-pdf","term_group":0,"term_taxonomy_id":290,"taxonomy":"post_tag","description":"","parent":0,"count":2,"filter":"raw"},{"term_id":297,"name":"\uc5ec\ub7ec \uc774\ubbf8\uc9c0 PDF \ubcc0\ud658","slug":"%ec%97%ac%eb%9f%ac-%ec%9d%b4%eb%af%b8%ec%a7%80-pdf-%eb%b3%80%ed%99%98","term_group":0,"term_taxonomy_id":297,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":293,"name":"\uc774\ubbf8\uc9c0 PDF \ubcc0\ud658","slug":"%ec%9d%b4%eb%af%b8%ec%a7%80-pdf-%eb%b3%80%ed%99%98","term_group":0,"term_taxonomy_id":293,"taxonomy":"post_tag","description":"","parent":0,"count":2,"filter":"raw"},{"term_id":295,"name":"\uc774\ubbf8\uc9c0 \ucc98\ub9ac","slug":"%ec%9d%b4%eb%af%b8%ec%a7%80-%ec%b2%98%eb%a6%ac","term_group":0,"term_taxonomy_id":295,"taxonomy":"post_tag","description":"","parent":0,"count":2,"filter":"raw"},{"term_id":298,"name":"\ud30c\uc774\uc36c PDF \uc0dd\uc131","slug":"%ed%8c%8c%ec%9d%b4%ec%8d%ac-pdf-%ec%83%9d%ec%84%b1","term_group":0,"term_taxonomy_id":298,"taxonomy":"post_tag","description":"","parent":0,"count":1,"filter":"raw"},{"term_id":299,"name":"\ud30c\uc774\uc36c \uc790\ub3d9\ud654","slug":"%ed%8c%8c%ec%9d%b4%ec%8d%ac-%ec%9e%90%eb%8f%99%ed%99%94","term_group":0,"term_taxonomy_id":299,"taxonomy":"post_tag","description":"","parent":0,"count":2,"filter":"raw"}],"_links":{"self":[{"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/posts\/2699","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/comments?post=2699"}],"version-history":[{"count":6,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/posts\/2699\/revisions"}],"predecessor-version":[{"id":2725,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/posts\/2699\/revisions\/2725"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/media\/2717"}],"wp:attachment":[{"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/media?parent=2699"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/categories?post=2699"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secondlife.lol\/en\/wp-json\/wp\/v2\/tags?post=2699"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}