我一整天都在研究这个问题,并且已经在SO和google上查看了很多问题,但到目前为止我还没有想出任何正确的事情。
我在运行iOS 5.1.1的iPad上拍了照片,并使用照片应用裁剪了它。然后我从资产库中获取它的引用,并获得未裁剪的全分辨率图像。
我发现裁剪信息包含在AdjustmentXMP
对象metadata
的{{1}}键中。
所以我使用XMP信息裁剪照片,这是我得到的:
原始照片(1,936 x 2,592):
正确裁剪的照片,如照片应用程序(1,420 x 1,938)中所示:
使用以下代码剪裁的照片
(也是1,420 x 1,938但是在右边太远的地方裁剪了大约200像素):
这是照片中的XMP数据:
ALAssetRepresentation
以下是我用于裁剪照片的代码:
<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>
我用多张图片重现了这个问题。如果我只使用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);
它会完美显示,但我需要全尺寸图像。
答案 0 :(得分:11)
这是一个棘手的问题!显然没有关于此XMP数据的文档,因此我们必须猜测如何解释它。有许多选择可做,而错误导致产生微妙错误的结果。
TL; DR:理论上你的代码看起来是正确的,但实际上它给出了错误的结果,我们可以尝试进行相当明显的调整。
图像文件可能包含其他元数据,指定在显示时是否(以及如何)旋转和/或翻转图像的原始数据。 UIImage
使用imageOrientation
属性和ALAssetRepresentation
is similar表达了这一点。
但是,CGImage
只是位图,没有存储方向。 -[ALAssetRepresentation fullResolutionImage]
以原始方向为您提供CGImage
,未应用任何调整。
在您的情况下,方向为3
,表示ALAssetOrientationRight
或UIImageOrientationRight
。查看软件(例如,UIImage
)查看此值,看到图像朝向右90°(顺时针),然后向左旋转90°(逆时针),然后再显示它。或者,换句话说,CGImage
从您在屏幕上看到的图像顺时针旋转90°。
(为了验证这一点,使用CGImageGetWidth()
和CGImageGetHeight()
获取CGImage的宽度和高度。你会发现CGImage是2592宽和1936高。这是从旋转90° ALAssetRepresentation
,其dimensions
应该是1936宽,高度为2592。您还可以使用正常方向UIImage
从CGImage
创建UIImageOrientationUp
,写下{ {1}}到一个文件,看看它是什么样的。)
XMP词典中的值似乎与UIImage
的方向相关。例如,裁剪矩形比它高,X平移大于Y平移等。有道理。
我们还必须决定XMP值应该在哪个坐标系中。很可能它是这两个中的一个:
CGImageCreateWithImageInRect()
以这种方式解释其CGImage
参数。让我们假设“翻转”是正确的,因为它通常更方便。无论如何,你的代码已经尝试这样做了。
字典包含仿射变换和裁剪矩形。我们猜测它应按此顺序解释:
如果我们手动尝试,这些数字似乎有用。这是一个粗略的图表,裁剪矩形为半透明的紫色:
在调用CG时,我们实际上不必遵循这些确切的步骤,但我们应该像我们一样行事。
我们只想调用rect
,而且很明显如何计算合适的裁剪矩形CGImageCreateWithImageInRect
。您的代码似乎正确执行此操作。
如果我们将图片裁剪到该矩形,然后从中创建(331,161,1938,1420)
(指定正确的方向,UIImage
),那么我们应该得到正确的结果。
但是,结果是错误的!你得到的是好像我们在笛卡尔坐标系中进行了操作:
或者,就好像图像以相反的方向旋转UIImageOrientationRight
,但我们保持相同的裁剪矩形:
这一切都很奇怪,我不明白出了什么问题,虽然我很乐意。
但修复似乎相当简单:只需翻转剪辑矩形即可。按上述方法计算后:
UIImageOrientationLeft
这有用吗? (对于这种情况,以及其他方向的图像?)