美文网首页
UIImage剪裁、压缩、拉伸等处理

UIImage剪裁、压缩、拉伸等处理

作者: cc_Jumper | 来源:发表于2018-08-02 22:00 被阅读458次

    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},按照下面代码即可截出中间区域。

    image.png

    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();
    

    相关文章

      网友评论

          本文标题:UIImage剪裁、压缩、拉伸等处理

          本文链接:https://www.haomeiwen.com/subject/nansvftx.html