一.图片常用加载格式分两种 一般线性式 和交错/渐进式

自上而下线性式

先模糊再清晰

就概率上而言线性式使用最多,应为他所占空间普片比渐进式小。而这两种方式对于app端开发人员无需关心,这种图片存储格式是由UI来决定的。

举个🌰 渐进式图片保存方式:

1.Photoshop存储为Progressive JPEG,首先打开一个图片,选择“文件 -> 存储为”,选择“JPEG”格式,点击“保存”按钮。在“JPEG选项”界面的“格式选项”中选择“连续”,然后在“扫描”选项中设置为“5”。

 

二.iOS代码实现

在app使用中网卡的情况下如果还是等到图片下载好了再显示图片可能给用户造成不好的体验,所以常见的方式就是来了多多给用户显示多少。下面通过代码实现图片下载一点显示一点.

 

a.这里首先会用到Imageio相关东西大体介绍下:

1.CGImageSourceRef 

An opaque type that represents an image source.

他的作用就是用来读取图片的数据的,image的数据除了图片数据外还有一些地址位置、设备信息、时间等信息、而这个类就是抽象出来干这个的方便我们获取到我们关心的数据.

2.CGImagesSourceUpdateData

void CGImageSourceUpdateData(CGImageSourceRef isrc, CFDataRef data, bool final);
Description    
Updates an incremental image source with new data.
Parameters    
isrc    
An image source.
data    
The data to add to the image source. Each time you call the function CGImageSourceUpdateData, the data parameter must contain all of the image file data accumulated so far.
final    
A value that specifies whether the data is the final set. Pass true if it is, false otherwise.

将图片数据继续追加到imageSource中去。

isrc imagesource类

data 类型式cfdata可以用nsmutabledata强制转换,为什么是nsmutabledata可以自己想想。此data必须需从头到尾一直包含了image信息的data。

final 此次追加的data是不是最后一次,所以告诉我们在追加的过程中要做好判断,判断这个数据是不是最后一个.

3.CGImageSourceCreateImageAtIndex

CGImageRef CGImageSourceCreateImageAtIndex(CGImageSourceRef isrc, size_t index, CFDictionaryRef options);
Description	
Creates a CGImage object for the image data associated with the specified index in an image source.
Parameters	
isrc	
An image source.
index	
The index that specifies the location of the image. The index is zero-based.
options	
A dictionary that specifies additional creation options. See Image Source Option Dictionary Keys for the keys you can supply.
Returns	
Returns a CGImage object. You are responsible for releasing this object using CGImageRelease.

通过imagesource转化出一个cgimage

index表示这个image的位置。默认写0

options是配置image的特殊信息的,比如kCGImageSourceShouldCache表示可以缓存,默认写NULL即可。

 

 

b.接下来会用到NSUrlSession的相关功能.这里要拿去到NSURLSessionDataDelegate的两个回调。

1.请后被相应后的回调  

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler    

通过他能得到response,通过reponse能够知道此次请求的数据长度。 内部一定要实现completionHandler(NSURLSessionResponseAllow),否则下面的回调将不会触发。

2每一次接收到数据的回调

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data  

通过data来完成一次次给iamgesource的拼装

 

 下面是代码实现:

#pragma mark -- 按条渐进式图片加载
-(void)startLoading:(NSURL *)url {
    NSURLSessionConfiguration * sessionConfig = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    NSURLSession * session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
    NSURLRequest * request = [NSURLRequest requestWithURL:url];
    NSURLSessionDataTask * task = [session dataTaskWithRequest:request];
    [task resume];
    _recieveData = [[NSMutableData alloc]init];  //用于接受data
    _imageSourceRef = CGImageSourceCreateIncremental(NULL); //创建可变的sourceref
    _isLoadingFinished = NO; //用于判断是否加载完毕
}

 

 //接受到响应获取data总长度

- (void)URLSession:(NSURLSession *)session
          dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
    
    _expectedLength = response.expectedContentLength;
    if (completionHandler) {
        completionHandler(NSURLSessionResponseAllow);
    }
}

  //拼接data生成图片

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data {
    

    [_recieveData appendData:data];
    if (_expectedLength <= _recieveData.length) {
        _isLoadingFinished = YES;
    }

    CGImageSourceUpdateData(_imageSourceRef, (__bridge CFDataRef)_recieveData, _isLoadingFinished);
    CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_imageSourceRef, 0, NULL);
    NSLog(@"%@",[NSThread currentThread]);
    dispatch_sync(dispatch_get_main_queue(), ^{
        _imageView.image = [UIImage imageWithCGImage:imageRef];
     });
    CGImageRelease(imageRef);
   
    NSLog(@"loading");
}

  

-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    _isLoadingFinished = YES;
    if (!_isLoadingFinished) {
        CGImageSourceUpdateData(_imageSourceRef, (__bridge CFDataRef)_recieveData, _isLoadingFinished);
        CGImageRef imageRef = CGImageSourceCreateImageAtIndex(_imageSourceRef, 0, NULL);
        dispatch_sync(dispatch_get_main_queue(), ^{
            _imageView.image = [UIImage imageWithCGImage:imageRef];
        });
        CGImageRelease(imageRef);
    }
}