When using CGContext, because the coordinates of Quartz 2D and UIKit are inconsistent, the context needs to be changed again to achieve the desired effect.

In Quartz 2D, the origin of coordinates is in the lower left corner of the canvas, while in UIKit, it is consistent with the screen coordinates, and the upper left corner is the origin of coordinates.

If I draw F at (0,0), I get the following in different coordinates.

2. Transformation of Quartz 2D and UIKit coordinate system

2.1 UIImage draw

In iOS UI development, take UIImage as an example, draw an image and set the frame of the image to (0, 0, 320, 320) to get the picture on the right of the image above.

If you read the transform of the Context using the following code, you can see that the Transform is not the identity matrix.

CGRect frame = CGRectMake(0.0, 0.0, 720, 1280); UIGraphicsBeginImageContext(frame.size); CGContextRef context = UIGraphicsGetCurrentContext(); CGAffineTransform contextTransform = CGContextGetCTM(context);;

The transform setting here will make Quartz 2D coincide with the origin of UIKit coordinates, which also facilitates the drawing of controls in UIKit. You can refer to the following figure for coordinate system changes.

This is why if you call CGContextDrawImage directly on the obtained context, you get an inverted image.

But if you use the drawInRect method of UIImage, the document reads: Instance Method draw(in:) Draws the entire image in the specified rectangle, scaling it as necessary to fit. Declaration func draw(in rect: CGRect) Parameters rect The rectangle (in the coordinate system of the graphics context) in which to draw the image. Discussion This method draws the entire image in the current graphics context, Respecting the image’s orientation setting. In the default coordinate system, images are situated down and to the right of the origin of the specified rectangle. This method respects any transforms applied to the current graphics context, however. This method draws the image at full opacity using the CGBlendMode.normal blend mode.

In other words, UIImage will be drawn with the same coordinates as UIKit’s internal coordinates, so you don’t have to do anything to change the coordinate system to draw the same image as the rect position, but this method will also draw the image based on the orientation of the image.

2.2 CGContextDrawImage draw

When you change the transform of the context, what’s actually changing is the frame itself.

When we call the draw method, we’re still using the internal coordinates of the frame, so when we want to draw an image that looks like UIKit based on the context that we got, we have to adjust the frame before we draw it.

// ContextScalectm (context, 1, -1); // ContextScalectm (context, 1, -1);

CGContextTranslateCTM(Context, 0, -imagesize.height); CGContextTranslateCTM(context, 0, -imagesize.height);

// Draw the pictureCGContextDrawImage(context, frame, image.CGImage);

3 Transform anchor point change

For example, in the image editing page, we often encounter the use of gestures to scale, rotate, and shift the image, and then generate a new image.

Depending on the gesture callback, we can modify view.transform so that the view on the interface changes in response to the gesture.

In this case, UIKit to make it easier for us to modify the UI, the transform of the view is anchored at the center of the view.

The UIView transform describes changing position using center.

Use this property to scale or rotate the view’s frame rectangle within its superview’s coordinate system. (To change the position of the view, modify the center property instead.) The default value of this property is CGAffineTransformIdentity.

For many other methods, the transform needs to be anchored at the top left corner, so there is a need for a transformation. The impact of the anchor point is shown below.In the UI modification, we can directly modify the Transform of the View using the callback values of the zoom and rotation gestures, and modify the center using the callback values of the displacement, so that we can achieve the desired effect. But this transform cannot be used to draw the context, because the coordinate system changes are anchored at the origin.

So for the position of the context in the existing coordinate system, where the anchor point is in the upper left corner, you need to change the transform once.

It can also be seen from the figure above that the anchor point only affects the position information and does not change the scaling and rotation.

UIImage *image; // Initialize the image

UIView *view; // Apply the changed view. The size of the view must be the same as the size of the image to ensure that the scale is correct.

CGAffineTransform transform = view.transform; CGSize imageSize = image.size; transform.tx = view.center.x; transform.ty = view.center.y; The transform = CGAffineTransformTranslate (transform, – imageSize. Width * 0.5, – imageSize. Height * 0.5);

Where tx and ty are the positions of the anchor points in the coordinate system

The current anchor point is in the center of the view, and we need to change it to the top left corner of the view so that it coincides with the origin of the frame. Where * (imagesize.width * 0.5, imagesize.height * 0.5) * is the position of anchor in the image, and transform is the change matrix when anchor is in the upper left corner of the view.

4. The Transform

To get the result in the middle of the figure above on CGContext, not only do you need to apply the changes of shrinking by 1/2 and rotating by 45 degrees, but you also need to adjust.

I said before that the ROTATION of the CGContext application is applied to the frame, in the same way that the view application rotation is applied to its own frame. Therefore, when the directly obtained CGContext and the optimized coordinate system is also the origin at the upper left corner, we can directly apply the calculated transform to the CGContext.

After that, because the drawing of the coordinate system is calculated in its own coordinate system, another rotation and displacement of the coordinate system are done to get the final result, similar to the operation in the following figure.

Note here that each new change is based on the previous change, so both the view and the transform of the context are made in order. This is consistent with matrix multiplication, and the order affects the result.