2020年10月4日日曜日

43: OfficeドキュメントをPDFへ、フル指定でUNOを用いてエクスポート

<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>

エクスポートされるセクション群、イメージ群クオリティ、ウォーターマーク、タギング、フォームフィールド群フォーマット、ブックマーク群やコメント群の出力有無、暗号化、制限、署名、等

話題


About: UNO (Universal Network Objects)
About: LibreOffice
About: Apache OpenOffice
About: Javaプログラミング言語
About: C++
About: Microsoft .NET Framework
About: Pythonプログラミング言語
About: LibreOffice Basic
About: Apache OpenOffice Basic
About: BeanShell
About: JavaScript

この記事の目次


開始コンテキスト



ターゲットコンテキスト



  • 読者は、任意のオフィス(ワードプロセッサ、スプレッドシート、プレゼンテーション)ドキュメントをPDFファイルへ、詳細な指定(エクスポートされるセクション群、イメージ群クオリティ、ウォーターマーク、タギング、フォームフィールド群フォーマット、ブックマーク群やコメント群の出力有無、暗号化、制約、署名、等)に基づいて、自分のプログラムから、LibreOfficeまたはApache OpenOfficeおよびUNOを用いてエクスポートする方法を知る。
ト書き
Hypothesizer 7、Objector 43A、Objector 43Bがコンピューターの前にいる。


オリエンテーション


Hypothesizer 7
本記事では、任意のオフィスドキュメントをPDFファイルへ、詳細な指定に基づいて、自分のプログラムから、LibreOfficeまたはApache OpenOfficeおよびUNOを用いてエクスポートする方法を知ります。

Objector 43A
それって、本当に「任意のオフィスドキュメント」なのか?

Hypothesizer 7
サー、実際には、それは、任意の、LibreOfficeまたはApache OpenOfficeのWriter、Calc、Impressドキュメントであり、それは、フォーマットに、もしくはそのドキュメントに関連付けられたファイルの存在さえにも、かかわらずです。

Objector 43A
はあ?何に「かかわらず」だって?

Hypothesizer 7
私たちは、LibreOfficeまたはApache OpenOfficeのWriter、Calc、Impressにロードされた、あるドキュメントをエクスポートします。そのドキュメントのロード元のファイルのフォーマットはどうでも構いません、もし仮に、そのようなファイルがあるとしても。

Objector 43A
そのようなファイルがないかもしれないと?

Hypothesizer 7
はい: そのドキュメントが、まだ格納されていない新たなドキュメントであれば、そのようなファイルはありません。

Objector 43A
ああ、もちろん。それでは、ファイルは、Microsoft Wordファイルでも、Microsoft Excelファイルでも、プレーンテキストファイルでも、CSVファイルでも、何でもいいわけか?

Hypothesizer 7
LibreOfficeまたはApache OpenOfficeがWriter、Calc、Impressドキュメントとしてロードできるものであれば、何でもよいです。

Objector 43B
どんな詳細仕様を指定できるの?

Hypothesizer 7
マダム、それは、本記事でお知りになれることですが、短く言うと、LibreOfficeまたはApache OpenOfficeのGUIでご指定になれる仕様全てです。

Objector 43B
それじゃあ、PDFファイルに署名することもできるの?

Hypothesizer 7
はい、おできになります。


本体


1: メカニズム


