美文网首页
iOS 后台不给图片宽高的处理

iOS 后台不给图片宽高的处理

作者: 刃之剑 | 来源:发表于2021-11-02 15:55 被阅读0次

一 .计算NSData

[[NSData alloc] initWithContentsOfURL:<#(nonnull NSURL *)#>]

转化为图片,然后进行宽高计算.

二.SD下载计算

sd_setImageWithURL:[NSURL URLWithString:url] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {

计算十张图片耗时: 
123.252071 ms

三.取图片URL的字节值

各种图头信息格式汇总

image.png
CF_INLINE uint16_t FNKSwapWebIntToInt16(uint16_t arg) {
    return CFSwapInt16BigToHost(arg);
}
CF_INLINE uint16_t FNKSwapWebIntToInt32(uint32_t arg) {
    return CFSwapInt32BigToHost(arg);
}

typedef enum : NSUInteger {
    FNKImagePrefetcherImageType_PNG,
    FNKImagePrefetcherImageType_GIF,
    FNKImagePrefetcherImageType_JPG,
    FNKImagePrefetcherImageType_BMP,
    FNKImagePrefetcherImageType_UNKOWN
} FNKImagePrefetcherImageType;

#define UN_FETCHED_IMAGE_SIZE CGSizeMake(CGFLOAT_MIN, CGFLOAT_MIN)

@interface FNKImagePrefetcher ()<NSURLSessionDataDelegate>

@property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, strong) NSOperationQueue *queue;
@property (nonatomic, strong) NSMutableData *downloadData;
@property (nonatomic, assign) FNKImagePrefetcherImageType imageType;
@property (nonatomic, assign) CGSize imageSize;

@property (nonatomic, assign) NSInteger maxTimerinterval;

@end

@implementation FNKImagePrefetcher {
    dispatch_semaphore_t _lock;
}

- (instancetype)initWithUrl:(NSURL *)url {
    return [self initWithUrl:url timeInterval:1.5];
}

- (instancetype)initWithUrl:(NSURL *)url timeInterval:(NSInteger) timeInterval {
    if (!url) return nil;
    self = [super init];
    if (self) {
        _maxTimerinterval = timeInterval;
        _imageUrl = url;
        _imageSize = UN_FETCHED_IMAGE_SIZE;
        _imageType = FNKImagePrefetcherImageType_UNKOWN;
    }
    return self;
}

- (NSOperationQueue *)queue {
    if (!_queue) {
        _queue = [[NSOperationQueue alloc] init];
        _queue.name = @"com.FNK.image.prefetcher.queue";
    }
    return _queue;
}

- (CGSize)fetchImageSize {
    return [self downloadDataWithUrl:_imageUrl];
}

- (CGSize )downloadDataWithUrl:(NSURL *)url {
    if (!_session) {
        NSURLSessionConfiguration *config = NSURLSessionConfiguration.defaultSessionConfiguration;
        config.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
        _session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:self.queue];
    }
    NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:3];
    NSURLSessionDataTask *task = [_session dataTaskWithRequest:request];
    _lock = dispatch_semaphore_create(0);
    [task resume];
    dispatch_time_t waitTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_maxTimerinterval * NSEC_PER_SEC));
    dispatch_semaphore_wait(_lock, waitTime);
    return _imageSize;
}

