如何通过查看目标 c 中的标题来提取 PNG 的宽度和高度? [英] How do I extract the width and height of a PNG from looking at the header in objective c?

查看:30
本文介绍了如何通过查看目标 c 中的标题来提取 PNG 的宽度和高度?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a need to find the dimensions of images online without downloading them. To accomplish this I do this:

+ (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 尺寸.

This (downloading the first 100 bytes) surprisingly works and I get the correct dimensions for PNGs this way.

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

However I do not think this is a very elegant approach. First, I chose to download the first 100 bytes by just guess and checking, making it as small as possible whilst still having it work okay.

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

Apparently in a PNG file there's this thing called a IHDR in the header and I have to find it and directly after it are the width and height. This gives me the impression that I should loop over the data and find this IHDR and get the dimensions. The problem is, when I NSLog the data I get something like this:

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

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

I have no idea how to handle looping over my NSData object and detecting the IHDR token and then converting the things that come after it to numbers. I also have no idea if requesting just 100 bytes for a PNG is requesting too much just to get the dimensions, or if it's requesting not enough

推荐答案

基本原理

根据 PNG 规范:

PNG 文件的前 8 个字节总是包含以下内容(十进制)值:137 80 78 71 13 10 26 10

The first eight bytes of a PNG file always contain the following (decimal) values: 137 80 78 71 13 10 26 10

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

So you have to read those to make sure you really have a PNG file.

那么,

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

The IHDR chunk must appear FIRST. It contains:

宽度:4 个字节

高度:4 个字节

等等……

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

So according to the structure of chunks, you first have to read the four bytes representing the length of the chunk's data field, then the four bytes representing the chunk's name, then the two 32-bit integers representing width and height, eight bytes in total.

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

So, the exact minimal number of bytes you must read in order to determine width and height is 8 + 4 + 4 + 8 = 24 bytes.

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

Once you have your NSData object, you simply have to access the bytes that it contains:

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

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

Optionally, but I recommend it strongly, check that you indeed have a PNG file:

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

确保您拥有 IHDR:

Make sure you have an IHDR:

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

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

Width and height can be accessed as big-endian encoded unsigned ints at offset 24 minus 8 and minus 4 bytes respectively:

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

编辑:修正缓冲区读取代码:PNG 实际上以大端序存储整数.

Edit: Fixed buffer reading code: PNG actually stores integers in big-endian.

这篇关于如何通过查看目标 c 中的标题来提取 PNG 的宽度和高度?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