C++でPDFグラフィックスを扱う方法

C++でPDFグラフィックスを扱う方法

Aspose.PDF FOSS for C++ には、PDFページ上に自由形状を直接描画するための小さなベクターグラフィックス API が含まれています — ライブラリのラスターレンダリングデバイス (BmpDevice, JpegDevice, TiffDevice) とは別で、これらは既存のページコンテンツを画像に変換します。本ガイドでは、Graph コンテナを作成し、Circle、Ellipse、Line 形状を追加し、GraphInfo でそれらの形状をスタイル設定し、完成した Graph をページに配置する手順を解説します。ライブラリは CMake を通じてプロジェクトに追加されます。

ステップバイステップガイド

ステップ 1: パッケージをインストール

ライブラリを CMake のサブディレクトリとして追加し、aspose_pdf_foss ターゲットにリンクします:

add_subdirectory(aspose.pdf-foss-for-cpp)
target_link_libraries(your_app PRIVATE aspose_pdf_foss)

ツールチェーンとヘッダーが解決するか、最小プログラムをコンパイルして確認します:

#include <aspose/pdf/document.hpp>
#include <iostream>

int main() {
    Aspose::Pdf::Document doc;
    std::cout << "Linked OK — pages: " << doc.Pages().Count() << "\n";
}

pages: 0 を出力するビルドが成功すれば、ライブラリが正しくリンクされていることが確認できます。


ステップ 2: 必要なクラスをインポートする

ドキュメント、シェイプコンテナ、3つの具体的シェイプ、およびそれらのスタイリングタイプのヘッダーをインクルードします:

#include <aspose/pdf/document.hpp>
#include <aspose/pdf/drawing/graph.hpp>
#include <aspose/pdf/drawing/circle.hpp>
#include <aspose/pdf/drawing/ellipse.hpp>
#include <aspose/pdf/drawing/line.hpp>
#include <aspose/pdf/graph_info.hpp>
#include <aspose/pdf/border_info.hpp>
#include <aspose/pdf/color.hpp>

using namespace Aspose::Pdf;
using namespace Aspose::Pdf::Drawing;

Graph、Shape、Circle、Ellipse、およびLineはAspose::Pdf::Drawing名前空間に存在します;GraphInfo、BorderInfo、ColorはAspose::Pdfの直下に存在します。


ステップ 3: グラフを作成し、ページに追加する

Graphは、Left()、Top()、Width()、Height()を使用してページ上に位置付けるコンテナであり、Shapes()を通じて内部に描画されたシェイプを保持します。設定が完了すると、Page.Paragraphs().Add()を介してページに配置されます。これは他のページコンテンツでも使用される同じコレクションです:

Document doc;
Page page = doc.Pages().Add();

auto graph = std::make_shared<Graph>();
graph->Left(50.0);
graph->Top(50.0);
graph->Width(400.0);
graph->Height(400.0);

page.Paragraphs().Add(graph);

ステップ 4: 円と楕円を描画する

CircleはPosX()、PosY()、Radius()でそのジオメトリを記述します。Ellipseは代わりにバウンディングボックスを使用します — Left()、Bottom()、Width()、Height()です。両方ともShapes()が返すベクターにShapeポインタとして追加し、Graphに追加されます:

auto circle = std::make_unique<Circle>();
circle->PosX(150.0);
circle->PosY(150.0);
circle->Radius(75.0);
graph->Shapes().push_back(std::move(circle));

auto ellipse = std::make_unique<Ellipse>();
ellipse->Left(20.0);
ellipse->Bottom(20.0);
ellipse->Width(120.0);
ellipse->Height(60.0);
graph->Shapes().push_back(std::move(ellipse));

両方のシェイプはShapeからCheckBounds(containerWidth, containerHeight)を継承し、これによりシェイプの現在のジオメトリが指定されたサイズのコンテナに収まるかどうかを報告します:

bool circleFits = circle->CheckBounds(graph->Width(), graph->Height());

ステップ5: 線を描く

Line はジオメトリを異なる方法で保存します: PositionArray() は座標のフラットな std::vector<float> を保持します — 各点につき x, y のペア — という形で、名前付きプロパティではありません。2点のセグメントには4つの値が必要です: 開始 x、開始 y、終了 x、終了 y。

auto line = std::make_unique<Line>();
line->PositionArray({0.0f, 0.0f, 400.0f, 400.0f});
graph->Shapes().push_back(std::move(line));

