这几天在做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)optionswidth:(NSInteger)w height:(NSInteger)hprogress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedWithFinishedBlock)completedBlock
{// Invoking this method without a completedBlock is pointlessNSParameterAssert(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 NSURLif (![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 delegateSDWebImageDownloaderOptions 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 refreshingdownloaderOptions &= ~SDWebImageDownloaderProgressiveDownload;// ignore image read from NSURLCache if image if cached but force refreshingdownloaderOptions |= 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 itelse 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:urlwidth: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 delegatedispatch_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,即192x108UIImageView *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:108progress:nilcompleted:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished){if (image){// do something with imageimageView.image = image;}}];//添加图片二,指定缓存大小和原图大小一样,为1920x1080UIImageView *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:1080progress:nilcompleted:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished){if (image){// do something with imageimageView2.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 contextUIGraphicsBeginImageContext(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 contextUIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();// End the contextUIGraphicsEndImageContext();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

SDWebImage指定缓存图片大小相关推荐

  1. iOS 指定压缩图片大小的解决方式

    文章转自:iOS 图片压缩限制大小最优解 这里的maxLength 入参 可以这样写 比如指定 压缩成400kb 400.f * 1024.f 即可 /** 压缩图片方法(先压缩质量再压缩尺寸)*/ ...

  2. 如何用快改图工具指定压缩图片大小

    我们在遇到好看的图片或自己拍的照片,都会对其进行一些处理,处理完成后将其保存,保存时发现自己要存的图片太多了,比较占内容.这种情况就需要压缩.那么,在压缩图片时,怎么压缩图片到指定大小呢? 大家可以使 ...

  3. ios html清除缓存图片,iOS利用SDWebImage实现缓存的计算与清理

    一般我们项目中的缓存一般分为2大块:一个是自己缓存的一些数据;还有一个就是我们使用的SDWebImage这个第三方库给我们自动缓存的图片文件缓存了. 实际项目中会配合设置里去清理缓存, 效果截图如下: ...

  4. iOS利用SDWebImage实现缓存的计算与清理

    概述 可以仅仅清理图片缓存, 也可以清理所有的缓存文件(包括图片.视频.音频等). 详细 代码下载:http://www.demodashi.com/demo/10717.html 一般我们项目中的缓 ...

  5. 检测SDWebImage有没有缓存图片 IOS 获取网络图片大小

    判断图片是否缓存NSURL *url = [NSURL URLWithString:[model.content objectForKey:@"image"]];//请求网络地址数 ...

  6. Android—Bitmap图片大小计算、压缩与三级缓存

    Bitmap对象占用内存大小: bitmap.getByteCount() 图片所占内存大小计算方式:图片长度 x 图片宽度 x 一个像素点占用的字节数. Android Bitmap使用的三种颜色格 ...

  7. 使用开源库 SDWebImage 异步下载缓存图片(持续更新)

    source  https://github.com/rs/SDWebImage APIdoc  http://hackemist.com/SDWebImage/doc Asynchronous im ...

  8. ios html清除缓存图片,iOS SDWebImage图片缓存处理

    前言 以前一直使用,也没有花太多时间去看看实现的机制,现在抽时间好好研究一下,只有明白里面的实现才能使用的更顺手,即便出现问题,也能很快定位问题的位置. 导入头文件#import "SDWe ...

  9. android 自动清理缓存图片吗,Android中Glide获取缓存大小并清除缓存图片

    清除Glide缓存 Glide自带清除缓存的功能,分别对应Glide.get(context).clearDiskCache();(清除磁盘缓存)与Glide.get(context).clearMe ...

最新文章

  1. android如何实现开机自动启动Service或app
  2. 电子老鼠闯迷宫pascal解题程序
  3. [Python unittest] 3-Organizing test code
  4. python全栈开发网络_Python 全栈开发:网络编程
  5. 100道接口测试面试题收好了!【建议收藏】
  6. 网狐6603服务器文档,【整理发布】网狐 6603 棋牌平台搭建图文详解(二)
  7. html代码不兼容edge,edge兼容模式怎么设置?edge浏览器兼容性设置方法
  8. ASP.NET网站制作
  9. CSMA/CD协议详解
  10. Redis高并发点赞
  11. 欧氏距离与余弦距离的关系
  12. python爬取股票网站的历史周价格
  13. Leetcode刷题100天(阿里云周赛)—查找数组中的所有重复项(哈希)—day42
  14. 中电资讯-政府工作报告提出2022“金融新任务”;代表共话数字经济;代表提议建立全国统一金融信息数据库
  15. mysql开发语言,纯干货
  16. vue h5(网页) 调用相机拍照和相册,实现多张图片上传功能
  17. ubuntu关闭系统自动更新
  18. 关于JavaScript中的空格。
  19. scrum看板视图切换时间线视图做项目管理
  20. 【备份】win10/11安装佳能 CP900打印机 驱动方法

热门文章

  1. [Minecraft教程]我的世界插件制作-计分板[Bukkit][Scoreboard]
  2. Excel VBA 窗体UserForm制作菜单栏
  3. 单片机原理与实践学习记录之51单片机I/O口简单应用
  4. 钓鱼比赛(平均概率公式:1 - (1-p)^ t)----百度2016研发工程师在线编程题
  5. python智联招聘爬虫
  6. php图像处理类实现缩放 裁剪 加水印,ThinkPHP图像的裁剪、缩放、加水印
  7. 第五届敏捷中国大会现场采访郭晓和张为民
  8. 【Python游戏】用Python 和 Pyglet 编写一个我的世界小游戏 | 附源码
  9. Go :垃圾收集器的简单测试(附完整源码)
  10. 旧版中 pytorch.rfft 函数与新版 pytorch.fft.rfft 函数对应修改问题