2009-10-11 103 views
7

我有幾個.png圖像(ETA:但格式也可能是JPEG或其他),我要在UITableViewCell s顯示。現在,爲了獲得行高,我加載圖像,獲得他們的size屬性,並使用它來計算出行的高度(計算任何必要的變化,因爲大部分圖像都被調整大小在被顯示之前)。爲了加快速度並減少內存使用量,我希望能夠在不加載圖像的情況下獲得size。有沒有辦法做到這一點?獲取圖像的大小而不加載到內存

注:我知道有一些快捷方式我可以實現消除這一問題,但有以下幾個原因,我不能提前調整圖像或收集的圖像尺寸提前,迫使我得到這個運行時的信息。

+1

CGImageSource是完美的API,但令人討厭的是它在iPhone上不可用。你可能必須自己實現它。也就是說,請記住,如果您使用+ imageWithContentsOfFile,UIImage將清除其數據:這將消除您的內存使用問題。 – 2009-10-11 23:13:35

回答

4

由於iOS的SDK 4.0,這個任務可以用的ImageIO框架(CGImageSource...)來完成。我已經回答了a similar question here

6

它應該很簡單。 PNG spec解釋了PNG datastream(這實際上是一個文件)。 IHDR部分包含有關圖像尺寸的信息。

所以你要做的是讀PNG「魔法值」,然後讀取兩個四字節整數,分別是寬度和高度。您可能還需要對這些值中的位進行重新排序(不確定它們是如何存儲的),但是一旦找出這些值,它將非常簡單。

+0

好主意,除了我忘了提及它可能不是一個PNG,這正是我現在所擁有的(編輯過的文章反映了這一點)。至少我應該支持JPEG,儘管我想我可以用你描述的類似方式來做。 – 2009-10-11 18:26:16

1

這很好地在Perl的Image::Size module中實現了十幾種格式 - 包括PNG和JPEG。爲了在目標C重新實現它只取Perl代碼和讀它作爲僞;-)

例如,pngsize()被定義爲

# pngsize : gets the width & height (in pixels) of a png file 
# cor this program is on the cutting edge of technology! (pity it's blunt!) 
# 
# Re-written and tested by [email protected] 
sub pngsize 
{ 
    my $stream = shift; 

    my ($x, $y, $id) = (undef, undef, "could not determine PNG size"); 
    my ($offset, $length); 

    # Offset to first Chunk Type code = 8-byte ident + 4-byte chunk length + 1 
    $offset = 12; $length = 4; 
    if (&$read_in($stream, $length, $offset) eq 'IHDR') 
    { 
     # IHDR = Image Header 
     $length = 8; 
     ($x, $y) = unpack("NN", &$read_in($stream, $length)); 
     $id = 'PNG'; 
    } 

    ($x, $y, $id); 
} 

jpegsize是隻有幾行更長。

0

低科技的解決方案:

,如果你知道圖片是什麼事前,店面形象與它們的文件名大小一起在一個XML文件或plist中(或者你喜歡的任何方式),只是在閱讀這些屬性

如果你不知道圖像是什麼(即它們將在運行時定義),那麼你必須在一個或另一個時間加載圖像。第一次加載它們時,將它們的高度和寬度保存在一個文件中,以便以後可以訪問它。

1

注:此功能不與iPhone壓縮的PNG工作,這壓縮是自動進行的XCode這裏改變圖像的頭,看到更多的細節,以及如何禁用此功能:http://discussions.apple.com/thread.jspa?threadID=1751896

未來版本的PSFramework也會解釋這個標題,敬請關注。


