質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

1回答

849閲覧

PDFをJpeg化したいがExe化したら動かなくなってしまった

Py_kokko_123

総合スコア0

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2022/10/24 01:52

編集2022/10/25 00:15

前提

初めて質問させていただきます。
excelファイルのシート名を指定して、フォルダ内の該当シートのみexcel→PDF化、
PDF→Jpeg化の変換ツールを作成しています。

実現したいこと

指定したフォルダ内のエクセルファイルを読み込んで
指定したシート名を持つシートのみ、excel→PDF、PDF→Jpegに変換したい。

発生している問題・エラーメッセージ

エラーメッセージなし。
JupyterNoteやAnacondaでは正常に動作していましたが
Exe化するとPDF→Jpeg化が動かなくなった。
※Jpeg化するにあたり、Popplerを環境変数に設定して実行しています。

該当のソースコード

from pathlib import Path from pdf2image import convert_from_path import os import win32com.client import datetime import os import tkinter as tk from tkinter import * from tkinter import ttk from tkinter import messagebox from tkinter import filedialog import openpyxl as xl #Excel to PDF def excel_PDF(): path = path_excel.get() path_pdf = path_p.get() # コンボボックス内の値の取得 #def select_combo(event): #global sheetA #sheet = combobox.get() #print(sheet) excel = win32com.client.Dispatch("Excel.Application") excel.Visible=True files = [] now = datetime.datetime.now() for filename in os.listdir(path): if os.path.isfile(os.path.join(path, filename)): files.append(filename) for i in range(0,len(files)): try: file = excel.Workbooks.Open(path + '/' + files[i]) file.WorkSheets(sheet).Select() name, ext = os.path.splitext(files[i]) print(i) file.ActiveSheet.ExportAsFixedFormat(0, path_pdf + '/' + name + now.strftime('_%Y%m%d%H%M%S')) except Exception as e: print(e) finally: excel.Quit() #Excel to JPG def excel_JPG(): path_pdf = path_p.get() path_jpg = path_j.get() files_pdf = [] for filename_pdf in os.listdir(path_pdf): if os.path.isfile(os.path.join(path_pdf, filename_pdf)): files_pdf.append(filename_pdf) print(files_pdf) for k in range(0,len(files_pdf)): # PDFファイルのパス pdf_path = path_pdf + '/' + files_pdf[k] #この1文で変換されたjpegファイルが、imageホルダー内に作られます。 convert_from_path(pdf_path, output_folder=path_jpg,fmt='jpeg',output_file=Path(pdf_path).stem) # Excelフォルダ指定先参照ボタンの関数 def excel_dirdialog_clicked(): iDir = os.path.abspath(os.path.abspath("__file__")) iDirPath = filedialog.askdirectory(initialdir = iDir) path_excel.set(iDirPath) # pdf出力先指定の関数 def pdf_outdirdialog_clicked(): iDir_out = os.path.abspath(os.path.abspath("__file__")) iDirPath_out = filedialog.askdirectory(initialdir = iDir_out) path_p.set(iDirPath_out) # jpg出力先指定の関数 def jpg_outdirdialog_clicked(): iDir_out = os.path.abspath(os.path.abspath("__file__")) iDirPath_out = filedialog.askdirectory(initialdir = iDir_out) path_j.set(iDirPath_out) #SHEET名の取得関数 def main(): global statusbar # ファイルの参照 def brouse_func(): fTyp = [("", ".xlsx")] file_name = filedialog.askopenfilename(filetypes=fTyp) statusbar["text"] = file_name # コンボボックスのリスト取得 # ファイル読み込み wb = xl.load_workbook(filename=file_name) sheets = wb.sheetnames combobox.config(values=sheets) #これでコンボボックスのリストを更新できる # コンボボックス内の値の取得 def select_combo(event): global sheet sheet = combobox.get() #GUIの設定 root = tk.Tk() root.title("Excel変換ツール") root.geometry("600x300") # Frame1(Excel)の作成 frame1 = ttk.Frame(root, padding=10) frame1.grid(row=0, column=1, sticky=E) # 「Excelフォルダ参照」ラベルの作成 IDirLabel = ttk.Label(frame1, text="Excel読込先指定>>", padding=(5, 2)) IDirLabel.pack(side=LEFT) # 「Excelフォルダ参照」エントリーの作成 path_excel = StringVar() IDirEntry = ttk.Entry(frame1, textvariable=path_excel, width=60) IDirEntry.pack(side=LEFT) # 「Excelフォルダ参照」ボタンの作成 IDirButton = ttk.Button(frame1, text="参照", command=excel_dirdialog_clicked) IDirButton.pack(side=LEFT) # Frame2(PDF出力先)の作成 frame2 = ttk.Frame(root, padding=10) frame2.grid(row=2, column=1, sticky=E) # 「PDF出力先」ラベルの作成 IDirLabel_out = ttk.Label(frame2, text="PDF出力先指定>>", padding=(5, 2)) IDirLabel_out.pack(side=LEFT) # 「PDF出力先」エントリーの作成 path_p = StringVar() IDirEntry_out = ttk.Entry(frame2, textvariable=path_p, width=60) IDirEntry_out.pack(side=LEFT) # 「PDF出力先」ボタンの作成 IDirButton_out = ttk.Button(frame2, text="参照", command=pdf_outdirdialog_clicked) IDirButton_out.pack(side=LEFT) # Frame3(PDF出力先)の作成 frame3 = ttk.Frame(root, padding=10) frame3.grid(row=4, column=1, sticky=E) # 「jpg出力先」ラベルの作成 IDirLabel_out = ttk.Label(frame3, text="JPG出力先指定>>", padding=(5, 2)) IDirLabel_out.pack(side=LEFT) # 「JPG出力先」エントリーの作成 path_j = StringVar() IDirEntry_out = ttk.Entry(frame3, textvariable=path_j, width=60) IDirEntry_out.pack(side=LEFT) # 「JPG出力先」ボタンの作成 IDirButton_out_jpg = ttk.Button(frame3, text="参照", command=jpg_outdirdialog_clicked) IDirButton_out_jpg.pack(side=LEFT) # Sheet Frame作成 frame = ttk.Labelframe(root, padding=10) frame.grid(row=1, column=1, sticky=E) # ステータスバー statusbar = tk.Label(frame, text="参照するファイルを選択してください。 ", bd=1, relief=tk.SUNKEN, anchor=tk.W) statusbar.pack(side=LEFT) # 参照ボタン brouse_button = tk.Button(frame, text="参照", command=brouse_func) brouse_button.pack(padx=10, side=tk.LEFT) ##コンボボックス v = tk.StringVar() sheets = [] #一旦、空リスト用意 combobox = ttk.Combobox(frame, textvariable=v, values=sheets, height=3, #コンボボックスクリックした時の表示数 state="readonly") #手入力禁止 combobox.bind('<<ComboboxSelected>>', select_combo) #コンボボックスで選択した時、select_comboが発動 combobox.pack(padx=10, pady=5, side=tk.BOTTOM) # Frame(PDF変換 実行ボタン)の作成 frame4 = ttk.Frame(root, padding=8) frame4.grid(row=5,column=1,sticky=W) # PDF変換 実行ボタンの設置 button1 = ttk.Button(frame4, text="Excel to PDF変換", command=excel_PDF) button1.pack(fill = "x", padx=30, side = "left") # Frame(JPG変換 実行ボタン)の作成 frame5 = ttk.Frame(root, padding=8) frame5.grid(row=6,column=1,sticky=W) # JPG変換 実行ボタンの設置 button2 = ttk.Button(frame5, text="PDF to JPG変換", command=excel_JPG) button2.pack(fill = "x", padx=30, side = "left") tk.mainloop()

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

