博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS_获取网络图片的尺寸Size的最优方法(附:宏定义单例)
阅读量:6034 次
发布时间:2019-06-20

本文共 8194 字,大约阅读时间需要 27 分钟。

hot3.png

        在iOS开发过程中经常需要通过网络请求加载图片,有时,需要在创建UIImageView或UIButton来显示图片之前需要提前知道图片的尺寸,根据图片尺寸创建对应大小的控件。但是对于网络图片来说,要想通过最优的方法获得尺寸就略微有点困难,大体思路有这么几种:

        1.通过服务器处理。即在下行图片路径时拼接该图片的宽高。这种方法最简单,避免了不必要的网络请求,只需要从URL中截取即可(需要前后台的配合);

        2.网络请求。如果有使用SDWebImage,则首先检查是否缓存过该图片,如果没有,先通过文件头获取图片大小(针对格式为png、gif、jpg文件获取其尺寸大小),如果获取失败,则下载完整的图片data,然后计算大小,如果有使用SDWebImage,则使用SDWebImage缓存该图片。

      ​(方法二的最大的缺点就是虽然获取头文件耗时比下载图片快很多,但是还是有延迟,会阻塞主线程UI的绘制,如果网速不好的话会影响用户体验;但是如果使用了SDWebImage缓存,只会在初次加载图片的时候卡顿而已。)

代码如下:​

//一个项目里面可能有好几个类都需要实现单例模式。为了更高效的编码,可以利用c语言中宏定义来实现。

//首先宏定义一个单例实现(在.pch/Header文件中拷贝如下代码加入即可)

//这里假设了实例的分享方法叫 shared"className"

//因为方法名 shared"className"是连在一起的,为了让宏能够正确替换掉签名中的“className”需要在前面加上 ##

//当宏的定义超过一行时,在末尾加上“\”表示下一行也在宏定义范围内。

//注意最后一行不需要加"\”。

