【问题标题】:iOS Image Orientation has Strange BehavioriOS 图像方向有奇怪的行为
【发布时间】:2012-05-22 22:58:54
【问题描述】:

在过去的几周里,我一直在使用 Objective-c 中的图像,并注意到很多奇怪的行为。首先,像许多其他人一样,我一直遇到这个问题,即用相机拍摄的图像(或用别人的相机拍摄并用彩信发送给我)旋转 90 度。我不确定为什么会发生这种情况(因此my question),但我能够想出一个便宜的解决方法。

这次我的问题是为什么会发生这种情况?苹果为什么要旋转图像?当我用相机正面朝上拍照时,除非我执行上面提到的代码,否则当我保存照片时,它会旋转保存。现在,直到几天前,我的解决方法还可以。

我的应用程序会修改图像的单个像素,特别是 PNG 的 alpha 通道(因此对于我的场景,任何 JPEG 转换都会被抛出窗口之外)。几天前,我注意到即使由于我的解决方法代码在我的应用程序中正确显示了图像,但当我的算法修改图像的各个像素时,它认为图像已旋转。所以不是修改图像顶部的像素,而是修改图像侧面的像素(因为它认为应该旋转)!我不知道如何旋转内存中的图像 - 理想情况下,我宁愿将 imageOrientation 标志全部擦除。

还有一些让我感到困惑的事情......当我拍照时,imageOrientation 设置为 3。我的解决方法代码足够聪明,可以实现这一点并将其翻转,因此用户永远不会注意到。此外,我将图像保存到库中的代码实现了这一点,将其翻转,然后将其保存,使其正确显示在相机胶卷中。

该代码如下所示:

NSData* pngdata = UIImagePNGRepresentation (self.workingImage); //PNG wrap 
UIImage* img = [self rotateImageAppropriately:[UIImage imageWithData:pngdata]];   
UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil);

当我将这个新保存的图像加载到我的应用程序中时,imageOrientation 为 0 - 正是我想要看到的,我的旋转解决方法甚至不需要运行(注意:从互联网加载图像时相反对于用相机拍摄的图像,imageOrientation 始终为 0,从而产生完美的行为)。出于某种原因,我的保存代码似乎抹去了这个imageOrientation 标志。我希望在用户拍照并将其添加到应用程序后立即窃取该代码并使用它来擦除我的 imageOrientation,但它似乎不起作用。 UIImageWriteToSavedPhotosAlbumimageOrientation 有什么特别的作用吗?

解决此问题的最佳方法是在用户完成拍摄后立即吹走imageOrientation。我认为苹果公司的轮换行为是有原因的,对吧?一些人认为这是苹果的缺陷。

(...如果你还没有迷路...注2:当我拍摄水平照片时,一切似乎都完美无缺,就像从互联网上拍摄的照片一样)

编辑:

以下是一些图像和场景的实际样子。根据迄今为止的 cmets,看起来这种奇怪的行为不仅仅是 iPhone 的行为,我认为这很好。

这是我用手机拍摄的照片(注意正确的方向),它与我拍摄照片时在手机上显示的完全一样:

这是我通过电子邮件将图片发送给自己后在 Gmail 中的样子(看起来 Gmail 处理得当):

这是图像在 Windows 中的缩略图(看起来处理不当):

下面是使用 Windows 照片查看器打开时实际图像的样子(仍未正确处理):

在这个问题的所有 cmets 之后,这就是我的想法...... iPhone 拍摄了一张图像,并说“要正确显示它,它需要旋转 90 度”。此信息将在 EXIF 数据中。 (为什么它需要旋转 90 度,而不是默认为垂直,我不知道)。从这里开始,Gmail 足够智能,可以读取和分析 EXIF 数据,并正确显示它。然而,Windows 不够聪明,无法读取 EXIF 数据,因此显示图像不正确。我的假设是否正确?

【问题讨论】:

  • 有趣...如果这是真的,为什么拍摄的图像设置为直角?我知道这不是 iPhone 的缺陷,因为我注意到当朋友(使用黑莓手机)拍摄图像并将其通过彩信发送给我时,会有类似的行为。
  • 看到您的相机写入元数据以将其旋转 90 度,某些操作系统会读取该元数据而其余的则不会。
  • 读得很好(请参阅下面的@Hadley 的回答 - 曾经在评论中)。所以我的应用程序显然需要足够智能来处理包含 EXIF 数据的图像,以及不包含它的图像......我仍然不明白为什么当我正面朝上拍照时,方向标志说它应该旋转90度?
  • 您将照片模式设置为纵向并且您没有将相机旋转到直角或设置了横向模式并且相机已在直角位置捕获图像,传感器将自动将方向设置为正确一。看看吧
  • 解决方案很可能是,您的应用需要读取元数据并旋转图像和/或根据要求修改元数据。

