46

我已经进行了足够的研究以使其正常工作,但无法修复它。从相机拍照后,只要我将图像存储为 UIImage,就可以了,但是一旦我将此图像存储为 PNG 表示形式,它就会旋转 90 度。

以下是我的代码和我尝试过的所有事情:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 
{
    NSString *mediaType = [info valueForKey:UIImagePickerControllerMediaType];

    if([mediaType isEqualToString:(NSString*)kUTTypeImage]) 
    {
        AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
        delegate.originalPhoto  = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
        NSLog(@"Saving photo");
        [self saveImage];
        NSLog(@"Fixing orientation");
        delegate.fixOrientationPhoto  = [self fixOrientation:[UIImage imageWithContentsOfFile:[delegate filePath:imageName]]];      
        NSLog(@"Scaling photo");
        delegate.scaledAndRotatedPhoto  =  [self scaleAndRotateImage:[UIImage imageWithContentsOfFile:[delegate filePath:imageName]]];
    }
    [picker dismissModalViewControllerAnimated:YES];
    [picker release];
}


- (void)saveImage
{
    AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    NSData *imageData = UIImagePNGRepresentation(delegate.originalPhoto);
    [imageData writeToFile:[delegate filePath:imageName] atomically:YES];
}

这里的 fixOrientation 和 scaleAndRotateImage 函数分别取自这里这里。当我将它们应用于 UIImage 时,它​​们可以正常工作并旋转图像,但如果我将图像保存为 PNG 表示并应用它们,它们就不起作用。

执行上述功能后请参考下图:

第一张照片是原始照片,第二张是保存的,第三张和第四张是在保存的图像上应用 fixorientation 和 scaleandrotate 功能后

4

8 回答 8

73

从 iOS 4.0 开始,当相机拍照时它在保存之前不会旋转它,它

只需在 JPEG 的 EXIF 数据中设置一个旋转标志。如果将 UIImage 保存为 JPEG,它

将设置旋转标志。PNG 不支持旋转标志,因此如果将 UIImage 保存为

PNG,它将被错误地旋转并且没有设置标志来修复它。所以如果你想要PNG

图像您必须自己旋转它们,为此请检查此链接

于 2012-06-01T12:35:09.767 回答
28

Rao 发布的 UIImage 扩展的 Swift 3.1 版本:

extension UIImage {
    func fixOrientation() -> UIImage {
        if self.imageOrientation == UIImageOrientation.up {
            return self
        }
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
        if let normalizedImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() {
            UIGraphicsEndImageContext()
            return normalizedImage
        } else {
            return self
        }
    }
}

用法:

let cameraImage = //image captured from camera
let orientationFixedImage = cameraImage.fixOrientation()

斯威夫特 4/5:

UIImageOrientation.up已重命名为UIImage.Orientation.up

于 2017-04-03T08:55:23.640 回答
27

斯威夫特 4.2

添加以下内容作为 UIImage 扩展,

extension UIImage {
    func fixOrientation() -> UIImage? {
        if self.imageOrientation == UIImage.Orientation.up {
            return self
        }

        UIGraphicsBeginImageContext(self.size)
        self.draw(in: CGRect(origin: .zero, size: self.size))
        let normalizedImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return normalizedImage
    }
}

示例用法:

let cameraImage = //image captured from camera
let orientationFixedImage = cameraImage.fixOrientation()

解释:

当您调用 UIImage 的draw(in:)函数时会发生神奇的事情,该函数会根据最初捕获的方向设置重新绘制图像。[链接到文档]

确保UIGraphicsBeginImageContext在调用 draw 之前调用图像的大小,以便draw在当前上下文的空间中重写 UIImage。

UIGraphicsGetImageFromCurrentImageContext让您捕获重绘图像的任何结果,并UIGraphicsEndImageContext结束并释放图形上下文。

于 2016-09-20T13:29:43.787 回答
6

我发现以下提示非常有用:

1. 自然产出是景观

2. .width / .height 受 .imageOrientation 影响

3 使用短尺寸而不是 .width


(1) 静态相机的“自然”输出是风景。

这是违反直觉的。肖像是 UIImagePickerController 等提供的唯一方式。但是当使用“普通”肖像相机时,你会得到 UIImageOrientationRight 作为“普通”方向

(我记得这一点的方式 - 视频的自然输出(当然)是风景;所以静止图像是相同的 - 即使 iPhone 都是关于肖像的。)


(2) .width 和 .height确实受 .imageOrientation 的影响!!!!!!!!!

一定要这样做,并在你的 iPhone 上尝试这两种方式,

NSLog(@"fromImage.imageOrientation is %d", fromImage.imageOrientation);
NSLog(@"fromImage.size.width  %f   fromImage.size.height  %f",
            fromImage.size.width, fromImage.size.height);