Hypothesizer 7
任意のドキュメントをPDFへエクスポートするメカニズムは、ある以前の記事(コンセプトあるJava実装あるC++実装あるC#実装あるPython実装あるLibreOfficeまたはApache OpenOffice Basic実装)で記述されたものと全く同じであり、ここではそれを繰り返しません。

本記事のテーマは、詳細なPDF仕様のためにセットするべきドキュメント格納プロパティです。


2: セットするべきドキュメント格納プロパティ


Hypothesizer 7
セットするべきドキュメント格納プロパティは、'FilterData'であり、それは、'::com::sun::star::beans::PropertyValue'の'sequence'を取ります。

Objector 43B
「'sequence'」って何なの、具体的には?

Hypothesizer 7
'sequence'で私が意味しているのは、あるUNOデータタイプです、'シーケンス一般'ではなく(それが、その用語を引用符で囲った理由です)。

Objector 43B
それじゃあ、そのデータタイプを代表する特定のクラスがあるわけ?

Hypothesizer 7
C++では、そうです。JavaおよびC#では、配列にマップされています。Pythonでは、'List'にマップされています。

Objector 43B
あらそう。

Hypothesizer 7
以下が、その'sequence'内に含めることのできるプロパティ群です(そのなかで、「any」以外のタイプは、UNOデータタイプです('any'はデータタイプでは全くなく、任意のUNOデータが受け入れられることを意味します))。

名前タイプ
PageRangestringページ群範囲: '' -> 全ページ、'1-2,4'、等
Selectionanyエクスポートされるセクション群: 当該ドキュメントのコントローラの'XSelectionSupplier.getSelection ()'によって得られたセクション、または恣意的なオブジェクト(例えば、あるセル群範囲)
UseLosslessCompressionbooleanロスレス圧縮が使われる: 'false' -> あるJPEG圧縮が使われる
Qualityshort%によるJPEGクオリティ
ReduceImageResolutionbooleanイメージ解像度群が下げられる
MaxImageResolutionshortDPIによる画像最大解像度: 75、150、300、600、1200
Watermarkstringウォーターマーク文字列
IsAddStreambooleanオリジナルドキュメントがエンベッドされる
SelectPdfVersionshortPDFバージョン: '0' -> PDF 1.4、'1' -> PDF/A-1
UseTaggedPDFbooleanタグ付けされたPDFが使われる
ExportFormFieldsbooleanフォームフィールド群がエクスポートされる
FormsTypeshortフォーム群タイプ: '0' -> FDF、'1' -> PDF、'2' -> HTML、'3' -> XML
AllowDuplicateFieldNamesboolean重複したフィールド名群が許される
ExportBookmarksbooleanブックマーク群がエクスポートされる
ExportPlaceholdersbooleanプレースホルダー群がエクスポートされる
ExportNotesbooleanコメント群がエクスポートされる
IsSkipEmptyPagesboolean自動的に挿入された空白ページ群がスキップされる
UseReferenceXObjectbooleanForm XObject群が使われる
ViewPDFAfterExportbooleanエクスポートが完了した後に、ターゲットファイルが表示される
InitialViewshortターゲットファイルのエクスポート後表示のための、初期ビュースタイル: '0' -> ページ群のみ、'1' -> ブックマーク群およびページ群、'2' -> サムネイル群とページ群
InitialPageshortターゲットファイルのエクスポート後表示のための、初期ページ番号
Magnificationshortターゲットファイルのエクスポート後表示のための、初期拡大方法: '0' -> デフォルト、'1' -> ページ全体がウィンドウにフィットする、'2' -> ページ幅がウィンドウにフィットする、'3' -> ページコンテンツがウィンドウにフィットするように想定されているが、必ずしもそうではない
Zoomshortターゲットファイルのエクスポート後表示のための、初期ズームファクター(%)
PageLayoutshortターゲットファイルのエクスポート後表示のための、初期ページレイアウトスタイル: '0' -> デフォルト, '1' -> 単一ページ, '2' -> 連続, '3' -> 対面2ページが横並びに表示され、それらのペアが縦に接続されて連続表示される
FirstPageOnLeftbooleanターゲットファイルのエクスポート後表示において、最初のページが左に表示される: 'PageLayout'が'3'の場合にのみ有効
ResizeWindowToInitialPagebooleanターゲットファイルのエクスポート後表示において、ウィンドウが初期ページに合わせてリサイズされる
CenterWindowbooleanターゲットファイルのエクスポート後表示において、ウィンドウがスクリーンの中央に置かれる
OpenInFullScreenModebooleanターゲットファイルのエクスポート後表示において、ウィンドウがフルスクリーンモードでオープンされる
DisplayPDFDocumentTitlebooleanターゲットファイルのエクスポート後表示において、ドキュメントタイトルが表示される
UseTransitionEffectsbooleanターゲットファイルのエクスポート後表示において、遷移エフェクトが使われる
HideViewerMenubarbooleanターゲットファイルのエクスポート後表示において、メニューバーが隠される
HideViewerToolbarbooleanターゲットファイルのエクスポート後表示において、ツールバーが隠される
HideViewerWindowControlsbooleanターゲットファイルのエクスポート後表示において、ウィンドウコントロール群が隠される
OpenBookmarkLevelsshortターゲットファイルのエクスポート後表示のための、オープンされるブックマークレベル群: '-1' -> 全て
ExportBookmarksToPDFDestinationbooleanブックマーク群が名前付きデスティネーション群としてエクスポートされる
ConvertOOoTargetToPDFTargetbooleanドキュメント内リンク群がPDF内ターゲット群へ変換される
ExportLinksRelativeFsysboolean相対的ファイルリンク群がエクスポートされる
PDFViewSelectionshortクロスドキュメントのリンク群のビューア: '0' -> デフォルトビューア、'1' -> PDFリーダーアプリケーション、'2' -> インターネットブラウザ
EncryptFilebooleanファイルが暗号化される
DocumentOpenPasswordstringオープン用パスワード
RestrictPermissionsboolean一部のアクションが制約される
PermissionPasswordstring制約されたアクション群用のパスワード
Printingshortプリント制約: '0' -> 不許可、'1' -> 低解像度でのみ許可(150 DPI)、'2' -> 高解像度でも許可
Changesshort変更制約: '0' -> 不許可、'1' -> 挿入、削除、ページ回転が許可される、'2' -> フォームフィールド群への記入が許可される、'3' -> フォームフィールド群への記入・コメントが許可される、'4' -> ページ群の抜き取りを除いて全てが許可される
EnableCopyingOfContentbooleanコンテンツのコピーが許可される
EnableTextAccessForAccessibilityToolsbooleanアクセシビリティツール群からのテキストアクセスが許可される
SignPDFbooleanファイルが署名される
SignatureCertificate::com::sun::star::security::XCertificate署名の証明書
SignaturePasswordstring署名の証明書のパスワード
SignatureLocationstring署名の所在地
SignatureReasonstring署名の理由
SignatureContactInfostring署名のコンタクト情報
SignatureTSAstring署名のタイムスタンプオーソリティーURL

Objector 43B
うん?ふーん. . .

Hypothesizer 7
それらのプロパティ群は、PDFエクスポートダイアログ中のセッティング群に対応しています、容易にご確認できるとおり。

Objector 43B
確認できるわよ、確かに、でも、そのダイアログの中の一部のセッティングは私には理解できないわ。

Hypothesizer 7
ああ。

Objector 43B
例えば、「Fit in window(ウィンドウサイズに合わせる)」ってどういう意味よ?「Fit width(幅を合わせる)」は、ページ幅がウィンドウにフィットすることを意味しているようだけど、「Fit in window(ウィンドウサイズに合わせる)」では、何がウィンドウにフィットするわけ?

Hypothesizer 7
その表現は言葉足らずですが、それは、肝心なものが抜けているからです: どの場合も、何かがウィンドウにフィットするわけであり(実際、他の何処にそれはフィットするというのでしょう)、問題は'何が'そこにフィットするかなのですが、「Fit in window(ウィンドウサイズに合わせる)」は、'何が'かを全然述べていません。. . .理解可能な表現は、'ページ全体をフィットさせる(ウィンドウに)'といったものでしょう。

Objector 43B
それに、いったいぜんたい、「fit visible(表示に合わせる)」って何なの?. . .「visible(表示)」がウィンドウにフィットするってこと?「visible(表示)」って何よ?. . .その表現がナンセンスに思えるのは、拡大方法が決まる前には何も表示されてないから、だから、拡大方法は、「visible(表示)」をウィンドウにフィットさせることによって決定などできない、だって、「visible(表示)」なんてまだ存在しないじゃん。. . .そんな表現、どうやって理解しろって言ってるわけ?

Hypothesizer 7
ああ、実のところ、それは、LibreOfficeやApache OpenOfficeが悪いのではなく、Adobe Acrobat Readerが悪いのです、その表現の出元である。

Objector 43B
あら. . .、分かった、でも、結局、それはどういう意味なわけ?

Hypothesizer 7
実のところ、「visible(表示)」は、'コンテンツ'を意味しているようです。

Objector 43B
はあ?

Hypothesizer 7
例えば、当該ページ上の文字群はコンテンツです。

Objector 43B
. . .余白だって、白いスペースとして見えると思うけど。

Hypothesizer 7
彼らの用語体系では、それは、'見えない'と呼ばれるようです。

Objector 43B
. . .それで?

Hypothesizer 7
したがって、基本的には、「Fit visible(表示に合わせる)」は、'コンテンツを含んでいるエリアがウィンドウにフィットする'ことを意味するようです。

Objector 43B
「基本的には」?

Hypothesizer 7
実のところ、厳密な意図が私には理解できません: 私が試みる限り、ページコンテンツ全体を包含する最小四角がウィンドウにうまくフィットするということにはなりません。

Objector 43B
. . .「continuous facing(連続見開き)」も、舌足らずに思えるわ、言いたそうなことは推測できるけど。

Hypothesizer 7
それは、2つの対面するページが横並びに表示され、そうしたペア群が、縦に連続して接続されて表示されることを意味します。

Objector 43A
どうすれば、'::com::sun::star::security::XCertificate'というタイプの証明書オブジェクトを取得できるのか?

Hypothesizer 7
事前に、LibreOfficeまたはApache OpenOfficeへ、あるNetwork Security Servicesデータベースを登録しておく必要があります。

Objector 43A
「Network Security Services」?. . .とにかく、どうすれば、そのデータベースをLibreOfficeへ登録できるのだ?

Hypothesizer 7
LibreOfficeまたはApache OpenOfficeのメニュー上で、'Tools(ツール)' -> 'Options...(オプション)'をクリックし、現われるダイアログ上で、左ペインで、'LibreOffice' -> 'Security(セキュリティ)'を選択し、右ペインで、'Certificate...(証明書)'をクリックし、現われるダイアログ上で、'Select NSS Path...(NSSパスを選択)'をクリックし、現われるダイアログ上で、データベースディレクトリを選択し、'OK'をクリックし、もう2回'OK'をクリックします。

Objector 43A
ふーん. . .、それで?

Hypothesizer 7
以下は、そのデータベース内のある証明書の証明書オブジェクトを作成するJavaコード断片です('a_certificateIssuerName'および'a_certificateSerialNumber'は、それぞれ、証明書発行者名およびシリアル番号、例えば、それぞれ、'CN=Tanichida,C=JP'および'{(byte) 0x00, (byte) 0xAA, (byte) 0xDD, (byte) 0xDF, (byte) 0xBF}'のような、そして、'getServiceInstance'は、グローバルUNOサービスインスタンスを取得するファンクション)。

@Java ソースコード
~
import com.sun.star.security.XCertificate;
import com.sun.star.xml.crypto.XSEInitializer;
import com.sun.star.xml.crypto.XSecurityEnvironment;
import com.sun.star.xml.crypto.XXMLSecurityContext;
~
public class UnoObjectsContext implements XComponentContext {
	~
	private XSecurityEnvironment i_networkSecurityServicesSecurityEnvironmentInXSecurityEnvironment;
	
	~
	
	public Object getServiceInstance (String a_serviceName, Class a_targetClass, List <Object> a_arguments) throws com.sun.star.uno.Exception {
		~
	}
	
	~
	
	public XCertificate getNetworkSecurityServicesCertificateInXCertificate (String a_certificateIssuerName, byte [] a_certificateSerialNumber) throws Exception {
		if (i_networkSecurityServicesSecurityEnvironmentInXSecurityEnvironment == null) {
			XSEInitializer l_networkSecurityServicesSecurityEnvironmentInitializerInXSEInitializer = (XSEInitializer) getServiceInstance ("com.sun.star.xml.crypto.SEInitializer", XSEInitializer.class, null);
			XXMLSecurityContext l_networkSecurityServicesSecurityContextInXXMLSecurityContext = l_networkSecurityServicesSecurityEnvironmentInitializerInXSEInitializer.createSecurityContext ("NetworkSecurityServices");
			if (l_networkSecurityServicesSecurityContextInXXMLSecurityContext.getSecurityEnvironmentNumber () > 0) {
				i_networkSecurityServicesSecurityEnvironmentInXSecurityEnvironment = l_networkSecurityServicesSecurityContextInXXMLSecurityContext.getSecurityEnvironmentByIndex (0);
			}
		}
		if (i_networkSecurityServicesSecurityEnvironmentInXSecurityEnvironment != null) {
			XCertificate [] l_networkSecurityServicesCertificatesArrayInXCertificate = i_networkSecurityServicesSecurityEnvironmentInXSecurityEnvironment.getPersonalCertificates ();
			return selectCertificateFromCertificatesArray (l_networkSecurityServicesCertificatesArrayInXCertificate, a_certificateIssuerName, a_certificateSerialNumber);
		}
		return null;
	}
	
	~
	
	private XCertificate selectCertificateFromCertificatesArray (XCertificate [] a_certificatesArrayInXCertificate, String a_certificateIssuerName, byte [] a_certificateSerialNumber) {
		if (a_certificatesArrayInXCertificate != null) {
			for (XCertificate l_certificateInXCertificate: a_certificatesArrayInXCertificate) {
				if (a_certificateIssuerName.equals (l_certificateInXCertificate.getIssuerName ())) {
					if (a_certificateSerialNumber == null) {
						return l_certificateInXCertificate;
					}
					else {
						byte [] l_certificateSerialNumber = l_certificateInXCertificate.getSerialNumber ();
						if (a_certificateSerialNumber.length == l_certificateSerialNumber.length) {
							int l_certificateSerialNumberByteIndex = 0;
							for (byte l_certificateSerialNumberByte: l_certificateSerialNumber) {
								if (a_certificateSerialNumber [l_certificateSerialNumberByteIndex] != l_certificateSerialNumberByte) {
									break;
								}
								l_certificateSerialNumberByteIndex ++;
							}
							if (l_certificateSerialNumberByteIndex == l_certificateSerialNumber.length) {
								return l_certificateInXCertificate;
							}
						}
					}
				}
			}
		}
		return null;
	}
}

Objector 43A
. . . 「シリアル番号」は、どうすれば知れるのだ?

Hypothesizer 7
LibreOfficeまたはApache OpenOfficeのPDFエクスポートダイアログからそれを見ることができます('Digital Signatures(デジタル署名)'タブを選択し、現われたダイアログ中で、'Select...(選択...)'を選択し、証明書を選択し、'View Certificate...(証明書の表示...)'をクリックし、現われたダイアログ中で、'Details(詳細)'タブを選択します)。

Objector 43A
ふーん。

Hypothesizer 7
注意点として、もしも、データベースにパスワードが付いていたら、LibreOfficeまたはApache OpenOfficeのインスタンスは、1度、パスワードを要求します。

Objector 43A
「1度」?

Hypothesizer 7
つまり、インスタンスが立ち上がった後、上記コードが最初に呼ばれた時、インスタンスは、パスワードを要求するダイアログを表示します。

Objector 43A
でも、インスタンスはヘッドレスモードにあるんだぜ!

Hypothesizer 7
それでは、非ヘッドレスモードにしなければならないでしょう。

Objector 43A
. . . それは不便だぞ。

Hypothesizer 7
知っています、しかし、残念ながら、パスワードをプログラムからセットする方法を私は知りません。

Objector 43A
. . . そこの'SignaturePassword'が使うべきものじゃないのか?

Hypothesizer 7
それは、証明書のパスワードであって、データベースのものではありません。

Objector 43A
ふーむ. . .

Hypothesizer 7
一つのオプションは、データベースからパスワードを取り除くことでしょう、もしも、それが許容できるのであれば。

Objector 43A
えーと. . .

Hypothesizer 7
パスワードをセットするというのがデータベースをプロテクトする唯一の方法というわけではないか思います: 例えば、データベースファイル群へのアクセスを単一のオペレーティングシステムユーザだけに限定することができます、オペレーティングシステムファイル権限的に。


3: 結びとその先


Hypothesizer 7
これで、任意のオフィス(ワードプロセッサ、スプレッドシート、プレゼンテーション)ドキュメントをPDFファイルへ、詳細な指定に基づいて、自分のプログラムから、LibreOfficeまたはApache OpenOfficeおよびUNOを用いてエクスポートする方法を知りました。

そのテクニックの基礎は、任意のファイルをUNOを直接に用いてコンバートする方法です(コンセプトあるJava実装あるC++実装あるC#実装あるPython実装あるLibreOfficeまたはApache OpenOffice Basic実装)。その方法を採用しさえすれば、効率上も機能上も多くの恩恵を得られるようになります。

ドキュメント格納プロパティを指定するだけでは、コントロールできないことは、ドキュメントに手を加えることによってコントロールできるでしょう、本シリーズで既に紹介されたか、これから紹介される多くの方法によって


参考資料


  • Apache OpenOffice Wiki. (2014/01/02). Apache OpenOffice Developer's Guide. Retrieved from https://wiki.openoffice.org/wiki/Documentation/DevGuide/OpenOffice.org_Developers_Guide
<このシリーズの前の記事 | このシリーズの目次 | このシリーズの次の記事>