Objective c 旋转CG图像
我有一个从UIImagePickerController获取的UIImage。当我从Objective c 旋转CG图像,objective-c,ios,uiimage,cgimage,Objective C,Ios,Uiimage,Cgimage,我有一个从UIImagePickerController获取的UIImage。当我从-(void)imagePickerController:(UIImagePickerController*)picker通过info:(NSDictionary*)info方法接收图像时,我将其直接放入UIImageView进行预览,并为用户提供保存或放弃图像的选项 当用户选择保存选项时,应用程序将获取图像的png数据并将其保存到其文档目录中。但是,在两种可能的设备方向之一(仅横向)下发生的情况是,图像被倒置
-(void)imagePickerController:(UIImagePickerController*)picker通过info:(NSDictionary*)info
方法接收图像时,我将其直接放入UIImageView进行预览,并为用户提供保存或放弃图像的选项
当用户选择保存选项时,应用程序将获取图像的png数据并将其保存到其文档目录中。但是,在两种可能的设备方向之一(仅横向)下发生的情况是,图像被倒置保存(更具体地说,从它应该的位置旋转180度)。因此,当我将图像加载到gallery中时,它看起来是颠倒的
(请参见图库中左下角的图像)
我已经计算出,UIImagePickerController的UIImage中的原始图像数据没有旋转,相反,方向存储为对象上的属性,仅在显示时应用。因此,我尝试使用我在网上找到的一些代码来旋转与UIImage关联的CGImage。但它似乎对图像没有任何影响。我使用的代码如下:
- (void)rotateImage:(UIImage*)image byRadians:(CGFloat)rads
{
// calculate the size of the rotated view's containing box for our drawing space
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,image.size.width, image.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(rads);
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
// Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef bitmap = UIGraphicsGetCurrentContext();
// Move the origin to the middle of the image you want to rotate and scale around the center.
CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2);
// Rotate the image context
CGContextRotateCTM(bitmap, rads);
// Now, draw the rotated/scaled image into the context
CGContextScaleCTM(bitmap, 1.0, -1.0);
CGContextDrawImage(bitmap, CGRectMake(image.size.width / 2, image.size.height / 2, image.size.width, image.size.height), [image CGImage]);
image = UIGraphicsGetImageFromCurrentImageContext();
image = [UIImage imageWithCGImage:image.CGImage scale:1.0 orientation:UIImageOrientationDown];
UIGraphicsEndImageContext();
}
我想知道为什么这段代码不起作用,因为我在网上找到的每一段进行图像旋转的代码似乎都不起作用
-(UIImage*) rotate:(UIImage*) src andOrientation:(UIImageOrientation)orientation
{
UIGraphicsBeginImageContext(src.size);
CGContextRef context=(UIGraphicsGetCurrentContext());
if (orientation == UIImageOrientationRight) {
CGContextRotateCTM (context, 90/180*M_PI) ;
} else if (orientation == UIImageOrientationLeft) {
CGContextRotateCTM (context, -90/180*M_PI);
} else if (orientation == UIImageOrientationDown) {
// NOTHING
} else if (orientation == UIImageOrientationUp) {
CGContextRotateCTM (context, 90/180*M_PI);
}
[src drawAtPoint:CGPointMake(0, 0)];
UIImage *img=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
用这个。。它工作完美!从UIImagePicker拾取图像时,请确保使用此功能:
例如:
UIImage *image;
image = [self rotate:image andOrientation:image.imageOrientation];
请确保在从文档目录中拾取照片的位置使用此功能。我遇到了您的问题。您必须使用
CGContextTranslateCTM(context,-rotatedSize.width/2,-rotatedSize.height/2)将上下文翻译回来代码>以及将图形中rect的原点设置为rotatedViewBox.frame.origin.x、rotatedViewBox.frame.origin.y。
使用此代码
UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,image.size.width, image.size.height)];
CGAffineTransform t = CGAffineTransformMakeRotation(0.3);
rotatedViewBox.transform = t;
CGSize rotatedSize = rotatedViewBox.frame.size;
UIGraphicsBeginImageContext(rotatedSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(context, rotatedSize.width/2, rotatedSize.height/2);
CGContextRotateCTM (context, 0.3);
CGContextScaleCTM(context, 1, -1);
CGContextTranslateCTM(context, -rotatedSize.width/2, -rotatedSize.height/2);
CGContextDrawImage(context, CGRectMake(-rotatedViewBox.frame.origin.x, -rotatedViewBox.frame.origin.y, image.size.width, image.size.height), [image CGImage]);
UIImage *nn = UIGraphicsGetImageFromCurrentImageContext();
NSLog(@"size is %f, %f",nn.size.width,nn.size.height);
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(nn, nil,nil,nil);
旋转和镜像UIImage CGImage备份数据-Swift
我最近想更正一个由CGImage
支持的UIImage
,以匹配所需的方向,而不是依赖api来遵守UIImageOrientation参数
func createMatchingBackingDataWithImage(imageRef: CGImage?, orienation: UIImageOrientation) -> CGImage?
{
var orientedImage: CGImage?
if let imageRef = imageRef {
let originalWidth = imageRef.width
let originalHeight = imageRef.height
let bitsPerComponent = imageRef.bitsPerComponent
let bytesPerRow = imageRef.bytesPerRow
let bitmapInfo = imageRef.bitmapInfo
guard let colorSpace = imageRef.colorSpace else {
return nil
}
var degreesToRotate: Double
var swapWidthHeight: Bool
var mirrored: Bool
switch orienation {
case .up:
degreesToRotate = 0.0
swapWidthHeight = false
mirrored = false
break
case .upMirrored:
degreesToRotate = 0.0
swapWidthHeight = false
mirrored = true
break
case .right:
degreesToRotate = 90.0
swapWidthHeight = true
mirrored = false
break
case .rightMirrored:
degreesToRotate = 90.0
swapWidthHeight = true
mirrored = true
break
case .down:
degreesToRotate = 180.0
swapWidthHeight = false
mirrored = false
break
case .downMirrored:
degreesToRotate = 180.0
swapWidthHeight = false
mirrored = true
break
case .left:
degreesToRotate = -90.0
swapWidthHeight = true
mirrored = false
break
case .leftMirrored:
degreesToRotate = -90.0
swapWidthHeight = true
mirrored = true
break
}
let radians = degreesToRotate * Double.pi / 180.0
var width: Int
var height: Int
if swapWidthHeight {
width = originalHeight
height = originalWidth
} else {
width = originalWidth
height = originalHeight
}
let contextRef = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
contextRef?.translateBy(x: CGFloat(width) / 2.0, y: CGFloat(height) / 2.0)
if mirrored {
contextRef?.scaleBy(x: -1.0, y: 1.0)
}
contextRef?.rotate(by: CGFloat(radians))
if swapWidthHeight {
contextRef?.translateBy(x: -CGFloat(height) / 2.0, y: -CGFloat(width) / 2.0)
} else {
contextRef?.translateBy(x: -CGFloat(width) / 2.0, y: -CGFloat(height) / 2.0)
}
contextRef?.draw(imageRef, in: CGRect(x: 0.0, y: 0.0, width: CGFloat(originalWidth), height: CGFloat(originalHeight)))
orientedImage = contextRef?.makeImage()
}
return orientedImage
}
Swift 3版本适用于:
用法:
let newCgImage = createMatchingBackingDataWithImage(imageRef: cgImageRef, orienation: .left)
这只是对前面答案的重构
func correctImageOrientation(cgImage: CGImage?, orienation: UIImage.Orientation) -> CGImage? {
guard let cgImage = cgImage else { return nil }
var orientedImage: CGImage?
let originalWidth = cgImage.width
let originalHeight = cgImage.height
let bitsPerComponent = cgImage.bitsPerComponent
let bytesPerRow = cgImage.bytesPerRow
let bitmapInfo = cgImage.bitmapInfo
guard let colorSpace = cgImage.colorSpace else { return nil }
let degreesToRotate = orienation.getDegree()
let mirrored = orienation.isMirror()
var width = originalWidth
var height = originalHeight
let radians = degreesToRotate * Double.pi / 180.0
let swapWidthHeight = Int(degreesToRotate / 90) % 2 != 0
if swapWidthHeight {
swap(&width, &height)
}
let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
context?.translateBy(x: CGFloat(width) / 2.0, y: CGFloat(height) / 2.0)
if mirrored {
context?.scaleBy(x: -1.0, y: 1.0)
}
context?.rotate(by: CGFloat(radians))
if swapWidthHeight {
swap(&width, &height)
}
context?.translateBy(x: -CGFloat(width) / 2.0, y: -CGFloat(height) / 2.0)
context?.draw(cgImage, in: CGRect(x: 0.0, y: 0.0, width: CGFloat(originalWidth), height: CGFloat(originalHeight)))
orientedImage = context?.makeImage()
return orientedImage
}
extension UIImage.Orientation {
func getDegree() -> Double {
switch self {
case .up, .upMirrored:
return 0.0
case .right, .rightMirrored:
return 90.0
case .down, .downMirrored:
return 180.0
case .left, .leftMirrored:
return -90.0
default:
return 0
}
}
func isMirror() -> Bool {
switch self {
case .up, .right, .down, .left:
return false
case .leftMirrored, .upMirrored, .downMirrored, .rightMirrored:
return true
default:
return false
}
}
}
很好的回答。。。我唯一要改变的是,“返回img;
”在“[img release];
”(这意味着release调用从未真正命中)之前被调用。此外,这假设此人没有使用弧。你知道为什么旋转是必要的吗?“你正在旋转上下文(及其坐标系),然后将图像绘制到其中。”因此,他们可以将上下文称为画架,对吗?不知道为什么他们没有。理解什么是“画架”(毕竟,大多数人都使用过画架)比理解什么是“背景”更容易。你的解决方案和你的解决方案有什么区别?您正在考虑更多的情况(例如镜像图像)。但还有什么?有些角度似乎不同,使用的方法也不同(CGContextRotateCTM
vs.rotate
)。另外,您正在通过
进行翻译,而其他解决方案没有考虑到这一点……还有什么区别?
func correctImageOrientation(cgImage: CGImage?, orienation: UIImage.Orientation) -> CGImage? {
guard let cgImage = cgImage else { return nil }
var orientedImage: CGImage?
let originalWidth = cgImage.width
let originalHeight = cgImage.height
let bitsPerComponent = cgImage.bitsPerComponent
let bytesPerRow = cgImage.bytesPerRow
let bitmapInfo = cgImage.bitmapInfo
guard let colorSpace = cgImage.colorSpace else { return nil }
let degreesToRotate = orienation.getDegree()
let mirrored = orienation.isMirror()
var width = originalWidth
var height = originalHeight
let radians = degreesToRotate * Double.pi / 180.0
let swapWidthHeight = Int(degreesToRotate / 90) % 2 != 0
if swapWidthHeight {
swap(&width, &height)
}
let context = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)
context?.translateBy(x: CGFloat(width) / 2.0, y: CGFloat(height) / 2.0)
if mirrored {
context?.scaleBy(x: -1.0, y: 1.0)
}
context?.rotate(by: CGFloat(radians))
if swapWidthHeight {
swap(&width, &height)
}
context?.translateBy(x: -CGFloat(width) / 2.0, y: -CGFloat(height) / 2.0)
context?.draw(cgImage, in: CGRect(x: 0.0, y: 0.0, width: CGFloat(originalWidth), height: CGFloat(originalHeight)))
orientedImage = context?.makeImage()
return orientedImage
}
extension UIImage.Orientation {
func getDegree() -> Double {
switch self {
case .up, .upMirrored:
return 0.0
case .right, .rightMirrored:
return 90.0
case .down, .downMirrored:
return 180.0
case .left, .leftMirrored:
return -90.0
default:
return 0
}
}
func isMirror() -> Bool {
switch self {
case .up, .right, .down, .left:
return false
case .leftMirrored, .upMirrored, .downMirrored, .rightMirrored:
return true
default:
return false
}
}
}