1. 图片剪裁方法
直接调用如下系统现成的图片剪裁方法,封装成- (UIImage *)imageByCropToRect:(CGRect)rect
接口
// CoreGraphics/CGImage.h
CG_EXTERN CGImageRef __nullable CGImageCreateWithImageInRect( CGImageRef cg_nullable image, CGRect rect) CG_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0);
// UIKit/UIImage.h
+ (UIImage *)imageWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation NS_AVAILABLE_IOS(4_0);
/*
图片剪裁接口
* 1.rect超过image.size则返回原图
* 2.rect可以是size的任何一个子集,比如取中间半区域 CG
*/
- (UIImage *)imageByCropToRect:(CGRect)rect {
rect.origin.x *= self.scale;
rect.origin.y *= self.scale;
rect.size.width *= self.scale;
rect.size.height *= self.scale; // pt -> px (point -> pixel)
if (rect.size.width <= 0 || rect.size.height <= 0) return nil;
CGImageRef imageRef = CGImageCreateWithImageInRect(self.CGImage, rect);
UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
CGImageRelease(imageRef);
return image;
}
// 测试图片剪裁接口
- (void)test {
UIImage *oriImg = [UIImage imageWithName:@"xxx.png"];
CGFloat sw = oriImg.size.width;
CGFloat sh = oriImg.size.height;
// 剪裁中间区域,大小为原图片尺寸的一半
CGRect halfCenterRect = CGRectMake(0.25 * sw, 0.25 * sh, 0.5 * sw, 0.5 * sh);
// 剪裁右下脚区域,大小为原图片尺寸的四分之一
CGRect rightBottomQuartRect = CGRectMake(0.75 * sw, 0.75 * sh, 0.25 * sw, 0.25 * sh);
UIImage *image1 = [image imageByCropToRect:halfCenterRect];
UIImage *image2 = [image imageByCropToRect:rightBottomQuartRect];
}
🤔思考:其实这里可以进一步将常用的剪裁区域封装成便捷函数,如下:
typedef NS_ENUM(NSInteger, UIImageCropStyle) { // 裁切类型
UIImageCropStyleLeft = 0, // 左半部分
UIImageCropStyleRight, // 右半部分
UIImageCropStyleCenter, // 中间部分
UIImageCropStyleTop, // 上半部分
UIImageCropStyleBottom, // 下半部分
};
- (UIImage *)imageByCropStyle:(UIImageCropStyle)style
{
CGFloat cropX = 0, cropY = 0, cropWidth = self.size.width, cropHeight = self.size.height;
if (style == UIImageCropStyleLeft)
{
cropWidth /= 2;
}
else if (style == UIImageCropStyleRight)
{
cropWidth /= 2;
cropX = cropWidth;
}
else if (style == UIImageCropStyleCenter)
{
if (cropWidth > cropHeight)
{
cropX = (cropWidth - cropHeight)/2;
cropWidth = cropHeight;
}
else if (cropWidth < cropHeight)
{
cropY = (cropHeight - cropWidth)/2;
cropHeight = cropWidth;
}
}
else if (style == UIImageCropStyleTop)
{
cropHeight /= 2;
}
else if (style == UIImageCropStyleBottom)
{
cropHeight /= 2;
cropY = cropHeight;
}
return [self imageByCropToRect:CGRectMake(cropX, cropY, cropWidth, cropHeight)];
}
// 从长方形区域中剪裁中间最大正方形区域
- (UIImage *)imageByCropToSquare
{
return [self imageByCropStyle:UIImageCropStyleCenter];
}
另一种裁剪思路: 使用UIImage的
- (void)drawRect:(CGRect)rect
方法设置rect区域超出设定的画布。如下图所示画布大小为蓝色区域,要使画布截取图片中间部分区域,则位置应满足如下图所示,(其中画布大小60 * 60,图片原始尺寸120 * 120)计算出左上角为{-30, -30},大小取图片大小,则drawRect = {-30, 30, 120, 120},按照下面代码即可截出中间区域。

