SDWebImage指定缓存图片大小

            这几天在做iOS上的网络图片的异步加载和缓存。网上查了下,决定用SDWebImage实现。按照网络的教程,走了一遍,没什么问题。但是程序运行起来发现加载起来的图片都变得很模糊,本人有一点平面设计的经验。推测是因为图片太大的造成的细节都是,从而使图片变的模糊。进到程序的缓存文件目录,可以看到下载的图片果真和直接从网页上下载的一样大,即图片没有经过压缩就被缓存起来了。但是我的要求应该是图片应该在保存时被压缩的啊,就像Android开源框架Afinal中的FinalBitmap做的一样。

            那么作为一个iOS新手真的不想去改SDWebImage得源码,于是刚开始就一直在google上找,找了不少时间,没找到。无奈之下,只能自己尝试着改了。还好要改动的东西比较简单。只需要在保存图片时将图片压缩一下在保存就好了。工程文件可以在本文最后下载。

先上运行结果:

 

测试用的两张图都是1920x1080的原图,从左边可以看出位于下方的那张图片已经变得很模糊了。从右边可看出,下面那张原图的大小是2.1M,而上面的那张图片只有34k,说明,缓存文件已经被处理过了。


          其实SDWebImage已经做了这方面的考虑,就是那个SDWebImageManager中的SDWebImageManagerDelegate中,

/**
 * Allows to transform the image immediately after it has been downloaded and just before to cache it on disk and memory.
 * NOTE: This method is called from a global queue in order to not to block the main thread.
 *
 * @param imageManager The current `SDWebImageManager`
 * @param image The image to transform
 * @param imageURL The url of the image to transform
 *
 * @return The transformed image object.
 */
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL;

只可惜前面我每仔细看框架,没发现有这个东西,自己在那边建Category,然后各种试,还好最终还是发现了这个方法。那么现在问题就比较简单了。经过代码追踪(其实就是按照关键字,进行代码的全文查找,哈哈),发现在


