简体   繁体   English

iOS PNG图像旋转90度

[英]iOS PNG Image rotated 90 degrees

In my iOS application I'm writing, I deal with PNGs because I deal with the alpha channel. 在我写的iOS应用程序中,我处理PNG因为我处理alpha通道。 For some reason, I can load a PNG into my imageView just fine, but when it comes time to either copy the image out of my application (onto the PasteBoard) or save the image to my camera roll, the image rotates 90 degrees. 出于某种原因,我可以加载PNG到我imageView就好了,但是当谈到时间中的图像复制了我的申请(到剪贴板)或图像保存到我的相机胶卷,图像旋转90度。

I've searched everywhere on this, and one of the things I learned is that if I used JPEGs, I wouldn't have this problem (it sounds), due to the EXIF information. 我在这里搜索了所有的东西,我学到的一件事是,如果我使用JPEG,由于EXIF信息,我不会有这个问题(听起来)。

My app has full copy/paste functionality, and here's the kicker (I'll write this in steps so it is easier to follow): 我的应用程序具有完整的复制/粘贴功能,这里是踢球者(我会在步骤中编写它以便更容易理解):

  1. Go to my camera roll and copy an image 转到我的相机胶卷并复制图像
  2. Go into my app and press "Paste", image pastes just fine, and I can do that all day 进入我的应用程序并按“粘贴”,图像粘贴就好了,我可以整天这样做
  3. Click the copy function I implemented, and then click "Paste", and the image pastes but is rotated. 单击我实现的复制功能,然后单击“粘贴”,图像粘贴但旋转。

I am 100% sure my copy and paste code isn't what is wrong here, because if I go back to Step 2 above, and click "save", the photo saves to my library but it is rotated 90 degrees! 我100%确定我的复制和粘贴代码没有错在这里,因为如果我回到上面的第2步,然后单击“保存”,照片将保存到我的库,但它旋转了90度!

What is even more strange is that it seems to work fine with images downloaded from the internet, but is very hit or miss with images I manually took with the phone. 更奇怪的是它似乎与从互联网上下载的图像一起工作正常,但是我手动用手机拍摄的图像非常受欢迎。 Some it works, some it doesn't... 有些它有效,有些则不...

Does anybody have any thoughts on this? 有没有人对此有任何想法? Any possible work arounds I can use? 我可以使用任何可能的工作吗? I'm pretty confident in the code being it works for about 75% of my images. 我对代码非常有信心,因为它适用于大约75%的图像。 I can post the code upon request though. 我可以根据要求发布代码。

For those that want a Swift solution, create an extension of UIImage and add the following method: 对于那些需要Swift解决方案的人,创建UIImage的扩展并添加以下方法:

func correctlyOrientedImage() -> UIImage {
    if self.imageOrientation == .up {
        return self
    }

    UIGraphicsBeginImageContextWithOptions(size, false, scale)
    draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
    let normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return normalizedImage ?? self;
}

If you're having trouble due to the existing image imageOrientation property, you can construct an otherwise identical image with different orientation like this: 如果由于现有的image imageOrientation属性而遇到问题,则可以构建具有不同方向的其他相同图像,如下所示:

CGImageRef imageRef = [sourceImage CGImage];

UIImage *rotatedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:UIImageOrientationUp];

You may need to experiment with just what orientation to set on your replacement images, possibly switching based on the orientation you started with. 您可能需要尝试在替换图像上设置的方向,可能会根据您开始的方向进行切换。

Also keep an eye on your memory usage. 还要留意你的内存使用情况。 Photography apps often run out, and this will double your storage per picture, until you release the source image. 摄影应用程序经常耗尽,这将使每张照片的存储空间翻倍,直到您发布源图像。

Took a few days, but I finally figured it out thanks to the answer @Dondragmer posted. 花了几天时间,但我终于想通了@Dondragmer发布的答案。 But I figured I'd post my full solution. 但我想我会发布完整的解决方案。

