Get size of image without loading in to memory

2020-03-02 01:55发布

I have several .png images (ETA: but the format could also be JPEG or something else) that I am going to display in UITableViewCells. Right now, in order to get the row heights, I load in the images, get their size properties, and use that to figure out how high to make the rows (calculating any necessary changes along the way, since most of the images get resized before being displayed). In order to speed things up and reduce memory usage, I'd like to be able to get size without loading the images. Is there a way to do this?

Note: I know that there are a number of shortcuts I could implement to eliminate this issue, but for several reasons I can't resize images in advance or collect the image sizes in advance, forcing me to get this info at run time.

8条回答
够拽才男人
2楼-- · 2020-03-02 02:11

imageUrl is an NSURL, also import ImageIO/ImageIO.h with <> around it.

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];
}
查看更多
We Are One
3楼-- · 2020-03-02 02:16

As of iOS SDK 4.0, this task can be accomplished with the ImageIO framework (CGImageSource...). I have answered a similar question here.

查看更多
贪生不怕死
4楼-- · 2020-03-02 02:16

It should be pretty simple. PNG spec has an explanation of a PNG datastream (which is effectively a file). IHDR section contains information about image dimensions.

So what you have to do is to read in PNG "magic value" and then read two four-byte integers, which will be width and height, respectively. You might also need to reorder bits in these values (not sure how are they stored), but once you figure that out, it will be very simple.

查看更多
在下西门庆
5楼-- · 2020-03-02 02:16

Try using the CGImageCreateWithPNGDataProvider and CGImageCreateWithJPEGDataProvider functions. I don't know whether they're lazy enough or not, or whether that's even possible for JPEG, but it's worth trying.

查看更多
聊天终结者
6楼-- · 2020-03-02 02:18

//Here's a quick & dirty port to 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);

}

查看更多
我只想做你的唯一
7楼-- · 2020-03-02 02:19

This is nicely implemented in Perl's Image::Size module for about a dozen formats -- including PNG and JPEG. In order to re-implement it in Objective C just take the perl code and read it as pseudocode ;-)

For instance, pngsize() is defined as

# 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 is only a few lines longer.

查看更多
登录 后发表回答