- (id<SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock;


方法中调用了transformDownloadedImage方法,从transformDownloadedImage的注释可以看到这个回调方法会将下载得到UIImage对象作为参数,然后将处理过后的UIImage对象返回。而downloadWithURL...方法则会先判断URL指向的图片是否已经缓存过了,如果没有缓存过话,就将下载得到的UIImage对象交给

transformDownloadedImage处理一下,然后调用保存数据方法storeImage:imageData:key:toDisk方法进行数据保存。

那么可以拷贝一下SDWebImageManager中的downloadWithURL...方法,然后添加两个参数height和width

/**
 * 重写下载图片方法,可以指定要缓存的图片大小(长、宽),同时作用于内存缓存和磁盘缓存
 */
- (id<SDWebImageOperation>)downloadWithURL:(NSURL *)url options:(SDWebImageOptions)options
                                  width:(NSInteger)w height:(NSInteger)h
                                  progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock
{
    // Invoking this method without a completedBlock is pointless
    NSParameterAssert(completedBlock);
    // Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, XCode won't
    // throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
    if ([url isKindOfClass:NSString.class])
    {
        url = [NSURL URLWithString:(NSString *)url];
    }
    
    // Prevents app crashing on argument type error like sending NSNull instead of NSURL
    if (![url isKindOfClass:NSURL.class])
    {
        url = nil;
    }
    
    __block SDWebImageCombinedOperation *operation = SDWebImageCombinedOperation.new;
    __weak SDWebImageCombinedOperation *weakOperation = operation;
    
    BOOL isFailedUrl = NO;
    @synchronized(self.failedURLs)
    {
        isFailedUrl = [self.failedURLs containsObject:url];
    }
    
    if (!url || (!(options & SDWebImageRetryFailed) && isFailedUrl))
    {
        dispatch_main_sync_safe(^
                                {
                                    NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil];
                                    completedBlock(nil, error, SDImageCacheTypeNone, YES);
                                });
        return operation;
    }
    
    @synchronized(self.runningOperations)
    {
        [self.runningOperations addObject:operation];
    }
    NSString *key = [self cacheKeyForURL:url];
    
    operation.cacheOperation = [self.imageCache queryDiskCacheForKey:key done:^(UIImage *image, SDImageCacheType cacheType)
                                {
                                    if (operation.isCancelled)
                                    {
                                        @synchronized(self.runningOperations)
                                        {
                                            [self.runningOperations removeObject:operation];
                                        }
                                        
                                        return;
                                    }
                                    
                                    if ((!image || options & SDWebImageRefreshCached) && (![self.delegate respondsToSelector:@selector(imageManager:shouldDownloadImageForURL:)] || [self.delegate imageManager:self shouldDownloadImageForURL:url]))
                                    {
                                        if (image && options & SDWebImageRefreshCached)
                                        {
                                            dispatch_main_sync_safe(^
                                                                    {
                                                                        // If image was found in the cache bug SDWebImageRefreshCached is provided, notify about the cached image
                                                                        // AND try to re-download it in order to let a chance to NSURLCache to refresh it from server.
                                                                        completedBlock(image, nil, cacheType, YES);
                                                                    });
                                        }
                                        
                                        // download if no image or requested to refresh anyway, and download allowed by delegate
                                        SDWebImageDownloaderOptions downloaderOptions = 0;
                                        if (options & SDWebImageLowPriority) downloaderOptions |= SDWebImageDownloaderLowPriority;
                                        if (options & SDWebImageProgressiveDownload) downloaderOptions |= SDWebImageDownloaderProgressiveDownload;
                                        if (options & SDWebImageRefreshCached) downloaderOptions |= SDWebImageDownloaderUseNSURLCache;
                                        if (image && options & SDWebImageRefreshCached)
                                        {
                                            // force progressive off if image already cached but forced refreshing
                                            downloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;
                                            // ignore image read from NSURLCache if image if cached but force refreshing
                                            downloaderOptions |= SDWebImageDownloaderIgnoreCachedResponse;
                                        }
                                        id<SDWebImageOperation> subOperation = [self.imageDownloader downloadImageWithURL:url options:downloaderOptions progress:progressBlock completed:^(UIImage *downloadedImage, NSData *data, NSError *error, BOOL finished)
                                                                                {
                                                                                    if (weakOperation.isCancelled)
                                                                                    {
                                                                                        dispatch_main_sync_safe(^
                                                                                                                {
                                                                                                                    completedBlock(nil, nil, SDImageCacheTypeNone, finished);
                                                                                                                });
                                                                                    }
                                                                                    else if (error)
                                                                                    {
                                                                                        dispatch_main_sync_safe(^
                                                                                                                {
                                                                                                                    completedBlock(nil, error, SDImageCacheTypeNone, finished);
                                                                                                                });
                                                                                        
                                                                                        if (error.code != NSURLErrorNotConnectedToInternet)
                                                                                        {
                                                                                            @synchronized(self.failedURLs)
                                                                                            {
                                                                                                [self.failedURLs addObject:url];
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                    else
                                                                                    {
                                                                                        BOOL cacheOnDisk = !(options & SDWebImageCacheMemoryOnly);
                                                                                        
                                                                                        if (options & SDWebImageRefreshCached && image && !downloadedImage)
                                                                                        {
                                                                                            // Image refresh hit the NSURLCache cache, do not call the completion block
                                                                                        }
                                                                                        // NOTE: We don't call transformDownloadedImage delegate method on animated images as most transformation code would mangle it
                                                                                        else if (downloadedImage && !downloadedImage.images && [self.delegate respondsToSelector:@selector(imageManager:transformDownloadedImage:withURL:
                                                                                                                                                    
                                                                                                                                width:height:)]) //定义新的回调方法
                                                                                        {
                                                                                            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
                                                                                                           {   //将设定的h和w传递给回调方法...tranformDownloadedImage...,这个回调方法需要在具体的Delegate中实现
                                                                                                               UIImage *transformedImage = [self.delegate imageManager:self transformDownloadedImage:downloadedImage withURL:url
                                                                                                                                            width:w height:h];
                                                                                                               
                                                                                                               dispatch_main_sync_safe(^
                                                                                                                                       {
                                                                                                                                           completedBlock(transformedImage, nil, SDImageCacheTypeNone, finished);
                                                                                                                                       });
                                                                                                               
                                                                                                               if (transformedImage && finished)
                                                                                                               {
                                                                                                                   NSData *dataToStore = [transformedImage isEqual:downloadedImage] ? data : nil;
                                                                                                                   [self.imageCache storeImage:transformedImage imageData:dataToStore forKey:key toDisk:cacheOnDisk];
                                                                                                               }
                                                                                                           });
                                                                                        }
                                                                                        else
                                                                                        {
                                                                                            dispatch_main_sync_safe(^
                                                                                                                    {
                                                                                                                        completedBlock(downloadedImage, nil, SDImageCacheTypeNone, finished);
                                                                                                                    });
                                                                                            
                                                                                            if (downloadedImage && finished)
                                                                                            {
                                                                                                [self.imageCache storeImage:downloadedImage imageData:data forKey:key toDisk:cacheOnDisk];
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                    
                                                                                    if (finished)
                                                                                    {
                                                                                        @synchronized(self.runningOperations)
                                                                                        {
                                                                                            [self.runningOperations removeObject:operation];
                                                                                        }
                                                                                    }
                                                                                }];
                                        operation.cancelBlock = ^{[subOperation cancel];};
                                    }
                                    else if (image)
                                    {
                                        dispatch_main_sync_safe(^
                                                                {
                                                                    completedBlock(image, nil, cacheType, YES);
                                                                });
                                        @synchronized(self.runningOperations)
                                        {
                                            [self.runningOperations removeObject:operation];
                                        }
                                    }
                                    else
                                    {
                                        // Image not in cache and download disallowed by delegate
                                        dispatch_main_sync_safe(^
                                                                {
                                                                    completedBlock(nil, nil, SDImageCacheTypeNone, YES);
                                                                });
                                        @synchronized(self.runningOperations)
                                        {
                                            [self.runningOperations removeObject:operation];
                                        }
                                    }
                                }];
    
    return operation;
}
同时拷贝SDWebImageManagerDelegate中的回调方法...transformDownloadedImage...方法,修改并增加参数height和width,在SDWebImageManager.h中的SDWebImageManagerDelegate中有:

//自定义方法,指定要转换的图片的长、宽
- (UIImage *)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL width:(NSInteger)w height:(NSInteger)h;
最后调用,使ViewController.h实现SDWebImageManagerDelegate,下面是 ViewController.m:
//
//  ViewController.m
//  MySDWEBIMAGE_0928
//
//  Created by wly on 13-9-28.
//  Copyright (c) 2013年 wly. All rights reserved.
//

#import "ViewController.h"
#import "SDImageCache.h"
#import "UIImageView+WebCache_HW.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    SDWebImageManager *manager = [SDWebImageManager sharedManager];
    manager.delegate = self;
    
    
    //添加图片一,指定缓存大小是原图的1/10,即192x108
    UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(40, 100, 100, 100)];
    imageView.contentMode = UIViewContentModeScaleAspectFill;
    [manager downloadWithURL:[NSURL URLWithString:@"http://c.hiphotos.baidu.com/album/w%3D1920%3Bcrop%3D0%2C0%2C1920%2C1080/sign=4e447d5d7acb0a4685228f305953cd47/c995d143ad4bd113314728955bafa40f4afb058a.jpg"]
                     options:0 width:192 height:108
                    progress:nil
                   completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
     {
         if (image)
         {
             // do something with image
             imageView.image = image;
         }
     }];
    
    //添加图片二,指定缓存大小和原图大小一样,为1920x1080
    UIImageView *imageView2 = [[UIImageView alloc]initWithFrame:CGRectMake(40, 300, 100, 100)];
    imageView2.contentMode = UIViewContentModeScaleAspectFill;
    
    [manager downloadWithURL:[NSURL URLWithString:@"http://c.hiphotos.baidu.com/album/w%3D1920%3Bcrop%3D0%2C0%2C1920%2C1080/sign=52823b0355e736d158138801a96074a1/10dfa9ec8a136327885cb7ec908fa0ec09fac7b8.jpg"]
                     options:0 width:1920 height:1080
                    progress:nil
                   completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
     {
         if (image)
         {
             // do something with image
             imageView2.image = image;
         }
     }];
    
    [self.view addSubview:imageView];
    [self.view addSubview:imageView2];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


-(UIImage*)imageManager:(SDWebImageManager *)imageManager transformDownloadedImage:(UIImage *)image withURL:(NSURL *)imageURL width:(NSInteger)w height:(NSInteger)h {
    //缩放图片
    // Create a graphics image context
    UIGraphicsBeginImageContext(CGSizeMake(w, h));
    
    // Tell the old image to draw in this new context, with the desired
    // new size
    [image drawInRect:CGRectMake(0,0,w, h)];
    
    // Get the new image from the context
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    // End the context
    UIGraphicsEndImageContext();
    return newImage;
}
@end
再是ViewController.h

//
//  ViewController.h
//  MySDWEBIMAGE_0928
//
//  Created by wly on 13-9-28.
//  Copyright (c) 2013年 wly. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "SDWebImageManager.h"
@interface ViewController : UIViewController <SDWebImageManagerDelegate>

@end

最后,在调试过程中遇到一个问题,就是传递CGFloat参数时,得到了一个很小的负数,即出现了奇怪的问题。有兴趣的朋友可看一下stackoverflow上的一篇文章:http://stackoverflow.com/questions/3018978/cgfloat-argument-type-incorrectly-traces-out-with-zero-value-why

转载请保留出处:http://blog.csdn.net/u011638883/article/details/12160963

工程文件:http://download.csdn.net/detail/u011638883/6338379





评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值