AssetsLibrary.framework
でカメラロールから生の画像データが取り出せるほか、ただ UIImagePickerController
を使うのに比べ柔軟にいろいろなことができる。それで、そのままふつうに使っていて遭遇する問題のひとつが、iOS 標準の写真アプリによる画像の加工に対応できないことであった。
「写真.app」では、カメラロールの写真に対しトリミングや自動補正、赤目補正などの加工を行うことができる。UIImagePickerControllerDelegate
の - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
メソッドで UIImagePickerControllerEditedImage
を info
から取り出せば、この加工後の画像を得ることができる。
AssetsLibrary.framework
を使って得られる画像には、写真.appで行った編集が反映されていない。写真.app による編集は Adobe の XMP フォーマットによってメタデータとして格納されている。これを再現するのは非常に困難だと考えられていた。
しかし CoreImage.framework
の CIFilter
クラスに + (NSArray)filterArrayFromSerializedXMP:(NSData )xmpData inputImageExtent:(CGRect)extent error:(NSError **)outError というメソッドがあると id:ninjinkun さんにより発見される。CIFilter
は一連のフィルターによる効果を XMP フォーマットでシリアライズ/デシリアライズする仕組みを備えていた。
+ (NSData*)serializedXMPFromFilters:(NSArray *)filters inputImageExtent:(CGRect)extent
+ (NSArray*)filterArrayFromSerializedXMP:(NSData *)xmpData inputImageExtent:(CGRect)extent error:(NSError **)outError
この CIFilter
のふたつのクラスメソッドを用いることで XMP データと CIFilter
の配列を相互に変換可能である。(ちなみに OS X にはない)
XMPからCIFilter作ってカメラロールで適用した画像操作を再現できるっぽい / “ios - Interpret XMP-Metadata in ALAssetRepresentation - Stack Overflow” http://t.co/3ZfxjJPW1o
— ninjinkun (@ninjinkun) May 14, 2013
ただしこれは iOS 6 以降でしか使えない。iOS 5 もある程度考慮したコードは以下のようになるはず。
ALAssetRepresentation *representation = imageAsset.defaultRepresentation; NSString *XMPString = representation.metadata[@"AdjustmentXMP"]; NSData *XMP = [XMPString dataUsingEncoding:NSUTF8StringEncoding]; UIImage *editedImage; if (XMP && [[CIFilter class] respondsToSelector:@selector(filterArrayFromSerializedXMP:inputImageExtent:error:)]) { CIImage *image = [CIImage imageWithCGImage:representation.fullResolutionImage]; NSError *error = nil; NSArray *filters = [CIFilter filterArrayFromSerializedXMP:XMP inputImageExtent:image.extent error:&error]; if (error) { NSLog(@"Error during CIFilter creation: %@", error); } CIContext *context = [CIContext contextWithOptions:nil]; for (CIFilter *filter in filters) { [filter setValue:image forKey:kCIInputImageKey]; image = filter.outputImage; } editedImage = [UIImage imageWithCGImage:[context createCGImage:image fromRect:image.extent]]; } else { editedImage = [UIImage imageWithCGImage:representation.fullResolutionImage scale:representation.scale orientation:(UIImageOrientation)representation.orientation]; }
注意点があり、この方法では赤目補正が効かない。赤目補正のフィルターは CIRedEyeCorrections という名前であるはずだが、Core Image Filter Reference には記載されていない。何らかの理由で使用できない状態に置かれているものとみられ、写真.app でのみ使えているようである。
適当に自動補正してトリミングした写真を再現するときの CIFilter の名前を以下に列挙する。
CIVibrance CIToneCurve CIHighlightShadowAdjust CIAffineTransform CICrop
このようなフィルターが写真.app では使われているようだ。
以上の方法で、iOS 6 以降については問題が解決され、AssetsLibrary.framework
を安心して使うことができる。
ということで、画像アップロードの際に写真.appでのトリミング操作が反映されるようになったはてなブログiPhoneアプリをどうぞご利用ください。
追記 (2013/12/11)
iOS 7のシミュレータで試したところ赤目補正が効いていた。
ログの様子
CIRedEyeCorrections: inputImage=nil inputCameraModel=nil inputCorrectionInfo=( { averageSkinLuminance = "0.3176471"; bitmaskThreshold = "0.07450981"; bitmaskX = "0.2054794"; bitmaskY = "0.4444444"; cornealReflectionThreshold = "0.8941177"; cornealReflectionX = "0.2100457"; cornealReflectionY = "0.4461806"; existingPupilAverage = "0.2156863"; existingPupilHigh = "0.4470589"; existingPupilLow = 0; existingPupilMedium = "0.1843137"; finalEyeCase = 0; forceCase = 0; fullImageHeight = 576; fullImageWidth = 438; imageOrientation = 1; imageSignalToNoiseRatio = 20; imageSpecialValue = 0; interocularDistance = 0; pointX = "0.2009132"; pointY = "0.4461806"; pupilShadeAlignment = 0; pupilShadeAverage = 0; pupilShadeHigh = 0; pupilShadeLow = 0; pupilShadeMedium = 0; repairRectangleMaximumX = "0.2465753"; repairRectangleMaximumY = "0.421875"; repairRectangleMinimumX = "0.1780822"; repairRectangleMinimumY = "0.4704861"; searchRectangleMaximumX = "0.3013698"; searchRectangleMaximumY = "0.3697917"; searchRectangleMinimumX = "0.1050228"; searchRectangleMinimumY = "0.5190972"; size = "0.01185013"; snappedX = "0.2009132"; snappedY = "0.4461806"; }, { averageSkinLuminance = "0.3529412"; bitmaskThreshold = "0.007843138"; bitmaskX = "0.4611872"; bitmaskY = "0.46875"; cornealReflectionThreshold = "0.9333334"; cornealReflectionX = "0.4611872"; cornealReflectionY = "0.4652778"; existingPupilAverage = "0.1764706"; existingPupilHigh = "0.4117647"; existingPupilLow = 0; existingPupilMedium = "0.1490196"; finalEyeCase = 0; forceCase = 0; fullImageHeight = 576; fullImageWidth = 438; imageOrientation = 1; imageSignalToNoiseRatio = 20; imageSpecialValue = 0; interocularDistance = 0; pointX = "0.4657534"; pointY = "0.4704861"; pupilShadeAlignment = 0; pupilShadeAverage = 0; pupilShadeHigh = 0; pupilShadeLow = 0; pupilShadeMedium = 0; repairRectangleMaximumX = "0.4931507"; repairRectangleMaximumY = "0.4392361"; repairRectangleMinimumX = "0.4292237"; repairRectangleMinimumY = "0.4913194"; searchRectangleMaximumX = "0.56621"; searchRectangleMaximumY = "0.3940972"; searchRectangleMinimumX = "0.369863"; searchRectangleMinimumY = "0.5434028"; size = "0.0124749"; snappedX = "0.4657534"; snappedY = "0.4704861"; } )>
@hkato193 @itok_twit @norio_nomura いまシミュレータで試した感じだとiOS 7では赤目補正が効くようでした。CIFilterの中にCIRedEyeCorrectionsっていうのが入っているし、見た目にも適用されているのが確認できました。
— Hiroki Kato (@cockscomb) 2013, 12月 11