lna*_*ger 8 objective-c cgimage ios alasset alassetslibrary
我一整天都在研究这个问题,并在SO和google上看了很多问题,但到目前为止我还没有提出任何正确的问题.
我在运行iOS 5.1.1的iPad上拍了一张照片,并使用照片应用裁剪了它.然后我从资产库中获取它的引用,并获得未裁剪的全分辨率图像.
我发现裁剪信息包含在我对象的AdjustmentXMP
键中.metadata
ALAssetRepresentation
所以我使用XMP信息裁剪照片,这是我得到的:
原始照片(1,936 x 2,592):
正确裁剪的照片,如照片应用程序(1,420 x 1,938)中所示:
使用下面的代码裁剪照片
(也是1,420 x 1,938,但是在右边太远处裁剪了大约200像素):
这是照片中的XMP数据:
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="XMP Core 4.4.0">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:aas="http://ns.apple.com/adjustment-settings/1.0/">
<aas:AffineA>1</aas:AffineA>
<aas:AffineB>0</aas:AffineB>
<aas:AffineC>0</aas:AffineC>
<aas:AffineD>1</aas:AffineD>
<aas:AffineX>-331</aas:AffineX>
<aas:AffineY>-161</aas:AffineY>
<aas:CropX>0</aas:CropX>
<aas:CropY>0</aas:CropY>
<aas:CropW>1938</aas:CropW>
<aas:CropH>1420</aas:CropH>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
Run Code Online (Sandbox Code Playgroud)
这是我用于裁剪照片的代码:
ALAssetRepresentation *rep = // Get asset representation
CGImageRef defaultImage = [rep fullResolutionImage];
// Values obtained from XMP data above:
CGRect cropBox = CGRectMake(0, 0, 1938, 1420);
CGAffineTransform transform = CGAffineTransformMake(1, 0, 0, 1, 331, 161);
// Apply the Affine Transform to the crop box:
CGRect transformedCropBox = CGRectApplyAffineTransform(cropBox, transform);
// Created a new cropped image:
CGImageRef croppedImage = CGImageCreateWithImageInRect(defaultImage, transformedCropBox);
// Create the UIImage:
UIImage *image = [UIImage imageWithCGImage:croppedImage scale:[rep scale] orientation:[rep orientation]];
CGImageRelease(croppedImage);
Run Code Online (Sandbox Code Playgroud)
我用多张图片重现了这个问题.如果我只是使用fullScreenImage
它完美显示,但我需要全尺寸图像.
Kur*_*vis 11
这是一个棘手的问题!显然没有关于此XMP数据的文档,因此我们必须猜测如何解释它.有许多选择可做,而错误导致产生微妙错误的结果.
TL; DR:理论上你的代码看起来是正确的,但实际上它给出了错误的结果,我们可以尝试一个相当明显的调整.
图像文件可以包含额外的元数据,指定在显示时是否应该(以及如何)旋转和/或翻转图像的原始数据.UIImage
用它的imageOrientation
属性来表达这一点,并且ALAssetRepresentation
是类似的.
但是,CGImage
s只是位图,没有存储方向.-[ALAssetRepresentation fullResolutionImage]
为您提供CGImage
原始方向,不应用任何调整.
在您的情况下,方向是3
,意义ALAssetOrientationRight
或UIImageOrientationRight
.查看软件(例如UIImage
)查看此值,看到图像朝向右90°(顺时针),然后向左旋转90°(逆时针),然后再显示它.或者,换句话说,CGImage
从您在屏幕上看到的图像顺时针旋转90°.
(为了验证这一点,使用CGImageGetWidth()
和得到CGImage的宽度和高度CGImageGetHeight()
.你应该发现CGImage是2592宽和1936高.它旋转了90° ALAssetRepresentation
,它dimensions
应该是1936宽,高2592.你也可以UIImage
从CGImage
使用正常方向创建一个UIImageOrientationUp
,写入UIImage
文件,看看它是什么样的.)
XMP字典中的值似乎与CGImage
方向相关.例如,裁剪矩形比它高,X平移大于Y平移等.有意义.
我们还必须决定XMP值应该在哪个坐标系中.很可能它是这两个中的一个:
CGImageCreateWithImageInRect()
以rect
这种方式解释其论点.让我们假设"翻转"是正确的,因为它通常更方便.无论如何,你的代码已经尝试这样做了.
字典包含仿射变换和裁剪矩形.我们猜测应该按此顺序解释:
如果我们手动尝试,这些数字似乎有效.这是一个粗略的图表,裁剪矩形为半透明的紫色:
在调用CG时,我们实际上不必遵循这些确切的步骤,但我们应该像我们一样行事.
我们只想打电话CGImageCreateWithImageInRect
,而且很明显如何计算合适的裁剪矩形(331,161,1938,1420)
.您的代码似乎正确执行此操作.
如果我们将图像裁剪到该矩形,然后UIImage
从中创建一个(指定正确的方向UIImageOrientationRight
),那么我们应该得到正确的结果.
但是,结果是错误的! 你得到的就像我们在笛卡尔坐标系中进行操作一样:
或者,就像图像旋转方向相反UIImageOrientationLeft
,但我们保持相同的裁剪矩形:
这一切都很奇怪,我不明白出了什么问题,尽管我很乐意.
但修复似乎相当简单:只需翻转剪辑矩形即可.在计算之后如上:
// flip the transformedCropBox in the image
transformedCropBox.origin.y = CGImageGetHeight(defaultImage) - CGRectGetMaxY(transformedCropBox);
Run Code Online (Sandbox Code Playgroud)
那样有用吗?(对于这种情况,以及其他方向的图像?)