teamikl

2022/10/24 04:49

ソースコードのインデントが崩れているので、 修正をお願いします。マークダウン記法を用いてコードブロック内に挿入してください。 exeファイルを作るのに使ったツールは何でしょうか。 ツールにより仕様が異なるため、対処方法が変わることがあります。 また、プログラムのファイル・ディレクトリ構造の情報も必要です。 "file" というフォルダが実行時のフォルダにあることを想定していませんか?
y_waiwai

2022/10/24 05:00

このままではコードが読めないので、質問を編集し、</>(コードの挿入)ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください
Py_kokko_123

2022/10/25 00:18

ご回答ありがとうございます。コードの記載を修正いたしました。ご確認いただけますでしょうか。 また、exeファイルを作るのに利用したのは、”Pyinstaller”です。(Onefileのみで実行して、Exe実行時のエラー確認しましたがエラーは出現せず、Jpeg化のみ動かない状況) ”file”というフォルダは想定していないはずです。 (かなりの初心者のため、自分が実行したいコードを色々なところから寄せ集めています。初歩的なミスもあるかと思いますが、ご教示いただけますと幸いです。)
teamikl

2022/10/25 02:25 編集

いくつか追加で確認点があります。 >Exe実行時のエラー確認しましたがエラーは出現せず エラー自体は表示される設定でしょうか?GUIプログラムのexe化の場合、 標準エラー出力がオフになっている場合があります。 意図的にエラーの出るコードを試し、exe化してもエラーが正常に出力されてるのを確認してください。 (pyinstaller のconsoleを有効にするオプションが必要になるかもしれません) >”file”というフォルダは想定していないはずです。 file ではなく __file__ だったようです。 (ソースコードのレイアウトが崩れて、__がマークダウン記法として解釈されてました) exe化で問題になるよくあるケースは、ファイル等の相対パスが デバッグ実行時とexeの実行時で異なるというものなのですが、 少し見た感じ、__file__ は exe化の際は実行ファイルではなく、元ソースのファイルの場所になるので exe化を想定したコードでは、代替として sys.executable を用います。 但し、何らかのエラーは出ると思うので、他にも問題はありそうです。
teamikl