// @interface#define singleton_interface(className) \+ (className *)shared##className;// @implementation#define singleton_implementation(className) \static className *_instance; \+ (id)allocWithZone:(NSZone *)zone \{ \static dispatch_once_t onceToken; \dispatch_once(&onceToken, ^{ \_instance = [super allocWithZone:zone]; \}); \return _instance; \} \+ (className *)shared##className \{ \static dispatch_once_t onceToken; \dispatch_once(&onceToken, ^{ \_instance = [[self alloc] init]; \}); \return _instance; \}********************************************************************然后头文件如下#import 《Foundation/Foundation.h》//特殊字符限制,将书名号改为尖括号#import "Singleton.h"@interface BLImageSize : NSObjectsingleton_interface(BLImageSize)      //公共的访问单例对象的方法+(CGSize)downloadImageSizeWithURL:(id)imageURL;@end*************************************************************************最后是.m文件实现#import "BLImageSize.h"#import "SDImageCache.h"//如果未使用SDWebImage,则忽略@implementation BLImageSizesingleton_implementation(BLImageSize)//传入的参数imageURL可以为NSString类型,也可以为NSURL​类型+(CGSize)getImageSizeWithURL:(id)imageURL{    NSURL* URL = nil;    if([imageURL isKindOfClass:[NSURL class]]){        URL = imageURL;    }    if([imageURL isKindOfClass:[NSString class]]){        URL = [NSURL URLWithString:imageURL];    }​    if(URL == nil) {        return CGSizeZero;    // url为空则返回CGSizeZero}​        NSString* absoluteString = URL.absoluteString;​    //如果未使用SDWebImage,则忽略;检查是否缓存过该图片#ifdef dispatch_main_sync_safe    if([[SDImageCache sharedImageCache] diskImageExistsWithKey:absoluteString])    {        UIImage* image = [[SDImageCache sharedImageCache] imageFromMemoryCacheForKey:absoluteString];        if(!image)        {            NSData* data = [[SDImageCache sharedImageCache] performSelector:@selector(diskImageDataBySearchingAllPathsForKey:) withObject:URL.absoluteString];            image = [UIImage imageWithData:data];        }        if(image)        {            return image.size;        }    }#endif        NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];    NSString* pathExtendsion = [URL.pathExtension lowercaseString];        CGSize size = CGSizeZero;    if([pathExtendsion isEqualToString:@"png"]){        size =  [self getPNGImageSizeWithRequest:request];    }    else if([pathExtendsion isEqual:@"gif"])    {        size =  [self getGIFImageSizeWithRequest:request];    }    else{        size = [self getJPGImageSizeWithRequest:request];    }    if(CGSizeEqualToSize(CGSizeZero, size))    {        // 如果获取文件头信息失败,发送异步请求请求原图        NSData* data = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:URL] returningResponse:nil error:nil];        UIImage* image = [UIImage imageWithData:data];        if(image)        {//如果未使用SDWebImage,则忽略;缓存该图片#ifdef dispatch_main_sync_safe            [[SDImageCache sharedImageCache] storeImage:image recalculateFromImage:YES imageData:data forKey:URL.absoluteString toDisk:YES];#endif            size = image.size;        }    }//如果对加载速度及用户体验要求不高的话,可以通过主线程获取图片大小//会阻塞主线程,慎重使用!!!if (CGSizeEqualToSize(CGSizeZero, size)) {        //直接获取图片大小        NSData *data = [NSData dataWithContentsOfURL:URL];        UIImage *image = [UIImage imageWithData:data];        size = image.size;}​    return size;}​​//  获取PNG图片的大小+(CGSize)getPNGImageSizeWithRequest:(NSMutableURLRequest*)request{    [request setValue:@"bytes=16-23" forHTTPHeaderField:@"Range"];    NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];    if(data.length == 8)    {        int w1 = 0, w2 = 0, w3 = 0, w4 = 0;        [data getBytes:&w1 range:NSMakeRange(0, 1)];        [data getBytes:&w2 range:NSMakeRange(1, 1)];        [data getBytes:&w3 range:NSMakeRange(2, 1)];        [data getBytes:&w4 range:NSMakeRange(3, 1)];        int w = (w1 << 24) + (w2 << 16) + (w3 << 8) + w4;        int h1 = 0, h2 = 0, h3 = 0, h4 = 0;        [data getBytes:&h1 range:NSMakeRange(4, 1)];        [data getBytes:&h2 range:NSMakeRange(5, 1)];        [data getBytes:&h3 range:NSMakeRange(6, 1)];        [data getBytes:&h4 range:NSMakeRange(7, 1)];        int h = (h1 << 24) + (h2 << 16) + (h3 << 8) + h4;        return CGSizeMake(w, h);    }    return CGSizeZero;}​//  获取GIF图片的大小+(CGSize)getGIFImageSizeWithRequest:(NSMutableURLRequest*)request{    [request setValue:@"bytes=6-9" forHTTPHeaderField:@"Range"];    NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];    if(data.length == 4)    {        short w1 = 0, w2 = 0;        [data getBytes:&w1 range:NSMakeRange(0, 1)];        [data getBytes:&w2 range:NSMakeRange(1, 1)];        short w = w1 + (w2 << 8);        short h1 = 0, h2 = 0;        [data getBytes:&h1 range:NSMakeRange(2, 1)];        [data getBytes:&h2 range:NSMakeRange(3, 1)];        short h = h1 + (h2 << 8);        return CGSizeMake(w, h);    }    return CGSizeZero;}​//  获取JPG图片的大小+(CGSize)getJPGImageSizeWithRequest:(NSMutableURLRequest*)request{    [request setValue:@"bytes=0-209" forHTTPHeaderField:@"Range"];    NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];        if ([data length] <= 0x58) {        return CGSizeZero;    }        if ([data length] < 210) {// 肯定只有一个DQT字段        short w1 = 0, w2 = 0;        [data getBytes:&w1 range:NSMakeRange(0x60, 0x1)];        [data getBytes:&w2 range:NSMakeRange(0x61, 0x1)];        short w = (w1 << 8) + w2;        short h1 = 0, h2 = 0;        [data getBytes:&h1 range:NSMakeRange(0x5e, 0x1)];        [data getBytes:&h2 range:NSMakeRange(0x5f, 0x1)];        short h = (h1 << 8) + h2;        return CGSizeMake(w, h);    } else {        short word = 0x0;        [data getBytes:&word range:NSMakeRange(0x15, 0x1)];        if (word == 0xdb) {            [data getBytes:&word range:NSMakeRange(0x5a, 0x1)];            if (word == 0xdb) {// 两个DQT字段                short w1 = 0, w2 = 0;                [data getBytes:&w1 range:NSMakeRange(0xa5, 0x1)];                [data getBytes:&w2 range:NSMakeRange(0xa6, 0x1)];                short w = (w1 << 8) + w2;                short h1 = 0, h2 = 0;                [data getBytes:&h1 range:NSMakeRange(0xa3, 0x1)];                [data getBytes:&h2 range:NSMakeRange(0xa4, 0x1)];                short h = (h1 << 8) + h2;                return CGSizeMake(w, h);            } else {// 一个DQT字段                short w1 = 0, w2 = 0;                [data getBytes:&w1 range:NSMakeRange(0x60, 0x1)];                [data getBytes:&w2 range:NSMakeRange(0x61, 0x1)];                short w = (w1 << 8) + w2;                short h1 = 0, h2 = 0;                [data getBytes:&h1 range:NSMakeRange(0x5e, 0x1)];                [data getBytes:&h2 range:NSMakeRange(0x5f, 0x1)];                short h = (h1 << 8) + h2;                return CGSizeMake(w, h);            }        } else {            return CGSizeZero;        }    }}@end

 

