iPhone - 将从前置摄像头拍摄的照片镜像显示

11
当使用iPhone 4的前置摄像头拍照时,所拍摄的图片与在iPhone屏幕上看到的内容是镜像的。如何恢复UIImage(而不是UIImageView)的“屏幕上”视图,并能够以此方式保存它?
我尝试过以下代码:
UIImage* transformedImage = [UIImage imageWithCGImage:pickedImage.CGImage scale:1.0 orientation:UIImageOrientationLeftMirrored];
UIImageWriteToSavedPhotosAlbum (transformedImage, self, @selector(photoSaved:didFinishSavingWithError:contextInfo:), nil);

将其放在屏幕上,然后保存图像。在屏幕上看到的几乎与保存的图像相同,但保存的图像会出现扭曲。

那么...我该如何恢复UIImage的“屏幕显示”视图(而不是UIImageView),并能够像这样保存它?

我也尝试过以下方式:

UIImage* pickedImage = [[info objectForKey:UIImagePickerControllerOriginalImage] retain];
UIImage* transformedImage;

CGSize imageSize = pickedImage.size;
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 1.0);
GContextRef ctx = UIGraphicsGetCurrentContext();

CGContextRotateCTM(ctx, 3.14);  // rotate by 180°
CGContextScaleCTM(ctx, 1.0, -1.0); // flip vertical
CGContextDrawImage(ctx, CGRectMake(0.0, 0.0, imageSize.width, imageSize.height), pickedImage.CGImage);
transformedImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

但是这只会得到一张黑色的图片。

8个回答

27
- (void)didTakePicture:(UIImage *)picture
{
    UIImage * flippedImage = [UIImage imageWithCGImage:picture.CGImage scale:picture.scale orientation:UIImageOrientationLeftMirrored];
    picture = flippedImage;
}

这不是真正的镜像。 - Jakub Truhlář
这并不总是有效的:如果您实例化UIImage而没有在UIImageView中显示它,则它没有CGImage可提供。 - igraczech

10

我知道这个问题已经有人回答过了,但是上面的答案对我没用,所以如果有其他人也遇到同样的问题...

UIImage *theImage = [info objectForKey:UIImagePickerControllerOriginalImage];
    if (picker.cameraDevice == UIImagePickerControllerCameraDeviceFront) {
        CGSize imageSize = theImage.size;
        UIGraphicsBeginImageContextWithOptions(imageSize, YES, 1.0);
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        CGContextRotateCTM(ctx, M_PI/2);
        CGContextTranslateCTM(ctx, 0, -imageSize.width);
        CGContextScaleCTM(ctx, imageSize.height/imageSize.width, imageSize.width/imageSize.height);
        CGContextDrawImage(ctx, CGRectMake(0.0, 0.0, imageSize.width, imageSize.height), theImage.CGImage);
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }

而 newImage 是您带有向上方向的新图像。


6
最好的方法是将图像绘制到一个新的上下文中。
CGSize imageSize = pickedImage.size;
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 1.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, imageSize.width, 0.0);
CGContextScaleCTM(ctx, -1.0, 1.0);
CGContextDrawImage(ctx, pickedImage.CGImage, CGRectMake(0.0, 0.0, imageSize.width, imageSize.height));
UIImage *transformedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum (transformedImage, self, @selector(photoSaved:didFinishSavingWithError:contextInfo:), nil);

这是凭记忆写的,没有借助编译器,请不要复制粘贴……


@Bill Dudney:UIGraphicsBeginImageContextWithOptions不会返回上下文;你如何设置它?CGContextDrawImage需要一个矩形。我假设我必须用0、0和图像大小来制作它? - Oliver
更新了新的和改进的代码,更有可能工作。你没有复制粘贴吧?你是阅读文档并自己编写的,对吧? :) - Bill Dudney
@Bill Dudney: :-) 我曾经复制/粘贴,但这是为了更容易地在 XCode 中理解它(带有方法/函数声明的链接、帮助等)。我现在仍在阅读文档 :-) - Oliver
@Bill Dudney:哇,有些我不理解的地方。图像被镜像(x轴)并向右旋转90度,呈现出变形的状态。大小的X和Y值似乎是相反的...我看不出是什么导致了图像旋转。你认为可能与图像exif存在冲突吗? - Oliver
为什么要使用CGContextTranslateCTM? - Oliver
显示剩余2条评论

