I have some pretty basic code to capture a still image using AVFoundation.
我有一些非常基本的代码来使用AVFoundation捕获静态图像。
AVCaptureDeviceInput *newVideoInput = [[AVCaptureDeviceInput alloc] initWithDevice:[self backFacingCamera] error:nil];
AVCaptureStillImageOutput *newStillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys:
AVVideoCodecJPEG, AVVideoCodecKey,
nil];
[newStillImageOutput setOutputSettings:outputSettings];
[outputSettings release];
AVCaptureSession *newCaptureSession = [[AVCaptureSession alloc] init];
[newCaptureSession beginConfiguration];
newCaptureSession.sessionPreset = AVCaptureSessionPreset640x480;
[newCaptureSession commitConfiguration];
if ([newCaptureSession canAddInput:newVideoInput]) {
[newCaptureSession addInput:newVideoInput];
}
if ([newCaptureSession canAddOutput:newStillImageOutput]) {
[newCaptureSession addOutput:newStillImageOutput];
}
self.stillImageOutput = newStillImageOutput;
self.videoInput = newVideoInput;
self.captureSession = newCaptureSession;
[newStillImageOutput release];
[newVideoInput release];
[newCaptureSession release];
My method that captures the still image is also pretty simple and prints out the orientation which is AVCaptureVideoOrientationPortrait:
我捕获静止图像的方法也非常简单,并打印出AVCaptureVideoOrientationPortrait的方向:
- (void) captureStillImage
{
AVCaptureConnection *stillImageConnection = [AVCamUtilities connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]];
if ([stillImageConnection isVideoOrientationSupported]){
NSLog(@"isVideoOrientationSupported - orientation = %d", orientation);
[stillImageConnection setVideoOrientation:orientation];
}
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:stillImageConnection
completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
ALAssetsLibraryWriteImageCompletionBlock completionBlock = ^(NSURL *assetURL, NSError *error) {
if (error) { // HANDLE }
};
if (imageDataSampleBuffer != NULL) {
CFDictionaryRef exifAttachments = CMGetAttachment(imageDataSampleBuffer, kCGImagePropertyExifDictionary, NULL);
if (exifAttachments) {
NSLog(@"attachements: %@", exifAttachments);
} else {
NSLog(@"no attachments");
}
self.stillImageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
self.stillImage = [UIImage imageWithData:self.stillImageData];
UIImageWriteToSavedPhotosAlbum(self.stillImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
else
completionBlock(nil, error);
}];
}
So the device understands it's in portrait mode as it should be, the exif attachements show me:
所以设备理解它应该是纵向模式,exif附件显示我:
PixelXDimension = 640;
PixelYDimension = 480;
so it seems to know that we're in 640x480 and that means WxH (obviously...)
所以它似乎知道我们在640x480,这意味着WxH(显然......)
However when I email the photo to myself from Apples Photos app, I get a 480x640 image if I check the properties in Preview. This didn't make any sense to me until I dug further into image properties to find out that the image orientation is set to "6 (Rotated 90 degrees CCW)" I'm sure CCW is counter clockwise
然而,当我从Apples Photos应用程序通过电子邮件将照片发送给自己时,如果我在预览中检查属性,则会获得480x640的图像。这对我来说没有任何意义,直到我进一步挖掘图像属性,发现图像方向设置为“6(旋转90度CCW)”我确定CCW是逆时针
So looking at the image in a browser: http://tonyamoyal.com/stuff/things_that_make_you_go_hmm/photo.JPG We see a the image rotated 90 degrees CCW and it is 640x480.
所以在浏览器中查看图像:http://tonyamoyal.com/stuff/things_that_make_you_go_hmm/photo.JPG我们看到图像旋转90度CCW,它是640x480。
I'm really confused about this behavior. When I take a 640x480 still image using AVFoundation, I would expect the default to have no rotated orientation. I expect a 640x480 image oriented exactly as my eye sees the image in the preview layer. Can someone explain why this is happening and how to configure the capture so that when I save my image to the server to later display in a web view, it is not rotated 90 degrees CCW?
我对这种行为感到很困惑。当我使用AVFoundation拍摄640x480静止图像时,我希望默认情况下没有旋转方向。我期待一个640x480的图像,就像我的眼睛看到预览图层中的图像一样。有人可以解释为什么会发生这种情况以及如何配置捕获,以便当我将图像保存到服务器以便稍后在Web视图中显示时,它不会旋转90度CCW?
1 个解决方案
#1
33
This happens because the orientation set in the metadata of the new image is being effected by the orientation of the AV system that creates it. The layout of the actual image data is of course different from the orientation mentioned in your metadata. Some image viewing programs respect the metadata orientation, some ignore it.
发生这种情况是因为在新图像的元数据中设置的方向受到创建它的AV系统的方向的影响。实际图像数据的布局当然不同于元数据中提到的方向。一些图像查看程序尊重元数据方向,有些则忽略它。
You can affect the metadata orientation of the AV system by calling:
您可以通过调用以下方式影响AV系统的元数据方向:
AVCaptureConnection *videoConnection = ...;
if ([videoConnection isVideoOrientationSupported])
[videoConnection setVideoOrientation:AVCaptureVideoOrientationSomething];
You can affect the metadata orientation of a UIImage by calling:
您可以通过调用以下内容来影响UIImage的元数据方向:
UIImage *rotatedImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:1.0f orientation:UIImageOrientationSomething];
But the actual data from the AVCapture system will always appear with the wider dimension as X and the narrower dimension as Y, and will appear to be oriented in LandscapeLeft.
但是来自AVCapture系统的实际数据将始终显示为更宽的尺寸为X,更窄的尺寸为Y,并且看起来将面向LandscapeLeft。
If you want the actual data to line up with what your metadata claims, you need to modify the actual data. You can do this by writing the image out to a new image using CGContexts and AffineTransforms. Or there is an easier workaround, use the UIImage+Resize package as discussed here. And resize the image to it's current size by calling:
如果您希望实际数据与元数据声明的内容对齐,则需要修改实际数据。您可以使用CGContexts和AffineTransforms将图像写入新图像。或者有一个更简单的解决方法,使用这里讨论的UIImage + Resize包。并通过调用以下方式将图像调整为当前大小:
UIImage *rotatedImage = [image resizedImage:CGSizeMake(image.size.width, image.size.height) interpolationQuality:kCGInterpolationDefault];
This will rectify the data's orientation as a side effect.
这将纠正数据的方向作为副作用。
If you don't want to include the whole UIImage+Resize thing you can checkout it's code and strip out the parts where the data is transformed.
如果你不想包含整个UIImage + Resize的东西,你可以检查它的代码并去掉数据转换的部分。
#1
33
This happens because the orientation set in the metadata of the new image is being effected by the orientation of the AV system that creates it. The layout of the actual image data is of course different from the orientation mentioned in your metadata. Some image viewing programs respect the metadata orientation, some ignore it.
发生这种情况是因为在新图像的元数据中设置的方向受到创建它的AV系统的方向的影响。实际图像数据的布局当然不同于元数据中提到的方向。一些图像查看程序尊重元数据方向,有些则忽略它。
You can affect the metadata orientation of the AV system by calling:
您可以通过调用以下方式影响AV系统的元数据方向:
AVCaptureConnection *videoConnection = ...;
if ([videoConnection isVideoOrientationSupported])
[videoConnection setVideoOrientation:AVCaptureVideoOrientationSomething];
You can affect the metadata orientation of a UIImage by calling:
您可以通过调用以下内容来影响UIImage的元数据方向:
UIImage *rotatedImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:1.0f orientation:UIImageOrientationSomething];
But the actual data from the AVCapture system will always appear with the wider dimension as X and the narrower dimension as Y, and will appear to be oriented in LandscapeLeft.
但是来自AVCapture系统的实际数据将始终显示为更宽的尺寸为X,更窄的尺寸为Y,并且看起来将面向LandscapeLeft。
If you want the actual data to line up with what your metadata claims, you need to modify the actual data. You can do this by writing the image out to a new image using CGContexts and AffineTransforms. Or there is an easier workaround, use the UIImage+Resize package as discussed here. And resize the image to it's current size by calling:
如果您希望实际数据与元数据声明的内容对齐,则需要修改实际数据。您可以使用CGContexts和AffineTransforms将图像写入新图像。或者有一个更简单的解决方法,使用这里讨论的UIImage + Resize包。并通过调用以下方式将图像调整为当前大小:
UIImage *rotatedImage = [image resizedImage:CGSizeMake(image.size.width, image.size.height) interpolationQuality:kCGInterpolationDefault];
This will rectify the data's orientation as a side effect.
这将纠正数据的方向作为副作用。
If you don't want to include the whole UIImage+Resize thing you can checkout it's code and strip out the parts where the data is transformed.
如果你不想包含整个UIImage + Resize的东西,你可以检查它的代码并去掉数据转换的部分。