简记:
CGAffineTransformMake(a,b,c,d,tx,ty)
ad缩放bc旋转tx,ty位移,基础的2D矩阵
公式
x=ax+cy+tx
y=bx+dy+ty
1.矩阵的基本知识:
struct CGAffineTransform
{
CGFloat a, b, c, d;
CGFloat tx, ty;
};
CGAffineTransform CGAffineTransformMake (CGFloat a,CGFloat b,CGFloat c,CGFloat d,CGFloat tx,CGFloat ty);
为了把二维图形的变化统一在一个坐标系里,引入了齐次坐标的概念,即把一个图形用一个三维矩阵表示,其中第三列总是(0,0,1),用来作为坐标系的标准。所以所有的变化都由前两列完成。
以上参数在矩阵中的表示为:
|a b 0|
|c d 0|
|tx ty 1|
运算原理:原坐标设为(X,Y,1);
|a b 0|
[X,Y, 1] |c d 0| = [aX + cY + tx bX + dY + ty 1] ;
|tx ty 1|
通过矩阵运算后的坐标[aX + cY + tx bX + dY + ty 1],我们对比一下可知:
第一种:设a=d=1, b=c=0.
[aX + cY + tx bX + dY + ty 1] = [X + tx Y + ty 1];
可见,这个时候,坐标是按照向量(tx,ty)进行平移,其实这也就是函数
CGAffineTransform CGAffineMakeTranslation(CGFloat tx,CGFloat ty)的计算原理。
第二种:设b=c=tx=ty=0.
[aX + cY + tx bX + dY + ty 1] = [aX dY 1];
可见,这个时候,坐标X按照a进行缩放,Y按照d进行缩放,a,d就是X,Y的比例系数,其实这也就是函数
CGAffineTransform CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)的计算原理。a对应于sx,d对应于sy。
第三种:设tx=ty=0,a=cosɵ,b=sinɵ,c=-sinɵ,d=cosɵ。
[aX + cY + tx bX + dY + ty 1] = [Xcosɵ - Ysinɵ Xsinɵ + Ycosɵ 1] ;
可见,这个时候,ɵ就是旋转的角度,逆时针为正,顺时针为负。其实这也就是函数
CGAffineTransform CGAffineTransformMakeRotation(CGFloat angle)的计算原理。angle即ɵ的弧度表示。
2.利用上面的变换写一个UIImage矩阵变换的例子:
下面是一个关于image的矩阵运算的例子,无外乎是运用以上三种变换的组合,达到所定义的效果
1 //UIImageOrientation的定义,定义了如下几种变换 2 typedef enum 3 { 4 UIImageOrientationUp, // default orientation 5 6 UIImageOrientationDown, // 180 deg rotation 7 8 UIImageOrientationLeft, // 90 deg CCW 9 10 UIImageOrientationRight, // 90 deg CW 11 12 UIImageOrientationUpMirrored, // as above but image mirrored along other axis. horizontal flip 13 14 UIImageOrientationDownMirrored, // horizontal flip 15 16 UIImageOrientationLeftMirrored, // vertical flip 17 18 UIImageOrientationRightMirrored, // vertical flip 19 20 } UIImageOrientation; 21 22 //按照UIImageOrientation的定义,利用矩阵自定义实现对应的变换; 23 24 -(UIImage *)transformImage:(UIImage *)aImage 25 26 { 27 28 CGImageRef imgRef = aImage.CGImage; 29 30 CGFloat width = CGImageGetWidth(imgRef); 31 32 CGFloat height = CGImageGetHeight(imgRef); 33 34 CGAffineTransform transform = CGAffineTransformIdentity; 35 36 CGRect bounds = CGRectMake(0, 0, width, height); 37 38 CGFloat scaleRatio = 1; 39 40 CGFloat boundHeight; 41 42 UIImageOrientation orient = aImage.imageOrientation; 43 44 switch(UIImageOrientationLeftMirrored) 45 46 { 47 48 case UIImageOrientationUp: 49 50 transform = CGAffineTransformIdentity; 51 52 break; 53 54 case UIImageOrientationUpMirrored: 55 56 transform = CGAffineTransformMakeTranslation(width, 0.0); 57 58 transform = CGAffineTransformScale(transform, -1.0, 1.0); //沿y轴向左翻 59 60 break; 61 62 case UIImageOrientationDown: 63 transform = CGAffineTransformMakeTranslation(width, height); 64 65 transform = CGAffineTransformRotate(transform, M_PI); 66 67 break; 68 69 case UIImageOrientationDownMirrored: 70 71 transform = CGAffineTransformMakeTranslation(0.0, height); 72 73 transform = CGAffineTransformScale(transform, 1.0, -1.0); 74 75 break; 76 77 case UIImageOrientationLeft: 78 79 boundHeight = bounds.size.height; 80 81 bounds.size.height = bounds.size.width; 82 83 bounds.size.width = boundHeight; 84 85 transform = CGAffineTransformMakeTranslation(0.0, width); 86 87 transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0); 88 89 break; 90 91 case UIImageOrientationLeftMirrored: 92 93 boundHeight = bounds.size.height; 94 95 bounds.size.height = bounds.size.width; 96 97 bounds.size.width = boundHeight; 98 99 transform = CGAffineTransformMakeTranslation(height, width); 100 101 transform = CGAffineTransformScale(transform, -1.0, 1.0); 102 103 transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0); 104 105 break; 106 107 case UIImageOrientationRight: //EXIF = 8 108 109 boundHeight = bounds.size.height; 110 111 bounds.size.height = bounds.size.width; 112 113 bounds.size.width = boundHeight; 114 115 transform = CGAffineTransformMakeTranslation(height, 0.0); 116 117 transform = CGAffineTransformRotate(transform, M_PI / 2.0); 118 119 break; 120 121 case UIImageOrientationRightMirrored: 122 123 boundHeight = bounds.size.height; 124 125 bounds.size.height = bounds.size.width; 126 127 bounds.size.width = boundHeight; 128 129 transform = CGAffineTransformMakeScale(-1.0, 1.0); 130 131 transform = CGAffineTransformRotate(transform, M_PI / 2.0); 132 133 break; 134 135 default: 136 137 [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"]; 138 139 } 140 141 UIGraphicsBeginImageContext(bounds.size); 142 143 CGContextRef context = UIGraphicsGetCurrentContext(); 144 145 if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) { 146 147 CGContextScaleCTM(context, -scaleRatio, scaleRatio); 148 149 CGContextTranslateCTM(context, -height, 0); 150 151 } 152 153 else { 154 155 CGContextScaleCTM(context, scaleRatio, -scaleRatio); 156 157 CGContextTranslateCTM(context, 0, -height); 158 159 } 160 161 CGContextConcatCTM(context, transform); 162 163 CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef); 164 165 UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext(); 166 167 UIGraphicsEndImageContext(); 168 169 return imageCopy; 170 171 }
借鉴: https://developer.apple.com/library/ios/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_affine/dq_affine.html