2.图片拉伸/压缩
- (UIImage *)imageByResizeToSize:(CGSize)size {
if (size.width <= 0 || size.height <= 0) return nil;
UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);
[self drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
// 加强,可设置contentMode及剪裁
- (UIImage *)imageByResizeToSize:(CGSize)size contentMode:(UIViewContentMode)contentMode {
if (size.width <= 0 || size.height <= 0) return nil;
UIGraphicsBeginImageContextWithOptions(size, NO, self.scale);
[self drawInRect:CGRectMake(0, 0, size.width, size.height) withContentMode:contentMode clipsToBounds:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
- (void)drawInRect:(CGRect)rect withContentMode:(UIViewContentMode)contentMode clipsToBounds:(BOOL)clips{
CGRect drawRect = YYCGRectFitWithContentMode(rect, self.size, contentMode);
if (drawRect.size.width == 0 || drawRect.size.height == 0) return;
if (clips) {
CGContextRef context = UIGraphicsGetCurrentContext();
if (context) {
CGContextSaveGState(context);
CGContextAddRect(context, rect);
CGContextClip(context);
[self drawInRect:drawRect];
CGContextRestoreGState(context);
}
} else {
[self drawInRect:drawRect];
}
}
CGRect YYCGRectFitWithContentMode(CGRect rect, CGSize size, UIViewContentMode mode) {
rect = CGRectStandardize(rect);
size.width = size.width < 0 ? -size.width : size.width;
size.height = size.height < 0 ? -size.height : size.height;
CGPoint center = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
switch (mode) {
case UIViewContentModeScaleAspectFit:
case UIViewContentModeScaleAspectFill: {
if (rect.size.width < 0.01 || rect.size.height < 0.01 ||
size.width < 0.01 || size.height < 0.01) {
rect.origin = center;
rect.size = CGSizeZero;
} else {
CGFloat scale;
if (mode == UIViewContentModeScaleAspectFit) {
if (size.width / size.height < rect.size.width / rect.size.height) {
scale = rect.size.height / size.height;
} else {
scale = rect.size.width / size.width;
}
} else {
if (size.width / size.height < rect.size.width / rect.size.height) {
scale = rect.size.width / size.width;
} else {
scale = rect.size.height / size.height;
}
}
size.width *= scale;
size.height *= scale;
rect.size = size;
rect.origin = CGPointMake(center.x - size.width * 0.5, center.y - size.height * 0.5);
}
} break;
case UIViewContentModeCenter: {
rect.size = size;
rect.origin = CGPointMake(center.x - size.width * 0.5, center.y - size.height * 0.5);
} break;
case UIViewContentModeTop: {
rect.origin.x = center.x - size.width * 0.5;
rect.size = size;
} break;
case UIViewContentModeBottom: {
rect.origin.x = center.x - size.width * 0.5;
rect.origin.y += rect.size.height - size.height;
rect.size = size;
} break;
case UIViewContentModeLeft: {
rect.origin.y = center.y - size.height * 0.5;
rect.size = size;
} break;
case UIViewContentModeRight: {
rect.origin.y = center.y - size.height * 0.5;
rect.origin.x += rect.size.width - size.width;
rect.size = size;
} break;
case UIViewContentModeTopLeft: {
rect.size = size;
} break;
case UIViewContentModeTopRight: {
rect.origin.x += rect.size.width - size.width;
rect.size = size;
} break;
case UIViewContentModeBottomLeft: {
rect.origin.y += rect.size.height - size.height;
rect.size = size;
} break;
case UIViewContentModeBottomRight: {
rect.origin.x += rect.size.width - size.width;
rect.origin.y += rect.size.height - size.height;
rect.size = size;
} break;
case UIViewContentModeScaleToFill:
case UIViewContentModeRedraw:
default: {
rect = rect;
}
}
return rect;
}
3.使用drawRect画出的图片模糊
如果是对@2x的图片直接使用UIGraphicsBeginImageContext(size)
会使图像变得模糊,需要使用UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale)
接口,下面是示例代码
UIView *targetView = xxx;
UIColor *bgColor = xxx;
// 想要在targetView上面覆盖一个image,有固定背景色,中间有固定大小logo图,
// 这样子绘制不会可以让image随着targetView变化,但是中间部分logo大小不变
CGFloat w = CGRectGetWidth(targetView.frame);
CGFloat h = w / ratio;
UIImage *image1 = [UIImage yyk_imageWithColor:bgColor size:CGSizeMake(w, h)];
UIImage *image2 = [UIImage imageNamed:@"logo"];
CGRect smallRect = CGRectMake((w - image2.size.width) / 2, (h - image2.size.height) / 2, image2.size.width, image2.size.height);
// UIGraphicsBeginImageContext(image1.size); 此方法绘制的图片可能会变模糊,使用下面接口不会
UIGraphicsBeginImageContextWithOptions(image1.size, NO, [UIScreen mainScreen].scale);
[image1 drawInRect:CGRectMake(0, 0, w, h)];
[image2 drawInRect:smallRect];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
网友评论