你会看到 .height 和 .width 交换,“即使”真正的像素是横向的。


(3) 简单地使用“短尺寸”而不是.width,通常可以解决很多问题

我发现这非常有帮助。假设您可能想要图像的顶部正方形:

CGRect topRectOfOriginal = CGRectMake(0,0, im.size.width,im.size.width);

这实际上是行不通的,当相机(“真的”)被横向握住时,你会得到一个压扁的图像。

但是,如果您非常简单地这样做

float shortDimension = fminf(im.size.width, im.size.height);
CGRect topRectOfOriginal = CGRectMake(0,0, shortDimension,shortDimension);

然后“一切都已解决”,您实际上“无需担心”方向标志。同样,第 (3) 点不是万灵药,但它通常可以解决所有问题。

希望它可以帮助某人节省一些时间。

于 2014-03-09T13:48:47.927 回答
3

我在这里找到了这段代码,它实际上为我修复了它。对于我的应用程序,我拍了一张照片并保存了它,每次我加载它时,它都会附加令人讨厌的旋转(我抬头一看,这显然与 EXIF 以及 iPhone 拍摄和存储图像的方式有关)。这段代码为我修复了它。我不得不说,它最初是作为类/扩展/类别的补充(您可以从链接中找到原件。我像下面这样使用它作为一个简单的方法,因为我真的不想做一个整体仅用于此的类或类别。我只使用了肖像,但我认为代码适用于任何方向。但我不确定

吐槽一下,代码如下:

- (UIImage *)fixOrientationForImage:(UIImage*)neededImage {

    // No-op if the orientation is already correct
    if (neededImage.imageOrientation == UIImageOrientationUp) return neededImage;

    // 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 (neededImage.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, neededImage.size.width, neededImage.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;

        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, neededImage.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;

        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, neededImage.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        case UIImageOrientationUp:
        case UIImageOrientationUpMirrored:
            break;
    }

    switch (neededImage.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, neededImage.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;

        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, neededImage.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, neededImage.size.width, neededImage.size.height,
                                             CGImageGetBitsPerComponent(neededImage.CGImage), 0,
                                             CGImageGetColorSpace(neededImage.CGImage),
                                             CGImageGetBitmapInfo(neededImage.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (neededImage.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            // Grr...
            CGContextDrawImage(ctx, CGRectMake(0,0,neededImage.size.height,neededImage.size.width), neededImage.CGImage);
            break;

        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,neededImage.size.width,neededImage.size.height), neededImage.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;
}

我不确定这对你有多大用处,但我希望它有所帮助:)

于 2015-12-08T23:11:32.167 回答
3

试试这个,你可以使用

NSData *somenewImageData = UIImageJPEGRepresentation(newimg,1.0);

代替

NSData *somenewImageData = UIImagePNGRepresentation(newimg);
于 2017-01-31T05:39:57.443 回答
1

请尝试以下代码

UIImage *sourceImage = ... // Our image
CGRect selectionRect = CGRectMake(100.0, 100.0, 300.0, 400.0);
CGImageRef resultImageRef = CGImageCreateWithImageInRect(sourceImage.CGImage,
selectionRect);
UIImage *resultImage = [[UIImage alloc] initWithCGImage:resultImageRef];

CGRect TransformCGRectForUIImageOrientation(CGRect source, UIImageOrientation orientation, CGSize imageSize) {
switch (orientation) {
case UIImageOrientationLeft: { // EXIF #8
  CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
  CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI_2);
  return CGRectApplyAffineTransform(source, txCompound);
}
case UIImageOrientationDown: { // EXIF #3
  CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
  CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI);
  return CGRectApplyAffineTransform(source, txCompound);
}
case UIImageOrientationRight: { // EXIF #6
  CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(0.0, imageSize.width);
  CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI + M_PI_2);
  return CGRectApplyAffineTransform(source, txCompound);
}
case UIImageOrientationUp: // EXIF #1 - do nothing
  default: // EXIF 2,4,5,7 - ignore
  return source;
}
}
  ...
UIImage *sourceImage = ... // Our image
 CGRect selectionRect = CGRectMake(100.0, 100.0, 300.0, 400.0);
CGRect transformedRect = TransformCGRectForUIImageOrientation(selectionRect,  sourceImage.imageOrientation, sourceImage.size);
CGImageRef resultImageRef = CGImageCreateWithImageInRect(sourceImage.CGImage, transformedRect);
UIImage *resultImage = [[UIImage alloc] initWithCGImage:resultImageRef];

我从以下链接中引用了更多详细信息

最好的祝福 :-)

于 2012-06-01T12:40:50.183 回答
0

试试这个代码:

NSData *imageData = UIImageJPEGRepresentation(delegate.originalPhoto,100);
于 2015-05-26T12:35:12.173 回答