update extract model
Showing
2 changed files
with
33 additions
and
23 deletions
1 | # PDF转图片脚本 | 1 | # PDF转图片脚本 |
2 | 2 | ||
3 | ## 主要处理逻辑 | 3 | ## 2种转化方式 |
4 | - 保存整个页面为png图片 | ||
4 | - 提取PDF页面中的图片对象 | 5 | - 提取PDF页面中的图片对象 |
5 | - 图片对象数目为0(如电子账单),保存整个页面为png图片 | 6 | - 图片对象数目为0(如电子账单),保存整个页面为png图片 |
6 | - 图片对象数目为1 | 7 | - 图片对象数目为1 |
7 | - 大图,保存图片对象 | 8 | - 大图,保存图片对象 |
8 | - 小图(如电子账单盖章),保存整个页面为png图片 | 9 | - 小图(如电子账单盖章),保存整个页面为png图片 |
9 | - 图片对象数目大于1 | 10 | - 图片对象数目大于1 |
10 | - 多大图,保存图片对象 | 11 | - 多整图,保存图片对象 |
11 | - 多碎图,根据宽高突变位置分组,拼接合并后保存 | 12 | - 多碎图,根据宽高突变位置分组,拼接合并后保存 |
12 | - 其他特殊情况:保存整个页面为png图片 | 13 | - 其他特殊情况:保存整个页面为png图片 |
13 | 14 | ||
15 | ## 已知问题 | ||
16 | - 提取图片对象方式下,整图与碎图通过宽高阈值区分,无法满足所有PDF。个别PDF中,整图很小时会被当做碎图合并,碎图很大时会被当做整图不合并 | ||
17 | |||
14 | ## 用法 | 18 | ## 用法 |
15 | - python3.6+ | 19 | - python3.6+ |
16 | - `pip install -r requirements.txt` | 20 | - `pip install -r requirements.txt` |
17 | - `python pdf_to_img.py pdf_path [img_path]` | ||
18 | |||
19 | | 参数 | 是否必须 | 说明 | 缺省值 | | ||
20 | | ---- | ---- | ---- | ---- | | ||
21 | | pdf_path | 是 | PDF文件或目录路径 | - | | ||
22 | | img_path | 否 | 图片保存路径 | PDF文件路径 | | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
21 | - `python pdf_to_img.py [-h] -i INPUT [-o OUTPUT] [-e]` | ||
22 | ``` | ||
23 | 可选参数: | ||
24 | -h, --help 查看帮助信息并退出 | ||
25 | -i INPUT, --input INPUT PDF文件或目录路径,必要参数 | ||
26 | -o OUTPUT, --output OUTPUT 输出图片保存路径,非必要参数,缺省值为PDF文件路径 | ||
27 | -e, --extract 默认采用整个页面保存png图片的方式,增加该选项选择提取图片方式转化图片 | ||
28 | ``` | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | import os | 1 | import os |
2 | import sys | 2 | import sys |
3 | import fitz | 3 | import fitz |
4 | import argparse | ||
4 | from PIL import Image | 5 | from PIL import Image |
5 | from io import BytesIO | 6 | from io import BytesIO |
6 | 7 | ||
7 | if sys.version_info[0] < 3: | 8 | if sys.version_info[0] < 3: |
8 | raise Exception("This program requires at least python3.6") | 9 | raise Exception("This program requires at least python3.6") |
9 | if len(sys.argv) < 2: | 10 | |
10 | print('用法:python pdf_to_img.py PDF文件或目录路径 [图片保存路径]') | 11 | parser = argparse.ArgumentParser(description='PDF转图片') |
11 | sys.exit(0) | 12 | parser.add_argument('-i', '--input', help='PDF文件或目录路径,必要参数', required=True) |
12 | if not os.path.exists(sys.argv[1]): | 13 | parser.add_argument('-o', '--output', help='输出图片保存路径,非必要参数,缺省值为PDF文件路径') |
13 | print('PDF文件或目录不存在: {0}'.format(sys.argv[1])) | 14 | parser.add_argument('-e', '--extract', help='默认采用整个页面保存png图片的方式,增加该选项选择提取图片方式转化图片', action="store_true") |
14 | sys.exit(0) | 15 | args = parser.parse_args() |
15 | 16 | ||
16 | LOG_BASE = '[pdf to img]' | 17 | LOG_BASE = '[pdf to img]' |
17 | 18 | ||
... | @@ -190,13 +191,13 @@ class PDFHandler: | ... | @@ -190,13 +191,13 @@ class PDFHandler: |
190 | page = pdf.loadPage(pno) | 191 | page = pdf.loadPage(pno) |
191 | self.page_to_png(page) | 192 | self.page_to_png(page) |
192 | 193 | ||
193 | def extract_image(self): | 194 | def extract_image(self, is_extract): |
194 | os.makedirs(self.img_dir_path, exist_ok=True) | 195 | os.makedirs(self.img_dir_path, exist_ok=True) |
195 | with fitz.Document(self.path) as pdf: | 196 | with fitz.Document(self.path) as pdf: |
196 | print('++++++++++' * 5) | 197 | print('++++++++++' * 5) |
197 | print('{0} [start] [pdf_path={1}] [metadata={2}]'.format(LOG_BASE, self.path, pdf.metadata)) | 198 | print('{0} [start] [pdf_path={1}] [metadata={2}]'.format(LOG_BASE, self.path, pdf.metadata)) |
198 | for pno in range(pdf.pageCount): | 199 | for pno in range(pdf.pageCount): |
199 | il = pdf.getPageImageList(pno) # 获取页面图片对象 | 200 | il = pdf.getPageImageList(pno) if is_extract else [] # 获取页面图片对象 |
200 | # (xref, smask, width, height, bpc, colorspace, alt.colorspace, name, filter, invoker) | 201 | # (xref, smask, width, height, bpc, colorspace, alt.colorspace, name, filter, invoker) |
201 | print('---------- page: {0} ----------'.format(pno)) | 202 | print('---------- page: {0} ----------'.format(pno)) |
202 | print('img_object_list: {0}'.format(il)) | 203 | print('img_object_list: {0}'.format(il)) |
... | @@ -230,26 +231,29 @@ class PDFHandler: | ... | @@ -230,26 +231,29 @@ class PDFHandler: |
230 | self.merge_il(pdf, pno, il) | 231 | self.merge_il(pdf, pno, il) |
231 | 232 | ||
232 | 233 | ||
233 | def extract_image(pdf_path, target_path): | 234 | def extract_image(pdf_path, target_path, is_extract): |
234 | pdf_handler = PDFHandler(pdf_path, target_path) | 235 | pdf_handler = PDFHandler(pdf_path, target_path) |
235 | pdf_handler.extract_image() | 236 | pdf_handler.extract_image(is_extract) |
236 | 237 | ||
237 | 238 | ||
238 | def main(): | 239 | def main(): |
239 | pdf_path = os.path.realpath(sys.argv[1]) | 240 | if not os.path.exists(args.input): |
241 | print('PDF文件或目录不存在: {0}'.format(args.input)) | ||
242 | return | ||
243 | pdf_path = os.path.realpath(args.input) | ||
240 | # 目录:遍历处理所有pdf文件 | 244 | # 目录:遍历处理所有pdf文件 |
241 | if os.path.isdir(pdf_path): | 245 | if os.path.isdir(pdf_path): |
242 | completed_count = 0 | 246 | completed_count = 0 |
243 | failed_list = [] | 247 | failed_list = [] |
244 | for parent, dirnames, filenames in os.walk(pdf_path): | 248 | for parent, dirnames, filenames in os.walk(pdf_path): |
245 | # 图片保存目录 | 249 | # 图片保存目录 |
246 | target_path = os.path.realpath(sys.argv[2]) if len(sys.argv) > 2 else parent | 250 | target_path = os.path.realpath(args.output) if args.output else parent |
247 | for pdf_file in filenames: | 251 | for pdf_file in filenames: |
248 | if not pdf_file.endswith('pdf') and not pdf_file.endswith('PDF'): | 252 | if not pdf_file.endswith('pdf') and not pdf_file.endswith('PDF'): |
249 | continue | 253 | continue |
250 | pdf_file_path = os.path.join(parent, pdf_file) | 254 | pdf_file_path = os.path.join(parent, pdf_file) |
251 | try: | 255 | try: |
252 | extract_image(pdf_file_path, target_path) | 256 | extract_image(pdf_file_path, target_path, args.extract) |
253 | except Exception as e: | 257 | except Exception as e: |
254 | print('{0} [failed] [err={1}] [pdf_path={2}]'.format(LOG_BASE, e, pdf_file_path)) | 258 | print('{0} [failed] [err={1}] [pdf_path={2}]'.format(LOG_BASE, e, pdf_file_path)) |
255 | failed_list.append(pdf_file_path) | 259 | failed_list.append(pdf_file_path) |
... | @@ -261,9 +265,9 @@ def main(): | ... | @@ -261,9 +265,9 @@ def main(): |
261 | # 文件:处理pdf文件 | 265 | # 文件:处理pdf文件 |
262 | else: | 266 | else: |
263 | # 图片保存目录 | 267 | # 图片保存目录 |
264 | target_path = os.path.realpath(sys.argv[2]) if len(sys.argv) > 2 else os.path.dirname(pdf_path) | 268 | target_path = os.path.realpath(args.output) if args.output else os.path.dirname(pdf_path) |
265 | try: | 269 | try: |
266 | extract_image(pdf_path, target_path) | 270 | extract_image(pdf_path, target_path, args.extract) |
267 | except Exception as e: | 271 | except Exception as e: |
268 | print('{0} [failed] [err={1}] [pdf_path={2}]'.format(LOG_BASE, e, pdf_path)) | 272 | print('{0} [failed] [err={1}] [pdf_path={2}]'.format(LOG_BASE, e, pdf_path)) |
269 | else: | 273 | else: | ... | ... |
-
Please register or sign in to post a comment