PS:

png和gif格式的图片头文件固定,可以准确找到宽高所在字节,只需要极少流量就可以获得图片大小。但是jpeg的头文件很混乱,我真的想说它根本就不分header和body,绘图软件编辑一次保存一次就添加一个标记码,然后存放宽高的标记码就消失在数据流的某个地方了,因为不知道有多少个绘图软件编辑过,也不知道绘图软件标记码里面的内容格式,所以手动获取jpeg图片的宽高基本不可能了​。

不过博主偶然发现了一个方法,大家可以尝试一下:

就是在图片url地址后面拼接参数@100p,利用获取JPG格式图片的方法即可获得JPEG图片的大小了。​

if (![imgUrl containsString:@"@"]) {

            imgUrl = [imgUrl stringByAppendingString:@"@100p"];

}

参考:

http://bbs.itheima.com/thread-158741-1-1.html

http://www.oschina.net/code/snippet_2248391_53038

http://www.2cto.com/kf/201405/304877.html

http://www.cocoachina.com/bbs/read.php?tid=455783

转载于:https://my.oschina.net/mexiaobai1315/blog/1359250

你可能感兴趣的文章
JMJS系统总结系列----Jquery分页扩展库(五)
查看>>
Excel技巧之——英文大小写转换(转)
查看>>
Google 翻译的妙用
查看>>
算法导论--python--插入排序
查看>>
Hydra用户手册
查看>>
常用的集合
查看>>
Unity3D工程源码目录
查看>>
杀死进程命令
查看>>
cookie 和session 的区别详解
查看>>
浮点数网络传输
查看>>
Mongodb对集合(表)和数据的CRUD操作
查看>>
面向对象类的解析
查看>>
tomcat如何修改发布目录
查看>>
CentOS 5.5 使用 EPEL 和 RPMForge 软件库
查看>>
Damien Katz弃Apache CouchDB,继以Couchbase Server
查看>>
Target runtime Apache Tomcat is not defined.错误解决方法
查看>>
某机字长为32位,存储容量为64MB,若按字节编址.它的寻址范围是多少?
查看>>
VC++ 监视文件(夹)
查看>>
【转】keyCode对照表及JS监听组合按键
查看>>
EFCodeFirst系列
查看>>