2022/10/25 02:19

よく見れば __file__ ではなく、"__file__" になってますね。 Python では、__file__ は特殊な変数で、 実行時に対象のソースのファイルのパスに置き換わるのですが、 "__file__" 文字列定数だと意味が違ってくるので、参考にした元コードを確認してもらったほうが良いかもしれません。 ディレクトリのパス自体は所得できているので、正常に動いて支障ないかもしれないけど、 恐らく誤ったコードです。
Py_kokko_123

2022/10/26 04:53 編集

ご回答ありがとうございます。 以下のようなコードを作成して、Exe化したところ正常に動きましたので 原因はPathではないかと思います。 <コード> from pdf2image import convert_from_path images = convert_from_path("C:/Users/users/Desktop/PDF_JPG変換ツール/PDF/test2.pdf",poppler_path = "C:/Program Files (x86)/poppler/bin") for i in range(len(images)): images[i].save('img'+str(i)+'.jpg', 'JPEG') "__file__"を修正して以下のようなコードにしてみました。 <コード> # Excelフォルダ指定先参照ボタンの関数 def excel_dirdialog_clicked(): iDir = os.path.abspath(os.path.abspath(sys.executable)) iDirPath = filedialog.askdirectory(initialdir = iDir) path_excel.set(iDirPath) print(iDir) # PDF出力指定の関数 def pdf_outdirdialog_clicked(): iDir_out = os.path.abspath(os.path.abspath(sys.executable)) iDirPath_out = filedialog.askdirectory(initialdir = iDir_out) path_p.set(iDirPath_out) print(iDir_out) # jpg出力先指定の関数 def jpg_outdirdialog_clicked(): iDir_out_jpg = os.path.abspath(os.path.abspath(sys.executable)) iDirPath_out_jpg = filedialog.askdirectory(initialdir = iDir_out_jpg) path_j.set(iDirPath_out_jpg) print(iDir_out_jpg) print結果は全て以下のように出力されており、JupyterNoteでは正常に動きました。 C:\Users\users\Anaconda3\python.exe C:\Users\users\Anaconda3\python.exe C:\Users\users\Anaconda3\python.exe ※Exe化した際は、「python.exe」のところが「●●.exe」(●●はエグゼ名) ですがやはりExe化すると、Jpeg化のみ動かなくなってしまいました。 Run-timer Information の情報を参考に、「バンドルされていますか?」を実行してみたところ JupyterNoteでは「running in a normal Python process」 Exe化では「running in a PyInstaller bundle」と出力されました。 何か関係がありますでしょうか。 Run-timer Information の情報に記載されている内容が難しく、あまり理解できておらず申し訳ありませんが お知恵お借りできれば幸いです。何卒よろしくお願いいたします。
teamikl