ステップ6: GraphInfo とコンテナ境界線でシェイプにスタイルを付ける

各シェイプのストロークとフィルは GraphInfo から取得され、Shape.GraphInfo() / GraphInfo(value) を通じて読み書きされます。ストローク幅(LineWidth()、デフォルトは 1.0f)、ストロークとフィルの色(Color()、FillColor())、およびダッシュパターン(DashArray()、DashPhase())が提供されます:

GraphInfo stroke;
stroke.LineWidth(2.0f);
stroke.Color(Color::FromRgb(1.0, 0.0, 0.0));
stroke.FillColor(Color::FromRgb(1.0, 0.9, 0.9));

Graph コンテナ自体は BorderInfo を持ち、Border() を通じて設定されます。この BorderInfo は、各エッジごとに 1 つの GraphInfo(Left()、Right()、Top()、Bottom())をグループ化し、さらにコンテナ自身のフレーム用に RoundedBorderRadius() を持ちます:

BorderInfo border{BorderSide::All, 1.5f, Color::Black()};
border.RoundedBorderRadius(6.0);
graph->Border(border);

ステップ7: ドキュメントを保存する

doc.Save("graphics.pdf");

よくある問題と対策

私が作成したシェイプはページに表示されません

単独で Circle、Ellipse、または Line を構築しても、所有する Graph の Shapes() が返すベクトルに追加され、さらにその Graph が Page.Paragraphs().Add() を介してページに追加されるまで効果がありません。構築、追加、Graph をページに加えるという 3 つのステップすべてが必要です。

シェイプが誤った位置に描画されます

Graph.Left() と Graph.Top() はページ上のコンテナの位置を決めます。シェイプのプロパティ(Circle.PosX()/PosY()、Ellipse.Left()/Bottom()、Line.PositionArray() 座標)はそのコンテナ内のジオメトリを記述します。出力がずれて見える場合は、コンテナの配置とシェイプ自身の座標の両方を確認してください。

CheckBounds returns false unexpectedly

CheckBounds(containerWidth, containerHeight) はシェイプ自身のジオメトリを渡された寸法と照合します――通常は所有する Graph の Width()/Height() であり、ページ全体のメディアボックスではありません。誤った寸法を渡すと、シェイプが実際には Graph 内に収まっていても偽陰性が発生します。

A Line 表示されない、または単一の点として表示される

PositionArray() は可視セグメントを記述するために、少なくとも 2 つの (x, y) ペア、すなわち 4 つの float 値が必要です。短いベクトルでは線は形成されません。

Confusing Circle with AnnotationType::Circle or CircleAnnotation

このライブラリには別個の PDF アノテーション API もあり、AnnotationType::Circle と CircleAnnotation は円形のマークアップアノテーションを表します。本ガイドで取り上げる Circle クラスは無関係です — Aspose::Pdf::Drawing にあり、アノテーションオブジェクトを追加するのではなくページコンテンツに直接描画します。

よくある質問

GraphInfo と BorderInfo の違いは何ですか?

GraphInfo は単一のストローク — 線幅、色、塗りつぶし色、破線パターン — をスタイル設定し、個々の形状(Shape.GraphInfo() を通じて)および BorderInfo 内のエッジごとに使用されます。BorderInfo は、4つの GraphInfo 値(Left()、Right()、Top()、Bottom())と RoundedBorderRadius() をまとめて、Graph コンテナ自身の枠線フレームを記述します。

形状を単色で塗りつぶすことはできますか?

はい。GraphInfo.FillColor() は、形状が所有する Graph を通じて描画される際に使用される塗りつぶし色を設定します。

Circle は Ellipse のようにバウンディングボックスを保持しますか?

No. Circle は PosX()、PosY()、および Radius() を公開します; Ellipse は Left()、Bottom()、Width()、および Height() を公開します。抽象的な Shape ベースと GraphInfo スタイリング以外に、共通のジオメトリ表現は共有していません。

1つの Graph が複数の形状を保持できますか?

はい。Graph.Shapes() はその Graph 内に配置された Shape オブジェクトの全コレクションを返します — 円、楕円、線はすべて同じコンテナに追加できます。

これはページを画像にレンダリングするのと同じですか?

いいえ。BmpDevice、JpegDevice、および TiffDevice は既存のページコンテンツを画像フォーマットにラスタライズします。Graph、Shape、Circle、Ellipse、および Line は、ドキュメントが作成または編集されている間に PDF コンテンツ内に新しいベクタージオメトリを直接構築します。

参照

 日本語