Work with graphics states in PS

Clip and transform graphics states of PS files using the C++ API

 

In PostScript, a graphic state is a collection of attributes that define how graphics are drawn on a page and allow you to create complex and varied graphics with a single set of commands. By saving and restoring graphic states, you can avoid redundant operations. You can also define reusable graphic styles and apply them to different document parts. Graphic state includes settings such as:

  • The thickness of lines (line width).
  • The shape of the ends of lines (round, square, or butt).
  • The shape of the junctions between lines (miter, round, or bevel).
  • The color of lines and fills (RGB, CMYK, or grayscale).
  • The font used for text and its size.
  • The matrix used to transform coordinates (scaling, rotation, translation).

Managing graphics states in PS documents (equivalent of canvases in XPS) is one of the main features offered by Aspose.Page for C++.

To transform graphics states of a PS file follow the next guide:

  1. Create a PS file using the PsDocument Class .
  2. Create a rectangle graphics path.
  3. Save the current graphics state, create a new graphics state and set it as current with the WriteGraphicsSave() Method.
  4. Translate the current graphics state using the Translate() Method.
  5. Set the paint in the current graphics state with the SetPaint() Method.
  6. Fill the graphics path by means of the Fill() method.
  7. Restore the previous graphics state with the WriteGraphicsRestore Method.
  8. Repeat steps 3-7 for adding more graphics states with other transformations using Scale() , Rotate() , Shear() and Transform() Methods.
  9. Close the current page by means of the ClosePage() method.
  10. Save the created PS document using the PsDocument.Save() Method.
