Iphone 获取图像大小而不加载到内存中

Iphone 获取图像大小而不加载到内存中,iphone,cocoa,cocoa-touch,uikit,core-graphics,Iphone,Cocoa,Cocoa Touch,Uikit,Core Graphics,我有几个.png图像(ETA:但格式也可以是JPEG或其他格式),我将在UITableViewCells中显示。现在,为了获得行高度,我加载图像,获取它们的大小属性,并使用该属性计算行的高度(计算沿途的任何必要更改,因为大多数图像在显示之前都会调整大小)。为了加快速度并减少内存使用,我希望能够在不加载图像的情况下获得大小。有办法做到这一点吗 注意:我知道有很多快捷方式可以解决这个问题,但由于一些原因,我无法提前调整图像大小或收集图像大小,迫使我在运行时获取这些信息。这应该很简单。对(实际上是一个

我有几个
.png
图像(ETA:但格式也可以是JPEG或其他格式),我将在
UITableViewCell
s中显示。现在,为了获得行高度,我加载图像,获取它们的
大小
属性,并使用该属性计算行的高度(计算沿途的任何必要更改,因为大多数图像在显示之前都会调整大小)。为了加快速度并减少内存使用,我希望能够在不加载图像的情况下获得
大小。有办法做到这一点吗


注意:我知道有很多快捷方式可以解决这个问题,但由于一些原因,我无法提前调整图像大小或收集图像大小,迫使我在运行时获取这些信息。

这应该很简单。对(实际上是一个文件)进行了解释。节包含有关图像尺寸的信息


所以你要做的就是读入PNG的“魔法值”,然后读入两个四字节的整数,分别是宽度和高度。您可能还需要对这些值中的位进行重新排序(不确定它们是如何存储的),但一旦您弄明白了这一点,这将非常简单。

尝试使用and函数。我不知道他们是否足够懒惰,也不知道JPEG是否可能做到这一点,但值得一试。

这在Perl中很好地实现了大约十几种格式,包括PNG和JPEG。为了在Objective 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 tmetro@vl.com
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只长几行。

低技术解决方案:

如果您事先知道图像是什么,请将图像大小及其文件名存储在XML文件或plist(或您喜欢的任何方式)中,然后在中读取这些属性


如果您不知道图像是什么(即,它们将在运行时定义),那么您必须在某个时间加载图像。第一次加载时,请将其高度和宽度保存在文件中,以便以后访问。

注意:此功能不适用于iPhone压缩PNG,此压缩由XCode自动执行并更改图像标题,请参阅此处的更多详细信息以及如何禁用此功能:

PSFramework的未来版本也将解释此标题,请继续关注


看看这个函数,她就是这么做的。仅读取PNG文件的30个字节并返回大小(CGSize)。此函数是处理图像的框架PSFramework()的一部分。尚未为其他图像格式实现,欢迎开发人员。该项目是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 );

}
CGSize PSPNGSizeFromMetaData(NSString*anFileName){
//包路径中的文件名。
NSString*fullFileName=[NSString stringWithFormat:@“%@/%@”,[[NSBundle mainBundle]bundlePath],anFileName];
//文件名转换为C字符串。
常量字符*文件名=[fullFileName UTF8String];
/*源文件*/
文件*填充;
//检查是否可以打开该文件。
if((infle=fopen(文件名,“rb”))==NULL)
{
NSLog(@“PSFramework Warning>>(PSPNGSizeFromMetaData)无法打开文件:%@),anFileName;
返回cgizezero;
}
//////  //////  //////  //////  //////  //////  //////  //////  //////  //////  ////// 
//缓冲区长度。
#定义字节长度30
//字节缓冲区。
无符号字符缓冲区[字节长度];
//只抓取第一个字节。
fread(缓冲区,1,字节长度,填充);
//关闭文件。
fclose(infle);
//////  //////  //////  //////  ////// 
//PNG签名。
无符号字符png_签名[8]={137,80,78,71,13,10,26,10};
//比较文件签名。
if((int)(memcmp(&buffer[0],&png_签名[0,8])){
NSLog(@“PSFramework Warning>>(PSPNGSizeFromMetaData):文件(%@)不是一个PNG文件。”,anFileName);
返回cgizezero;
}
//////  //////  //////  //////  ////// //////   //////  //////  //////  ////// 
//计算大小。仅隔离每个大小(宽度、高度)的四个字节。
整数宽度[4];
整数高度[4];
对于(int d=16;d<(16+4);d++){
宽度[d-16]=缓冲区[d];
高度[d-16]=缓冲器[d+4];
}
//将字节转换为长(整数)

long resultWidth=(宽度[0]//这是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);

公共静态大小PNGSize(字符串文件名)
{
//PNG签名。
字节[]png_签名={137,80,78,71,13,10,26,10}

尝试 { 使用(FileStream-stream=File.OpenRead(文件名)) { 字节[]buf=新字节[30]; if(stream.Read(buf,0,30)==30) { int i=0; int imax=png_signature.Length; 对于(i=0;iint resultWidth=buf[16]从iOS SDK 4.0开始,这个任务可以通过ImageIO框架(
CGImageSource…
)来完成。我已经回答了。

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];
}

好主意,除了我忘了提到它可能不是PNG,这正是我现在碰巧拥有的(编辑后反映了这一点)。我至少也应该支持JPEG,尽管我想我可以用与您描述的类似的方式来实现。CGImageSource是实现这一点的完美API,但令人恼火的是它在iPhone上不可用。您可能需要自己实现它。也就是说,请记住UIImage将