【问题标题】:How to load an image and rotate it according to it's orientation exif data and save it with UIImageOrientationUp exif data如何加载图像并根据它的方向 exif 数据旋转它并使用 UIImageOrientationUp exif 数据保存它
【发布时间】:2018-12-22 12:53:09
【问题描述】:

如何加载图像并根据它的orientationexif数据进行旋转并使用UIImageOrientationUpexif数据(或没有任何方向exif数据)保存它,以便不处理exif方向数据的软件将正确显示图片?

【问题讨论】:

    标签: ios objective-c swift uiimage uiimageorientation


    【解决方案1】:

    加载图片就这么简单:

    UIImage *image = [UIImage imageNamed:@"NameOfImageHere"];
    

    或者如果你有图像数据:

    NSData *imageData = [[NSData alloc] init];
    UIImage *image = [UIImage imageWithData: imageData];
    

    以下方法将帮助您使用UIImage中的exif数据修复方向

    - (UIImage *)imageByFixingOrientation {
    
        UIImage *image = self;
    
        if (image.imageOrientation == UIImageOrientationUp) return image;
    
        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:
                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;
    }
    

    【讨论】:

      【解决方案2】:

      Swift 4 相当于我之前的 Objective-c 方法作为扩展:

      extension UIImage {
      
          func byFixingOrientation(andResizingImageToNewSize newSize: CGSize? = nil) -> UIImage {
      
              guard let cgImage = self.cgImage else { return self }
      
              let orientation = self.imageOrientation
              guard orientation != .up else { return UIImage(cgImage: cgImage, scale: 1, orientation: .up) }
      
              var transform = CGAffineTransform.identity
              let size = newSize ?? self.size
      
              if (orientation == .down || orientation == .downMirrored) {
                  transform = transform.translatedBy(x: size.width, y: size.height)
                  transform = transform.rotated(by: .pi)
              }
              else if (orientation == .left || orientation == .leftMirrored) {
                  transform = transform.translatedBy(x: size.width, y: 0)
                  transform = transform.rotated(by: CGFloat.pi / 2)
              }
              else if (orientation == .right || orientation == .rightMirrored) {
                  transform = transform.translatedBy(x: 0, y: size.height)
                  transform = transform.rotated(by: -(CGFloat.pi / 2))
              }
      
              if (orientation == .upMirrored || orientation == .downMirrored) {
                  transform = transform.translatedBy(x: size.width, y: 0);
                  transform = transform.scaledBy(x: -1, y: 1)
              }
              else if (orientation == .leftMirrored || orientation == .rightMirrored) {
                  transform = transform.translatedBy(x: size.height, y: 0)
                  transform = transform.scaledBy(x: -1, y: 1)
              }
      
              // Now we draw the underlying CGImage into a new context, applying the transform calculated above.
              guard let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height),
                                        bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0,
                                        space: cgImage.colorSpace!, bitmapInfo: cgImage.bitmapInfo.rawValue)
              else {
                  return UIImage(cgImage: cgImage, scale: 1, orientation: orientation)
              }
      
              ctx.concatenate(transform)
      
              // Create a new UIImage from the drawing context
              switch (orientation) {
              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))
              }
      
              return UIImage(cgImage: ctx.makeImage() ?? cgImage, scale: 1, orientation: .up)
          }
      }
      

      用法-1

      let newImage = image.byFixingOrientation()
      

      Usage-2(固定方向并将图像调整为新尺寸)

      let newImage = image.byFixingOrientation(andResizingImageToNewSize: CGSize(width: 200, height: 200))
      

      【讨论】:

      • 感谢@AamirR!如果我执行 newImage = image.byFixingOrientation() 然后将 newImage 保存到文件 (jpeg) 中,图像的方向 Exif 数据将是什么?
      • .up 将是新的方向,所以它不会被 exif 方向感知程序自动处理
      • 我只是尝试了您的解决方案,但它不起作用:(当我尝试使用非 exif 方向感知程序加载生成的图像时,图像以错误的方向显示:(
      • 我尝试编译,如果我没有犯任何错误 CGContext(data: nil, width: ...) 相当于 CGBitmapContextCreate 但我没有看到相当于 ctx.concatenate(transform) :(
      • CGContextConcatCTM(ctx, transform);
      猜你喜欢
      • 1970-01-01
      • 2021-10-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-15
      • 1970-01-01
      • 2014-08-13
      • 1970-01-01
      相关资源
      最近更新 更多