SDWebImage網絡圖片的圓角裁切和不變形處理

掛一張梓沐的圖片做爲原始素材

t-io(真的是一個狠牛X的網絡通信框架)的創始人給了我靈感,用梓木的照片作素材(PS:哈哈,已經獲得受權,特地給我挑了這張讓我寫博客),正題開始git

先說網絡圖片

- (void)tio_imageUrl:(NSString *)urlStr placeHolderImageName:(NSString *)placeHolderStr radius:(CGFloat)radius {
    NSURL *url;

    // 省略
    
    url = [NSURL URLWithString:urlStr];

    if (radius != 0.0) {
        // 有圓角,讀取圓角的緩存圖片
        NSString *cacheurlStr = [urlStr stringByAppendingFormat:@"radius=%.1f",radius];
        
        UIImage *cacheImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:cacheurlStr];
        if (cacheImage) {
            self.image = cacheImage;
        }
        else {
            [self sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:placeHolderStr] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                if (!error) {
                    // 開始裁剪處理
                    UIImage *radiusImage = [self.image imageWithCornerRadius:radius size:self.frame.size];
                    self.image = radiusImage;
                    [[SDImageCache sharedImageCache] storeImage:radiusImage forKey:cacheurlStr completion:nil];
                    //清除原有非圓角圖片緩存
                    [[SDImageCache sharedImageCache] removeImageForKey:urlStr withCompletion:nil];
                }
            }];
        }
    }
    else {
        [self sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:placeHolderStr] completed:nil];
    }
}
複製代碼
  1. 先根據圖片URLString拼接圓角參數到SD查詢有無圖片
  2. 如有直接從SDImageCache讀取給 self.image顯示
  3. 若沒有開始SD下載、下載後裁剪、self.image顯示、向SDImageCache存入裁剪後的圖片,key是圖片URLString拼接圓角參數

其次是圓角裁剪

你們通常不會採起github

imageView.layer.cornerRadius = 20;
imageView.layer.masksToBounds = YES;
複製代碼

這樣形成離屏渲染,特別是在列表中,當快速滑動列表,生理上的卡頓就會迸發緩存

我使用UIGraphics進行裁剪圓角bash

- (instancetype)imageWithCornerRadius:(CGFloat)cornerRadius size:(CGSize)newSize
{
    UIImage *originImage = self;
    
    // 開始裁切圓角
    CGRect bounds = CGRectMake(0, 0, newSize.width, newSize.height);
    UIGraphicsBeginImageContextWithOptions(newSize, NO, UIScreen.mainScreen.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:bounds
                                                    cornerRadius:cornerRadius];
    CGContextAddPath(context, path.CGPath);
    CGContextClip(context);
    [originImage drawInRect:bounds];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
複製代碼

接下來,對於填充模式UIViewContentModeScaleAspectFill

當咱們使用上述方法進行裁切圓角,而後直接給imageView顯示,會出現圖片變形拉伸或者壓縮markdown

可是,有的朋友會採用以下方式,對控件imageView的contentMode進行設置,並裁剪多餘的地方網絡

imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
複製代碼

理想很好 現實以下框架

很明顯,從「變胖」的梓沐就知道,這段代碼並無起什麼做用,但這是爲何呢??又從何時開始「變胖」的??oop

咱們一步步探尋優化

首先,咱們看看開始裁切前的原始圖片

斷點處確定OK,畢竟還沒開始切url

再打個斷點看看切完圓角後的圖片

梓沐居然變胖了!

「變胖」的問題出在

[originImage drawInRect:bounds];
複製代碼

將梓沐原圖一個像素不落的所有硬生生的在新的尺寸內繪製,除非原圖寬高比與目標尺寸newSize寬高比一致,不然就是壓縮或拉伸。

那麼等imageView拿到的圖片就已是變形的、並且和imageView尺寸同樣的圖片,因此也沒有多餘的部分值得clipsToBounds去裁剪,因此contentModel和clipsToBounds無效。

因此咱們須要在裁切圓角前先行作一個處理:轉成目標尺寸同比例的圖片

scaleImage:方法以下

- (UIImage *)scaleImage:(CGSize)newSize
{
    CGFloat width = self.size.width;
    CGFloat height = self.size.height;
    
    CGFloat scale = newSize.width / newSize.height;
    CGFloat imageScale = width / height;
    
    if (imageScale > scale) {
        // 以高爲準
        width = height * scale;
    } else if (imageScale < scale) {
        // 以寬爲準
        height = width / scale;
    } else {
        // 正常比例
    }
    
    // 中心放大
    CGRect frame = CGRectMake((self.size.width - width) * 0.5, (self.size.height - height) * 0.5, width, height);
    
    CGImageRef imageRef = [self CGImage];
    imageRef = CGImageCreateWithImageInRect(imageRef, frame);
    UIImage *image = [UIImage imageWithCGImage:imageRef];
    
    
    return image;
}
複製代碼

***官方吐槽:***這個代碼顯然是沒有優化,那麼多判斷徹底能夠用宏解決,順便也還能擴展各類contentMode的處理,這個後續會講,也很簡單

這是咱們要的最終效果

處理先後進行對比

處理前

處理後

我只實現了UIViewContentModeScaleAspectFill的效果 其餘效果作法同樣,如上述所說,在scaleImage方法內能夠擴展,實現裁剪的居上、居左、居右等,也能夠添加上左下右的裁剪偏移量等等

思路都很簡單,沒有什麼特別,工做這麼多年,一點點寫吧,以前也沒養成寫博客的習慣

文末小源碼:GitHub

相關文章
相關標籤/搜索