2022/10/26 06:24 編集

> Exe化したところ正常に動きましたので > 原因はPathではないかと思います。 お互いの認識に齟齬がでないように言葉尻の確認ですが、 convert_from_path 自体は単体でexe化をしても動いたので、 原因は Path が濃厚ということですよね? >os.path.abspath(os.path.abspath(sys.executable)) abspath を2回重ねてます askdirectory への指定はファイルではなくディレクトリのpathなので os.path.dirname(os.path.abspath(sys.executable)) とすべきです。 但し、exe化でない場合に正しく動いた説明にはならないので、 問題は他にあるはず。 convert_from_path へ渡す引数 をprint して 通常実行・exe化での実行結果を比較してみてください。
teamikl

2022/10/26 06:09

補足: os.path.abspath(os.path.abspath(sys.executable)) sys.executable をそのまま使うと、通常実行時に python.exe の場所になってしまうので sys.frozen の有無をチェックして、通常実行時・EXEでの実行を区別する必要があります。 具体的なコードは、回答のリンク先を参照してください。
teamikl

2022/10/26 06:23

エラーが出てないということなので該当しないかもしれませんが、 関連で、以下も確認してみてください。 (エラー自体が出ない設定になっている可能性もあります) Python3 Tkinter exe化後のPDFの画像変換ができない https://teratail.com/questions/254226
teamikl

2022/10/26 07:17

私の環境 (win10) ではpyinstaller を使ってexeしてもjpgファイルに変換できました。 なので、コードの問題ではなく実行環境の問題かもしれません。 exe化した際の環境変数(os.environ)で外部プログラムの場所にPATHが通っているかを確認してみてください。 但し、その場合でも何らかのエラーは出るはずなので、 エラーの設定を先に確認してください。 (意図的にエラーを起こし、exe化した際に正常にエラーが出力されるかどうか)
Py_kokko_123

2022/10/26 11:26 編集

ありがとうございます。 意図的にエラーを起こしたファイルをexe化したところ(Pyinstaller ●●.py --onefile) エラーが表示されることを確認しました。 (--noconsoleオプションをつけるとエラー表示されないため、つけていません) >exe化した際の環境変数(os.environ)で外部プログラムの場所にPATHが通っているかを確認してみてください。 確認すべきPathはPopplerのパスという理解であっていますでしょうか? Pythonを再度インストールしなおしてみるなどしましたが、やはりexe化をするとJpeg化のみ動かなくなってしまいますが、画面がちらついているので何かしら走っているような気配はあるようです。。
teamikl

2022/10/26 13:05

> エラーが表示されることを確認しました。 これなら大丈夫です。私の環境でも --onefile オプションのみで確認済。 エラーもないとなると原因の特定が困難ですが、 他に懸念があるとすれば、変換対象の PDF ファイル等かな。 ⇛ excel to PDF で変換した PDF ではなく、他の PDF ファイルを対象に試してみる。 > 確認すべきPathはPopplerのパスという理解であっていますでしょうか? はい。具体的には pdfimages という名前の実行ファイルのある場所です。 (convert_from_path が呼び出す外部プログラム) 画面のちらつきに関しては確認してませんが、 convert_from_path 関数は、呼び出した外部プログラムの終了を待つため 処理時間が長かったりすると、その間 GUI は応答しなくなります。 今回の質問とは別問題ですが、スレッドを使って呼び出す事で回避できます。 (マルチスレッドになるので、プログラムの完了を GUI に通知したい場合は、 スレッド間のやり取りで少し複雑な手順が必要になってきます)
teamikl