#pragma -mark NSURLSessionDataDelegate

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
    didReceiveData:(NSData *)data {
    if (!data) return;
    if (!_downloadData) {
        _downloadData = [[NSMutableData alloc] init];
    }
    [_downloadData appendData:data];
    if (_downloadData.length < 2) return;
    
    if (_imageType == FNKImagePrefetcherImageType_UNKOWN) {
        self.imageType = [self fetchImageTtypeFormData:_downloadData];
    }
    
    // 解析数据
    switch (_imageType) {
        case FNKImagePrefetcherImageType_JPG:
        {
            _imageSize = [self fetchHWFromJPGData:_downloadData];
        }
            break;
        case FNKImagePrefetcherImageType_PNG:
        {
            _imageSize = [self fetchHWFromPNGData:_downloadData];
        }
            break;
        case FNKImagePrefetcherImageType_BMP:
        {
            _imageSize = [self fetchHWFromGIFData:_downloadData];
        }
            break;
        case FNKImagePrefetcherImageType_GIF:
        {
            _imageSize = [self fetchHWFromGIFData:_downloadData];
        }
            break;
            
        default:
            break;
    }
    
    // 获取到提前数据结束
    if (!CGSizeEqualToSize(self.imageSize, UN_FETCHED_IMAGE_SIZE)) {
        [dataTask cancel];
        dispatch_semaphore_signal(_lock);
    }
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error {
    if (CGSizeEqualToSize(self.imageSize, UN_FETCHED_IMAGE_SIZE)) {
        if (_downloadData) {
            UIImage *image = [UIImage imageWithData:_downloadData];
            if (image) _imageSize = image.size;
        }
    }
    
    dispatch_semaphore_signal(_lock);
}

- (FNKImagePrefetcherImageType)fetchImageTtypeFormData:(NSData *)data {
    if(data.length < 2) return FNKImagePrefetcherImageType_UNKOWN;
    
    UInt8 word0 = 0x0, word1 = 0x0;
    [data getBytes:&word0 range:NSMakeRange(0, 1)];
    [data getBytes:&word1 range:NSMakeRange(1, 1)];
    
    if (word0 == 0xFF && word1 == 0xD8) {
        return FNKImagePrefetcherImageType_JPG;
    }else if (word0 == 0x89 && word1 == 0x50) {
        return FNKImagePrefetcherImageType_PNG;
    }else if (word0 == 0x47 && word1 == 0x49) {
        return FNKImagePrefetcherImageType_GIF;
    }else if (word0 == 0x42 && word1 == 0x4D) {
        return FNKImagePrefetcherImageType_BMP;
    }
    return FNKImagePrefetcherImageType_UNKOWN;
}

- (CGSize)fetchHWFromJPGData:(NSData *)data {
    CGSize size = CGSizeZero;
    // jpeg 文件格式头中有JFTF也有EXIF,EXIF相对复杂,具体头部结构可以见https://blog.csdn.net/ryfdizuo/article/details/41250775
    // FF D8 FF E0 (XX XX 这两字节为长度) ('JF' 'TF' 转为ascll码值)
    UInt8 word0 = 0x0, word1 = 0x0, word2 = 0x0, word3 = 0x0;
    [data getBytes:&word0 range:NSMakeRange(0, 1)];
    [data getBytes:&word1 range:NSMakeRange(1, 1)];
    [data getBytes:&word2 range:NSMakeRange(2, 1)];
    [data getBytes:&word3 range:NSMakeRange(3, 1)];
    if (word0 == 0xFF && word1 == 0xD8 && word2 == 0xFF && word3 == 0xE0) {
        UInt8 c0 = 0, c1 = 0, c2 = 0, c3 = 0;
        [data getBytes:&c0 range:NSMakeRange(6, 1)];
        [data getBytes:&c1 range:NSMakeRange(7, 1)];
        [data getBytes:&c2 range:NSMakeRange(8, 1)];
        [data getBytes:&c3 range:NSMakeRange(9, 1)];
        if (c0 == 'J' && c1 == 'F' && c2 == 'I' && c3 == 'F') {
            UInt16 block_length = 0;
            [data getBytes:&block_length range:NSMakeRange(4, 2)];
            block_length = FNKSwapWebIntToInt16(block_length);
            int i = 4;
            do {
                i += block_length;
                if (i > data.length) {
                    break;
                }
                UInt8 aW = 0x0;
                [data getBytes:&aW range:NSMakeRange(i, 1)];
                if (aW != 0xFF) {
                    break;
                }
                
                UInt8 ca = 0x0;
                [data getBytes:&ca range:NSMakeRange(i+1, 1)];
                if (ca >= 0xC0 && ca<= 0xC3) {
                    /**
                     图片信息段 FF CO (xx xx 该段长度) XX(抛弃字节,不用) (HH HH 高度) (WW WW 宽度) ...后面是其他信息。
                     这里宽高段和 png gif 等都不一样,jpg 是高在前
                     */
                    UInt16 w = 0, h = 0;
                    [data getBytes:&h range:NSMakeRange(i + 5, 2)];
                    [data getBytes:&w range:NSMakeRange(i + 7, 2)];
                    w = FNKSwapWebIntToInt16(w);
                    h = FNKSwapWebIntToInt16(h);
                    size = CGSizeMake(w, h);
                    break;
                }else {
                    i += 2;
                    [data getBytes:&block_length range:NSMakeRange(i, 2)];
                    block_length = FNKSwapWebIntToInt16(block_length);
                }
            } while (i < data.length);
        }
        
    }
    return size;
}

- (CGSize)fetchHWFromPNGData:(NSData *)data {
    /**
     png 头格式
     89 50 4E 47 0D 0A 1A 0A (4byte IDHR) (4Byte CHUNKTYPE) (4Byte WIDTH) (4Byte HEIGHT) ....
     至少需要24bytes
     */
    if (data.length < 24) return CGSizeZero;
    UInt32 w = 0, h = 0;
    [data getBytes:&w range:NSMakeRange(16, 4)];
    [data getBytes:&h range:NSMakeRange(20, 4)];
    w = FNKSwapWebIntToInt32(w);
    h = FNKSwapWebIntToInt32(h);
    return CGSizeMake(w, h);
}

- (CGSize)fetchHWFromGIFData:(NSData *)data {
    /**
     GIF 头格式
     47 49 46 38 39 61 (2Byte WIDTH) (2Byte HEIGHT) ....
     至少需要10bytes
     */
    if (data.length < 10) return CGSizeZero;
    UInt16 w = 0, h = 0;
    [data getBytes:&w range:NSMakeRange(6, 2)];
    [data getBytes:&h range:NSMakeRange(8, 2)];
    return CGSizeMake(w, h);
}

- (CGSize)fetchHWFromBMPData:(NSData *)data {
    /**
     BMP 头格式可见http://www.fastgraph.com/help/bmp_os2_header_format.html
     */
    if (data.length < 29) return CGSizeZero;
    UInt32 length = 0;
    [data getBytes:&length range:NSMakeRange(14, 4)];
    length = FNKSwapWebIntToInt32(length);
    
    if (length == 12) {
        UInt16 w = 0, h = 0;
        [data getBytes:&w range:NSMakeRange(18, 2)];
        [data getBytes:&h range:NSMakeRange(820, 2)];
        w = FNKSwapWebIntToInt16(w);
        h = FNKSwapWebIntToInt16(h);
        return CGSizeMake(w, h);
    }else {
        UInt32 w = 0, h = 0;
        [data getBytes:&w range:NSMakeRange(18, 4)];
        [data getBytes:&h range:NSMakeRange(22, 4)];
        w = FNKSwapWebIntToInt32(w);
        h = FNKSwapWebIntToInt32(h);
        return CGSizeMake(w, h);
    }
    
    return CGSizeZero;
}

@end

取十张图片计算耗时有点大.
1483.412027 ms~4000ms

暂时还是SD计算比较快

相关文章

网友评论

      本文标题:iOS 后台不给图片宽高的处理

      本文链接:https://www.haomeiwen.com/subject/rbnxzltx.html