10

我需要在不下载图像的情况下在线查找图像的尺寸。为此,我这样做:

+ (CGSize) getImageDimensions:(NSString *)url {

   // Send a synchronous request
    NSMutableURLRequest * urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString: url]];
    NSString *rangeString = [url hasSuffix: @"png"] ? @"bytes=0-100" : @"bytes=0-1300";
    [urlRequest setValue:rangeString forHTTPHeaderField:@"Range"];
    NSURLResponse * response = nil;
    NSError * error = nil;
    NSData * data = [NSURLConnection sendSynchronousRequest:urlRequest
                                          returningResponse:&response
                                                      error:&error];
    if (error == nil)
        return [UIImage imageWithData: data].size;
    else
        return CGSizeMake(0, 0);

}

这(下载前 100 个字节)出人意料地有效,我通过这种方式获得了 PNG 的正确尺寸。

但是我不认为这是一个非常优雅的方法。首先,我选择通过猜测和检查来下载前 100 个字节,使其尽可能小,同时仍然可以正常工作。

显然,在 PNG 文件中,标题中有一个称为 IHDR 的东西,我必须找到它,然后是宽度和高度。这给我的印象是我应该遍历数据并找到这个 IHDR 并获取尺寸。问题是,当我 NSLog 数据时,我得到如下信息:

... 49484452 000003b7 000001a7 08060000 006c2da0 b100000a 41694343 50494343 2050726f 66696c65 ...

我不知道如何处理循环遍历我的 NSData 对象并检测 IHDR 令牌,然后将其后的内容转换为数字。我也不知道只为 PNG 请求 100 个字节是否只是为了获取尺寸而请求太多,或者它是否请求不够

4

1 回答 1

23

基本原理

根据PNG规范

PNG文件的前八个字节始终包含以下(十进制)值:137 80 78 71 13 10 26 10

因此,您必须阅读这些内容以确保您确实拥有 PNG 文件。

然后,

IHDR 块必须首先出现。它包含:

宽度:4 字节

高度:4 字节

ETC...

所以根据chunks的结构,你首先要读取代表chunk数据域长度的四个字节,然后是代表chunk名字的四个字节,然后是代表宽度和高度的两个32位整数,一共八个字节.

因此,为了确定宽度和高度,您必须读取的确切最小字节数是 8 + 4 + 4 + 8 = 24 bytes

Objective-C 代码

一旦你有了你的 NSData 对象,你只需要访问它包含的字节:

unsigned char buffer[24];
[data getBytes:buffer length:24];

可选,但我强烈推荐它,检查您是否确实有一个 PNG 文件:

unsigned char png_header[] = {137, 80, 78, 71, 13, 10, 26, 10};
if (memcmp(buffer, png_header, 8)) {
     // this is not a PNG !
}

确保您有 IHDR:

unsigned char ihdr_name[] = "IHDR";
if (memcmp(buffer+8+4, ihdr_name, 4)) {
    // not an IHDR chunk, invalid PNG file
}

宽度和高度可以作为大端编码的无符号整数分别在偏移量 24 减 8 和减 4 字节处访问:

unsigned int width = OSReadBigInt32(buffer + 24 - 8);
unsigned int height = OSReadBigInt32(buffer + 24 - 4);

编辑:固定缓冲区读取代码:PNG实际上以大端存储整数。

于 2013-05-23T22:41:00.747 回答