Работа с преобразованиями в PostScript | С++
Преобразование содержимого в PS Document
В этой статье мы рассмотрим, как выполнять различные преобразования: перемещение, масштабирование, вращение и сдвиг прямоугольного контура, добавленного в PsDocument.
Мы разбиваем один фрагмент кода на несколько частей кода: начало, конец и каждое преобразование отдельно. Преобразование в PostScript всегда выполняется в графическом состоянии, которое связано операторами “gsave” и “grestore”. Поэтому в нашем PsDocument есть методы “WriteGraphicsSave()” и “WriteGraphicsRestore()”. Между этими методами мы можем добавлять любой контент, включая вложенное графическое состояние, а также выполнять любые преобразования или обрезку. Эти преобразования не повлияют на внешние графические состояния, но повлияют на вложенные.
Если мы выполним преобразование без методов “WriteGraphicsSave()” и “WriteGraphicsRestore()”, мы сделаем его в графическом состоянии верхнего уровня, и весь контент, находящийся в PsDocument, будет подвергнут этому преобразованию. .
Алгоритм настройки любого преобразования содержимого документа с нуля включает следующие шаги:
- Создайте выходной поток для полученного PS-файла.
- Создайте PsSaveOptions.
- Создайте PsDocument с уже созданным выходным потоком и сохраните параметры.
- Сохраните состояние графики. Итак, мы создали новое графическое состояние, предыдущее графическое состояние было помещено в стек графических состояний.
- Добавьте необходимые преобразования: перемещение, масштабирование, вращение, сдвиг или любую их комбинацию. В нашем коде мы показываем влияние каждого компонента трансформации отдельно и в итоге по 3 одновременно.
- Добавьте необходимый контент, который требуется трансформировать. В нашем случае мы создали прямоугольник GraphicsPath на основе прямоугольника, а затем заполнили его. Мы создали один прямоугольник перед любыми преобразованиями и просто заполняли его после каждого преобразования в текущем графическом состоянии.
- Восстановите состояние графики, чтобы вернуться к предыдущему состоянию, на которое не влияют примененные преобразования. В нашем случае это состояние графики верхнего уровня.
В этом фрагменте кода мы создаем PsDocument из выходного потока и PsSaveOptions, преобразуем состояние графики верхнего уровня в точки 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 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Теперь мы создаем новое графическое состояние, которое будет перенесено на 250 точек по оси X относительно графического состояния верхнего уровня, и добавляем к этому новому графическому состоянию тот же прямоугольный путь, окрашенный синим цветом. В конце концов мы выходим из текущего состояния графики в состояние графики верхнего уровня.
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);
Здесь мы создаем графическое состояние, которое будет масштабироваться на 0,5 по оси X и 0,75 по оси Y, и добавляем к этому новому графическому состоянию тот же прямоугольный путь, окрашенный красным цветом. В конце концов мы выходим из текущего состояния графики в состояние графики верхнего уровня.
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.