最近项目中碰到图像处理跟动画,记录下来,当你看到是希望对你有所帮助。
所谓难者不会,会者不难,有不对的地方欢迎不吝赐教,大神轻喷。
矩阵
struct CGAffineTransform
{
CGFloat a, b, c, d;
CGFloat tx, ty;
};
矩阵变换后的坐标计算
/**
* 方法一
*
*/
//变换前
CGPoint point = CGPointMake(x, y);
CGFloat x1 = ax + cy + tx;
CGFloat y1 = bx + dy + ty;
//变换后
CGPoint point = CGPointMake(x1, y1);
/**
* 方法二
*
* @param rect 要转化的rect
* @param transform 变换后的transform
*/
CGRect rect;
CGAffineTransform transform;
CGRectApplyAffineTransform(rect, transform);
/*==============================================*/
//转换点的方法
CGPointApplyAffineTransform(<#CGPoint point#>, <#CGAffineTransform t#>)
视图绕某一点旋转
// 调用方法
[self correctAnchorPointForView:view];
CGAffineTransform transform = CGAffineTransformRotate(_lastTransform, (M_PI*count/2)); self.fatherView.transform = transform;
[self setDefaultAnchorPointforView:view];
#pragma mark -- private methods 图片中心点操作
- (void)setDefaultAnchorPointforView:(UIView *)view
{
[self setAnchorPoint:CGPointMake(0.5f, 0.5f) forView:view];
}
- (void)correctAnchorPointForView:(UIView *)view
{
CGPoint anchorPoint = CGPointZero;
CGPoint superviewCenter = view.superview.center;
// superviewCenter是view的superview 的 center 在view.superview.superview中的坐标。
CGPoint viewPoint = [view convertPoint:superviewCenter fromView:view.superview.superview];
// 转换坐标,得到superviewCenter 在 view中的坐标
anchorPoint.x = (viewPoint.x) / view.bounds.size.width;
anchorPoint.y = (viewPoint.y) / view.bounds.size.height;
[self setAnchorPoint:anchorPoint forView:view];
}
- (void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view
{
CGPoint oldOrigin = view.frame.origin;
view.layer.anchorPoint = anchorPoint;
CGPoint newOrigin = view.frame.origin;
CGPoint transition;
transition.x = newOrigin.x - oldOrigin.x;
transition.y = newOrigin.y - oldOrigin.y;
view.center = CGPointMake (view.center.x - transition.x, view.center.y - transition.y);
}
⚠️⚠️⚠️注意
通过矩阵变换来操作视图会改变视图的坐标系。给视图添加移动手势的时候可能会出现错乱的现象
要把视图的坐标系转换以后再进行操作
图片处理
截图方法:
截图的时候发现图片截的有问题 注意这里的rect是图片的分辨率
CGRect rect = CGRectMake((CGImageGetWidth(cgImage))*37*PB_ScreenRatio/theImage.size.width, CGImageGetHeight(cgImage)*(31+PB_NaviHeight)/theImage.size.height, CGImageGetWidth(cgImage)*kWidth/PB_ScreenW, CGImageGetHeight(cgImage)*KHeight/PB_ScreenH);
CGImageRef imageRefRect = CGImageCreateWithImageInRect(cgImage, rect);
UIImage * newImage = [UIImage imageWithCGImage:imageRefRect];
UIGraphicsEndImageContext();
图片旋转 获取旋转后的image
+ (UIImage *)ehs_imageWithRotation:(UIImage *)image rotationDegree:(CGFloat)degree
{
//将image转化成context
//获取图片像素的宽和高
size_t width = image.size.width * image.scale;
size_t height = image.size.height * image.scale;
//颜色通道为8 因为0-255 经过了8个颜色通道的变化
//每一行图片的字节数 因为我们采用的是ARGB/RGBA 所以字节数为 width * 4
size_t bytesPerRow =width * 4;
//图片的透明度通道
CGImageAlphaInfo info =kCGImageAlphaPremultipliedFirst;
CGContextRef context = CGBitmapContextCreate(nil, width, height, 8, bytesPerRow, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault|info);
if (!context) {
return nil;
}
//将图片渲染到图形上下文中
CGContextDrawImage(context, CGRectMake(0, 0, width, height), image.CGImage);
//旋转context
uint8_t* data =(uint8_t*) CGBitmapContextGetData(context);
//旋转欠的数据
vImage_Buffer src = { data,height,width,bytesPerRow};
//旋转后的数据
vImage_Buffer dest= { data,height,width,bytesPerRow};
//背景颜色
Pixel_8888 backColor = {0,0,0,0};
//填充颜色
vImage_Flags flags = kvImageBackgroundColorFill;
vImageRotate_ARGB8888(&src, &dest, nil, degree * M_PI/180.f, backColor, flags);
//将conetxt转换成image
CGImageRef imageRef = CGBitmapContextCreateImage(context);
UIImage * rotateImage = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
return rotateImage;
}
获取镜像后的图片
+ (UIImage *)fixOrientation:(UIImage *)aImage rotation:(UIImageOrientation)orientation{
if (orientation == UIImageOrientationUp)
return aImage;
CGAffineTransform transform = CGAffineTransformIdentity;
switch (orientation) {
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);
break;
default:
break;
}
switch (orientation) {
case UIImageOrientationUpMirrored:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
default:
break;
}
CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
CGImageGetBitsPerComponent(aImage.CGImage), 0,
CGImageGetColorSpace(aImage.CGImage),
CGImageGetBitmapInfo(aImage.CGImage));
CGContextConcatCTM(ctx, transform);
switch (aImage.imageOrientation) {
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
// Grr...
CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
break;
default:
CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
break;
}
CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
UIImage *img = [UIImage imageWithCGImage:cgimg];
CGContextRelease(ctx);
CGImageRelease(cgimg);
return img;
}
绘制
项目中碰到一个这样的需求 要给图片覆膜效果如下
//这里不能直接添加一个view,要改变image的overlay
[image drawInRect:CGRectMake(0, 0, rect.size.width, currentWavePointY) blendMode:kCGBlendModeOverlay alpha:1.0];
绘制半透明贝塞尔曲线
UIImage *image = [PB_ImageColor imageWithColor:PB_UIColor(0x80FFFFFF) size:rect.size];
[image drawInRect:CGRectMake(0, currentWavePointY, rect.size.width, rect.size.height-currentWavePointY) blendMode:kCGBlendModeNormal alpha:1.0];
UIBezierPath *path = [[UIBezierPath alloc]init];
[path moveToPoint:startPoint];
[path addCurveToPoint:endPoint controlPoint1:controlPoint1 controlPoint2:controlPoint2];
// 创建 shapeLayer
_firstWaveLayer = [[CAShapeLayer alloc]init];
[self.layer addSublayer:_firstWaveLayer];
_firstWaveLayer.path = path.CGPath;
_firstWaveLayer.fillColor = [UIColor clearColor].CGColor;
_firstWaveLayer.strokeColor = _firstWaveColor.CGColor;
_firstWaveLayer.lineWidth = 8;
UIBezierPath *path1 = [[UIBezierPath alloc]init];
[path1 moveToPoint:startPointA];
[path1 addCurveToPoint:endPointA controlPoint1:controlPoint1A controlPoint2:controlPoint2A];
// 创建 shapeLayer
_secondWaveLayer = [[CAShapeLayer alloc]init];
[self.layer addSublayer:_secondWaveLayer];
_secondWaveLayer.path = path1.CGPath;
_secondWaveLayer.fillColor = [UIColor clearColor].CGColor;
_secondWaveLayer.strokeColor = PB_UIColorAlphaHalf(0xE1E1E1).CGColor;
_secondWaveLayer.lineWidth = 8;
//半透明效果
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size{
if (!color || size.width <= 0 || size.height <= 0) return nil;
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, color.CGColor);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
滤镜
滤镜使用GPUImage
参考[https://www.jianshu.com/p/c5c5f806473c]
图片缩放
这里碰到了旋转后的图片缩放
方法比较麻烦,没想到好的办法硬着头皮算,上图比较好理解
原理:前提1.view的大小跟image相同 旋转完以后view大小变成红色部分
2.假设边框大小跟image大小相同 即为绿色部分
保持view内image大小不变 计算新的view的frame ,根据新的frame计算缩放比例
重新赋值给frame, 要使黄色区域超出边框 要计算出边框点到黄色区域的距离,取最大距离来进行等比例缩放。
以下是涉及到的计算公式
//边框顶点 到图片iamge的距离
//(y - p1.y)/(p2.y-p1.y) = (x - p1.x)/(p2.x - p1.x)
//海伦公式 s = sqrt(p(p-a)(p-b)(p-c));
//两点之间的距离 ABS(AB) = sqrt((x1-x2)(x1-x2)+(y1 - y2)(y1 - y2))
代码有点乱就不上代码乱。如有不妥欢迎指正。
qq:604630178