标签: iphone objective-c ios


【解决方案1】:

我对其进行了研发并发现,每个图像文件都有元数据属性。如果元数据指定图像的方向,除 Mac 之外的其他操作系统通常会忽略该方向。大多数拍摄的图像都将其元数据属性设置为直角。所以 Mac 以 90 度旋转的方式显示它。您可以在 Windows 操作系统中以正确的方式看到相同的图像。

有关更多详细信息,请阅读此答案http://graphicssoft.about.com/od/digitalphotography/f/sideways-pictures.htm

尝试在 http://www.exifviewer.org/http://regex.info/exif.cgihttp://www.addictivetips.com/internet-tips/view-complete-exif-metadata-information-of-any-jpeg-image-online/ 阅读您图片的 exif

【讨论】:

  • 哇!我不知道 EXIF 数据中有这么多信息! regex.info/exif.cgi 是一个令人难以置信的网站!今晚我肯定会在这个网站上玩弄图像。我必须测试每一个场景,图像是直接拍摄的,图像是从互联网上拍摄的,图像是旋转拍摄的,等等。非常感谢!
  • 第一个 exif 链接现在已断开,第二个已更新为 exif.regex.info/exif.cgi 我试图编辑答案,但 @cj-dennis 出于某种原因拒绝了它。
【解决方案2】:

当我从相机获取图像时,我遇到了同样的问题,我输入了以下代码来修复它。添加方法 scaleAndRotateImage from here

- (void) imagePickerController:(UIImagePickerController *)thePicker didFinishPickingMediaWithInfo:(NSDictionary *)imageInfo {
            // Images from the camera are always in landscape, so rotate
                    UIImage *image = [self scaleAndRotateImage: [imageInfo objectForKey:UIImagePickerControllerOriginalImage]];
    //then save the image to photo gallery or wherever  
        }


- (UIImage *)scaleAndRotateImage:(UIImage *) image {
    int kMaxResolution = 320;

    CGImageRef imgRef = image.CGImage;

    CGFloat width = CGImageGetWidth(imgRef);
    CGFloat height = CGImageGetHeight(imgRef);


    CGAffineTransform transform = CGAffineTransformIdentity;
    CGRect bounds = CGRectMake(0, 0, width, height);
    if (width > kMaxResolution || height > kMaxResolution) {
        CGFloat ratio = width/height;
        if (ratio > 1) {
            bounds.size.width = kMaxResolution;
            bounds.size.height = bounds.size.width / ratio;
        }
        else {
            bounds.size.height = kMaxResolution;
            bounds.size.width = bounds.size.height * ratio;
        }
    }

    CGFloat scaleRatio = bounds.size.width / width;
    CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
    CGFloat boundHeight;
    UIImageOrientation orient = image.imageOrientation;
    switch(orient) {

        case UIImageOrientationUp: //EXIF = 1
            transform = CGAffineTransformIdentity;
            break;

        case UIImageOrientationUpMirrored: //EXIF = 2
            transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            break;

        case UIImageOrientationDown: //EXIF = 3
            transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationDownMirrored: //EXIF = 4
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
            transform = CGAffineTransformScale(transform, 1.0, -1.0);
            break;

        case UIImageOrientationLeftMirrored: //EXIF = 5
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
            transform = CGAffineTransformScale(transform, -1.0, 1.0);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationLeft: //EXIF = 6
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
            transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
            break;

        case UIImageOrientationRightMirrored: //EXIF = 7
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeScale(-1.0, 1.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        case UIImageOrientationRight: //EXIF = 8
            boundHeight = bounds.size.height;
            bounds.size.height = bounds.size.width;
            bounds.size.width = boundHeight;
            transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
            transform = CGAffineTransformRotate(transform, M_PI / 2.0);
            break;

        default:
            [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];

    }

    UIGraphicsBeginImageContext(bounds.size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
        CGContextScaleCTM(context, -scaleRatio, scaleRatio);
        CGContextTranslateCTM(context, -height, 0);
    }
    else {
        CGContextScaleCTM(context, scaleRatio, -scaleRatio);
        CGContextTranslateCTM(context, 0, -height);
    }

    CGContextConcatCTM(context, transform);

    CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
    UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return imageCopy;
}

【讨论】:

  • 你的 scaleAndRotateImage 代码是什么样的? google了一下,和这里的一样吗? discussions.apple.com/thread/1537011?start=0&tstart=0
  • 哇...哈哈!效果非常好!我在上面的评论中使用了代码。我的问题得到了两个惊人的答案!我认为这意味着我问的问题太大了……非常感谢。我将进行一些深入测试,但到目前为止,方向问题对于垂直和水平拍摄的照片都非常有效。
  • 我认为您的方法缺少一部分,但是链接仍然足以让我解决其余部分并最终让我的图像裁剪视图正常工作,所以谢谢:)跨度>
  • 我很高兴它有帮助..:)
  • 此代码块是否保留了原始图像的外观但将方向更改为向上?
