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 ファイルの最初の8バイトには、常に次の (10 進数) 値が含まれます: 137 80 78 71 13 10 26 10

そのため、実際に PNG ファイルがあることを確認するためにそれらを読む必要があります。

それで、

IHDR チャンクは最初に表示される必要があります。を含む:

幅: 4 バイト

高さ: 4 バイト

等...

したがって、チャンクの構造に従って、最初にチャンクのデータ フィールドの長さを表す 4 バイト、次にチャンクの名前を表す4バイト、次に幅と高さを表す 2 つの 32 ビット整数、合計8バイトを読み取る必要があります。 .

したがって、幅と高さを決定するために読み取る必要がある正確な最小バイト数は 8 + 4 + 4 + 8 = 24 バイトです。

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 に答える