So basically I had to write a method to intelligently auto-rotate my images. 所以基本上我必须编写一种方法来智能地自动旋转我的图像。 The downside is that I have to call this method everywhere throughout my code and it is kind of processor intensive, especially when working on mobile devices, but the plus side is that I can take images, copy images, paste images, and save images and they all rotate properly. 缺点是我必须在我的代码中随处调用这种方法,这是一种处理器密集型,特别是在移动设备上工作时,但优点是我可以拍摄图像,复制图像,粘贴图像,保存图像和它们都旋转得很好。 Here's the code I ended up using (the method isn't 100% complete yet, still need to edit memory leaks and what not). 这是我最终使用的代码(该方法尚未100%完成,仍然需要编辑内存泄漏,什么不是)。

I ended up learning that the very first time an image was insert into my application (whether that be due to a user pressing "take image", "paste image", or "select image", for some reason it insert just fine without auto rotating. At this point, I stored whatever the rotation value was in a global variable called imageOrientationWhenAddedToScreen . This made my life easier because when it came time to manipulate the image and save the image out of the program, I simply checked this cached global variable and determined if I needed to properly rotate the image. 我最终了解到第一次将图像插入到我的应用程序中(无论是由于用户按下“拍摄图像”,“粘贴图像”或“选择图像”,由于某种原因它插入就好了没有自动在这一点上,我存储了一个名为imageOrientationWhenAddedToScreen的全局变量中的旋转值。这使我的生活更轻松,因为当操作图像并将图像保存到程序之外时,我只是检查了这个缓存的全局变量并确定我是否需要正确旋转图像。

    - (UIImage*) rotateImageAppropriately:(UIImage*) imageToRotate {
    //This method will properly rotate our image, we need to make sure that
    //We call this method everywhere pretty much...

    CGImageRef imageRef = [imageToRotate CGImage];
    UIImage* properlyRotatedImage;

    if (imageOrientationWhenAddedToScreen == 0) {
       //Don't rotate the image
        properlyRotatedImage = imageToRotate;

    } else if (imageOrientationWhenAddedToScreen == 3) {

        //We need to rotate the image back to a 3
        properlyRotatedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:3];

    } else if (imageOrientationWhenAddedToScreen == 1) {

        //We need to rotate the image back to a 1
        properlyRotatedImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:1];        

    }

    return properlyRotatedImage;

}

I am still not 100% sure why Apple has this weird image rotation behavior (try this... Take your phone and turn it upside down and take a picture, you'll notice that the final picture turns out right side up - perhaps this is why Apple has this type of functionality?). 我仍然不能100%肯定为什么Apple有这种奇怪的图像旋转行为(试试这个......拿起你的手机并将其翻转并拍照,你会注意到最后的图片是正确的 - 也许这这就是为什么Apple有这种功能?)。

I know I spent a great deal of time figuring this out, so I hope it helps other people! 我知道我花了很多时间搞清楚这一点,所以我希望它能帮助其他人!

This "weird rotation" behavior is really not that weird at all. 这种“奇怪的轮换”行为真的不是那么奇怪。 It is smart, and by smart I mean memory efficient. 它很聪明,聪明的我指的是内存效率。 When you rotate an iOS device the camera hardware rotates with it. 旋转iOS设备时,相机硬件随之旋转。 When you take a picture that picture will be captured however the camera is oriented. 当您拍摄照片时,将拍摄照片,但相机是朝向的。 The UIImage is able to use this raw picture data without copying by just keeping track of the orientation it should be in. When you use UIImagePNGRepresentation() you lose this orientation data and get a PNG of the underlying image as it was taken by the camera. UIImage能够使用这些原始图片数据而无需复制,只需跟踪它应该处于的方向。当您使用UIImagePNGRepresentation()您将丢失此方向数据并获取相机拍摄的基础图像的PNG 。 To fix this instead of rotating you can tell the original image to draw itself to a new context and get the properly oriented UIImage from that context. 要修复此问题而不是旋转,您可以告诉原始图像将自己绘制到新的上下文并从该上下文中获取正确定向的UIImage

UIImage *image = ...;

//Have the image draw itself in the correct orientation if necessary
if(!(image.imageOrientation == UIImageOrientationUp ||
    image.imageOrientation == UIImageOrientationUpMirrored))
{
    CGSize imgsize = image.size;
    UIGraphicsBeginImageContext(imgsize);
    [image drawInRect:CGRectMake(0.0, 0.0, imgsize.width, imgsize.height)];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
}

NSData *png = UIImagePNGRepresentation(image);

Here is one more way to achieve that: 这是实现这一目标的另一种方法:

@IBAction func rightRotateAction(sender: AnyObject) {

    let imgToRotate = CIImage(CGImage: sourceImageView.image?.CGImage)
    let transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))
    let rotatedImage = imgToRotate.imageByApplyingTransform(transform)
    let extent = rotatedImage.extent()
    let contex = CIContext(options: [kCIContextUseSoftwareRenderer: false])
    let cgImage = contex.createCGImage(rotatedImage, fromRect: extent)
    adjustedImage = UIImage(CGImage: cgImage)!
    UIView.transitionWithView(sourceImageView, duration: 0.5, options: UIViewAnimationOptions.TransitionCrossDissolve, animations: {
            self.sourceImageView.image = self.adjustedImage
        }, completion: nil)
}

