C++ で画像を OFD(Open Fixed-layout Document)形式に変換する処理は、ドキュメント処理システムにおいてよくある要件の一つです。特に中国語圏では、OFD は公式文書のアーカイブ、交換、配布に広く使用される標準フォーマットとなっています。実際の開発では、スキャンした文書や画像ファイルを OFD ドキュメントに変換し、統一的に保存・管理したり、電子文書管理システムや自動化ワークフローに統合したりするケースが多くあります。 画像から OFD への変換処理を低レベルから実装する場合、画像形式の解析、ページサイズの設定、ドキュメント構造の構築など、複雑な処理を実装する必要があります。また、生成されるファイルが OFD 仕様に準拠していることを保証する必要もあります。 Spire.PDF for C++ を使用すれば、シンプルな API を利用して画像を OFD に簡単に変換できます。このライブラリは PNG、JPG、BMP、TIFF、EMF などの一般的な画像形式をサポートしており、ドキュメント構造の生成や描画処理も自動的に行われます。 本記事では、C++ で画像を OFD ドキュメントへ変換する方法を解説し、単一画像の変換、複数画像を用いた複数ページ OFD の生成、さらにバッチ変換の実装例も紹介します。 クイックナビゲーション 画像から OFD への変換について 事前準備 C++ で単一画像を OFD に変換 C++ で複数画像を複数ページ OFD に変換 画像を固定ページサイズに適合させる 画像をバッチで OFD に変換 注意点 よくある質問 1. 画像から OFD への変換について OFD は XML ベースの固定レイアウト文書形式であり、PDF と似た機能を持ちながら、中国語環境における文字セットや政府文書規格に対応するよう最適化されています。 画像を OFD に変換する処理は、本質的には OFD 仕様に準拠したドキュメント構造を作成し、そのページ内に画像を埋め込むことを意味します。 画像を OFD に変換する代表的な利用シナリオには以下があります。 スキャンした請求書や領収書のデジタルアーカイブ 統一された電子文書ストレージシステムの構築 文書処理ワークフローの自動化 従来の画像文書を標準化された電子文書へ変換 一般的な実装フローは以下の通りです。 ドキュメントオブジェクトを作成 画像をページ上に描画 OFD 形式としてエクスポート 2. 事前準備 C++ で画像を OFD に変換する前に、まず Spire.PDF for C++ をインストールして設定する必要があります。 NuGet からインストール(推奨) Spire.PDF を C++ プロジェクトに追加する最も簡単な方法は NuGet を利用することです。 NuGet を使用すると、ライブラリファイルと依存関係が自動的にダウンロード・設定されます。 インストール手順: Visual Studio でプロジェクトを開く ソリューション エクスプローラーで 参照 を右クリック NuGet パッケージの管理 を選択 Spire.PDF.Cpp を検索 インストール をクリック インストール後、コードでライブラリを読み込みます。 #include "Spire.Pdf.o.h" 手動インストール または、 Spire.PDF for C++ をダウンロード し、include と lib ディレクトリをプロジェクトに設定して手動で統合することも可能です。 詳細は以下のガイドを参照してください。 C++ アプリケーションに Spire.PDF for C++ を統合する方法 3. C++ で単一画像を OFD に変換 以下のサンプルコードは、単一の画像ファイルを OFD ドキュメントへ変換する方法を示しています。コードではまず PDF ドキュメントオブジェクトを作成し、画像を読み込み、ページに描画した後、最終的に OFD 形式で保存します。 #include "Spire.Pdf.o.h" using namespace Spire::Pdf; int main() { // 新しい PDF ドキュメントを作成します PdfDocument* ofd = new PdfDocument(); // 画像ファイルを読み込みます auto image = PdfImage::FromFile(L"Sample.jpg"); // 画像のサイズに基づいてページサイズを計算します float pageWidth = image->GetWidth(); float pageHeight = image->GetHeight(); // 画像サイズに一致するページを追加します auto page = ofd->GetPages()->Add(new SizeF(pageWidth, pageHeight)); // ページ上に画像を描画します page->GetCanvas()->DrawImage(image, 0, 0, pageWidth, pageHeight); // OFD ファイルとして保存します ofd->SaveToFile(L"ImageToOfd.ofd", FileFormat::OFD); // リソースを解放します delete ofd; return 0; } 以下の図は、元画像から生成された OFD ドキュメントの表示例です。 主なクラスとメソッド PdfDocument ドキュメントオブジェクトを表し、ページの作成や最終的な OFD ファイルの出力を行います。 PdfImage::FromFile() 指定パスから画像ファイルを読み込み、ページ上に描画可能な画像オブジェクトを作成します。 PdfDocument::GetPages()->Add() ドキュメントに新しいページを追加します。本例では画像サイズに合わせてページサイズを設定しています。 PdfCanvas::DrawImage() 指定された位置とサイズで画像をページキャンバスに描画します。 SaveToFile() ドキュメントをディスクに保存し、FileFormat::OFD を指定することで OFD 形式で出力します。 この方法により、画像を正しい比率のまま OFD ページ内に表示でき、元画像の品質を維持できます。 ページ余白の削除(任意) ofd->GetPageSettings()->SetMargins(0.0); 余白を残す場合: ofd->GetPageSettings()->SetMargins(10.0); ページの余白を適切に設定することで、ページレイアウトの見栄えをコントロールできます。 注意:コード実行時に C++ のバージョン互換性の問題が発生する場合、以下の方法で対応できます。 方法 1:プロジェクトのプロパティ → C/C++ → プリプロセッサ → プリプロセッサ定義 に _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING を追加 方法 2:プロジェクトのプロパティ → 構成プロパティ → 全般 にて、C++ 言語標準 を ISO C++14 標準 (/std:c++14) に設定 4. C++ で複数画像を複数ページ OFD に変換 文書のアーカイブやバッチ処理のシナリオでは、複数の画像を 1 つの OFD ファイルに統合する必要があることがよくあります。以下の例では、複数ページからなる OFD 文書を作成し、各ページに異なる画像を配置する方法を示します。 コードは画像ファイルのリストを順に処理し、各画像に対して個別のページを作成します。ページサイズは画像の寸法に基づいて設定され、画像は対応するページに描画されます。 #include "Spire.Pdf.o.h" #include <vector> #include <filesystem> #include <algorithm> using namespace Spire::Pdf; namespace fs = std::filesystem; int main() { // 新しい PDF ドキュメントを作成します(OFD として保存するため) PdfDocument* ofd = new PdfDocument(); // 画像フォルダを指定します std::wstring folderPath = L"./images"; // フォルダを走査します for (const auto& entry : fs::directory_iterator(folderPath)) { if (!entry.is_regular_file()) continue; std::wstring path = entry.path().wstring(); std::wstring ext = entry.path().extension().wstring(); // 比較しやすいように小文字へ変換します std::transform(ext.begin(), ext.end(), ext.begin(), ::towlower); // 対応している画像形式かどうかを判定します if (ext == L".png" || ext == L".jpg" || ext == L".jpeg" || ext == L".bmp") { // 画像を読み込みます auto image = PdfImage::FromFile(path.c_str()); // 画像サイズを取得します float pageWidth = image->GetWidth(); float pageHeight = image->GetHeight(); // ページを作成します auto page = ofd->GetPages()->Add(new SizeF(pageWidth, pageHeight)); // 画像を描画します page->GetCanvas()->DrawImage(image, 0, 0, pageWidth, pageHeight); } } // OFD ファイルとして保存します ofd->SaveToFile(L"multi_page_document.ofd", FileFormat::OFD); // リソースを解放します delete ofd; return 0; } 生成された OFD ドキュメントでは、各画像が独立したページに配置されます。 この実装では、画像ファイルのコレクションを順に処理し、各画像ごとに独立したページを作成して適切なサイズで描画します。生成された OFD 文書は、1 つのファイル内にすべての元画像の順序とレイアウトを保持します。 注意:#include <filesystem> は C++17 以降の標準でのみ使用可能です。 5. 画像を固定ページサイズに適合させる 多くの実務的な文書ワークフローでは、ページは通常 標準ページサイズ に従う必要があり、画像の元のサイズをそのまま使用することはありません。たとえば、スキャンした契約書、表、報告書などは、A4 や Letter などの標準ページフォーマットに統一することが求められます。 これを実現するには、まず固定サイズのページを作成し、画像を縦横比を維持したままスケーリングして、ページ内に適切に収めます。 以下の例では、縦横比を保持しつつ、画像を固定ページサイズに合わせて縮小・拡大する方法を示します。 #define NOMINMAX #include "Spire.Pdf.o.h" #include <algorithm> using namespace Spire::Pdf; int main() { // 新しい PDF ドキュメントを作成します PdfDocument* ofd = new PdfDocument(); // 固定サイズのページ(例:A4)を追加します PdfPageBase* page = ofd->GetPages()->Add(PdfPageSize::A4); // 画像を読み込みます auto image = PdfImage::FromFile(L"Sample.jpg"); // ページのサイズを取得します float pageWidth = page->GetCanvas()->GetClientSize().GetWidth(); float pageHeight = page->GetCanvas()->GetClientSize().GetHeight(); // 画像のサイズを取得します float imgWidth = image->GetWidth(); float imgHeight = image->GetHeight(); // アスペクト比を維持したスケーリング比率を計算します float scale = std::min(pageWidth / imgWidth, pageHeight / imgHeight); float scaledWidth = imgWidth * scale; float scaledHeight = imgHeight * scale; // ページ上にスケーリング後の画像を描画します page->GetCanvas()->DrawImage(image, 0, 0, scaledWidth, scaledHeight); // OFD ファイルとして保存します ofd->SaveToFile(L"FixedPageSize.ofd", FileFormat::OFD); // リソースを解放します delete ofd; return 0; } 以下のスクリーンショットは、画像が固定ページサイズ(A4)に合わせてスケーリングされ、縦横比が保持される様子を示しています。 この方法により、異なるサイズの画像であっても標準化された文書レイアウト内に統一して配置でき、元の比率を維持して画像の歪みを防ぐことができます。同じ技術は、複数の画像から多ページの OFD 文書を生成する場合にも適用可能です。 6. 画像をバッチで OFD に変換 自動化文書処理システムでは、多数の画像ファイルを一括で OFD 文書に変換する必要があることがよくあります。コードの再利用性を高めるため、変換処理のロジックを独立した関数としてカプセル化し、複数のファイルをループで処理する方法が有効です。 以下の例では、基本的なエラー処理と進捗表示を含む、シンプルなバッチ処理の実装方法を示しています。 #include "Spire.Pdf.o.h" #include <vector> #include <iostream> #include <filesystem> #include <algorithm> using namespace Spire::Pdf; namespace fs = std::filesystem; void ConvertImageToOFD(const std::wstring& inputPath, const std::wstring& outputPath) { // 新しい PDF ドキュメントを作成します(OFD を生成するため) PdfDocument* ofd = new PdfDocument(); try { // 画像ファイルを読み込みます auto image = PdfImage::FromFile(inputPath.c_str()); // ページサイズを計算します(画像サイズと一致させます) float pageWidth = image->GetWidth(); float pageHeight = image->GetHeight(); // 画像サイズに一致するページを追加します auto page = ofd->GetPages()->Add(new SizeF(pageWidth, pageHeight)); // ページ上に画像を描画します page->GetCanvas()->DrawImage(image, 0, 0, pageWidth, pageHeight); // OFD ファイルとして保存します ofd->SaveToFile(outputPath.c_str(), FileFormat::OFD); std::wcout << L"変換完了:" << inputPath << L" -> " << outputPath << std::endl; } catch (const std::exception& ex) { std::wcout << L"変換中にエラーが発生しました:" << inputPath << L" : " << ex.what() << std::endl; } // ドキュメントを解放します delete ofd; } int main() { // 走査する画像フォルダを定義します std::wstring folderPath = L"./images"; // フォルダ内のすべてのファイルを走査し、自動的に変換を実行します for (const auto& entry : fs::directory_iterator(folderPath)) { // 通常のファイルのみ処理します if (!entry.is_regular_file()) continue; fs::path filePath = entry.path(); std::wstring ext = filePath.extension().wstring(); // 拡張子を小文字に変換して比較しやすくします std::transform(ext.begin(), ext.end(), ext.begin(), ::towlower); // 対応している画像形式かどうかを判定します if (ext == L".png" || ext == L".jpg" || ext == L".jpeg" || ext == L".bmp") { // 入力画像のパスを取得します std::wstring inputPath = filePath.wstring(); // 対応する OFD の出力パスを生成します(画像と同じ名前) fs::path outputPath = filePath.parent_path() / (filePath.stem().wstring() + L".ofd"); // 変換を実行します ConvertImageToOFD(inputPath, outputPath.wstring()); } } std::wcout << L"一括変換が完了しました。" << std::endl; return 0; } このバッチ処理方式は、以下の利点を提供します: 再利用可能なモジュール化された変換関数 個別ファイルでの失敗に対応したエラー処理機構 進捗状況を容易に監視できる出力 明確なリソース管理 この実装では、各画像を独立して処理するため、個別の変換失敗が全体のバッチ処理を中断することはありません。 7. 注意事項 画像ファイルのパス 画像ファイルのパスが正しくアクセス可能であることを確認してください。画像を読み込む際は、絶対パスを使用するか、作業ディレクトリを確認することを推奨します: // 信頼性を高めるために絶対パスを使用 auto image = PdfImage::FromFile(L"C:Documentsscanned_invoice.png"); メモリ管理 PdfDocument や PdfImage オブジェクトは適切に解放し、メモリリークを防いでください。使用後は動的に割り当てたオブジェクトを必ず削除します: delete ofd; サポートされていない画像形式 Spire.PDF は PNG、JPEG、BMP、EMF、TIFF などの一般的な画像形式をサポートしています。入力ファイルがサポート対象であることを確認してください。サポートされていない形式の場合は、事前に画像処理ライブラリで対応形式に変換してください。 ページサイズに関する注意 画像のサイズに基づいてページを作成する場合、大きすぎる画像は OFD 文書の閲覧や印刷に問題を引き起こす可能性があります。大きな画像にはサイズ制限や縮小処理を行うことを推奨します: #define NOMINMAX #include <algorithm> // 最大ページサイズの制限を適用 const float MAX_WIDTH = 1000.0f; const float MAX_HEIGHT = 1400.0f; float pageWidth = std::min(static_cast<float>(image->GetWidth()), MAX_WIDTH); float pageHeight = std::min(static_cast<float>(image->GetHeight()), MAX_HEIGHT); ファイルの文字コード 中文文字や特殊文字を含むファイルパスを扱う場合は、std::wstring のようなワイド文字列を使用し、正しいエンコーディングを保証してください。これにより、ファイル操作での文字化けやエラーを防げます。 C++ 言語標準 一部の環境でコンパイル問題が発生する場合、以下の方法で対応可能です: 方法1:プロジェクトのプロパティ → C/C++ → プリプロセッサ → プリプロセッサ定義 に _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING を追加 方法2:プロジェクトのプロパティ → 構成プロパティ → 全般 にて、C++ 言語標準 を ISO C++14 標準 (/std:c++14) に設定 まとめ 本記事では、Spire.PDF for C++ を使用して画像を OFD 文書に変換する方法を紹介しました。シンプルな API 呼び出しにより、単一画像の変換、多数画像からの多ページ文書生成、さらにはバッチ処理による変換などを容易に実現できます。 この技術は、スキャン文書のデジタル化、電子文書管理、そして自動化された文書処理ワークフローにおいて幅広く応用可能です。 OFD 変換に加えて、Spire.PDF for C++ は PDF 文書の作成、編集、変換、さまざまな形式への出力など、豊富な機能を提供します。本ライブラリを利用することで、開発者は複雑な文書処理タスクを効率的に実行しつつ、生成される文書が業界標準に準拠していることを保証できます。 フル機能を体験したい場合は、30 日間無料ライセンスを申請 してください。 8. よくある質問(FAQ) 画像を OFD に変換する際、サードパーティ製ソフトは必要ですか? 必要ありません。Spire.PDF は、画像から OFD への変換を単独で実行でき、Adobe Acrobat やその他の外部 PDF ソフトウェアに依存する必要はありません。 OFD 変換で対応している画像形式は何ですか? Spire.PDF は、PNG、JPEG、BMP、EMF、TIFF などの一般的な画像形式に対応しています。 Spire.PDF はバッチ処理に適していますか? はい。Spire.PDF はサーバー環境向けに最適化されており、大量の画像変換タスクを効率的に処理できます。 変換前に透かしやテキストを追加できますか? 可能です。Spire.PDF では、ページキャンバス上にテキストや画像を描画できるため、OFD にエクスポートする前に透かしを追加することができます。 関連チュートリアル: C++ で PDF/OFD 文書にテキスト透かしを追加する方法 C++ で PDF/OFD 文書に画像透かしを追加する方法 OFD 出力で画像品質は影響を受けますか? 影響ありません。変換プロセス中、元の画像の解像度と品質は保持され、ページサイズも画像の大きさに応じて自動で調整されます。