[python]PDFのオブジェクト情報を取得して注釈をつける(テキスト、画像、オブジェクト) 画像にだけ位置情報RECTを入れるようにした
ダウンロード - getpdfinfov20241019.zip
サンプルコード
行番号 | ソース |
---|---|
001 | #!/usr/bin/env python3 |
002 | # coding: utf-8 |
003 | # 20240828 出力結果のテキスト少し読みやすくした |
004 | # 20240912 出力結果を注釈にして付与する形式にした |
005 | # 20240927 フォント情報とオブジェクトの塗り情報を入れるようにした |
006 | # 20240929 MSゴシック等SJISのフォント名に対応した |
007 | # 20241019 画像の位置情報RECTを入れた |
008 | # |
009 | import sys |
010 | import os |
011 | import pymupdf |
012 | |
013 | # 入力ファイル受け取り |
014 | argFilePath = sys.argv |
015 | pdf_file_path = str(argFilePath[1]) |
016 | #テスト用 |
017 | # pdf_file_path = "/Users/SOMEUID/Desktop/SOME.pdf" |
018 | |
019 | |
020 | #パスからベースファイル名とコンテナを取得 |
021 | container_directory = os.path.dirname(pdf_file_path) |
022 | file_name = os.path.basename(pdf_file_path) |
023 | base_file_name = os.path.splitext(file_name)[0] |
024 | #保存先ディレクトリ |
025 | save_dir_name = base_file_name + "情報" |
026 | save_dir_path = os.path.join(container_directory, save_dir_name) |
027 | os.makedirs(save_dir_path, exist_ok=True) |
028 | # テキスト保存先パス |
029 | save_file_path = save_dir_path + "/" + base_file_name + ".PDF情報.txt" |
030 | # フォント一覧用テキスト |
031 | save_font_list_file_path = save_dir_path + "/" + base_file_name + ".FontList.txt" |
032 | list_fontname = set() |
033 | # カラー一覧用テキスト |
034 | save_color_list_file_path = save_dir_path + "/" + base_file_name + ".ColorList.txt" |
035 | list_color = set() |
036 | #注釈入れたPDFの保存先 |
037 | pdf_save_file_path = save_dir_path + "/" + base_file_name + ".PDF情報.pdf" |
038 | # PDFドキュメントを開く |
039 | pdf_document = pymupdf.open(pdf_file_path) |
040 | ################### |
041 | def float_to_hex(float_color_no): |
042 | if float_color_no is None: |
043 | return "None" |
044 | red = int(float_color_no[0] * 255) |
045 | green = int(float_color_no[1] * 255) |
046 | blue = int(float_color_no[2] * 255) |
047 | hex_color = "#{:02X}{:02X}{:02X}".format(red, green, blue) |
048 | return hex_color |
049 | |
050 | def int_to_rgb(color_int): |
051 | red = (color_int >> 16) & 0xFF |
052 | green = (color_int >> 8) & 0xFF |
053 | blue = color_int & 0xFF |
054 | return red, green, blue |
055 | |
056 | ################### |
057 | #テキストファイルを用意して |
058 | with open(save_file_path, "w", encoding="utf-8") as file: |
059 | #PDFページを順に処理 |
060 | for page_number in range(len(pdf_document)): |
061 | #PDFページを開いて |
062 | pdf_page = pdf_document.load_page(page_number) |
063 | #PDFページの回転を調べる |
064 | rotation_angle = pdf_page.rotation |
065 | #テキスト用の変えページ |
066 | print(f"PAGE No:{page_number + 1} ----------------------") |
067 | file.write(f"PAGE No:{page_number + 1} ----------------------\n") |
068 | if rotation_angle == 0: |
069 | file.write(f"PAGE 回転:{rotation_angle}\n") |
070 | else: |
071 | file.write(f"PAGE 回転:{rotation_angle}※※※\n") |
072 | ################### |
073 | list_draw_object = pdf_page.get_drawings() |
074 | for item_draw in list_draw_object: |
075 | seqno_no = item_draw['seqno'] |
076 | fill_color = item_draw['fill'] |
077 | fill_color_hex = float_to_hex(fill_color) |
078 | list_color.add(fill_color_hex) |
079 | print(f"塗色: {fill_color_hex}") |
080 | line_color = item_draw['color'] |
081 | line_color_hex = float_to_hex(line_color) |
082 | list_color.add(line_color_hex) |
083 | print(f"線色: {line_color_hex}") |
084 | draw_rect = item_draw['rect'] |
085 | print(f"RECT: {draw_rect}") |
086 | left_top_x = draw_rect.x0 |
087 | left_top_y = draw_rect.y0 |
088 | rect_add_annot = pymupdf.Rect(left_top_x, left_top_y, left_top_x + |
089 | 20, left_top_y + 20) |
090 | |
091 | # コンソールに表示 |
092 | print(f"DRAW {seqno_no}:") |
093 | print(f" - 線色: {line_color_hex}") |
094 | print(f" - 塗色: {fill_color_hex}") |
095 | |
096 | # テキストファイル用にも書き出す |
097 | file.write(f"DRAW {seqno_no}:") |
098 | file.write(f" - 線色: {line_color_hex}") |
099 | file.write(f" - 塗色: {fill_color_hex}") |
100 | file.write(f"\n") |
101 | |
102 | # 同じ内容を注釈用のテキストにする |
103 | list_annot_text = [] |
104 | list_annot_text.append(f"DRAW {seqno_no}:") |
105 | list_annot_text.append(f" - 線色: {line_color_hex}") |
106 | list_annot_text.append(f" - 塗色: {fill_color_hex}") |
107 | str_annot_text = "\n".join(list_annot_text) |
108 | |
109 | # 注釈追加 |
110 | obj_add_annot = pdf_page.add_text_annot( |
111 | rect_add_annot.tl, str_annot_text, "Comment") |
112 | strSetTitle = (f"DRAW:NO: {seqno_no}") |
113 | obj_add_annot.set_info({ |
114 | 'title': 'DRAW情報', |
115 | 'author': 'DRAW情報', |
116 | 'subject': strSetTitle |
117 | }) |
118 | |
119 | ################### |
120 | |
121 | # ページ内のテキスト情報を取得 |
122 | list_text_block = pdf_page.get_text("dict") |
123 | # テキストブロックの数だけ繰り返し |
124 | for item_block in list_text_block['blocks']: |
125 | if 'lines' in item_block: |
126 | for line in item_block['lines']: |
127 | for span in line['spans']: |
128 | text_no = item_block['number'] |
129 | font_name = span['font'] |
130 | byte_sequence = font_name.encode('latin-1') |
131 | font_name = byte_sequence.decode('shift_jis') |
132 | list_fontname.add(font_name) |
133 | font_size = span['size'] |
134 | text_bbox = span['bbox'] |
135 | color_int = span['color'] |
136 | color_hex = "#{:06X}".format(color_int) |
137 | list_fontname.add(color_hex) |
138 | list_color.add(color_hex) |
139 | left_top_x = text_bbox[0] |
140 | left_top_y = text_bbox[1] |
141 | box_w = text_bbox[2] - text_bbox[0] |
142 | box_h = 20 |
143 | rect_add_annot = pymupdf.Rect( |
144 | left_top_x, left_top_y, left_top_x + box_w, left_top_y + box_h) |
145 | |
146 | # コンソールに表示 |
147 | print(f"TEXT {text_no}:") |
148 | print(f" - Font: {font_name}") |
149 | print(f" - Size: {font_size}") |
150 | print(f" - Color: {color_hex}") |
151 | |
152 | # テキストファイル用にも書き出す |
153 | file.write(f"TEXT {text_no}:\n") |
154 | file.write(f" - Font: {font_name}\n") |
155 | file.write(f" - Size: {font_size}\n") |
156 | file.write(f" - Color: {color_hex}\n") |
157 | file.write(f"\n") |
158 | |
159 | # 同じ内容を注釈用のテキストにする |
160 | list_annot_text = [] |
161 | list_annot_text.append(f"TEXT {text_no}:") |
162 | list_annot_text.append(f" - Font: {font_name}") |
163 | list_annot_text.append(f" - Size: {font_size}") |
164 | list_annot_text.append(f" - Color: {color_hex}") |
165 | str_annot_text = "\n".join(list_annot_text) |
166 | |
167 | # 注釈追加 |
168 | obj_add_annot = pdf_page.add_text_annot( |
169 | rect_add_annot.tl, str_annot_text) |
170 | strSetTitle = (f"TEXT:NO: {text_no}") |
171 | obj_add_annot.set_info({ |
172 | 'title': 'テキスト情報', |
173 | 'author': 'テキスト情報', |
174 | 'subject': strSetTitle |
175 | }) |
176 | |
177 | ################### |
178 | # ページ内の画像情報を取得 |
179 | image_list = pdf_page.get_images(full=True) |
180 | #画像の数 |
181 | num_cnt_images = len(image_list) |
182 | if num_cnt_images == 0: |
183 | print(f"ページ:{page_number + 1} には画像がありません") |
184 | file.write(f"ページ:{page_number + 1} には画像がありません\n\n") |
185 | else: |
186 | print(f"ページ:{page_number + 1} には画像が {num_cnt_images}点ありました") |
187 | file.write(f"ページ:{page_number + 1} には画像が {num_cnt_images}点ありました\n") |
188 | |
189 | # 画像情報の表示 |
190 | for img_index, item_image in enumerate(image_list, start=1): |
191 | xref = item_image[0] |
192 | pixmap_ref = pymupdf.Pixmap(pdf_document, xref) |
193 | base_image = pdf_document.extract_image(xref) |
194 | image_ext = base_image["ext"] |
195 | # 画像のサイズ |
196 | image_bytes = base_image["image"] |
197 | image_size = len(image_bytes) / (1024 * 1024) |
198 | # ピクセルサイズと解像度 |
199 | image_width = pixmap_ref.width |
200 | image_height = pixmap_ref.height |
201 | # img_rect = pdf_page.get_image_rects(xref)[0] |
202 | #画像の位置RECTを取得(同一画像が同一ページに複数配置されている場合はリストになる) |
203 | list_image_rects = pdf_page.get_image_rects(xref) |
204 | #RECT画像の位置情報の数だけ繰り返す |
205 | for rect_index, img_rect in enumerate(list_image_rects, start=1): |
206 | # RECT左上 |
207 | left_top_x = img_rect.x0 |
208 | left_top_y = img_rect.y0 |
209 | # 幅 縦 |
210 | rect_width = img_rect.width |
211 | rect_height = img_rect.height |
212 | #解像度 |
213 | resolution_width = image_width / (rect_width / 72) |
214 | resolution_height = image_height / (rect_height / 72) |
215 | resolution_width = round(resolution_width) |
216 | resolution_height = round(resolution_height) |
217 | #カラースペース判定 |
218 | colorspace = "" |
219 | num_colorspace = base_image.get('colorspace', 1) |
220 | if pixmap_ref.is_monochrome == 0: |
221 | if pixmap_ref.is_unicolor == True: |
222 | colorspace = "ユニ/SPOT" |
223 | else: |
224 | colorspace = "マルチ/ICC" |
225 | else: |
226 | colorspace = "モノ/単色" |
227 | #カラースペース判定 ここの判定に自信がない |
228 | if num_colorspace == 1: |
229 | colorspace = (f"{colorspace} :Gray/BW") |
230 | elif num_colorspace == 2: |
231 | colorspace = (f"{colorspace}: Gray/BWA") |
232 | elif num_colorspace == 3: |
233 | colorspace = (f"{colorspace}: RGB") |
234 | elif num_colorspace == 4: |
235 | colorspace = (f"{colorspace}: CMYK") |
236 | else: |
237 | colorspace = (f"{colorspace}: Unknown: ") |
238 | #コンソールに表示 |
239 | print(f"Image {img_index}:") |
240 | print(f" - Xref: {xref}") |
241 | print(f" - Size: {base_image['width']}x{base_image['height']}") |
242 | print(f" - Resolution: {resolution_width}x{resolution_height} ppi") |
243 | # print(f" - Format: {image_ext}")書き出し後だから意味ない |
244 | print(f" - ColorSpace: {colorspace} : {num_colorspace}") |
245 | print(f" - Image Size: {image_size:.3f} MB") |
246 | print(f" - Rect: {img_rect}") |
247 | # 同じ内容を注釈用のテキストにする |
248 | list_annot_text = [] |
249 | list_annot_text.append(f"Image {img_index}:") |
250 | list_annot_text.append(f" - Xref: {xref}") |
251 | list_annot_text.append(f" - Size: {base_image['width']}x{base_image['height']}") |
252 | list_annot_text.append(f" - Resolution: {resolution_width}x{resolution_height} ppi") |
253 | # list_annot_text.append(f" - Format: {image_ext}")書き出し後だから意味ない |
254 | list_annot_text.append(f" - ColorSpace: {colorspace} : {num_colorspace}") |
255 | list_annot_text.append(f" - Image Size: {image_size:.3f} MB") |
256 | list_annot_text.append(f" - Rect: {img_rect}") |
257 | str_annot_text = "\n".join(list_annot_text) |
258 | rect_add_annot = pymupdf.Rect(left_top_x, 50, left_top_y, 50) |
259 | #注釈追加 |
260 | obj_add_annot = pdf_page.add_text_annot(img_rect.tl, str_annot_text,"Tag") |
261 | strSetTitle = (f"画像:XREF: {xref}") |
262 | obj_add_annot.set_info({ |
263 | 'title': '画像情報', |
264 | 'author': '埋め込み画像情報', |
265 | 'subject': strSetTitle |
266 | }) |
267 | #テキストファイル用にも書き出す |
268 | file.write(f"Image {img_index}:\n") |
269 | file.write(f" - Xref: {xref}\n") |
270 | file.write(f" - Size: {base_image['width']}x{base_image['height']}\n") |
271 | file.write(f" - Resolution: {resolution_width}x{resolution_height} ppi\n") |
272 | #file.write(f" - Format: {image_ext}\n") 書き出し後だから意味ない |
273 | file.write(f" - ColorSpace: {colorspace}: {num_colorspace}\n") |
274 | file.write(f" - Image Size: {image_size:.3f} MB\n") |
275 | file.write(f"\n") |
276 | |
277 | file.close() |
278 | |
279 | with open(save_font_list_file_path, "w", encoding="utf-8") as font_Info_file: |
280 | sorted_list_fontname = sorted(list_fontname) |
281 | str_add_fontList = "\n".join(map(str, sorted_list_fontname)) |
282 | font_Info_file.write(f"{str_add_fontList}\n") |
283 | font_Info_file.write(f"\n") |
284 | font_Info_file.close() |
285 | |
286 | with open(save_color_list_file_path, "w", encoding="utf-8") as color_Info_file: |
287 | sorted_list_colorname = sorted(list_color) |
288 | str_add_colorList = "\n".join(map(str, sorted_list_colorname)) |
289 | color_Info_file.write(f"{str_add_colorList}\n") |
290 | color_Info_file.write(f"\n") |
291 | color_Info_file.close() |
292 | |
293 | #全ページ終わったら注釈の入ったPDFを別名保存する |
294 | pdf_document.save(pdf_save_file_path) |
295 | #開いていたPDFを閉じて |
296 | pdf_document.close() |
297 | #処理終了 |
298 | sys.exit(0) |
AppleScriptで生成しました |
| 固定リンク