본문 바로가기

iOS

[iOS] ALAsset으로 Custom Image 생성하기

iOS4.0 부터 지원하는 ALAssetLibrary framework를 사용하면 UIImagePickerController를 사용하지 않아도 사용자 iOS기기에 저장되어 있는 사진 또는 비디오를 가져 올수 있다. 


ALAasetLibrary는 크게 ALAasetsLibrary > ALAssetsGroup > ALAsset 으로 이루어져 있고, ALAssetLibrary를 통해 ALAssetsGroup를 부르고 ALAssetsGroup을 통해 최종적으로 사진 또는 비디오 정보를 가지고 있는 ALAsset을 가져 온다. 이 문서는 ALAssetLibrary 자체를 다루는 내용이 아니기 때문에 불러오는 방법에 대해서는 생략 한다.


ALAsset 클래스를 보면 defaultRepresentation 이 있고 여기에 실제 이미지 정보를 가지고 있다. 물론 Exif 정보나 thumbnail은 defaultRepresentation을 거치지 않아도 ALAsset을 통해 바로 불러 올수 있다.


thumbnail, fullscreenImage, fullResolutionImage를 불러오는 방법은 다음과 같다.



// thumbnail
CGImageRef imageRef = CGImageCreateCopy(asset.thumbnail); UIImage *thumbnail = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); // fullScreen 화면에 맞는 크기의 이미지 CGImageRef imageRef = CGImageCreateCopy(asset.defaultRepresentation.fullScreenImage); UIImage *fullScreenImage = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); // fullResolution 원본 이미지 CGImageRef imageRef = CGImageCreateCopy(asset.defaultRepresentation.fullResolutionImage); UIImage *fullResolutionImage = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef);


위의 3가지 크기를 이용하면 대부분의 앱개발이 가능 하겠지만, fullScreenImage, fullResolutionImage는 생성을 할때 많은 연산이 필요로 하므로 Performance에 문제가 생길수도 있다. 예를 들어 UITableView에서 fullScreenImage를 동시에 여러개를 생성한다면 어느 디바이스건 UI가 얼어 버리는 현상이 발생한다. 


그럼 fullScreenImage 보다는 작지만 thumbnail 보단 큰 이미지를 생성하려면 어떻게 해야 하는가? (fullScreenImage 보다 작은 이미지를 생성한다면 UI가 얼어 버리는 현상 발생 빈도를 줄어 들게 할 수 있을것이다)


필자가 찾은 방법은 AssetRePresentation의 getBytes를 통해 사진 또는 비디오에 대한 데이터를 불러온 뒤에 해당 데이터를 통해 CGImageRef를 생성하는 방법이다. 전달하는 size를 통해 이미지 크기를 조절 할 수 있다.

- (CGImageRef)getThumbnailWithALAsset:(ALAsset *)asset withSize:(float)size { ALAssetRepresentation *representation = asset.defaultRepresentation; CGImageRef imageRef = nil; NSData *data = nil; uint8_t *buffer = (uint8_t *)malloc(sizeof(uint8_t)*[representation size]); if (buffer != NULL) { NSError *error = nil; NSUInteger bytesRead = [representation getBytes:buffer fromOffset:0 length:[representation size] error:&error]; data = [NSData dataWithBytes:buffer length:bytesRead]; free(buffer); } if ([data length]) { CGImageSourceRef sourceRef = CGImageSourceCreateWithData((CFDataRef)data, nil); NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: (id)kCFBooleanTrue, kCGImageSourceCreateThumbnailFromImageIfAbsent, (id)kCFBooleanTrue, kCGImageSourceCreateThumbnailFromImageAlways, (id)[NSNumber numberWithFloat:size], kCGImageSourceThumbnailMaxPixelSize, (id)kCFBooleanTrue, kCGImageSourceCreateThumbnailWithTransform, nil]; imageRef = CGImageSourceCreateThumbnailAtIndex(sourceRef, 0, (CFDictionaryRef)options); if (sourceRef) CFRelease(sourceRef); } return imageRef;

}


위의 방법으로 생성된 CGImageRef 를 이용하여 이미지를 생성하면 된다. 단 비디오일 경우 AssetRepresentation을 메모리에 올리는 과정에서 비디오의 길이가 길 경우 (용량이 클 경우) 메모리 부족으로 앱이 죽어 버리는 경우가 있으니 ALAsset이 비디오일 경우에는 기존의 AssetRepresentation의 fullScreenImage 또는 fullResolution을 이용하는게 좋다.


또한 위의 방법을 이용하여 많은 이미지를 동시에 생성할 경우 생성할 당시 메모리가 많이 필요하므로 상황에 따라 주의에서 사용할 필요가 있다. 필자는 아직까진 이미지를 생성하면서 메모리가 부족에서 앱이 죽어 버리는 현상은 없었다. (단 ALAsset이 비디오일 때는 앱이 죽을수도 있다)