看到這個功能,她就是這麼做的。只讀取PNG文件的30個字節並返回大小(CGSize)。該功能是處理稱爲PSFramework(http://sourceforge.net/projects/photoshopframew/)的圖像框架的一部分。尚未實現其他圖像格式,歡迎開發者。該項目是GNU許可下的開源軟件。

CGSize PSPNGSizeFromMetaData(NSString* anFileName) { 

    // File Name from Bundle Path. 
    NSString *fullFileName = [NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] bundlePath], anFileName ]; 

    // File Name to C String. 
    const char* fileName = [fullFileName UTF8String]; 

    /* source file */ 
    FILE * infile;  

    // Check if can open the file. 
    if ((infile = fopen(fileName, "rb")) == NULL) 
    { 
     NSLog(@"PSFramework Warning >> (PSPNGSizeFromMetaData) can't open the file: %@", anFileName); 
     return CGSizeZero; 

    } 

    ////// ////// ////// ////// ////// ////// ////// ////// ////// ////// ////// 

    // Lenght of Buffer. 
    #define bytesLenght 30 

    // Bytes Buffer. 
    unsigned char buffer[bytesLenght]; 

    // Grab Only First Bytes. 
    fread(buffer, 1, bytesLenght, infile); 

    // Close File. 
    fclose(infile); 

    ////// ////// ////// ////// ////// 

    // PNG Signature. 
    unsigned char png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; 

    // Compare File signature. 
    if ((int)(memcmp(&buffer[0], &png_signature[0], 8))) { 

     NSLog(@"PSFramework Warning >> (PSPNGSizeFromMetaData) : The file (%@) don't is one PNG file.", anFileName);  
     return CGSizeZero; 

    } 

    ////// ////// ////// ////// ////// ////// ////// ////// ////// ////// 

    // Calc Sizes. Isolate only four bytes of each size (width, height). 
    int width[4]; 
    int height[4]; 
    for (int d = 16; d < (16 + 4); d++) { 
     width[ d-16] = buffer[ d ]; 
     height[d-16] = buffer[ d + 4]; 
    } 

    // Convert bytes to Long (Integer) 
    long resultWidth = (width[0] << (int)24) | (width[1] << (int)16) | (width[2] << (int)8) | width[3]; 
    long resultHeight = (height[0] << (int)24) | (height[1] << (int)16) | (height[2] << (int)8) | height[3]; 

    // Return Size. 
    return CGSizeMake(resultWidth, resultHeight); 

} 

1

//這裏有一個快速&髒口C#


public static Size PNGSize(string fileName) 
{ 
    // PNG Signature. 
    byte[] png_signature = {137, 80, 78, 71, 13, 10, 26, 10};

try { using (FileStream stream = File.OpenRead(fileName)) { byte[] buf = new byte[30]; if (stream.Read(buf, 0, 30) == 30) { int i = 0; int imax = png_signature.Length; for (i = 0; i < imax; i++) { if (buf[i] != png_signature[i]) break; } // passes sig test if (i == imax) { // Calc Sizes. Isolate only four bytes of each size (width, height). // Convert bytes to integer int resultWidth = buf[16] << 24 | buf[17] << 16 | buf[18] << 8 | buf[19]; int resultHeight = buf[20] << 24 | buf[21] << 16 | buf[22] << 8 | buf[23]; // Return Size. return new Size(resultWidth, resultHeight); } } } } catch { } return new Size(0, 0);

}

1

imageUrl是一個NSURL,它還在其周圍導入了ImageIO/ImageIO.h和<>。

CGImageSourceRef imageSourceRef = CGImageSourceCreateWithURL((CFURLRef)imageUrl, NULL); 

if (!imageSourceRef) 
    return; 

CFDictionaryRef props = CGImageSourceCopyPropertiesAtIndex(imageSourceRef, 0, NULL); 

NSDictionary *properties = (NSDictionary*)CFBridgingRelease(props); 

if (!properties) { 
    return; 
} 

NSNumber *height = [properties objectForKey:@"PixelHeight"]; 
NSNumber *width = [properties objectForKey:@"PixelWidth"]; 
int height = 0; 
int width = 0; 

if (height) { 
    height = [height intValue]; 
} 
if (width) { 
    width = [width intValue]; 
}