2022/10/26 13:18

確認したい事がもう一点、通常実行時とexe化での実行時で ファイルの置き場所もしくはファイル名に日本語が含まれてませんか? 日本語ファイル名を対象にすると、変換自体はできたものの文字化けを起こしたので。
Py_kokko_123

2022/10/27 01:32

色々とありがとうございます。 ファイル名に日本語が含まれていたため、「excel_converter.py」にてエグゼ化を試みてみましたが やはりJpeg化のみ実行不可となりました。 #この1文で変換されたjpegファイルが、imageホルダー内に作られます。 convert_from_path(pdf_path, output_folder=path_jpg,fmt='jpeg',output_file=Path(pdf_path).stem) 上記のコードでJPEG化を実行しているのですが、コード内でPoppler/binのパスを指定していないことが原因かと思い、 convert_from_path(pdf_path, output_folder=path_jpg,fmt='jpeg',output_file=Path(pdf_path).stem,poppler_path= /poppler/bin) のようにパス指定をしてみましたが、以下のようなエラーが出現しJupyterNote上でも実行不可となりました。 pywintypes.com_error: (-2147418111, '呼び出し先が呼び出しを拒否しました。', None, None)
teamikl

2022/10/27 04:30

poppler_path= /poppler/bin は想定していませんでしたが、 環境変数の PATH に通せばよいはずです。 追加で poppler_path での設定というのは、 単体でテストした場合に成功してるということなので、 その説明がつかなくなります。 >> convert_from_path へ渡す引数 をprint して >> 通常実行・exe化での実行結果を比較してみてください。 ここの情報が未確認なのでお願いします。 デバッグで確認してほしいのは、通常実行時とexe化での実行時における convert_from_path へ渡す引数 output_folder, output_file の値です。
Py_kokko_123

2022/10/27 07:48

>追加で poppler_path での設定というのは、 単体でテストした場合に成功してるということなので、 その説明がつかなくなります。 なるほど、たしかにそうですね。 >convert_from_path へ渡す引数 output_folder, output_file の値です。 確認がもれていました。 検証したところ、JupyterでもExe化でも以下のようなエラーが出現しました。 NameError: name 'output_folder' is not defined NameError: name 'output_file' is not defined Jupyterではprint(output_folder)やprint(putput_file)を入れてしまうと エラーのため途中で止まってしまいJPEG化もできない状態でした。 Jupyterではprint(●●)を削除すると、所定のフォルダに格納され、想定通りのファイル名でJPEG化されているため、どこかで値をとることはできているのではないかと思います。
teamikl

2022/10/27 07:57

> 検証したところ、JupyterでもExe化でも以下のようなエラーが出現しました。 NameError: name 'output_folder' is not defined NameError: name 'output_file' is not defined 変数名ではなく、convert_from_path に渡している それぞれの引数の値です。 print(f"{pdf_path=}, output_folder={path_jpg}, output_file={Path(pdf_path).stem}") という感じで、convert_from_path の直前あたりで確認してみてください。
Py_kokko_123

2022/10/27 23:41

Jupyter>> pdf_path='C:/Users/UserName/Desktop/PDF_JPG変換ツール/PDF/test2_20221026193447.pdf', output_folder=C:/Users/UserName/Desktop/PDF_JPG変換ツール/JPG, output_file=test2_20221026193447 Exe>> pdf_path='C:/Users/UserName/Desktop/PDF_JPG変換ツール/PDF/test2_20221026193447.pdf', output_folder=C:/Users/UserName/Desktop/PDF_JPG変換ツール/JPG, output_file=test2_20221026193447 何度もすみません、お示しのコードにて取得してJupyterとExeそれぞれで実施してみましたが 同じ値を取得してきているようです。
teamikl