Transform graphics states of a PS
    // The path to the documents directory.
    System::String dataDir = RunExamples::GetDataDir_WorkingWithCanvas();
    
    //Create output stream for PostScript document
    {
        System::SharedPtr<System::IO::Stream> outPsStream = System::MakeObject<System::IO::FileStream>(dataDir + u"output/" + u"Transformations_outPS.ps", System::IO::FileMode::Create);
        // Clearing resources under 'using' statement
        System::Details::DisposeGuard<1> __dispose_guard_0({ outPsStream});
        // ------------------------------------------
        
        try
        {
            //Create save options with default values
            System::SharedPtr<PsSaveOptions> options = System::MakeObject<PsSaveOptions>();
            
            // Create new 1-paged PS Document
            System::SharedPtr<PsDocument> document = System::MakeObject<PsDocument>(outPsStream, options, false);
            
            document->Translate(100.0f, 100.0f);
            
            //Create graphics path from the rectangle
            System::SharedPtr<System::Drawing::Drawing2D::GraphicsPath> path = System::MakeObject<System::Drawing::Drawing2D::GraphicsPath>();
            path->AddRectangle(System::Drawing::RectangleF(0.0f, 0.0f, 150.0f, 100.0f));
            
            ////////////////////////////////////// No transformations ///////////////////////////////////////////////////////////////
            //Set paint in graphics state on upper level
            document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Orange()));
            
            //Fill the first rectangle that is on on upper level graphics state and that is without any transformations.
            document->Fill(path);
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            
            
            ////////////////////////////////////// Translation //////////////////////////////////////////////////////////////////////
            
            //Save graphics state in order to return back to this state after transformation
            document->WriteGraphicsSave();
            
            //Displace current graphics state on 250 to the right. So we add translation component to the current transformation.
            document->Translate(250.0f, 0.0f);
            
            //Set paint in the current graphics state
            document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Blue()));
            
            //Fill the second rectangle in the current graphics state (has translation transformation)
            document->Fill(path);
            
            //Restore graphics state to the previus (upper) level
            document->WriteGraphicsRestore();
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            
            //Displace on 200 to the bottom.
            document->Translate(0.0f, 200.0f);
            
            ////////////////////////////////////// Scaling //////////////////////////////////////////////////////////////////////////
            //Save graphics state in order to return back to this state after transformation
            document->WriteGraphicsSave();
            
            //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.
            document->Scale(0.5f, 0.75f);
            
            //Set paint in the current graphics state
            document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Red()));
            
            //Fill the third rectangle in the current graphics state (has scale transformation)
            document->Fill(path);
            
            //Restore graphics state to the previus (upper) level
            document->WriteGraphicsRestore();
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            
            //Displace upper level graphics state on 250 to the right.
            document->Translate(250.0f, 0.0f);
            
            
            ////////////////////////////////////// Rotation //////////////////////////////////////////////////////////////////////
            //Save graphics state in order to return back to this state after transformation
            document->WriteGraphicsSave();
            
            //Rotate current graphics state on 45 degrees around origin of current graphics state (350, 300). So we add rotation component to the current transformation.
            document->Rotate(45);
            
            //Set paint in the current graphics state
            document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Green()));
            
            //Fill the fourth rectangle in the current graphics state (has rotation transformation)
            document->Fill(path);
            
            //Restore graphics state to the previus (upper) level
            document->WriteGraphicsRestore();
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            
            //Returns upper level graphics state back to the left and displace on 200 to the bottom.
            document->Translate(-250.0f, 200.0f);
            
            
            ////////////////////////////////////// Shearing //////////////////////////////////////////////////////////////////////
            //Save graphics state in order to return back to this state after transformation
            document->WriteGraphicsSave();
            
            //Shear current graphics state. So we add shear component to the current transformation.
            document->Shear(0.1f, 0.2f);
            
            //Set paint in the current graphics state
            document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Pink()));
            
            //Fill the fifth rectangle in the current graphics state (has shear transformation)
            document->Fill(path);
            
            //Restore graphics state to the previus (upper) level
            document->WriteGraphicsRestore();
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            
            //Displace upper level graphics state on 250 to the right.
            document->Translate(250.0f, 0.0f);
            
            
            ////////////////////////////////////// Complex transformation ////////////////////////////////////////////////////////
            //Save graphics state in order to return back to this state after transformation
            document->WriteGraphicsSave();
            
            //Transform current graphics state with complex transformation. So we add translation, scale and rotation components to the current transformation.
            document->Transform(System::MakeObject<System::Drawing::Drawing2D::Matrix>(1.2f, -0.965925f, 0.258819f, 1.5f, 0.f, 50.0f));
            
            //Set paint in the current graphics state
            document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Aquamarine()));
            
            //Fill the sixth rectangle in the current graphics state (has complex transformation)
            document->Fill(path);
            
            //Restore graphics state to the previus (upper) level
            document->WriteGraphicsRestore();
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            
            //Returns upper level graphics state back to the left and displace on 200 to the bottom.
            document->Translate(-250.0f, 200.0f);
            
            
            ////////////////////////////////////// Again no transformation ////////////////////////////////////////////////////////
            // Demonstrates that current graphics state's color is orange that was set up at the beginning of the code. 
            //Fill the seventh rectangle in the current graphics state (has no transformation)
            document->Fill(path);
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            //Close current page
            document->ClosePage();
            
            //Save the document
            document->Save();
        }
        catch(...)
        {
            __dispose_guard_0.SetCurrentException(std::current_exception());
        }
    }

To add Clips to the graphics state of a PS file follow the next guide:

  1. Create a PS file using the PsDocument Class .
  2. Create a rectangle graphics path.
  3. Save the current graphics state, create a new graphics stateand and set it as current with the WriteGraphicsSave() Method.
  4. Translate the current graphics state using the Translate() Method.
  5. Create a circle graphics path.
  6. Add clipping by circle to the current graphics state using the Clip() Method.
  7. Set the paint in the current graphics state with the SetPaint() Method.
  8. Fill the rectangle graphics path by means of the Fill() Method.
  9. Restore the previous graphics state with WriteGraphicsRestore() Method.
  10. Translate the current graphics state using the Translate() Method.
  11. Create a System.Drawing.Pen object.
  12. Set a stroke in the current graphics state with the SetStroke() Method.
  13. Draw the rectangle graphics path above the clipped rectangle by means of the Draw() Method.
  14. Close the current page by means of the ClosePage() Method.
  15. Save the created PS document using the PsDocument.Save() Method.
