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:
- Create an output stream for the resulting PS file.
- Create PsSaveOptions.
- Create PsDocument with the already created output stream and save options.
- Save a graphics state. As we created a new graphics state, the previous graphics state was put in a graphics states stack.
- 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.
- 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.
- 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()
The result of running this code is
You can download examples and data files from GitHub.