2022/10/28 02:42

双方でpath が同じということは、 実行環境に問題がありそうですね。 単体テストで成功したときは、path 内に日本語は含まれていましたか? (実行環境の違いにより、exeでの実行の場合のみ文字コードが適切に扱えない等) 他は、エラーもなく私の環境では再現していないので、 環境の導入手順をすり合わせていくしか無いのかな。 win32com 利用なので勝手に windows 想定でしたが 実行環境で何か特筆すべき点があれば教えてください。 (追記: 私がテストしたのは anaconda ではなく、 公式からインストールしたものでした)
Py_kokko_123

2022/10/28 08:10

Windows10を利用しています。 JupyterNote、Anaconda3で実行時は成功 Anaconda3でPyinstallerを利用してExe化したところJPEG化のみ実行不可でした。 公式からインストールしたものというのは、何を利用されていますでしょうか?(素人で申し訳ありません) ちなみにコマンドプロンプトで実行した際にはエラーが出ていましたが、おそらくそれは環境構築が出来ていないため(モジュールがインストールされていないため)だと推測していました。
teamikl

2022/10/28 10:48

> 単体テストで成功したときは、path 内に日本語は含まれていましたか? こちらの確認をお願いします。 公式からのインストールは、https://www.python.org/downloads/ からダウンロードしたものです。 バージョンは 3.8.8 で、venv で環境下に必要モジュール類をインストールしました。 poppler は4年くらい前にインストールしていて、導入経路は失念してます。バージョンは0.68.0 > ちなみにコマンドプロンプトで実行した際にはエラーが出ていましたが、おそらくそれは環境構築が出来ていないため(モジュールがインストールされていないため)だと推測していました。 これは、出来上がった exe ファイルを実行したときですか? 環境変数PATHの確認等に見落としがありそうです。念の為エラーメッセージと exe ファイルの実行方法も教えてください。私はコマンドプロンプトからの実行で試しました。
teamikl

2022/10/28 11:29 編集

試してもらいたいことがもう一点、 「PDF_JPG変換ツール」というフォルダ名ですが、 日本語を含まないフォルダ名で試してみてください。 実行場所のフォルダに日本語が含まれていると エラーもなくファイルも生成されないことを確認しました。 PDFのファイル名自体は、(文字化けするものの) 日本語が含まれていても変換できることは確認しています。 通常実行時とexe化して実行する際の、 プログラムを実行する現在の作業ディレクトリ 確認方法 import os print(os.getcwd())
teamikl

2022/10/28 11:43

対処方法ですが、恐らく 外部ライブラリ側の問題の為、そちらに手を加えるのは難しいので、 一旦別の場所に移動してから変換処理を実行し、 後で元に戻す等の回避手段を取らないといけないかもしれません。
guest

回答1

0

直接回答ではありませんが、exe化した際の異なる実行環境への対応

  • ファイルのPATH
  • 環境変数

をそれぞれ通常実行とexeでの実行を出力してみて違いを比べてみてください。
(exe化でコンソール出力が無効になってる場合は、exe作成時に --console オプションで有効に)

exe化での実行ではパスの所得方法が変わってくるので、
sys.frozen の有無により、exe可での実行かどうかを判別します。


ライブラリを動かすのに必要なファイルが含まれているかどうかの確認

convert_from_path を呼び出すだけのプログラムを作成して、
exe化して実行してみてください。

これにより path の問題なのか、JPG 化のライブラリをexeで使う場合の問題かを切り分けます。

path 問題の場合は、Run-timer Information の情報を参考に、
exe化した実行環境での path の扱いに対応させます。
後者の場合は pyinstaller で exeに含めるファイルの構成の見直しが必要です。


参考:

投稿2022/10/25 03:06

teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問