Embedded Python:ExcelからPDFに変換する方法(Windows環境のみ)
開発者の皆さん、こんにちは!
PythonでExcelからPDFへ変換を行うには、pywinを使うとできるらしいので、IRISにあるデータをDataframeに設定した後Excelに出力し、ExcelからPDFに変換する流れを、Embedded Pythonで試してみました。
メモ:pywinはWindows環境下で動くモジュールのようです。
Excelに出力するデータですが、例では、SELECTの結果をDataframeに格納する方法を利用しています。グローバル変数の情報をDataframeに格納する方法については、以下の記事で詳しくご紹介しています。ぜひご参照ください。
Embedded Python で IRIS グローバル($LB) を Pandas Dataframe に変換する方法
まずは、必要なモジュールをインストールする必要があるので、pywin32 モジュールを irispipを使ってインストールします。
以下の例では、IRIS for Health が c:\InterSystems\IRISHealth にインストールされている状態で実行しています。
Embedded Pythonは、IRIS/IRIS for Health どちらでも利用できます。
c:\InterSystems\IRISHealth\bin>irispip install --target c:\InterSystems\IRISHealth\mgr\python pywin32
Collecting pywin32
Using cached pywin32-304-cp39-cp39-win_amd64.whl (12.2 MB)
Installing collected packages: pywin32
Successfully installed pywin32-304
// 以下省略
pywin32モジュールインストール後、以下の作業を行うことで、Embedded Python でExcelからPDFへの変換を実行できるようになりました。
- 専用DLL(pythoncom39.dll とpywintypes39.dll)を c:\windows\system32以下にコピー
- pywin32のパス2種(<IRISインストールディレクトリ>\mgr\python\win32\lib と <IRISインストールディレクトリ>\mgr\python\win32)を sys.pathに追加
- IRISのサービスアカウントを管理者ユーザに変更:ご参考「サービスアカウントの変更について【IRIS】」
それぞれの手続きをご紹介します。
1. 専用DLL(pythoncom39.dll とpywintypes39.dll)を c:\windows\system32以下にコピー
インストール後、さっそく import win32com.client を実行したいところですが、IRISターミナルから起動するPythonシェルで実行すると以下のエラーが出てしまいます。
>>> import win32com.client
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "c:\intersystems\irishealth\mgr\python\win32com\__init__.py", line 5, in <module>
import win32api, sys, os
ModuleNotFoundError: No module named 'win32api
このエラーをググりますと、以下の投稿に辿り着き、
How to fix "ImportError: DLL load failed" while importing win32api
👆52番の回答を試してみると、インポートできるようになりました。
具体的な手続きは以下の通りです。
irispipでインストールしたpywin32の2種類のDLL(pythoncom39.dll とpywintypes39.dll)を c:\windows\system32にコピーします。
irispipでインストールされる場所:<IRISインストールディレクトリ>\mgr\python\pywin32_system32
例)C:\InterSystems\IRISHealth\mgr\python\pywin32_system32
2. pywin32のパス2種を sys.pathに追加
import win32com.client を行うため、sys.pathにpywin32のインストールで用意される以下2つのディレクトリを追加する必要がありました。
参考記事:http://blog.livedoor.jp/blackcode/archives/python-win32api-import-error....
- <IRISインストールディレクトリ>\mgr\python\win32\lib
- <IRISインストールディレクトリ>\mgr\python\win32
例は以下の通りです。
import sys
sys.path += ['C:\InterSystems\IRISHealth\mgr\python\win32\lib','C:\InterSystems\IRISHealth\mgr\python\win32']
3. IRISのサービスアカウントを管理者ユーザに変更
1、2までで、import win32com.client は成功しますが、肝心のExcelからPDFへ変換する流れでエラーが出ます😢。
どうやら、ExcelからPDF変換の流れを管理者権限で実行する必要があり、IRISのサービスアカウントが規定(SYSTEMアカウント)である場合に失敗します。
IRISのサービスアカウントを管理者に変更します(管理者権限でコマンドプロンプトを起動した後、以下のコマンドを実行します)。
例)<IRISインストールディレクトリ>\bin> irisinstall setserviceusername 構成名 ユーザ名 パスワード
c:\InterSystems\IRISHealth\bin>irisinstall setserviceusername IRISHealth userx passwordx
サービスアカウント変更後、IRISの再起動が必要となります。
※サービスアカウントを変更した場合の注意点
サービスアカウントを LOCAL_SYSTEM から変更すると、権限が不足するため、IRIS開始時の共有メモリの取得に Large Page (※)が使用できなくなります。
※Windows上でのCaché共有メモリの割り当てについて
Large Pageを使用するためには、変更したアカウントに対して"メモリ内のページのロック" 特権を付与する必要があります。
“メモリ内のページのロック” 特権の付与は、ローカルセキュリティポリシー(secpol.msc)より実施します。
1~3までの手続きを行った後、以下のPythonスクリプトファイルを実行できるようになります。
スクリプト例では、2つ関数を用意しています。以下それぞれの概要です。
関数:CreateExcel(ファイルフルパス) では、Test.Personテーブルを作成し、テストデータを4件登録し、Excel出力しています。(関数最後にTest.PersonをDropしています)
Excel出力の為、openpyxlとpandasのインストールが必要です。irispipでインストールしてから実行してください。
例)
c:\InterSystems\IRISHealth\bin\irispip install --target c:\InterSystems\IRISHealth\mgr\python openpyxl
c:\InterSystems\IRISHealth\bin\irispip install --target c:\InterSystems\IRISHealth\mgr\python pandas
関数:Output(エクセルファイルフルパス,PDFファイルフルパス) では、関数CreateExcel()を呼び出し、Excelファイルを準備してから、PDF変換を行っています。
第1引数:出力したいエクセルファイル名をフルパスで指定します。例)c:\\temp\\Book4.xlsx
第2引数:Excelから変換するPDF保存名でフルパスで指定します。 例)c:\\temp\\Book4.pdf
サンプルコードは以下の通りです。
import sys
sys.path += ['C:\InterSystems\IRISHealth\mgr\python\win32\lib','C:\InterSystems\IRISHealth\mgr\python\win32']
# 以下 python.exeから実行する時のパス
sys.path+=['c:\intersystems\irishealth\mgr\python','c:\intersystems\irishealth\lib\python']
import iris
#--------------------------------------------
import win32com.client
import pandas as pd
import openpyxl
from openpyxl.utils.dataframe import dataframe_to_rows
def CreateExcel(filename):
sql="create table Test.Person (Name VARCHAR(50),Email VARCHAR(50))"
rs=iris.sql.exec(sql)
rs=iris.sql.exec("insert into Test.Person (Name,Email) VALUES('テスト1','test1@mail.com')")
rs=iris.sql.exec("insert into Test.Person (Name,Email) VALUES('テスト2','test2@mail.com')")
rs=iris.sql.exec("insert into Test.Person (Name,Email) VALUES('テスト3','test3@mail.com')")
rs=iris.sql.exec("insert into Test.Person (Name,Email) VALUES('テスト4','test4@mail.com')")
df=iris.sql.exec("select Name,Email from Test.Person").dataframe()
#df.to_excel(filename)
wb=openpyxl.Workbook()
ws = wb.create_sheet(title="シート1")
ws.append(['行番号', '名前', 'メール'])
for i,row in enumerate(dataframe_to_rows(df,header=False)):
if i==0:
continue
ws.append(row)
wb.save(filename)
wb.close()
rs=iris.sql.exec("drop table Test.Person")
def Output(filename,pdfname):
CreateExcel(filename)
excel = win32com.client.Dispatch("Excel.Application")
wb=excel.WorkBooks.Open(filename)
wb.WorkSheets("シート1").Select()
wb.ActiveSheet.ExportAsFixedFormat(0,pdfname)
excel.quit()
上記コードを c:\WorkSpace\TryPython\ExcelToPDF.py に配置した状態とします。
ObjectScritpからの実行例は以下の通りです。
set sys=##class(%SYS.Python).Import("sys")
do sys.path.append("c:\WorkSpace\TryPython")
set e=##class(%SYS.Python).Import("ExcelToPDF")
do e.Output("c:\\temp\\Book5.xlsx","c:\\temp\\Book5.pdf")
Pythonシェルからの実行例は以下の通りです。
C:\WorkSpace\TryPython> python
Python 3.9.10 (tags/v3.9.10:f2f3f53, Jan 17 2022, 15:14:21) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path+=['C:\WorkSpace\TryPython']
>>> import ExcelToPDF as e
>>> e.Output("c:\\temp\\Book6.xlsx","c:\\temp\\Book6.pdf")
少し前準備が多いですが、Pythonの機能を活用してIRISにあるデータをExcel出力+PDF変換までできました🐍
Pythonとても便利ですね!