我一直在试图让AVFoundation相机以正确的方向(即设备方向)拍摄照片,但我无法让它发挥作用。
我看了教程,我看过WWDC演示文稿,我已经下载了WWDC示例程序,但即便如此也没有。
我的应用程序的代码是......
AVCaptureConnection *videoConnection = [CameraVC connectionWithMediaType:AVMediaTypeVideo fromConnections:[imageCaptureOutput connections]];
if ([videoConnection isVideoOrientationSupported])
{
[videoConnection setVideoOrientation:[UIApplication sharedApplication].statusBarOrientation];
}
[imageCaptureOutput captureStillImageAsynchronouslyFromConnection:videoConnection
completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error)
{
if (imageDataSampleBuffer != NULL)
{
//NSLog(@"%d", screenOrientation);
//CMSetAttachment(imageDataSampleBuffer, kCGImagePropertyOrientation, [NSString stringWithFormat:@"%d", screenOrientation], 0);
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
[self processImage:image];
}
}];
(processImage使用与WWDC代码相同的writeImage ...方法)
来自WWDC应用程序的代码是......
AVCaptureConnection *videoConnection = [AVCamDemoCaptureManager connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]];
if ([videoConnection isVideoOrientationSupported]) {
[videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
}
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection
completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer != NULL) {
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
UIImage *image = [[UIImage alloc] initWithData:imageData];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:[image CGImage]
orientation:(ALAssetOrientation)[image imageOrientation]
completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
id delegate = [self delegate];
if ([delegate respondsToSelector:@selector(captureStillImageFailedWithError:)]) {
[delegate captureStillImageFailedWithError:error];
}
}
}];
[library release];
[image release];
} else if (error) {
id delegate = [self delegate];
if ([delegate respondsToSelector:@selector(captureStillImageFailedWithError:)]) {
[delegate captureStillImageFailedWithError:error];
}
}
}];
在他们的代码开头,他们将AVOrientation设置为肖像,这似乎很奇怪,但我试图让它检测设备的当前方向并使用它。
正如您所看到的,我已经将[UIApplication sharedApplication] statusBarOrientation设置为尝试获取此功能,但它仍然只能以纵向保存照片。
任何人都可以就我需要做的事情提供任何帮助或建议吗?
谢谢!
奥利弗
答案 0 :(得分:45)
嗯,这是我永远的水力压裂,但我已经做到了!
我正在寻找的代码是
[UIDevice currentDevice].orientation;
这就是这样的
AVCaptureConnection *videoConnection = [CameraVC connectionWithMediaType:AVMediaTypeVideo fromConnections:[imageCaptureOutput connections]];
if ([videoConnection isVideoOrientationSupported])
{
[videoConnection setVideoOrientation:[UIDevice currentDevice].orientation];
}
它完美无缺:D
Woop woop!
答案 1 :(得分:14)
这不是更干净吗?
AVCaptureVideoOrientation newOrientation;
switch ([[UIDevice currentDevice] orientation]) {
case UIDeviceOrientationPortrait:
newOrientation = AVCaptureVideoOrientationPortrait;
break;
case UIDeviceOrientationPortraitUpsideDown:
newOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
break;
case UIDeviceOrientationLandscapeLeft:
newOrientation = AVCaptureVideoOrientationLandscapeRight;
break;
case UIDeviceOrientationLandscapeRight:
newOrientation = AVCaptureVideoOrientationLandscapeLeft;
break;
default:
newOrientation = AVCaptureVideoOrientationPortrait;
}
[stillConnection setVideoOrientation: newOrientation];
答案 2 :(得分:11)
以下是来自AVCam,我也加了它:
- (void)deviceOrientationDidChange{
UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
AVCaptureVideoOrientation newOrientation;
if (deviceOrientation == UIDeviceOrientationPortrait){
NSLog(@"deviceOrientationDidChange - Portrait");
newOrientation = AVCaptureVideoOrientationPortrait;
}
else if (deviceOrientation == UIDeviceOrientationPortraitUpsideDown){
NSLog(@"deviceOrientationDidChange - UpsideDown");
newOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
}
// AVCapture and UIDevice have opposite meanings for landscape left and right (AVCapture orientation is the same as UIInterfaceOrientation)
else if (deviceOrientation == UIDeviceOrientationLandscapeLeft){
NSLog(@"deviceOrientationDidChange - LandscapeLeft");
newOrientation = AVCaptureVideoOrientationLandscapeRight;
}
else if (deviceOrientation == UIDeviceOrientationLandscapeRight){
NSLog(@"deviceOrientationDidChange - LandscapeRight");
newOrientation = AVCaptureVideoOrientationLandscapeLeft;
}
else if (deviceOrientation == UIDeviceOrientationUnknown){
NSLog(@"deviceOrientationDidChange - Unknown ");
newOrientation = AVCaptureVideoOrientationPortrait;
}
else{
NSLog(@"deviceOrientationDidChange - Face Up or Down");
newOrientation = AVCaptureVideoOrientationPortrait;
}
[self setOrientation:newOrientation];
}
并确保将此添加到您的init方法:
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[notificationCenter addObserver:self
selector:@selector(deviceOrientationDidChange)
name:UIDeviceOrientationDidChangeNotification object:nil];
[self setOrientation:AVCaptureVideoOrientationPortrait];
答案 3 :(得分:4)
有两件事需要注意
a)正如Brian King所写 - LandscapeRight和LandscapeLeft在枚举中交换。请参阅AVCamCaptureManager示例:
// AVCapture and UIDevice have opposite meanings for landscape left and right (AVCapture orientation is the same as UIInterfaceOrientation)
else if (deviceOrientation == UIDeviceOrientationLandscapeLeft)
orientation = AVCaptureVideoOrientationLandscapeRight;
else if (deviceOrientation == UIDeviceOrientationLandscapeRight)
orientation = AVCaptureVideoOrientationLandscapeLeft;
b)还有UIDeviceOrientationFaceUp
和UIDeviceOrientationFaceDown
个状态,如果您尝试设置为视频方向,则视频将无法录制。调用[UIDevice currentDevice].orientation
时确保不要使用它们!
答案 4 :(得分:3)
如果您正在使用AVCaptureVideoPreviewLayer,则可以在视图控制器中执行以下操作。
(假设您有一个名为“previewLayer”的AVCaptureVideoPreviewLayer实例)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
[self.previewLayer setOrientation:[[UIDevice currentDevice] orientation]];
}
答案 5 :(得分:2)
我在Swift中编写此代码,以防有人可能需要。
步骤1:生成方向通知(在viewDidLoad
中)
UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("deviceOrientationDidChange:"), name: UIDeviceOrientationDidChangeNotification, object: nil)
步骤2:拍照。在这里,我们将交换videoConnection
的方向。在AVFoundation中,方向略有变化,尤其是横向方向。所以我们将交换它。例如,我们会从LandscapeRight
更改为LandscapeLeft
而反之亦然
func takePicture() {
if let videoConnection = stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo) {
var newOrientation: AVCaptureVideoOrientation?
switch (UIDevice.currentDevice().orientation) {
case .Portrait:
newOrientation = .Portrait
break
case .PortraitUpsideDown:
newOrientation = .PortraitUpsideDown
break
case .LandscapeLeft:
newOrientation = .LandscapeRight
break
case .LandscapeRight:
newOrientation = .LandscapeLeft
break
default :
newOrientation = .Portrait
break
}
videoConnection.videoOrientation = newOrientation!
stillImageOutput!.captureStillImageAsynchronouslyFromConnection(videoConnection) {
(imageDataSampleBuffer, error) -> Void in
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
dispatch_async(dispatch_get_main_queue()) {
let image = UIImage(data: imageData!)!
let portraitImage = image.fixOrientation()
}
}
}
}
}
注意:请注意横向方向的新方向值。恰恰相反。 (这是罪魁祸首:: UHHHH)
步骤3:修正方向(UIImage扩展名)
extension UIImage {
func fixOrientation() -> UIImage {
if imageOrientation == UIImageOrientation.Up {
return self
}
var transform: CGAffineTransform = CGAffineTransformIdentity
switch imageOrientation {
case UIImageOrientation.Down, UIImageOrientation.DownMirrored:
transform = CGAffineTransformTranslate(transform, size.width, size.height)
transform = CGAffineTransformRotate(transform, CGFloat(M_PI))
break
case UIImageOrientation.Left, UIImageOrientation.LeftMirrored:
transform = CGAffineTransformTranslate(transform, size.width, 0)
transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2))
break
case UIImageOrientation.Right, UIImageOrientation.RightMirrored:
transform = CGAffineTransformTranslate(transform, 0, size.height)
transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))
break
case UIImageOrientation.Up, UIImageOrientation.UpMirrored:
break
}
switch imageOrientation {
case UIImageOrientation.UpMirrored, UIImageOrientation.DownMirrored:
CGAffineTransformTranslate(transform, size.width, 0)
CGAffineTransformScale(transform, -1, 1)
break
case UIImageOrientation.LeftMirrored, UIImageOrientation.RightMirrored:
CGAffineTransformTranslate(transform, size.height, 0)
CGAffineTransformScale(transform, -1, 1)
case UIImageOrientation.Up, UIImageOrientation.Down, UIImageOrientation.Left, UIImageOrientation.Right:
break
}
let ctx: CGContextRef = CGBitmapContextCreate(nil, Int(size.width), Int(size.height), CGImageGetBitsPerComponent(CGImage), 0, CGImageGetColorSpace(CGImage), CGImageAlphaInfo.PremultipliedLast.rawValue)!
CGContextConcatCTM(ctx, transform)
switch imageOrientation {
case UIImageOrientation.Left, UIImageOrientation.LeftMirrored, UIImageOrientation.Right, UIImageOrientation.RightMirrored:
CGContextDrawImage(ctx, CGRectMake(0, 0, size.height, size.width), CGImage)
break
default:
CGContextDrawImage(ctx, CGRectMake(0, 0, size.width, size.height), CGImage)
break
}
let cgImage: CGImageRef = CGBitmapContextCreateImage(ctx)!
return UIImage(CGImage: cgImage)
}
}
答案 6 :(得分:1)
这使用视图控制器的方向方法。这对我有用,希望对你有用。
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
AVCaptureConnection *videoConnection = self.prevLayer.connection;
[videoConnection setVideoOrientation:(AVCaptureVideoOrientation)toInterfaceOrientation];
}
答案 7 :(得分:1)
在Swift中你应该这样做:
videoOutput = AVCaptureVideoDataOutput()
videoOutput!.setSampleBufferDelegate(self, queue: dispatch_queue_create("sample buffer delegate", DISPATCH_QUEUE_SERIAL))
if captureSession!.canAddOutput(self.videoOutput) {
captureSession!.addOutput(self.videoOutput)
}
videoOutput!.connectionWithMediaType(AVMediaTypeVideo).videoOrientation = AVCaptureVideoOrientation.PortraitUpsideDown
它对我来说很完美!
答案 8 :(得分:1)
Swift 4和Swift 5。
我们在这里:
private var requests = [VNRequest]()
let exifOrientation = exifOrientationFromDeviceOrientation()
let imageRequestHandler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: exifOrientation, options: [:])
do {
try imageRequestHandler.perform(self.requests)
} catch {
print(error)
}
public func exifOrientationFromDeviceOrientation() -> CGImagePropertyOrientation {
let curDeviceOrientation = UIDevice.current.orientation
let exifOrientation: CGImagePropertyOrientation
switch curDeviceOrientation {
case UIDeviceOrientation.portraitUpsideDown: // Device oriented vertically, home button on the top
exifOrientation = .upMirrored
case UIDeviceOrientation.landscapeLeft: // Device oriented horizontally, home button on the right
exifOrientation = .left
case UIDeviceOrientation.landscapeRight: // Device oriented horizontally, home button on the left
exifOrientation = .right
case UIDeviceOrientation.portrait: // Device oriented vertically, home button on the bottom
exifOrientation = .up
default:
exifOrientation = .up
}
return exifOrientation
}
答案 9 :(得分:0)
您还可以创建一个中间CIImage,并获取属性字典
NSDictionary *propDict = [aCIImage properties];
NSString *orientString = [propDict objectForKey:kCGImagePropertyOrientation];
相应变换:)
我喜欢在iOS5中访问所有这些图像元数据是多么容易!
答案 10 :(得分:0)
在启动捕获会话之后以及每当设备旋转时,在预览层中更新方向。
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { [weak self] context in
if let connection = self?.previewLayer?.connection, connection.isVideoOrientationSupported {
if let orientation = AVCaptureVideoOrientation(orientation: UIDevice.current.orientation) {
connection.videoOrientation = orientation
}
}
}, completion: nil)
super.viewWillTransition(to: size, with: coordinator)
}
extension AVCaptureVideoOrientation {
init?(orientation: UIDeviceOrientation) {
switch orientation {
case .landscapeRight: self = .landscapeLeft
case .landscapeLeft: self = .landscapeRight
case .portrait: self = .portrait
case .portraitUpsideDown: self = .portraitUpsideDown
default: return nil
}
}
}
答案 11 :(得分:-1)
如何使用AVCaptureFileOutput?
- (void)detectVideoOrientation:(AVCaptureFileOutput *)captureOutput {
for(int i = 0; i < [[captureOutput connections] count]; i++) {
AVCaptureConnection *captureConnection = [[captureOutput connections] objectAtIndex:i];
if([captureConnection isVideoOrientationSupported]) {
[captureConnection setVideoOrientation:[[UIDevice currentDevice] orientation]];
}
}
}