【解决方案3】:

iPhone/iPad 生成的任何图像都保存为横向左,并带有指定实际方向的 EXIF 方向标记 (Exif.Image.Orientation)。

它具有以下值: 1:横向左 6:纵向正常 3:横向右 4:纵向倒置

在 IOS 中,EXIF 信息被正确读取,图像以与拍摄时相同的方式显示。但在 Windows 中,不使用 EXIF 信息。

如果您在 GIMP 中打开这些图像之一,它会说该图像具有旋转信息。

【讨论】:

    【解决方案4】:

    我确切地知道你的问题是什么。您正在使用 UIImagePicker,这在各个方面都很奇怪。我建议您将 AVFoundation 用于相机,它可以提供方向和质量的灵活性。使用 AVCaptureSession。 你可以在这里获取代码How to save photos taken using AVFoundation to Photo Album?

    【讨论】:

      【解决方案5】:

      我遇到了这个问题,因为我遇到了类似的问题,但使用的是 Swift。只是想链接到适用于我的任何其他 Swift 开发人员的答案:https://stackoverflow.com/a/26676578/3904581

      这是一个可以有效解决问题的 Swift sn-p:

      let orientedImage = UIImage(CGImage: initialImage.CGImage, scale: 1, orientation: initialImage.imageOrientation)!
      

      超级简单。一行代码。问题解决了。

      【讨论】:

      【解决方案6】:

      快速复制/粘贴 Dilip 的 excellent answer 的 Swift 翻译。

      import Darwin
      
      class func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage {
      
          let imgRef = imageSource.CGImage;
      
          let width = CGFloat(CGImageGetWidth(imgRef));
          let height = CGFloat(CGImageGetHeight(imgRef));
      
          var bounds = CGRectMake(0, 0, width, height)
      
          var scaleRatio : CGFloat = 1
          if (width > maxResolution || height > maxResolution) {
      
              scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
              bounds.size.height = bounds.size.height * scaleRatio
              bounds.size.width = bounds.size.width * scaleRatio
          }
      
          var transform = CGAffineTransformIdentity
          let orient = imageSource.imageOrientation
          let imageSize = CGSizeMake(CGFloat(CGImageGetWidth(imgRef)), CGFloat(CGImageGetHeight(imgRef)))
      
      
          switch(imageSource.imageOrientation) {
          case .Up :
              transform = CGAffineTransformIdentity
      
          case .UpMirrored :
              transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
              transform = CGAffineTransformScale(transform, -1.0, 1.0);
      
          case .Down :
              transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
              transform = CGAffineTransformRotate(transform, CGFloat(M_PI));
      
          case .DownMirrored :
              transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
              transform = CGAffineTransformScale(transform, 1.0, -1.0);
      
          case .Left :
              let storedHeight = bounds.size.height
              bounds.size.height = bounds.size.width;
              bounds.size.width = storedHeight;
              transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
              transform = CGAffineTransformRotate(transform, 3.0 * CGFloat(M_PI) / 2.0);
      
          case .LeftMirrored :
              let storedHeight = bounds.size.height
              bounds.size.height = bounds.size.width;
              bounds.size.width = storedHeight;
              transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
              transform = CGAffineTransformScale(transform, -1.0, 1.0);
              transform = CGAffineTransformRotate(transform, 3.0 * CGFloat(M_PI) / 2.0);
      
          case .Right :
              let storedHeight = bounds.size.height
              bounds.size.height = bounds.size.width;
              bounds.size.width = storedHeight;
              transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
              transform = CGAffineTransformRotate(transform, CGFloat(M_PI) / 2.0);
      
          case .RightMirrored :
              let storedHeight = bounds.size.height
              bounds.size.height = bounds.size.width;
              bounds.size.width = storedHeight;
              transform = CGAffineTransformMakeScale(-1.0, 1.0);
              transform = CGAffineTransformRotate(transform, CGFloat(M_PI) / 2.0);
      
          default : ()
          }
      
          UIGraphicsBeginImageContext(bounds.size)
          let context = UIGraphicsGetCurrentContext()
      
          if orient == .Right || orient == .Left {
              CGContextScaleCTM(context, -scaleRatio, scaleRatio);
              CGContextTranslateCTM(context, -height, 0);
          } else {
              CGContextScaleCTM(context, scaleRatio, -scaleRatio);
              CGContextTranslateCTM(context, 0, -height);
          }
      
          CGContextConcatCTM(context, transform);
          CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
      
          let imageCopy = UIGraphicsGetImageFromCurrentImageContext();
          UIGraphicsEndImageContext();
      
          return imageCopy;
      }
      

      【讨论】:

      • 谢谢,但什么是“让比率 = 宽度/高度;”用于?我在那个 {} 中看不到任何使用比率的地方
      【解决方案7】:

      这次我的问题是为什么会这样?苹果为什么要旋转图片?

      这个问题的答案很简单。苹果没有旋转图像。这就是混乱所在。

      CCD 摄像头不旋转,因此始终以横向模式拍照。

      Apple 做了一件非常聪明的事情 - 与其花所有时间旋转图像 - 将数兆字节的数据四处移动 - 只需将其标记为图片是如何拍摄的。

      OpenGL 非常容易进行转换 - 所以数据永远不会被打乱 - 只是它是如何绘制的。

      因此是方向元数据。

      如果您想裁剪、调整大小等,这将成为一个问题 - 但一旦您知道发生了什么,您只需定义您的矩阵,一切都会解决。

      【讨论】:

      • 感谢您的解释。想想就知道是常识,但没有其他谷歌搜索结果解释它。
      【解决方案8】:

      尝试将图像格式更改为 .jpeg。这对我有用

      【讨论】:

        【解决方案9】:

        对于其他使用 Xamarin 的人,这里是 Dilip 的 great answer 的 C# 翻译,感谢 thattyson 提供的 Swift translation

        public static UIImage RotateCameraImageToProperOrientation(UIImage imageSource, nfloat maxResolution) {
        
            var imgRef = imageSource.CGImage;
        
            var width = (nfloat)imgRef.Width;
            var height = (nfloat)imgRef.Height;
        
            var bounds = new CGRect(0, 0, width, height);
        
            nfloat scaleRatio = 1;
        
            if (width > maxResolution || height > maxResolution) 
            {
                scaleRatio = (nfloat)Math.Min(maxResolution / bounds.Width, maxResolution / bounds.Height);
                bounds.Height = bounds.Height * scaleRatio;
                bounds.Width = bounds.Width * scaleRatio;
            }
        
            var transform = CGAffineTransform.MakeIdentity();
            var orient = imageSource.Orientation;
            var imageSize = new CGSize(imgRef.Width, imgRef.Height);
            nfloat storedHeight;
        
            switch(imageSource.Orientation) {
                case UIImageOrientation.Up:
                    transform = CGAffineTransform.MakeIdentity();
                    break;
        
                case UIImageOrientation.UpMirrored :
                    transform = CGAffineTransform.MakeTranslation(imageSize.Width, 0.0f);
                    transform = CGAffineTransform.Scale(transform, -1.0f, 1.0f);
                    break;
        
                case UIImageOrientation.Down :
                    transform = CGAffineTransform.MakeTranslation(imageSize.Width, imageSize.Height);
                    transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI);
                    break;
        
                case UIImageOrientation.DownMirrored :
                    transform = CGAffineTransform.MakeTranslation(0.0f, imageSize.Height);
                    transform = CGAffineTransform.Scale(transform, 1.0f, -1.0f);
                    break;
        
                case UIImageOrientation.Left:
                    storedHeight = bounds.Height;
                    bounds.Height = bounds.Width;
                    bounds.Width = storedHeight;
                    transform = CGAffineTransform.MakeTranslation(0.0f, imageSize.Width);
                    transform = CGAffineTransform.Rotate(transform, 3.0f * (nfloat)Math.PI / 2.0f);
                    break;
        
                case UIImageOrientation.LeftMirrored :
                    storedHeight = bounds.Height;
                    bounds.Height = bounds.Width;
                    bounds.Width = storedHeight;
                    transform = CGAffineTransform.MakeTranslation(imageSize.Height, imageSize.Width);
                    transform = CGAffineTransform.Scale(transform, -1.0f, 1.0f);
                    transform = CGAffineTransform.Rotate(transform, 3.0f * (nfloat)Math.PI / 2.0f);
                    break;
        
                case UIImageOrientation.Right :
                    storedHeight = bounds.Height;
                    bounds.Height = bounds.Width;
                    bounds.Width = storedHeight;
                    transform = CGAffineTransform.MakeTranslation(imageSize.Height, 0.0f);
                    transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI / 2.0f);
                    break;
        
                case UIImageOrientation.RightMirrored :
                    storedHeight = bounds.Height;
                    bounds.Height = bounds.Width;
                    bounds.Width = storedHeight;
                    transform = CGAffineTransform.MakeScale(-1.0f, 1.0f);
                    transform = CGAffineTransform.Rotate(transform, (nfloat)Math.PI / 2.0f);
                    break;
        
                default :
                    break;
            }
        
            UIGraphics.BeginImageContext(bounds.Size);
            var context = UIGraphics.GetCurrentContext();
        
            if (orient == UIImageOrientation.Right || orient == UIImageOrientation.Left) {
                context.ScaleCTM(-scaleRatio, scaleRatio);
                context.TranslateCTM(-height, 0);
            } else {
                context.ScaleCTM(scaleRatio, -scaleRatio);
                context.TranslateCTM(0, -height);
            }
        
            context.ConcatCTM(transform);
            context.DrawImage(new CGRect(0, 0, width, height), imgRef);
        
            var imageCopy = UIGraphics.GetImageFromCurrentImageContext();
            UIGraphics.EndImageContext();
        
            return imageCopy;
        }
        

        【讨论】:

        • 在花了很多时间玩这个之后,这有助于解决我的问题!令人难以置信的是,Xamarin 没有对此提供一些内置支持,因为它现在是 Microsoft 产品。
        【解决方案10】:

        为 Swift 3 快速重构(有人可以对其进行测试并确认一切正常吗?):

        static func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage {
            let imgRef = imageSource.cgImage
        
            let width = CGFloat(imgRef!.width)
            let height = CGFloat(imgRef!.height)
        
            var bounds = CGRect(x: 0, y: 0, width: width, height: height)
        
            var scaleRatio : CGFloat = 1
            if width > maxResolution || height > maxResolution {
        
                scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
                bounds.size.height = bounds.size.height * scaleRatio
                bounds.size.width = bounds.size.width * scaleRatio
            }
        
            var transform = CGAffineTransform.identity
            let orient = imageSource.imageOrientation
            let imageSize = CGSize(width: imgRef!.width, height: imgRef!.height)
        
            switch imageSource.imageOrientation {
            case .up :
                transform = CGAffineTransform.identity
        
            case .upMirrored :
                transform = CGAffineTransform(translationX: imageSize.width, y: 0)
                transform = transform.scaledBy(x: -1, y: 1)
        
            case .down :
                transform = CGAffineTransform(translationX: imageSize.width, y: imageSize.height)
                transform = transform.rotated(by: CGFloat.pi)
        
            case .downMirrored :
                transform = CGAffineTransform(translationX: 0, y: imageSize.height)
                transform = transform.scaledBy(x: 1, y: -1)
        
            case .left :
                let storedHeight = bounds.size.height
                bounds.size.height = bounds.size.width
                bounds.size.width = storedHeight
                transform = CGAffineTransform(translationX: 0, y: imageSize.width)
                transform = transform.rotated(by: 3.0 * CGFloat.pi / 2.0)
        
            case .leftMirrored :
                let storedHeight = bounds.size.height
                bounds.size.height = bounds.size.width
                bounds.size.width = storedHeight
                transform = CGAffineTransform(translationX: imageSize.height, y: imageSize.width)
                transform = transform.scaledBy(x: -1, y: 1)
                transform = transform.rotated(by: 3.0 * CGFloat.pi / 2.0)
        
            case .right :
                let storedHeight = bounds.size.height
                bounds.size.height = bounds.size.width
                bounds.size.width = storedHeight
                transform = CGAffineTransform(translationX: imageSize.height, y: 0)
                transform = transform.rotated(by: CGFloat.pi / 2.0)
        
            case .rightMirrored :
                let storedHeight = bounds.size.height
                bounds.size.height = bounds.size.width
                bounds.size.width = storedHeight
                transform = CGAffineTransform(scaleX: -1, y: 1)
                transform = transform.rotated(by: CGFloat.pi / 2.0)
        
            }
        
            UIGraphicsBeginImageContext(bounds.size)
            let context = UIGraphicsGetCurrentContext()
        
            if orient == .right || orient == .left {
        
                context!.scaleBy(x: -scaleRatio, y: scaleRatio)
                context!.translateBy(x: -height, y: 0)
            } else {
                context!.scaleBy(x: scaleRatio, y: -scaleRatio)
                context!.translateBy(x: 0, y: -height)
            }
        
            context!.concatenate(transform)
            context!.draw(imgRef!, in: CGRect(x: 0, y: 0, width: width, height: height))
        
            let imageCopy = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
        
            return imageCopy!
        }
        

        【讨论】:

          【解决方案11】:

          带有Dilip's answer安全检查的Swift 4版本。

          public static func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat = 320) -> UIImage? {
          
              guard let imgRef = imageSource.cgImage else {
                  return nil
              }
          
              let width = CGFloat(imgRef.width)
              let height = CGFloat(imgRef.height)
          
              var bounds = CGRect(x: 0, y: 0, width: width, height: height)
          
              var scaleRatio : CGFloat = 1
              if (width > maxResolution || height > maxResolution) {
          
                  scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
                  bounds.size.height = bounds.size.height * scaleRatio
                  bounds.size.width = bounds.size.width * scaleRatio
              }
          
              var transform = CGAffineTransform.identity
              let orient = imageSource.imageOrientation
              let imageSize = CGSize(width: CGFloat(imgRef.width), height: CGFloat(imgRef.height))
          
              switch(imageSource.imageOrientation) {
              case .up:
                  transform = .identity
              case .upMirrored:
                  transform = CGAffineTransform
                      .init(translationX: imageSize.width, y: 0)
                      .scaledBy(x: -1.0, y: 1.0)
              case .down:
                  transform = CGAffineTransform
                      .init(translationX: imageSize.width, y: imageSize.height)
                      .rotated(by: CGFloat.pi)
              case .downMirrored:
                  transform = CGAffineTransform
                      .init(translationX: 0, y: imageSize.height)
                      .scaledBy(x: 1.0, y: -1.0)
              case .left:
                  let storedHeight = bounds.size.height
                  bounds.size.height = bounds.size.width;
                  bounds.size.width = storedHeight;
                  transform = CGAffineTransform
                      .init(translationX: 0, y: imageSize.width)
                      .rotated(by: 3.0 * CGFloat.pi / 2.0)
              case .leftMirrored:
                  let storedHeight = bounds.size.height
                  bounds.size.height = bounds.size.width;
                  bounds.size.width = storedHeight;
                  transform = CGAffineTransform
                      .init(translationX: imageSize.height, y: imageSize.width)
                      .scaledBy(x: -1.0, y: 1.0)
                      .rotated(by: 3.0 * CGFloat.pi / 2.0)
              case .right :
                  let storedHeight = bounds.size.height
                  bounds.size.height = bounds.size.width;
                  bounds.size.width = storedHeight;
                  transform = CGAffineTransform
                      .init(translationX: imageSize.height, y: 0)
                      .rotated(by: CGFloat.pi / 2.0)
              case .rightMirrored:
                  let storedHeight = bounds.size.height
                  bounds.size.height = bounds.size.width;
                  bounds.size.width = storedHeight;
                  transform = CGAffineTransform
                      .init(scaleX: -1.0, y: 1.0)
                      .rotated(by: CGFloat.pi / 2.0)
              }
          
              UIGraphicsBeginImageContext(bounds.size)
              if let context = UIGraphicsGetCurrentContext() {
                  if orient == .right || orient == .left {
                      context.scaleBy(x: -scaleRatio, y: scaleRatio)
                      context.translateBy(x: -height, y: 0)
                  } else {
                      context.scaleBy(x: scaleRatio, y: -scaleRatio)
                      context.translateBy(x: 0, y: -height)
                  }
          
                  context.concatenate(transform)
                  context.draw(imgRef, in: CGRect(x: 0, y: 0, width: width, height: height))
              }
          
              let imageCopy = UIGraphicsGetImageFromCurrentImageContext()
              UIGraphicsEndImageContext()
          
              return imageCopy
          }
          

          【讨论】:

          • 您也可以在不创建变量作为存储的情况下执行(bounds.size.height, bounds.size.width) = (bounds.size.width, bounds.size.height)
          • 我有时会遇到问题,缩放后图像底部出现一条白线。这是因为 CGFloat 似乎不够精确。我用bounds.size.height.round()bounds.size.width.round() 解决了这个问题
          【解决方案12】:

          这是 Dilip 出色答案的 Swift3 版本

          func rotateCameraImageToProperOrientation(imageSource : UIImage, maxResolution : CGFloat) -> UIImage {
              let imgRef = imageSource.cgImage!;
          
              let width = CGFloat(imgRef.width);
              let height = CGFloat(imgRef.height);
          
              var bounds = CGRect(x: 0, y: 0, width: width, height: height)
          
              var scaleRatio : CGFloat = 1
              if (width > maxResolution || height > maxResolution) {
                  scaleRatio = min(maxResolution / bounds.size.width, maxResolution / bounds.size.height)
                  bounds.size.height = bounds.size.height * scaleRatio
                  bounds.size.width = bounds.size.width * scaleRatio
              }
          
              var transform = CGAffineTransform.identity
              let orient = imageSource.imageOrientation
              let imageSize = CGSize(width: width, height: height)
          
          
              switch(imageSource.imageOrientation) {
                  case .up :
                      transform = CGAffineTransform.identity
          
                  case .upMirrored :
                      transform = CGAffineTransform(translationX: imageSize.width, y: 0.0);
                      transform = transform.scaledBy(x: -1, y: 1);
          
                  case .down :
                      transform = CGAffineTransform(translationX: imageSize.width, y: imageSize.height);
                      transform = transform.rotated(by: CGFloat(Double.pi));
          
                  case .downMirrored :
                      transform = CGAffineTransform(translationX: 0.0, y: imageSize.height);
                      transform = transform.scaledBy(x: 1, y: -1);
          
                  case .left :
                      let storedHeight = bounds.size.height
                      bounds.size.height = bounds.size.width;
                      bounds.size.width = storedHeight;
                      transform = CGAffineTransform(translationX: 0.0, y: imageSize.width);
                      transform = transform.rotated(by: 3.0 * CGFloat(Double.pi) / 2.0);
          
                  case .leftMirrored :
                      let storedHeight = bounds.size.height
                      bounds.size.height = bounds.size.width;
                      bounds.size.width = storedHeight;
                      transform = CGAffineTransform(translationX: imageSize.height, y: imageSize.width);
                      transform = transform.scaledBy(x: -1, y: 1);
                      transform = transform.rotated(by: 3.0 * CGFloat(Double.pi) / 2.0);
          
                  case .right :
                      let storedHeight = bounds.size.height
                      bounds.size.height = bounds.size.width;
                      bounds.size.width = storedHeight;
                      transform = CGAffineTransform(translationX: imageSize.height, y: 0.0);
                      transform = transform.rotated(by: CGFloat(Double.pi) / 2.0);
          
                  case .rightMirrored :
                      let storedHeight = bounds.size.height
                      bounds.size.height = bounds.size.width;
                      bounds.size.width = storedHeight;
                      transform = CGAffineTransform(scaleX: -1.0, y: 1.0);
                      transform = transform.rotated(by: CGFloat(Double.pi) / 2.0);
              }
          
              UIGraphicsBeginImageContext(bounds.size)
              let context = UIGraphicsGetCurrentContext()!
          
              if orient == .right || orient == .left {
                  context.scaleBy(x: -scaleRatio, y: scaleRatio);
                  context.translateBy(x: -height, y: 0);
              } else {
                  context.scaleBy(x: scaleRatio, y: -scaleRatio);
                  context.translateBy(x: 0, y: -height);
              }
          
              context.concatenate(transform);
              context.draw(imgRef, in: CGRect(x: 0, y: 0, width: width, height: height))
          
              let imageCopy = UIGraphicsGetImageFromCurrentImageContext();
              UIGraphicsEndImageContext();
          
              return imageCopy!;
          }
          

          【讨论】:

            【解决方案13】:

            您可以通过此代码修复此 HECI 旋转图像

            Swift 5 扩展:

            extension UIImage {
                /// Fix image orientaton to protrait up
                func fixedOrientation() -> UIImage? {
                    guard imageOrientation != UIImage.Orientation.up else {
                        // This is default orientation, don't need to do anything
                        return self.copy() as? UIImage
                    }
            
                    guard let cgImage = self.cgImage else {
                        // CGImage is not available
                        return nil
                    }
            
                    guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
                        return nil // Not able to create CGContext
                    }
            
                    var transform: CGAffineTransform = CGAffineTransform.identity
            
                    switch imageOrientation {
                    case .down, .downMirrored:
                        transform = transform.translatedBy(x: size.width, y: size.height)
                        transform = transform.rotated(by: CGFloat.pi)
                    case .left, .leftMirrored:
                        transform = transform.translatedBy(x: size.width, y: 0)
                        transform = transform.rotated(by: CGFloat.pi / 2.0)
                    case .right, .rightMirrored:
                        transform = transform.translatedBy(x: 0, y: size.height)
                        transform = transform.rotated(by: CGFloat.pi / -2.0)
                    case .up, .upMirrored:
                        break
                    @unknown default:
                        fatalError("Missing...")
                        break
                    }
            
                    // Flip image one more time if needed to, this is to prevent flipped image
                    switch imageOrientation {
                    case .upMirrored, .downMirrored:
                        transform = transform.translatedBy(x: size.width, y: 0)
                        transform = transform.scaledBy(x: -1, y: 1)
                    case .leftMirrored, .rightMirrored:
                        transform = transform.translatedBy(x: size.height, y: 0)
                        transform = transform.scaledBy(x: -1, y: 1)
                    case .up, .down, .left, .right:
                        break
                    @unknown default:
                        fatalError("Missing...")
                        break
                    }
            
                    ctx.concatenate(transform)
            
                    switch imageOrientation {
                    case .left, .leftMirrored, .right, .rightMirrored:
                        ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
                    default:
                        ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
                        break
                    }
            
                    guard let newCGImage = ctx.makeImage() else { return nil }
                    return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up)
                }
            }
            

            目标 C 代码:

            -(UIImage *)scaleAndRotateImage:(UIImage *)image{
                    // No-op if the orientation is already correct
                    if (image.imageOrientation == UIImageOrientationUp) return image;
                    
                    // We need to calculate the proper transformation to make the image upright.
                    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
                    CGAffineTransform transform = CGAffineTransformIdentity;
                    
                    switch (image.imageOrientation) {
                        case UIImageOrientationDown:
                        case UIImageOrientationDownMirrored:
                            transform = CGAffineTransformTranslate(transform, image.size.width, image.size.height);
                            transform = CGAffineTransformRotate(transform, M_PI);
                            break;
                            
                        case UIImageOrientationLeft:
                        case UIImageOrientationLeftMirrored:
                            transform = CGAffineTransformTranslate(transform, image.size.width, 0);
                            transform = CGAffineTransformRotate(transform, M_PI_2);
                            break;
                            
                        case UIImageOrientationRight:
                        case UIImageOrientationRightMirrored:
                            transform = CGAffineTransformTranslate(transform, 0, image.size.height);
                            transform = CGAffineTransformRotate(transform, -M_PI_2);
                            break;
                        case UIImageOrientationUp:
                        case UIImageOrientationUpMirrored:
                            break;
                    }
                    
                    switch (image.imageOrientation) {
                        case UIImageOrientationUpMirrored:
                        case UIImageOrientationDownMirrored:
                            transform = CGAffineTransformTranslate(transform, image.size.width, 0);
                            transform = CGAffineTransformScale(transform, -1, 1);
                            break;
                            
                        case UIImageOrientationLeftMirrored:
                        case UIImageOrientationRightMirrored:
                            transform = CGAffineTransformTranslate(transform, image.size.height, 0);
                            transform = CGAffineTransformScale(transform, -1, 1);
                            break;
                        case UIImageOrientationUp:
                        case UIImageOrientationDown:
                        case UIImageOrientationLeft:
                        case UIImageOrientationRight:
                            break;
                    }
                    
                    // Now we draw the underlying CGImage into a new context, applying the transform
                    // calculated above.
                    CGContextRef ctx = CGBitmapContextCreate(NULL, image.size.width, image.size.height,
                                                             CGImageGetBitsPerComponent(image.CGImage), 0,
                                                             CGImageGetColorSpace(image.CGImage),
                                                             CGImageGetBitmapInfo(image.CGImage));
                    CGContextConcatCTM(ctx, transform);
                    switch (image.imageOrientation) {
                        case UIImageOrientationLeft:
                        case UIImageOrientationLeftMirrored:
                        case UIImageOrientationRight:
                        case UIImageOrientationRightMirrored:
                            // Grr...
                            CGContextDrawImage(ctx, CGRectMake(0,0,image.size.height,image.size.width), image.CGImage);
                            break;
                            
                        default:
                            CGContextDrawImage(ctx, CGRectMake(0,0,image.size.width,image.size.height), image.CGImage);
                            break;
                    }
                    
                    // And now we just create a new UIImage from the drawing context
                    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
                    UIImage *img = [UIImage imageWithCGImage:cgimg];
                    CGContextRelease(ctx);
                    CGImageRelease(cgimg);
                    return img;
            }
            

            代码的使用

             UIImage *img=[info objectForKey:UIImagePickerControllerOriginalImage];
            
             img=[self scaleAndRotateImage:img];
             NSData *image = UIImageJPEGRepresentation(img, 0.1);
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-08-29
              • 1970-01-01
              • 2011-12-27
              • 2015-02-28
              • 2012-06-16
              • 2021-06-06
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多