Trabajar con transformaciones en PostScript | C++
Transformar un contenido en documento PS
En este artículo, consideramos cómo realizar diferentes transformaciones: traslación, escalado, rotación y corte en un trazado rectangular agregado a PsDocument.
Dividimos un fragmento de código en varias partes de código: el principio, el final y cada transformación por separado. Una transformación en PostScript se realiza siempre en un estado gráfico vinculado por los operadores “gsave” y “grestore”. Por lo tanto, en nuestro PsDocument, existen los métodos “WriteGraphicsSave()” y “WriteGraphicsRestore()”. Entre estos métodos, podemos agregar cualquier contenido, incluido el estado de los gráficos anidados, y realizar transformaciones o recortes. Estas transformaciones no afectarán los estados de los gráficos externos, pero sí afectarán los estados anidados.
Si hacemos una transformación sin los métodos “WriteGraphicsSave()” y “WriteGraphicsRestore()” la hacemos en el estado gráfico del nivel superior y todo el contenido que esté en PsDocument será sometido a esta transformación. .
Un algoritmo para establecer cualquier transformación en el contenido de un documento desde cero incluye los siguientes pasos:
- Cree una secuencia de salida para el archivo PS resultante.
- Cree PsSaveOptions.
- Cree PsDocument con el flujo de salida ya creado y las opciones de guardado.
- Guarde un estado de gráficos. Entonces creamos un nuevo estado de gráficos, el estado de gráficos anterior se colocó en una pila de estados de gráficos.
- Agregue la transformación necesaria: traslación, escala, rotación, corte o cualquier combinación de ellas. En nuestro código, mostramos la influencia de cada componente de transformación por separado y al final 3 a la vez.
- Agregue el contenido necesario que se requiere para transformar. En nuestro caso, creamos un rectángulo GraphicsPath a partir del rectángulo y luego lo rellenamos. Creamos un rectángulo antes de cualquier transformación y simplemente lo rellenamos después de cada transformación en el estado de gráficos actual.
- Restaure el estado de los gráficos para volver al estado anterior donde las transformaciones aplicadas no afectan. En nuestro caso, es un estado de gráficos de nivel superior.
En este fragmento de código, creamos PsDocument a partir de un flujo de salida y PsSaveOptions, traducimos el estado de los gráficos de nivel superior a los puntos 100,100 para compensar el primer rectángulo y, finalmente, creamos el primer rectángulo GraphicsPath a partir del rectá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));
Aquí configuramos el color Naranja como la pintura actual para el estado de los gráficos de nivel superior y rellenamos este rectángulo.
El archivo PS resultante demostrará la primera forma que se encuentra en el estado de gráficos de nivel superior y no ha sufrido ninguna transformación.
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 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Ahora creamos un nuevo estado de gráficos que se trasladará en 250 puntos por el eje X en relación con el estado de gráficos de nivel superior y agregamos a estos nuevos estados de gráficos la misma ruta rectangular pintada con color Azul. Al final, salimos del estado de gráficos actual en el estado de gráficos de nivel 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 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Traduce el estado de los gráficos de nivel superior para colocar los siguientes rectángulos.
1 //Displace on 200 to the bottom.
2 document->Translate(0.0f, 200.0f);
Aquí creamos un estado de gráficos que se escalará en 0,5 por el eje X y 0,75 por el eje Y y agregaremos a estos nuevos estados de gráficos la misma ruta del rectángulo pintada con color Rojo. Al final, salimos del estado de gráficos actual en el estado de gráficos de nivel 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 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Traduce el estado de los gráficos de nivel superior para colocar los siguientes rectángulos.
1 //Displace upper level graphics state on 250 to the right.
2 document->Translate(250.0f, 0.0f);
Luego creamos un nuevo estado de gráficos que se rotará 45 grados en el sentido de las agujas del reloj con respecto al estado de gráficos de nivel superior y agregamos a estos nuevos estados de gráficos la misma ruta rectangular pintada con color Verde. Al final, salimos del estado de gráficos actual en el estado de gráficos de nivel 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 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Traduzca el estado de los gráficos de nivel superior para colocar los siguientes rectángulos en el espacio en blanco de la 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);
Luego creamos un nuevo estado de gráficos que se cortará y agregaremos a este nuevo estado de gráficos el mismo trazado del rectángulo pintado con color Rosa. Al final, salimos del estado de gráficos actual en el estado de gráficos de nivel 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 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Traduzca el estado de los gráficos de nivel superior para colocar los siguientes rectángulos en el espacio en blanco de la página.
1 //Displace upper level graphics state on 250 to the right.
2 document->Translate(250.0f, 0.0f);
Ahora creamos el último estado gráfico que se someterá a una transformación compleja que contiene componentes de traducción, escalado y rotación y agregamos a este nuevo estado gráfico la misma ruta rectangular pintada con el color Aguamarina. Al final, salimos del estado de gráficos actual en el estado de gráficos de nivel 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 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Traduzca el estado de los gráficos de nivel superior para colocar el último rectángulo en el espacio en blanco de la 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);
El último rectángulo relleno que colocamos nuevamente en el estado de gráficos del nivel superior muestra que no sufrió transformaciones de los estados de los gráficos del nivel inferior ni cambios de colores en él. Color naranja se deja pintura actual.
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 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Finalmente cerramos la página actual y guardamos el 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 }
El resultado de ejecutar este código es el siguiente
Puede descargar ejemplos y archivos de datos desde GitHub.