What is the correct way to import & save Photos fr

2019-01-31 15:27发布

I am Importing Photos from the iPhone Album to the documents folder of my application. This is my code.

for (int j=0; j<[assetArray count]; j++) {

    ALAsset *assest = [assetArray objectAtIndex:j];
    CGImageRef imageRef = assest.defaultRepresentation.fullResolutionImage;
    UIImage *image = [UIImage imageWithCGImage:imageRef];
    NSData *imageData = UIImageJPEGRepresentation(image);
    [imageData writeToFile:documentsPath atomically:YES];
}

Its working fine but when I try to Import higher resolution Images it takes more time. What is the correct way to Import with least time? BTW: It takes more time when I convert the image into NSData.

2条回答
Summer. ? 凉城
2楼-- · 2019-01-31 16:00

It's dangerous to use the fullResolutionImage for this task for several reasons. Some remarks:

  1. For large images memory problems could occur. when using the fullResolutionImage method. Please note, that the Photo-Library (on the iPad at least) can also contain RAW-images.
  2. The performance is suboptimal as internally from the imagefile ImageIO creates first a CGImageRef that is then converted to a JPEG. This takes time.
  3. The AssetLibrary can also contain videos. In such a case fullResolutionImage only returns a previewImage of the video, but not the actual video.
  4. It's no problem to store the actual Asset-Objects as these are small in memory.

A far better approach to write out the images to the documents directory, would be to use the getBytes method of ALAssetsRepresentation. This should be way faster and more efficient memory wise. It also gives you the original image file (incl. metadata) and also works for videos.

Your example code rewritten then would look like that:

//reading out the orginal images
    for (int j=0; j<[assetArray count]; j++) {

    ALAssetRepresentation *representation = [[assetArray objectAtIndex:j] defaultRepresentation];
    NSString* filename = [documentPath stringByAppendingPathComponent:[representation filename]];

    [[NSFileManager defaultManager] createFileAtPath:filename contents:nil attributes:nil];
    NSOutputStream *outPutStream = [NSOutputStream outputStreamToFileAtPath:filename append:YES];
    [outPutStream open];

    long long offset = 0;
    long long bytesRead = 0;

    NSError *error;
    uint8_t * buffer = malloc(131072);
    while (offset<[representation size] && [outPutStream hasSpaceAvailable]) {
        bytesRead = [representation getBytes:buffer fromOffset:offset length:131072 error:&error];
        [outPutStream write:buffer maxLength:bytesRead];
        offset = offset+bytesRead;
    }
    [outPutStream close];
    free(buffer);
}


//reading out the fullScreenImages and thumbnails
for (int j=0; j<[assetArray count]; j++) 
{
    @autoreleasepool
    {

        ALAsset *asset = [assetArray objectAtIndex:j];

         NSString *orgFilename = [representation filename];
         NSString *filenameFullScreen = [NSString stringWithFormat:@"%@_fullscreen.png",[orgFilename stringByDeletingPathExtension]]
         NSString* pathFullScreen = [documentPath stringByAppendingPathComponent:filenameFullScreen];

         CGImageRef imageRefFullScreen = [[asset defaultRepresentation] fullScreenImage];
         UIImage *imageFullScreen = [UIImage imageWithCGImage:imageRefFullScreen];
         NSData *imageDataFullScreen = UIImagePNGRepresentation(imageFullScreen);
         [imageDataFullScreen writeToFile:pathFullScreen atomically:YES];

         NSString *filenameThumb = [NSString stringWithFormat:@"%@_thumb.png",[orgFilename stringByDeletingPathExtension]]
         NSString* pathThumb = [documentPath stringByAppendingPathComponent:filenameThumb];

         CGImageRef imageRefThumb = [asset thumbnail];
         UIImage *imageThumb = [UIImage imageWithCGImage:imageRefThumb];
         NSData *imageDataThumb = UIImagePNGRepresentation(imageThumb);
         [imageDataThumb writeToFile:pathThumb atomically:YES];

    }
}
查看更多
放我归山
3楼-- · 2019-01-31 16:00

I was using ELCImagePicker and was facing same problem while importing multiple photos at a time from photos library using asselts. We can not reduce time taken to import but crash issue will be resolved.

for (int j=0; j<[assetArray count]; j++) 
{
    @autoreleasepool // This is compiler level feature so will only work on xcode 4.1 or above
    {
         ALAsset *assest = [assetArray objectAtIndex:j];
         CGImageRef imageRef = assest.defaultRepresentation.fullResolutionImage;
         UIImage *image = [UIImage imageWithCGImage:imageRef];
         NSData *imageData = UIImagePNGRepresentation(image);
         [imageData writeToFile:documentsPath atomically:YES];
    }
}

If possible try to store only AssetURL in assetArray instead of whole ALAsset object and create ALAsset at a time from url so may be it helps to reduce memory consumption. In such case you will need to use blocks as

ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
    CGImageRef iref = [[myasset defaultRepresentation] fullResolutionImage];
    if (iref) //You have image so use it 
    {
    }
};

ALAssetsLibraryAccessFailureBlock failureblock  = ^(NSError *myerror)
{
    NSLog(@"Can't get image - %@",[myerror localizedDescription]);
};

ALAssetsLibrary* assetslibrary = [[[ALAssetsLibrary alloc] init] autorelease];
[assetslibrary assetForURL:imageURL resultBlock:resultblock failureBlock:failureblock];
查看更多
登录 后发表回答