Add Clip to graphics state of a PS
    // The path to the documents directory.
    System::String dataDir = RunExamples::GetDataDir_WorkingWithCanvas();
    
    //Create output stream for PostScript document
    {
        System::SharedPtr<System::IO::Stream> outPsStream = System::MakeObject<System::IO::FileStream>(dataDir + u"output/" + u"Clipping_outPS.ps", System::IO::FileMode::Create);
        // Clearing resources under 'using' statement
        System::Details::DisposeGuard<1> __dispose_guard_0({ outPsStream});
        // ------------------------------------------
        
        try
        {
            //Create save options with default values
            System::SharedPtr<PsSaveOptions> options = System::MakeObject<PsSaveOptions>();
            
            // Create new 1-paged PS Document
            System::SharedPtr<PsDocument> document = System::MakeObject<PsDocument>(outPsStream, options, false);
            
            //Create graphics path from the rectangle
            System::SharedPtr<System::Drawing::Drawing2D::GraphicsPath> rectanglePath = System::MakeObject<System::Drawing::Drawing2D::GraphicsPath>();
            rectanglePath->AddRectangle(System::Drawing::RectangleF(0.0f, 0.0f, 300.0f, 200.0f));
            
            ////////////////////////////////////// Clipping by shape //////////////////////////////////////////////////////////////////////
            
            //Save graphics state in order to return back to this state after transformation
            document->WriteGraphicsSave();
            
            //Displace current graphics state on 100 points to the right and 100 points to the bottom.
            document->Translate(100.0f, 100.0f);
            
            //Create graphics path from the circle
            System::SharedPtr<System::Drawing::Drawing2D::GraphicsPath> circlePath = System::MakeObject<System::Drawing::Drawing2D::GraphicsPath>();
            circlePath->AddEllipse(System::Drawing::RectangleF(50.0f, 0.0f, 200.0f, 200.0f));
            
            //Add clipping by circle to the current graphics state
            document->Clip(circlePath);
            
            //Set paint in the current graphics state
            document->SetPaint(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Blue()));
            
            //Fill the rectangle in the current graphics state (with clipping)
            document->Fill(rectanglePath);
            
            //Restore graphics state to the previus (upper) level
            document->WriteGraphicsRestore();
            
            //Displace upper level graphics state on 100 points to the right and 100 points to the bottom.
            document->Translate(100.0f, 100.0f);
            
            System::SharedPtr<System::Drawing::Pen> pen = System::MakeObject<System::Drawing::Pen>(System::MakeObject<System::Drawing::SolidBrush>(System::Drawing::Color::get_Blue()), 2.0f);
            pen->set_DashStyle(System::Drawing::Drawing2D::DashStyle::Dash);
            
            document->SetStroke(pen);
            
            //Draw the rectangle in the current graphics state (has no clipping) above clipped rectangle
            document->Draw(rectanglePath);
            
            ////////////////////////////////////// Clipping by text //////////////////////////////////////////////////////////////////////
            
            //Save graphics state in order to return back to this state after transformation
            document->WriteGraphicsSave();
            
            //Displace current graphics state on 100 points to the right and 100 points to the bottom.
            document->Translate(0.0f, 350.0f);
            
            int32_t fontSize = 120;
            System::SharedPtr<System::Drawing::Font> font = System::MakeObject<System::Drawing::Font>(u"Arial", static_cast<float>(fontSize), System::Drawing::FontStyle::Bold);
            
            //Clip rectangle by text's outline
            document->ClipText(u"ABC", font, 20.0f, static_cast<float>(fontSize + 10));
            document->Fill(rectanglePath);
            
            document->WriteGraphicsRestore();
            
            document->Translate(0.0f, 350.0f);
            
            document->SetStroke(pen);
            //Draw the rectangle in the current graphics state (has no clipping) above clipped rectangle
            document->Draw(rectanglePath);
            
            //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            
            //Close current page
            document->ClosePage();
            
            //Save the document
            document->Save();
        }
        catch(...)
        {
            __dispose_guard_0.SetCurrentException(std::current_exception());
        }
    }

PS What is PS File Format

PS (PostScript) is a powerful page‑description language that combines text and graphics in a device‑independent way. It is widely supported by printers and professional image editors. PS files contain the rendering instructions for the page and can be converted to PDF, EPS, or raster formats.