ALAsset Image Size

2019-05-06 21:19发布

Given an ALAsset that represents a photo, is it possible to retrieve the size of the photo (height and width) without loading the image into a UIImageView and also without using the aspectRationThumnail method?

5条回答
淡お忘
2楼-- · 2019-05-06 22:02

Just a note: iOS 5.1 introduces a new property dimensions for an ALAssetRepresentation instance. This returns a CGSize structure with the dimensions of the original image and might be the best solution for this problem in the future.

Cheers,

Hendrik

查看更多
狗以群分
3楼-- · 2019-05-06 22:10
float width = asset.defaultRepresentation.dimensions.width;
float height = asset.defaultRepresentation.dimensions.height;

it fast, stable, and gives the actual dimensions. I've used it with ALAsset of videos.

查看更多
等我变得足够好
4楼-- · 2019-05-06 22:10
float width = CGImageGetWidth(asset.defaultRepresentation.fullResolutionImage);
float height = CGImageGetHeight(asset.defaultRepresentation.fullResolutionImage);

or same for asset.defaultRepresentation.fullScreenImage...

查看更多
做个烂人
5楼-- · 2019-05-06 22:11

A simpler way to access the image size is through [ALAssetRepresentation metadata]. On the images I tested on, this NSDictionary contained keys named PixelWidth and PixelHeight, which were NSNumber objects with the values you'd expect.

However, there seem to be no particular guarantees about the exact keys you'll find, so make sure your app can deal with cases where those keys aren't in the metadata. Also see iOS ALAsset image metadata for some cautions about speed and thread safety.

Comparison

I tested both methods - loading the image data in CGImageSourceRef or reading the metadata - on my iPad's entire asset library. Both methods returned the same sizes to within FLT_EPSILON. Apart from 2 outliers which took double time, the run times out of 16 repetitions were very similar:

Method                     | Mean time +/- 95% confidence
Size from CGImageSourceRef |    0.1787 +/- 0.0004
Size from metadata         |    0.1789 +/- 0.0015

So, neither method has a performance benefit. It is entirely possible that the metadata dictionary is constructed on demand by reading the image data.

查看更多
混吃等死
6楼-- · 2019-05-06 22:22

Update

This didn't work as originally offered, as noted in the comments. I've fixed it, but it now loads all the image data, which the OP was trying to avoid. It still avoids the additional, and still worse step, of decompressing the data into an image.

  1. Get the defaultRepresentation of the ALAsset.
  2. Get the data for the ALAssetRepresentation.
  3. Use an adaptation of this handy sizeOfImageAtURL function. Thank you, shpakovski.

The code below represents the steps above.

// This method requires the ImageIO.framework
// This requires memory for the size of the image in bytes, but does not decompress it.
- (CGSize)sizeOfImageWithData:(NSData*) data;
{
    CGSize imageSize = CGSizeZero;
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef) data, NULL);
    if (source)
    {
        NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:NO] forKey:(NSString *)kCGImageSourceShouldCache];

        NSDictionary *properties = (__bridge_transfer NSDictionary*) CGImageSourceCopyPropertiesAtIndex(source, 0, (__bridge CFDictionaryRef) options);

        if (properties)
        {
            NSNumber *width = [properties objectForKey:(NSString *)kCGImagePropertyPixelWidth];
            NSNumber *height = [properties objectForKey:(NSString *)kCGImagePropertyPixelHeight];
            if ((width != nil) && (height != nil))
                imageSize = CGSizeMake(width.floatValue, height.floatValue);
        }
        CFRelease(source);
    }
    return imageSize;
}

- (CGSize)sizeOfAssetRepresentation:(ALAssetRepresentation*) assetRepresentation;
{
    // It may be more efficient to read the [[[assetRepresentation] metadata] objectForKey:@"PixelWidth"] integerValue] and corresponding height instead.
    // Read all the bytes for the image into NSData.
    long long imageDataSize = [assetRepresentation size];
    uint8_t* imageDataBytes = malloc(imageDataSize);
    [assetRepresentation getBytes:imageDataBytes fromOffset:0 length:imageDataSize error:nil];
    NSData *data = [NSData dataWithBytesNoCopy:imageDataBytes length:imageDataSize freeWhenDone:YES];

    return [self sizeOfImageWithData:data];
}

- (CGSize)sizeOfAsset:(ALAsset*) asset;
{
    return [self sizeOfAssetRepresentation:[asset defaultRepresentation]];
}
查看更多
登录 后发表回答