iOS:图像在保存为 PNG 表示数据后旋转 90 度
Posted
技术标签:
【中文标题】iOS:图像在保存为 PNG 表示数据后旋转 90 度【英文标题】:iOS: Image get rotated 90 degree after saved as PNG representation data 【发布时间】:2012-06-06 16:32:26 【问题描述】:我已经进行了足够的研究以使其正常工作,但无法修复它。从相机拍照后,只要我将图像存储为 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 函数分别取自 here 和 here。当我将它们应用于 UIImage 时,它们可以正常工作并旋转图像,但如果我将图像保存为 PNG 表示并应用它们,它们就不起作用。
以上功能执行后请参考下图:
【问题讨论】:
1.image clicked from iPhone in Portrait mode gets rotated by 90 degree 2.Camera image changes orientation 不,伙计。您粘贴有关此问题的所有链接。我都经历了! 匿名,如果你低估了这个问题,那么你还没有理解这个问题!我可以看到你在这里遇到了这个问题 - ***.com/questions/3554244/… :-) 你解决了吗? iphone image captured from camera rotate -90 degree automatically的可能重复 非常有用:1. 自然输出是横向 2. .width / .height 受 .imageOrientation 影响 【参考方案1】:从 ios 4.0 开始,当相机拍照时它在保存之前不会旋转它,它
只需在JPEG的EXIF数据中设置一个旋转标志。如果将UIImage保存为JPEG,它
会设置旋转标志。PNGs 不支持旋转标志,所以如果你将 UIImage 保存为
PNG,它将被错误地旋转并且没有设置标志来修复它。所以如果你想要 PNG
您必须自己旋转图像,为此请查看link。
【讨论】:
我建议阅读此answer. 特别是“an0”的答案似乎是最简洁的。【参考方案2】: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
【讨论】:
对于 swift 4-5:只需将UIImageOrientation.up
替换为 UIImage.Orientation.up
【参考方案3】:
斯威夫特 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:)
函数时会发生神奇的事情,该函数尊重最初捕获的方向设置重绘图像。 [link to docs]
确保在调用draw之前使用图像大小调用UIGraphicsBeginImageContext
,让draw
在当前上下文空间中重写UIImage。
UIGraphicsGetImageFromCurrentImageContext
可让您捕捉重绘图像的任何结果,而UIGraphicsEndImageContext
结束并释放图形上下文。
【讨论】:
非常有帮助。谢谢!! 可能是迄今为止不使用黑客功能的最佳答案。非常漂亮。 @return0 谢谢!请考虑为答案投票。 错误Cannot assign to value: function call returns immutable value
已添加说明。 @bluewraith & xleon。【参考方案4】:
我发现以下提示非常有用:
1。自然输出是风景
2。 .width / .height 受 .imageOrientation 影响
3 使用短尺寸而不是 .width
(1) 静态相机的“自然”输出IS LANDSCAPE。
这是违反直觉的。肖像是 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) 点不是万能药,但它通常可以解决所有问题。
希望它可以帮助某人节省一些时间。
【讨论】:
我想在最后一个例子中你应该在某处使用shortDimension
(也许不是第二行中的im.size.width
?)【参考方案5】:
我找到了这个代码here,它实际上为我修复了它。对于我的应用程序,我拍了一张照片并保存了它,每次我加载它时,它都会附加令人讨厌的旋转(我抬头一看,这显然与 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;
我不确定这对你有多大用处,但我希望它有所帮助:)
【讨论】:
它工作正常,但压缩了图像质量。旋转后的图像质量不好。 感谢您的回答。我在我的应用程序中使用了你的代码,但我收到了崩溃报告,从这个函数返回的图像不知何故被破坏了,似乎这个函数导致内存泄漏,这就是原因。您是否遇到同样的问题,我该如何解决? @Ananta Prasad 嗯,我会检查一下并回复你。 @Karapetyan 我会调查是什么导致了你的问题。你用的是什么 Xcode?span> 【参考方案6】:试试这个, 你可以使用
NSData *somenewImageData = UIImageJPEGRepresentation(newimg,1.0);
而不是
NSData *somenewImageData = UIImagePNGRepresentation(newimg);
【讨论】:
【参考方案7】:请尝试以下代码
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];
我从以下链接中引用了更多detail
最好的问候 :-)
【讨论】:
谢谢,但它也不起作用。我使用 CGRect selectionRect = CGRectMake(0, 0, sourceImage.size.width, sourceImage.size.height);旋转完整图像,但仍显示旋转 90 度。请注意,我在本地将图像存储在文档文件夹中后执行此操作。谢谢。 从哪里传递“CGRect TransformCGRectForUIImageOrientation(CGRect source, UIImageOrientationorientation, CGSize imageSize)中的“orientation”值【参考方案8】:试试这个代码:
NSData *imageData = UIImageJPEGRepresentation(delegate.originalPhoto,100);
【讨论】:
这并没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方发表评论 - 您可以随时评论自己的帖子,一旦您有足够的reputation,您就可以comment on any post。 将图像存储为 PNGRepresentation 时会出现旋转问题。如果您将图像存储为 JPEGRepresentation,图像将不会旋转!以上是关于iOS:图像在保存为 PNG 表示数据后旋转 90 度的主要内容,如果未能解决你的问题,请参考以下文章
Android:如何保存不是(JPEG 和 PNG)的图像文件? [旋转后]