Trabalhar com Transformações em PostScript | C++

Transformar um conteúdo num Documento PS

Neste artigo, veremos como realizar diferentes transformações: translação, dimensionamento, rotação e cisalhamento num percurso retangular adicionado ao PsDocument.

Dividimos um trecho de código em vários trechos: o início, o fim e cada transformação em separado. Uma transformação em PostScript é sempre realizada num estado gráfico ligado aos operadores “gsave” e “grestore”. Assim, no nosso PsDocument, existem os métodos “WriteGraphicsSave()” e “WriteGraphicsRestore()”. Entre estes métodos, podemos adicionar qualquer conteúdo, incluindo estados gráficos aninhados, e realizar quaisquer transformações ou recortes. Estas transformações não afetarão os estados gráficos externos, mas afetarão os estados gráficos aninhados.

Se realizarmos uma transformação sem os métodos “WriteGraphicsSave()” e “WriteGraphicsRestore()”, esta será feita no estado gráfico do nível superior e todo o conteúdo presente no PsDocument será submetido a esta transformação.

Um algoritmo para definir qualquer transformação no conteúdo de um documento a partir do zero inclui os seguintes passos:

  1. Criar um fluxo de saída para o ficheiro PS resultante.
  2. Criar PsSaveOptions.
  3. Criar PsDocument com o fluxo de saída já criado e guardar as opções.
  4. Guardar um estado gráfico. Assim, criámos um novo estado gráfico e o estado gráfico anterior foi colocado numa pilha de estados gráficos.
  5. Adicione a transformação necessária: translação, escala, rotação, cisalhamento ou qualquer combinação das mesmas. No nosso código, mostramos a influência de cada componente da transformação em separado e, no final, 3 componentes de cada vez.
  6. Adicione o conteúdo necessário para a transformação. No nosso caso, criamos um retângulo GraphicsPath a partir do retângulo e preenchemo-lo. Criamos um retângulo antes de qualquer transformação e preenchemo-lo após cada transformação no estado gráfico atual.
  7. Restauramos o estado gráfico para voltar ao estado anterior, onde a(s) transformação(ões) aplicada(s) não afeta(m). No nosso caso, trata-se de um estado gráfico de nível superior.

Neste trecho de código, criamos o PsDocument a partir de um fluxo de saída e o PsSaveOptions, transladamos o estado gráfico de nível superior para os pontos 100 e 100 para deslocar o primeiro retângulo e, por fim, criamos o primeiro retângulo GraphicsPath a partir do retângulo.

 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));

Aqui, definimos a cor Laranja como a tinta atual para o estado gráfico de nível superior e preenchemos este retângulo.

O ficheiro PS resultante demonstrará a primeira forma localizada no estado gráfico de nível superior e que não sofreu qualquer transformação.

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            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Agora, criamos um novo estado gráfico que será transladado em 250 pontos pelo eixo X em relação ao estado gráfico de nível superior e adicionamos a este novo estado gráfico o mesmo caminho retangular pintado com a cor Azul. No final, saímos do estado gráfico atual no estado gráfico de nível superior.

 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            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Traduza o estado dos gráficos de nível superior para colocar os retângulos seguintes.

1            //Displace on 200 to the bottom.
2            document->Translate(0.0f, 200.0f);

Aqui, criamos um estado gráfico que será dimensionado em 0,5 no eixo X e 0,75 no eixo Y e adicionamos a estes novos estados gráficos o mesmo percurso retangular pintado com a cor Vermelho. No final, saímos do estado gráfico atual para o estado gráfico de nível superior.

 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            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Traduza o estado gráfico de nível superior para colocar os retângulos seguintes.

1            //Displace upper level graphics state on 250 to the right.
2            document->Translate(250.0f, 0.0f);

De seguida, criamos um novo estado gráfico que será rodado 45 graus no sentido dos ponteiros do relógio em relação ao estado gráfico de nível superior e adicionamos a este novo estado gráfico o mesmo caminho retangular pintado com a cor Verde. No final, saímos do estado gráfico atual no estado gráfico de nível superior.

 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            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Traduza o estado gráfico de nível superior para colocar os retângulos seguintes no espaço em branco da página.

1            //Returns upper level graphics state back to the left and displace on 200 to the bottom.
2            document->Translate(-250.0f, 200.0f);

De seguida, criamos um novo estado gráfico que será distorcido e adicionamos a este novo estado gráfico o mesmo caminho retangular pintado com a cor Rosa. No final, saímos do estado gráfico atual no estado gráfico de nível superior.

 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            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Traduza o estado gráfico de nível superior para colocar os retângulos seguintes no espaço em branco da página.

1            //Displace upper level graphics state on 250 to the right.
2            document->Translate(250.0f, 0.0f);

Agora, criamos o último estado gráfico que irá sofrer uma transformação complexa, contendo componentes de translação, escala e rotação, e adicionamos a este novo estado gráfico o mesmo caminho retangular pintado com a cor Aquamarine. No final, saímos do estado gráfico atual para o estado gráfico de nível superior.

 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            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Traduza o estado gráfico de nível superior para colocar o último retângulo no espaço em branco da página.

1            //Returns upper level graphics state back to the left and displace on 200 to the bottom.
2            document->Translate(-250.0f, 200.0f);

O último retângulo preenchido que colocámos novamente no estado gráfico de nível superior mostra que não sofreu transformações nos estados gráficos do nível inferior nem alterações de cor. A cor laranja é a tinta atual restante.

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            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Por fim, fechamos a página atual e guardamos o documento.

 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    }

Veja como trabalhar com transformações no documento PS em .NET ou Java.


O resultado da execução deste código é o seguinte:

Transformações

Pode descarregar exemplos e ficheiros de dados do GitHub.

Have any questions about Aspose.Page?



Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.