iOS_获取网络图片的尺寸Size的最优方法(附:宏定义单例)
iOS_获取网络图片的尺寸Size的最优方法(附:宏定义单例)
xiaobai1315 发表于3个月前
iOS_获取网络图片的尺寸Size的最优方法(附:宏定义单例)
  • 发表于 3个月前
  • 阅读 10
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 十分钟定制你的第一个小程序>>>   

        在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 : NSObject

singleton_interface(BLImageSize)      //公共的访问单例对象的方法

+(CGSize)downloadImageSizeWithURL:(id)imageURL;

@end

*************************************************************************

最后是.m文件实现

#import "BLImageSize.h"

#import "SDImageCache.h"//如果未使用SDWebImage,则忽略

@implementation BLImageSize

singleton_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

共有 人打赏支持
粉丝 4
博文 151
码字总数 37692
×
xiaobai1315
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: