PostScript での変換操作 | C++
PS Document 内のコンテンツを変換する
この記事では、PsDocument に追加された長方形パスに対して、移動、拡大縮小、回転、傾斜といった様々な変換を行う方法について説明します。
1つのコードスニペットを複数のコードに分割し、開始、終了、そして各変換を個別に実行します。PostScript における変換は、常に “gsave” 演算子と “grestore” 演算子によってバインドされたグラフィック状態で実行されます。そのため、PsDocument には “WriteGraphicsSave()” と “WriteGraphicsRestore()” というメソッドが用意されています。これらのメソッドを使用することで、ネストされたグラフィック状態を含むあらゆるコンテンツを追加し、変換やクリッピングを行うことができます。これらの変換は、外側のグラフィック状態には影響しませんが、ネストされたグラフィック状態には影響します。
“WriteGraphicsSave()” メソッドと “WriteGraphicsRestore()” メソッドを使用せずに変換を行うと、上位レベルのグラフィックス状態で変換が行われ、PsDocument 内のすべてのコンテンツがこの変換の対象になります。
ドキュメントのコンテンツにあらゆる変換を最初から設定するアルゴリズムは、以下の手順で構成されます。
- 生成されるPSファイル用の出力ストリームを作成します。
- PsSaveOptions を作成します。
- 既に作成済みの出力ストリームと保存オプションを使用して、 PsDocument を作成します。
- グラフィックス状態を保存します。新しいグラフィックス状態を作成し、以前のグラフィックス状態はグラフィックス状態スタックに格納されます。
- 必要な変換(平行移動、拡大縮小、回転、傾斜、またはこれらの組み合わせ)を追加します。このコードでは、各変換コンポーネントの影響を個別に、そして最後に一度に3つずつ示しています。
- 変換に必要なコンテンツを追加します。この例では、四角形から四角形 GraphicsPath を作成し、それを塗りつぶしました。変換を行う前に四角形を1つ作成し、現在のグラフィックス状態における各変換の後にその四角形を塗りつぶしました。
- グラフィックス状態を復元して、適用された変換の影響を受けない前の状態に戻します。この例では、上位レベルのグラフィックス状態です。
このコードでは、出力ストリームと PsSaveOptions から PsDocument を作成し、上位レベルのグラフィックス状態をポイント 100,100 に変換して最初の四角形をオフセットし、最後に四角形から最初の四角形 GraphicsPath を作成します。
1 // The path to the documents directory.
2 System::String dataDir = RunExamples::GetDataDir_WorkingWithCanvas();
3
4 //Create output stream for PostScript document
5 {
6 System::SharedPtr<System::IO::Stream> outPsStream = System::MakeObject<System::IO::FileStream>(dataDir + u"Transformations_outPS.ps", System::IO::FileMode::Create);
7 // Clearing resources under 'using' statement
8 System::Details::DisposeGuard<1> __dispose_guard_0({ outPsStream});
9 // ------------------------------------------
10
11 try
12 {
13 //Create save options with default values
14 System::SharedPtr<PsSaveOptions> options = System::MakeObject<PsSaveOptions>();
15
16 // Create new 1-paged PS Document
17 System::SharedPtr<PsDocument> document = System::MakeObject<PsDocument>(outPsStream, options, false);
18
19 document->Translate(100.0f, 100.0f);
20
21 //Create graphics path from the rectangle
22 System::SharedPtr<System::Drawing::Drawing2D::GraphicsPath> path = System::MakeObject<System::Drawing::Drawing2D::GraphicsPath>();
23 path->AddRectangle(System::Drawing::RectangleF(0.0f, 0.0f, 150.0f, 100.0f));
ここでは、上位レベルのグラフィックス状態の現在のペイントとしてオレンジ色を設定し、この四角形を塗りつぶします。
結果として得られるPSファイルは、上位レベルのグラフィックス状態にあり、変換されていない最初の図形を示します。
1 ////////////////////////////////////// No transformations ///////////////////////////////////////////////////////////////
2 //Set paint in graphics state on upper level
3 document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Orange()));
4
5 //Fill the first rectangle that is on on upper level graphics state and that is without any transformations.
6 document->Fill(path);
7 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ここで、上位レベルのグラフィックス状態を基準にX軸で250ポイント移動する新しいグラフィックス状態を作成し、この新しいグラフィックス状態に青で塗りつぶされた同じ長方形パスを追加します。最後に、上位レベルのグラフィックス状態上で現在のグラフィックス状態から抜け出します。
1 ////////////////////////////////////// Translation //////////////////////////////////////////////////////////////////////
2
3 //Save graphics state in order to return back to this state after transformation
4 document->WriteGraphicsSave();
5
6 //Displace current graphics state on 250 to the right. So we add translation component to the current transformation.
7 document->Translate(250.0f, 0.0f);
8
9 //Set paint in the current graphics state
10 document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Blue()));
11
12 //Fill the second rectangle in the current graphics state (has translation transformation)
13 document->Fill(path);
14
15 //Restore graphics state to the previus (upper) level
16 document->WriteGraphicsRestore();
17 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
次の四角形を配置するために、上位レベルのグラフィックス状態を変換します。
1 //Displace on 200 to the bottom.
2 document->Translate(0.0f, 200.0f);
ここでは、X軸で0.5、Y軸で0.75にスケーリングされるグラフィックス状態を作成し、この新しいグラフィックス状態に赤色で塗りつぶされた同じ長方形パスを追加します。
最後に、上位レベルのグラフィックス状態で現在のグラフィックス状態を終了します。
1 ////////////////////////////////////// Scaling //////////////////////////////////////////////////////////////////////////
2 //Save graphics state in order to return back to this state after transformation
3 document->WriteGraphicsSave();
4
5 //Scale current graphics state on 0.5 in X axis and on 0.75f in Y axis. So we add scale component to the current transformation.
6 document->Scale(0.5f, 0.75f);
7
8 //Set paint in the current graphics state
9 document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Red()));
10
11 //Fill the third rectangle in the current graphics state (has scale transformation)
12 document->Fill(path);
13
14 //Restore graphics state to the previus (upper) level
15 document->WriteGraphicsRestore();
16 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
次の四角形を配置するために、上位レベルのグラフィックス状態を変換します。
1 //Displace upper level graphics state on 250 to the right.
2 document->Translate(250.0f, 0.0f);
次に、上位レベルのグラフィックス状態に対して時計回りに45度回転した新しいグラフィックス状態を作成し、この新しいグラフィックス状態に緑で塗りつぶされた同じ長方形パスを追加します。最後に、上位レベルのグラフィックス状態上で現在のグラフィックス状態を終了します。
1 ////////////////////////////////////// Rotation //////////////////////////////////////////////////////////////////////
2 //Save graphics state in order to return back to this state after transformation
3 document->WriteGraphicsSave();
4
5 //Rotate current graphics state on 45 degrees around origin of current graphics state (350, 300). So we add rotation component to the current transformation.
6 document->Rotate(45);
7
8 //Set paint in the current graphics state
9 document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Green()));
10
11 //Fill the fourth rectangle in the current graphics state (has rotation transformation)
12 document->Fill(path);
13
14 //Restore graphics state to the previus (upper) level
15 document->WriteGraphicsRestore();
16 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
次の四角形をページ上の空白スペースに配置するために、上位レベルのグラフィックス状態を変換します。
1 //Returns upper level graphics state back to the left and displace on 200 to the bottom.
2 document->Translate(-250.0f, 200.0f);
次に、せん断される新しいグラフィック状態を作成し、この新しいグラフィック状態に、ピンク 色で塗りつぶされた同じ長方形パスを追加します。
最後に、上位レベルのグラフィック状態で現在のグラフィック状態を終了します。
1 ////////////////////////////////////// Shearing //////////////////////////////////////////////////////////////////////
2 //Save graphics state in order to return back to this state after transformation
3 document->WriteGraphicsSave();
4
5 //Shear current graphics state. So we add shear component to the current transformation.
6 document->Shear(0.1f, 0.2f);
7
8 //Set paint in the current graphics state
9 document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Pink()));
10
11 //Fill the fifth rectangle in the current graphics state (has shear transformation)
12 document->Fill(path);
13
14 //Restore graphics state to the previus (upper) level
15 document->WriteGraphicsRestore();
16 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
次の四角形をページ上の空白スペースに配置するために、上位レベルのグラフィックス状態を変換します。
1 //Displace upper level graphics state on 250 to the right.
2 document->Translate(250.0f, 0.0f);
ここで、移動、拡大縮小、回転といった複雑な変換処理が行われる最後のグラフィックス状態を作成し、この新しいグラフィックス状態に、アクアマリン 色で塗りつぶされた同じ長方形パスを追加します。
最後に、上位レベルのグラフィックス状態において、現在のグラフィックス状態から抜け出します。
1 ////////////////////////////////////// Complex transformation ////////////////////////////////////////////////////////
2 //Save graphics state in order to return back to this state after transformation
3 document->WriteGraphicsSave();
4
5 //Transform current graphics state with complex transformation. So we add translation, scale and rotation components to the current transformation.
6 document->Transform(System::MakeObject<System::Drawing::Drawing2D::Matrix>(1.2f, -0.965925f, 0.258819f, 1.5f, 0.f, 50.0f));
7
8 //Set paint in the current graphics state
9 document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Aquamarine()));
10
11 //Fill the sixth rectangle in the current graphics state (has complex transformation)
12 document->Fill(path);
13
14 //Restore graphics state to the previus (upper) level
15 document->WriteGraphicsRestore();
16 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
最後の四角形をページ上の空白スペースに配置するために、上位レベルのグラフィックス状態を変換します。
1 //Returns upper level graphics state back to the left and displace on 200 to the bottom.
2 document->Translate(-250.0f, 200.0f);
最後に上位レベルのグラフィックス状態に再配置した塗りつぶされた四角形は、下位レベルのグラフィックス状態の変換や色の変更を受けていないことを示しています。
オレンジ色は現在のペイントのままです。
1 ////////////////////////////////////// Again no transformation ////////////////////////////////////////////////////////
2 // Demonstrates that current graphics state's color is orange that was set up at the beginning of the code.
3 //Fill the seventh rectangle in the current graphics state (has no transformation)
4 document->Fill(path);
5 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
最後に現在のページを閉じてドキュメントを保存します。
1 //Close current page
2 document->ClosePage();
3
4 //Save the document
5 document->Save();
6 }
7 catch(...)
8 {
9 __dispose_guard_0.SetCurrentException(std::current_exception());
10 }
11 }
このコードを実行すると次のようになります
サンプルとデータ ファイルは GitHub からダウンロードできます。