UIImagePickerControllerから画像を読み込み、選択した写真をアプリのドキュメントディレクトリに保存します。
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *data1 = UIImagePNGRepresentation(image);
NSString *fileName = "1.png";
NSString *path = //get Document path, then add fileName
BOOL succ = [data1 writeToFile:path atomically:YES];
しかし、画像をドキュメントに保存した後、画像が90度回転していることがわかり、UIImagePNGRepresentationをUIImageJPEGRepresentationに変更しました。今回は問題ありませんが、誰が何が問題なのか知っていますか?
私は同じ問題を抱えてその理由を理解しました:iOS 4.0以降、カメラが写真を撮るとき、保存する前に回転させず、JPEGのEXIFデータに回転フラグを設定するだけです。
UIImageをJPEGとして保存すると、回転フラグが設定されます。
PNGは回転フラグをサポートしていないため、UIImageをPNGとして保存すると、誤って回転し、それを修正するためのフラグが設定されません。したがって、PNGが必要な場合は、自分で回転させる必要があります。
私はこれをPNG保存機能のバグと呼びますが、それは単なる意見です(少なくともこのことについて警告するはずです)。
これを試してください:
func rotateImage(image: UIImage) -> UIImage {
if (image.imageOrientation == UIImageOrientation.Up ) {
return image
}
UIGraphicsBeginImageContext(image.size)
image.drawInRect(CGRect(Origin: CGPoint.zero, size: image.size))
let copy = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return copy
}
この問題は次のコードで解決します。
- (UIImage *)scaleAndRotateImage:(UIImage *)image
{
int kMaxResolution = 640;
CGImageRef imgRef = image.CGImage;
CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);
CGAffineTransform transform = CGAffineTransformIdentity;
CGRect bounds = CGRectMake(0, 0, width, height);
if (width > kMaxResolution || height > kMaxResolution) {
CGFloat ratio = width/height;
if (ratio > 1) {
bounds.size.width = kMaxResolution;
bounds.size.height = bounds.size.width / ratio;
}
else {
bounds.size.height = kMaxResolution;
bounds.size.width = bounds.size.height * ratio;
}
}
CGFloat scaleRatio = bounds.size.width / width;
CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
CGFloat boundHeight;
UIImageOrientation orient = image.imageOrientation;
switch(orient) {
case UIImageOrientationUp: //EXIF = 1
transform = CGAffineTransformIdentity;
break;
case UIImageOrientationUpMirrored: //EXIF = 2
transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
transform = CGAffineTransformScale(transform, -1.0, 1.0);
break;
case UIImageOrientationDown: //EXIF = 3
transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case UIImageOrientationDownMirrored: //EXIF = 4
transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
break;
case UIImageOrientationLeftMirrored: //EXIF = 5
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
transform = CGAffineTransformScale(transform, -1.0, 1.0);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
break;
case UIImageOrientationLeft: //EXIF = 6
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
break;
case UIImageOrientationRightMirrored: //EXIF = 7
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeScale(-1.0, 1.0);
transform = CGAffineTransformRotate(transform, M_PI / 2.0);
break;
case UIImageOrientationRight: //EXIF = 8
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
transform = CGAffineTransformRotate(transform, M_PI / 2.0);
break;
default:
[NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];
}
UIGraphicsBeginImageContext(bounds.size);
CGContextRef context = UIGraphicsGetCurrentContext();
if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {
CGContextScaleCTM(context, -scaleRatio, scaleRatio);
CGContextTranslateCTM(context, -height, 0);
}
else {
CGContextScaleCTM(context, scaleRatio, -scaleRatio);
CGContextTranslateCTM(context, 0, -height);
}
CGContextConcatCTM(context, transform);
CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);
UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return imageCopy;
}
次のSwift関数は問題を解決します。
var rotatedCopy: UIImage {
if (imageOrientation == UIImageOrientation.Up) {
return self
}
UIGraphicsBeginImageContext(size)
drawInRect(CGRect(Origin: CGPoint.zeroPoint, size: size))
let copy = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return copy
}
drawInRect
関数が画像の向きを考慮に入れるからといって、それは簡単です。
this response に基づいて、UIImagePNGRepresentationでのこの問題を修正するために、このUIImage拡張機能を作成しました。そのため、UIKit func UIImagePNGRepresentationの代わりに、このクラスfunc UIImage.PNGRepresentation(img: UIImage)
を使用することを提案します。
Swift 3コード:
// MyUIImage.Swift
// MyEasyMovie-Public-App
//
// Created by Ahmed Zahraz on 19/12/2016.
// Copyright © 2016 AhmedZahraz. All rights reserved.
import Foundation
import UIKit
extension UIImage {
public class func PNGRepresentation(_ img: UIImage) -> Data? {
// No-op if the orientation is already correct
if (img.imageOrientation == UIImageOrientation.up) {
return UIImagePNGRepresentation(img);
}
// 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.
var transform:CGAffineTransform = CGAffineTransform.identity
if (img.imageOrientation == UIImageOrientation.down
|| img.imageOrientation == UIImageOrientation.downMirrored) {
transform = transform.translatedBy(x: img.size.width, y: img.size.height)
transform = transform.rotated(by: CGFloat(M_PI))
}
if (img.imageOrientation == UIImageOrientation.left
|| img.imageOrientation == UIImageOrientation.leftMirrored) {
transform = transform.translatedBy(x: img.size.width, y: 0)
transform = transform.rotated(by: CGFloat(M_PI_2))
}
if (img.imageOrientation == UIImageOrientation.right
|| img.imageOrientation == UIImageOrientation.rightMirrored) {
transform = transform.translatedBy(x: 0, y: img.size.height);
transform = transform.rotated(by: CGFloat(-M_PI_2));
}
if (img.imageOrientation == UIImageOrientation.upMirrored
|| img.imageOrientation == UIImageOrientation.downMirrored) {
transform = transform.translatedBy(x: img.size.width, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
}
if (img.imageOrientation == UIImageOrientation.leftMirrored
|| img.imageOrientation == UIImageOrientation.rightMirrored) {
transform = transform.translatedBy(x: img.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.
let ctx:CGContext = CGContext(data: nil, width: Int(img.size.width), height: Int(img.size.height),
bitsPerComponent: img.cgImage!.bitsPerComponent, bytesPerRow: 0,
space: img.cgImage!.colorSpace!,
bitmapInfo: img.cgImage!.bitmapInfo.rawValue)!
ctx.concatenate(transform)
if (img.imageOrientation == UIImageOrientation.left
|| img.imageOrientation == UIImageOrientation.leftMirrored
|| img.imageOrientation == UIImageOrientation.right
|| img.imageOrientation == UIImageOrientation.rightMirrored
) {
ctx.draw(img.cgImage!, in: CGRect(x:0,y:0,width:img.size.height,height:img.size.width))
} else {
ctx.draw(img.cgImage!, in: CGRect(x:0,y:0,width:img.size.width,height:img.size.height))
}
// And now we just create a new UIImage from the drawing context
let cgimg:CGImage = ctx.makeImage()!
let imgEnd:UIImage = UIImage(cgImage: cgimg)
return UIImagePNGRepresentation(imgEnd)
}
}
Swift 4のステファンの回答が更新されました。
func rotateImage(image: UIImage) -> UIImage {
if (image.imageOrientation == UIImage.Orientation.up) {
return image
}
UIGraphicsBeginImageContext(image.size)
image.draw(in: CGRect(Origin: .zero, size: image.size))
let copy = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return copy!
}
その後:
var originalImage = yourImage.image!
image = rotateImage(image: originalImage)