iOS PNG 图像旋转 90 度
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10307521/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iOS PNG Image rotated 90 degrees
提问by Boeckm
In my iOS application I'm writing, I deal with PNGs because I deal with the alpha channel. 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.
在我编写的 iOS 应用程序中,我处理 PNG,因为我处理 alpha 通道。出于某种原因,我可以将 PNG 加载到我的imageView
就好了,但是当需要从我的应用程序中复制图像(到 PasteBoard)或将图像保存到我的相机胶卷时,图像会旋转 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):
我的应用程序具有完整的复制/粘贴功能,这里是踢球者(我将分步编写,以便更容易理解):
- Go to my camera roll and copy an image
- Go into my app and press "Paste", image pastes just fine, and I can do that all day
- 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. I can post the code upon request though.
有没有人对此有任何想法?我可以使用任何可能的解决方法?我对代码非常有信心,因为它适用于我大约 75% 的图像。我可以根据要求发布代码。
采纳答案by Boeckm
Took a few days, but I finally figured it out thanks to the answer @Dondragmer posted. But I figured I'd post my full solution.
花了几天时间,但由于@Dondragmer 发布的答案,我终于弄明白了。但我想我会发布我的完整解决方案。
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 有这种奇怪的图像旋转行为(试试这个……把你的手机倒过来拍一张,你会注意到最后的照片是正面朝上的——也许这个这就是为什么苹果有这种功能?)。
I know I spent a great deal of time figuring this out, so I hope it helps other people!
我知道我花了很多时间来解决这个问题,所以我希望它可以帮助其他人!
回答by Tom J
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;
}
回答by Dondragmer
If you're having trouble due to the existing image imageOrientation
property, you can construct an otherwise identical image with different orientation like this:
如果由于现有的图像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.
还要注意您的内存使用情况。摄影应用程序经常用完,这将使每张照片的存储空间增加一倍,直到您发布源图像。
回答by Joe
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. 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. 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.
这种“奇怪的轮换”行为真的一点也不奇怪。它很聪明,我所说的聪明是指内存效率高。当您旋转 iOS 设备时,相机硬件会随之旋转。当您拍照时,该照片将被捕获,但相机是定向的。UIImage 能够使用原始图片数据而无需复制,只需跟踪它应该处于的方向。当您使用时,UIImagePNGRepresentation()
您会丢失此方向数据并获得相机拍摄的底层图像的 PNG。要解决此问题而不是旋转,您可以告诉原始图像将自身绘制到新的上下文并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);
回答by Dharmesh Kheni
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)
}
回答by KudoCC
You can use Image I/O to save PNG image to file(or NSMutableData
) with respect to the orientation of the image. In the example below I save the PNG image to a file at path
.
您可以使用 Image I/O 根据图像NSMutableData
的方向将 PNG 图像保存到文件(或)。在下面的示例中,我将 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
.
您也可以将图像保存为NSData
usingCGImageDestinationCreateWithData
和 passNSMutableData
而不是NSURL
in CGImageDestinationCreateWithURL
。