Working with Transformations in PS file | Python

Transform a content in PS Document

This article explores how to apply various transformations-translation, scaling, rotation, and shearing to a rectangle path added to a PsDocument.

We’ve broken down a single code snippet into multiple sections: the beginning, the end, and each transformation individually. In PostScript, transformations are always performed within a graphics state delimited by the “gsave” and “grestore” operators. Therefore, our PsDocument includes methods such as “write_graphics_save()” and “write_graphics_restore()” to establish and reset these graphics states. Between these methods, any content, including nested graphics states, can be added, allowing for transformations or clipping. These transformations affect only the nested graphics states and do not impact the outer ones. However, if a transformation is performed without using “write_graphics_save()” and “write_graphics_restore()” methods, it affects the graphics state of the upper level, and all content within the PsDocument is subjected to this transformation.

The algorithm for applying any transformation to a document’s content from scratch involves the following steps:

  1. Create an output stream for the resulting PS file.
  2. Create PsSaveOptions.
  3. Create PsDocument with the already created output stream and save options.
  4. Save a graphics state. As we created a new graphics state, the previous graphics state was put in a graphics states stack.
  5. Apply necessary transformations: translation, scale, rotation, shear, or any combination of it. In our code, we show the influence of every transformation component separately and 3 ones at a time in the end.
  6. Add necessary content that is required to transform. In our case, we created a reactangle aspose.pydrawing.GraphicsPath and then fill it. We created one rectangle before any transformations and just fill it after every transformation in the current graphics state.
  7. Restore the graphics state to return back to the previous one where applied transformation(s) doesn’t affect. In our case, it is an upper-level graphics state.

In this code snippet, we initiate the creation of a PsDocument using an output stream and PsSaveOptions. We then perform a translation of the upper-level graphics state to the coordinates (100, 100) to offset the first rectangle. Finally, we generate the first rectangle.

  1data_dir = Util.get_data_dir_working_with_canvas()
  2
  3# Create an output stream for the PostScript document
  4with open(data_dir + "Transformations_outPS.ps", "wb") as out_ps_stream:
  5    # Create save options with default values
  6    options = PsSaveOptions()
  7    
  8    # Create a new 1-paged PS Document
  9    document = PsDocument(out_ps_stream, options, False)
 10    
 11    document.translate(100, 100)
 12    
 13    # Create a graphics path from the rectangle
 14    path = aspose.pydrawing.drawing2d.GraphicsPath()
 15    path.add_rectangle(aspose.pydrawing.RectangleF(0, 0, 150, 100))
 16    
 17    ##################################### No transformations ###############################################################
 18    # Set the paint in the graphics state on upper level
 19    document.set_paint(aspose.pydrawing.SolidBrush(aspose.pydrawing.Color.orange))
 20    
 21    # Fill the first rectangle that is on the upper level graphics state and is without any transformations.
 22    document.fill(path)
 23    ########################################################################################################################
 24    
 25    
 26    
 27    ##################################### Translation ######################################################################
 28    
 29    # Save the graphics state in order to return back to this state after the transformation
 30    document.write_graphics_save()
 31    
 32    # Displace the current graphics state on 250 to the right. So we add a translation component to the current transformation.
 33    document.translate(250., 0.)
 34    
 35    # Set the paint in the current graphics state
 36    document.set_paint(aspose.pydrawing.SolidBrush(aspose.pydrawing.Color.blue))
 37    
 38    # Fill the second rectangle in the current graphics state (has translation transformation)
 39    document.fill(path)
 40    
 41    # Restore the graphics state to the previus (upper) level
 42    document.write_graphics_restore()
 43    ########################################################################################################################
 44    
 45    
 46    # Displace on 200 to the bottom.
 47    document.translate(0., 200.)
 48    
 49    ##################################### Scaling ##########################################################################
 50    # Save graphics state in order to return back to this state after transformation
 51    document.write_graphics_save()
 52    
 53    # Scale the current graphics state on 0.5 in X axis and on 0.75f in Y axis. So we add a scale component to the current transformation.
 54    document.scale(0.5, 0.75)
 55    
 56    # Set the paint in the current graphics state
 57    document.set_paint(aspose.pydrawing.SolidBrush(aspose.pydrawing.Color.red))
 58    
 59    # Fill the third rectangle in the current graphics state (has scale transformation)
 60    document.fill(path)
 61    
 62    # Restore the graphics state to the previus (upper) level
 63    document.write_graphics_restore()
 64    #####################################################################################################################
 65    
 66    
 67    # Displace the upper level graphics state on 250 to the right.
 68    document.translate(250., 0.)
 69    
 70    
 71    ##################################### Rotation ######################################################################
 72    #Save graphics state in order to return back to this state after transformation
 73    document.write_graphics_save()
 74    
 75    # Rotate the current graphics state on 45 degrees around the origin of the current graphics state (350, 300). So we add a rotation component to the current transformation.
 76    document.rotate(float(45))
 77    
 78    # Set the paint in the current graphics state
 79    document.set_paint(aspose.pydrawing.SolidBrush(aspose.pydrawing.Color.green))
 80    
 81    # Fill the fourth rectangle in the current graphics state (has rotation transformation)
 82    document.fill(path)
 83    
 84    # Restore the graphics state to the previus (upper) level
 85    document.write_graphics_restore()
 86    #####################################################################################################################
 87    
 88    
 89    # Returns the upper level graphics state back to the left and displace on 200 to the bottom.
 90    document.translate(-250., 200.)
 91    
 92    
 93    ##################################### Shearing ######################################################################
 94    # Save the graphics state in order to return back to this state after the transformation
 95    document.write_graphics_save()
 96    
 97    # Shear the current graphics state. So we add shear component to the current transformation.
 98    document.shear(0.1, 0.2)
 99    
100    # Set the paint in the current graphics state
101    document.set_paint(aspose.pydrawing.SolidBrush(aspose.pydrawing.Color.pink))
102    
103    # Fill the fifth rectangle in the current graphics state (has shear transformation)
104    document.fill(path)
105    
106    # Restore the graphics state to the previus (upper) level
107    document.write_graphics_restore()
108    #####################################################################################################################
109    
110    
111    # Displace the upper level graphics state on 250 to the right.
112    document.translate(250., 0.)
113    
114    
115    ##################################### Complex transformation ########################################################
116    # Save the graphics state in order to return back to this state after the transformation
117    document.write_graphics_save()
118    
119    # Transform the current graphics state with the complex transformation. So we add the translation, scale and rotation components to the current transformation.
120    document.transform(aspose.pydrawing.drawing2d.Matrix(1.2, -0.965925, 0.258819, 1.5, 0., 50.))
121    
122    # Set the paint in the current graphics state
123    document.set_paint(aspose.pydrawing.SolidBrush(aspose.pydrawing.Color.aquamarine))
124    
125    # Fill the sixth rectangle in the current graphics state (has complex transformation)
126    document.fill(path)
127    
128    # Restore graphics state to the previus (upper) level
129    document.write_graphics_restore()
130    #####################################################################################################################
131    
132    
133    # Returns the upper level graphics state back to the left and displace on 200 to the bottom.
134    document.translate(-250., 200.)
135    
136    
137    ##################################### Again no transformation ########################################################
138    # Demonstrates that current graphics state's color is orange that was set up at the beginning of the code. 
139    # Fill the seventh rectangle in the current graphics state (has no transformation)
140    document.fill(path)
141    #####################################################################################################################
142    
143    # Close the current page
144    document.close_page()
145    
146    # Save the document
147    document.save()

See working with transformations in PS document in .NET, Java.

The result of running this code is

Add Transformations

You can download examples and data files from GitHub.

Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.