5

Andrew Park的答案非常好。这是Swift版本。

func flipImage(image: UIImage!) -> UIImage! {
    let imageSize:CGSize = image.size;
    UIGraphicsBeginImageContextWithOptions(imageSize, true, 1.0);
    let ctx:CGContextRef = UIGraphicsGetCurrentContext()!;
    CGContextRotateCTM(ctx, CGFloat(M_PI/2.0));
    CGContextTranslateCTM(ctx, 0, -imageSize.width);
    CGContextScaleCTM(ctx, imageSize.height/imageSize.width, imageSize.width/imageSize.height);
    CGContextDrawImage(ctx, CGRectMake(0.0, 0.0, imageSize.width, imageSize.height), image.CGImage);
    let newImage:UIImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage
}

5

以下是针对 Swift 3 更新的更为简单的答案:

func flipImage(image: UIImage) -> UIImage {
    guard let cgImage = image.cgImage else {
        // Could not form CGImage from UIImage for some reason.
        // Return unflipped image
        return image
    }
    let flippedImage = UIImage(cgImage: cgImage, 
                               scale: image.scale, 
                               orientation: .leftMirrored)
    return flippedImage
}

在许多情况下,UIImage没有CGImage等效项,因此这通常是无用的。 - Stephen Radford
我正在寻找一种解决方案,可以翻转前置摄像头的预览图像。这个方法在photoOutput中起作用。 - Patrick.Bellot

5

您可能希望镜像相机拍摄的图像,但原始图像是正确的。可以拍摄一个包含文字的图片进行比较。


3
作为其他答案的补充,我也遇到了同样的问题。但是只翻转最终图像只是解决一半,因为当您使用前置摄像头拍照时,UIPickerController显示的预览图像仍然是反转的(镜像)。
基于从互联网获取的某些代码,我创建了一个Pod以获得此所需的行为:
安装后,您只需调用这两行代码与您的UIImagePickerController一起使用: https://github.com/lucasecf/LEMirroredImagePicker
self.mirrorFrontPicker = [[LEMirroredImagePicker alloc] initWithImagePicker:pickerController];
[self.mirrorFrontPicker mirrorFrontCamera];

就是这样,简单明了。你可以在GitHub链接的README中查找更多信息。


嘿,LEImagePickerController似乎无法正常工作,预览仍然是镜像的(iOS7,iPhone 4S)。 - Zoltán Matók
1
嗨! 之前的代码相当老了。现在,我创建了一个Pod并更新了代码以适应较新版本的iOS。如果你愿意,可以再次在github上检查项目。 - Lucas Eduardo
1
刚试了一下,太棒了!(在iOS 8.3、Swift和Xcode 6.3.1上尝试过)我同意仅翻转最终图像似乎不是一个好的用户体验。感谢您创建LEDMirroredImagePicker!非常容易使用! - Alex
非常容易使用,但最终结果仍然是镜像的。你只需要先倒转相机显示屏。所以,例如当我自拍时,感觉非常奇怪。如果有一种方法可以简单地不翻转预览,那就太好了。尽管如此,这仍然是一个很酷的Pod! - bmurmistro

0

我想给 @Lucas Eduardo 点赞,我已经尝试将组件LEImagePickerController集成到我的项目中,如下所示:

- (void)onCamera:(id)sender {
    UIImagePickerController* imagePicker = [[UIImagePickerController alloc] init];
    imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    imagePicker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
    imagePicker.delegate = self;

    //cover the switch button at the top right corner, I just need user take photo with the front facing camera
    UIView* view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
    view.center = CGPointMake(CGRectGetWidth(imagePicker.view.bounds) - CGRectGetWidth(view.bounds)/2, CGRectGetHeight(view.bounds)/2);
    view.backgroundColor = [UIColor blackColor];
    [imagePicker.view addSubview:view];

    LEMirroredImagePicker* mirrorFrontPicker = [[LEMirroredImagePicker alloc] initWithImagePicker:imagePicker];
    [mirrorFrontPicker mirrorFrontCamera];

    [self presentViewController:imagePicker animated:YES completion:nil];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接