You can use Image I/O to save PNG image to file(or NSMutableData ) with respect to the orientation of the image. 您可以使用Image I / O将PNG图像相对于图像的方向保存到文件(或NSMutableData )。 In the example below I save the PNG image to a file at path . 在下面的示例中,我将PNG图像保存到path的文件。

- (BOOL)savePngFile:(UIImage *)image toPath:(NSString *)path {
    NSData *data = UIImagePNGRepresentation(image);
    int exifOrientation = [UIImage cc_iOSOrientationToExifOrientation:image.imageOrientation];
    NSDictionary *metadata = @{(__bridge id)kCGImagePropertyOrientation:@(exifOrientation)};
    NSURL *url = [NSURL fileURLWithPath:path];
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    if (!source) {
        return NO;
    }
    CFStringRef UTI = CGImageSourceGetType(source);
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL((__bridge CFURLRef)url, UTI, 1, NULL);
    if (!destination) {
        CFRelease(source);
        return NO;
    }
    CGImageDestinationAddImageFromSource(destination, source, 0, (__bridge CFDictionaryRef)metadata);
    BOOL success = CGImageDestinationFinalize(destination);
    CFRelease(destination);
    CFRelease(source);
    return success;
}

cc_iOSOrientationToExifOrientation: is a method of UIImage category. cc_iOSOrientationToExifOrientation:是一种UIImage类别的方法。

+ (int)cc_iOSOrientationToExifOrientation:(UIImageOrientation)iOSOrientation {
    int exifOrientation = -1;
    switch (iOSOrientation) {
        case UIImageOrientationUp:
            exifOrientation = 1;
            break;

        case UIImageOrientationDown:
            exifOrientation = 3;
            break;

        case UIImageOrientationLeft:
            exifOrientation = 8;
            break;

        case UIImageOrientationRight:
            exifOrientation = 6;
            break;

        case UIImageOrientationUpMirrored:
            exifOrientation = 2;
            break;

        case UIImageOrientationDownMirrored:
            exifOrientation = 4;
            break;

        case UIImageOrientationLeftMirrored:
            exifOrientation = 5;
            break;

        case UIImageOrientationRightMirrored:
            exifOrientation = 7;
            break;

        default:
            exifOrientation = -1;
    }
    return exifOrientation;
}

You can alternatively save the image to NSData using CGImageDestinationCreateWithData and pass NSMutableData instead of NSURL in CGImageDestinationCreateWithURL . 您也可以使用CGImageDestinationCreateWithData将图像保存到NSData并在CGImageDestinationCreateWithURL传递NSMutableData而不是NSURL

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM