IOS-UIImageView-如何处理 UIImage 图像定位

是否可以设置 UIImageView来处理图像方向?当我设置的 UIImageView图像与方向 好吧(这是照片从相机辊) ,图像是旋转到右边,但我想显示它在适当的方向,因为它是采取。

我知道我可以旋转图像数据,但它可能做得更优雅?

115091 次浏览

If I understand, what you want to do is disregard the orientation of the UIImage? If so then you could do this:

UIImage *originalImage = [... whatever ...];


UIImage *imageToDisplay =
[UIImage imageWithCGImage:[originalImage CGImage]
scale:[originalImage scale]
orientation: UIImageOrientationUp];

So you're creating a new UIImage with the same pixel data as the original (referenced via its CGImage property) but you're specifying an orientation that doesn't rotate the data.

here is a workable sample cod, considering the image orientation:

#define rad(angle) ((angle) / 180.0 * M_PI)
- (CGAffineTransform)orientationTransformedRectOfImage:(UIImage *)img
{
CGAffineTransform rectTransform;
switch (img.imageOrientation)
{
case UIImageOrientationLeft:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -img.size.height);
break;
case UIImageOrientationRight:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -img.size.width, 0);
break;
case UIImageOrientationDown:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -img.size.width, -img.size.height);
break;
default:
rectTransform = CGAffineTransformIdentity;
};


return CGAffineTransformScale(rectTransform, img.scale, img.scale);
}




- (UIImage *)croppedImage:(UIImage*)orignialImage InRect:(CGRect)visibleRect{
//transform visible rect to image orientation
CGAffineTransform rectTransform = [self orientationTransformedRectOfImage:orignialImage];
visibleRect = CGRectApplyAffineTransform(visibleRect, rectTransform);


//crop image
CGImageRef imageRef = CGImageCreateWithImageInRect([orignialImage CGImage], visibleRect);
UIImage *result = [UIImage imageWithCGImage:imageRef scale:orignialImage.scale orientation:orignialImage.imageOrientation];
CGImageRelease(imageRef);
return result;
}

You can completely avoid manually doing the transforms and scaling yourself, as suggested by an0 in this answer here:

- (UIImage *)normalizedImage {
if (self.imageOrientation == UIImageOrientationUp) return self;


UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
[self drawInRect:(CGRect){0, 0, self.size}];
UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return normalizedImage;
}

The documentation for the UIImage methods size and drawInRect explicitly states that they take into account orientation.

I converted the code in Anomie's answer here (copy-pasted above by suvish valsan) into Swift:

func fixOrientation() -> UIImage {
if self.imageOrientation == UIImageOrientation.Up {
return self
}


var transform = CGAffineTransformIdentity


switch self.imageOrientation {
case .Down, .DownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height)
transform = CGAffineTransformRotate(transform, CGFloat(M_PI));


case .Left, .LeftMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2));


case .Right, .RightMirrored:
transform = CGAffineTransformTranslate(transform, 0, self.size.height);
transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2));


case .Up, .UpMirrored:
break
}


switch self.imageOrientation {


case .UpMirrored, .DownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0)
transform = CGAffineTransformScale(transform, -1, 1)


case .LeftMirrored, .RightMirrored:
transform = CGAffineTransformTranslate(transform, self.size.height, 0)
transform = CGAffineTransformScale(transform, -1, 1);


default:
break;
}


// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
let ctx = CGBitmapContextCreate(
nil,
Int(self.size.width),
Int(self.size.height),
CGImageGetBitsPerComponent(self.CGImage),
0,
CGImageGetColorSpace(self.CGImage),
UInt32(CGImageGetBitmapInfo(self.CGImage).rawValue)
)


CGContextConcatCTM(ctx, transform);


switch self.imageOrientation {
case .Left, .LeftMirrored, .Right, .RightMirrored:
// Grr...
CGContextDrawImage(ctx, CGRectMake(0, 0, self.size.height,self.size.width), self.CGImage);


default:
CGContextDrawImage(ctx, CGRectMake(0, 0, self.size.width,self.size.height), self.CGImage);
break;
}


// And now we just create a new UIImage from the drawing context
let cgimg = CGBitmapContextCreateImage(ctx)


let img = UIImage(CGImage: cgimg!)


return img;
}

(I replaced all occurencies of the parameter image with self, because my code is an extension on UIImage).


EDIT: Swift 3 version.

The method returns an optional, because many of the intermediate calls can fail and I don't like to use !.

func fixOrientation() -> UIImage? {


guard let cgImage = self.cgImage else {
return nil
}


if self.imageOrientation == UIImageOrientation.up {
return self
}


let width  = self.size.width
let height = self.size.height


var transform = CGAffineTransform.identity


switch self.imageOrientation {
case .down, .downMirrored:
transform = transform.translatedBy(x: width, y: height)
transform = transform.rotated(by: CGFloat.pi)


case .left, .leftMirrored:
transform = transform.translatedBy(x: width, y: 0)
transform = transform.rotated(by: 0.5*CGFloat.pi)


case .right, .rightMirrored:
transform = transform.translatedBy(x: 0, y: height)
transform = transform.rotated(by: -0.5*CGFloat.pi)


case .up, .upMirrored:
break
}


switch self.imageOrientation {
case .upMirrored, .downMirrored:
transform = transform.translatedBy(x: width, y: 0)
transform = transform.scaledBy(x: -1, y: 1)


case .leftMirrored, .rightMirrored:
transform = transform.translatedBy(x: height, y: 0)
transform = transform.scaledBy(x: -1, y: 1)


default:
break;
}


// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
guard let colorSpace = cgImage.colorSpace else {
return nil
}


guard let context = CGContext(
data: nil,
width: Int(width),
height: Int(height),
bitsPerComponent: cgImage.bitsPerComponent,
bytesPerRow: 0,
space: colorSpace,
bitmapInfo: UInt32(cgImage.bitmapInfo.rawValue)
) else {
return nil
}


context.concatenate(transform);


switch self.imageOrientation {


case .left, .leftMirrored, .right, .rightMirrored:
// Grr...
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: height, height: width))


default:
context.draw(cgImage, in: CGRect(x: 0, y: 0, width: width, height: height))
}


// And now we just create a new UIImage from the drawing context
guard let newCGImg = context.makeImage() else {
return nil
}


let img = UIImage(cgImage: newCGImg)


return img;
}

(Note: Swift 3 version odes compile under Xcode 8.1, but haven't tested it actually works. There might be a typo somewhere, mixed up width/height, etc. Feel free to point/fix any errors).

UIImage extension in Swift. You don't need to do all that flipping at all, really. Objective-C original is here, but I've added the bit that respects the alpha of the original image (crudely, but it works to differentiate opaque images from transparent images).

// from https://github.com/mbcharbonneau/UIImage-Categories/blob/master/UIImage%2BAlpha.m
// Returns true if the image has an alpha layer
private func hasAlpha() -> Bool {
guard let cg = self.cgImage else { return false }
let alpha = cg.alphaInfo
let retVal = (alpha == .first || alpha == .last || alpha == .premultipliedFirst || alpha == .premultipliedLast)
return retVal
}


func normalizedImage() -> UIImage? {
if self.imageOrientation == .up {
return self
}
UIGraphicsBeginImageContextWithOptions(self.size, !self.hasAlpha(), self.scale)
var rect = CGRect.zero
rect.size = self.size
self.draw(in: rect)
let retVal = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return retVal
}

This method first checks the current orientation of UIImage and then it changes the orientation in a clockwise way and return UIImage.You can show this image as

self.imageView.image = rotateImage(currentUIImage)

   func rotateImage(image:UIImage)->UIImage
{
var rotatedImage = UIImage();
switch image.imageOrientation
{
case UIImageOrientation.Right:
rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Down);
            

case UIImageOrientation.Down:
rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Left);
            

case UIImageOrientation.Left:
rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Up);
    

default:
rotatedImage = UIImage(CGImage:image.CGImage!, scale: 1, orientation:UIImageOrientation.Right);
}
return rotatedImage;
}

Swift 4 version

extension UIImage {


func rotate() -> UIImage {
var rotatedImage = UIImage()
guard let cgImage = cgImage else {
print("could not rotate image")
return self
}
switch imageOrientation {
case .right:
rotatedImage = UIImage(cgImage: cgImage, scale: scale, orientation: .down)
case .down:
rotatedImage = UIImage(cgImage: cgImage, scale: scale, orientation: .left)
case .left:
rotatedImage = UIImage(cgImage: cgImage, scale: scale, orientation: .up)
default:
rotatedImage = UIImage(cgImage: cgImage, scale: scale, orientation: .right)
}
    

return rotatedImage
}
}

I converted the code from @Nicolas Miari answer to Swift 3 in case anybody needs it

func fixOrientation() -> UIImage
{


if self.imageOrientation == UIImageOrientation.up {
return self
}


var transform = CGAffineTransform.identity


switch self.imageOrientation {
case .down, .downMirrored:
transform = transform.translatedBy(x: self.size.width, y: self.size.height)
transform = transform.rotated(by: CGFloat(M_PI));


case .left, .leftMirrored:
transform = transform.translatedBy(x: self.size.width, y: 0);
transform = transform.rotated(by: CGFloat(M_PI_2));


case .right, .rightMirrored:
transform = transform.translatedBy(x: 0, y: self.size.height);
transform = transform.rotated(by: CGFloat(-M_PI_2));


case .up, .upMirrored:
break
}




switch self.imageOrientation {


case .upMirrored, .downMirrored:
transform = transform.translatedBy(x: self.size.width, y: 0)
transform = transform.scaledBy(x: -1, y: 1)


case .leftMirrored, .rightMirrored:
transform = transform.translatedBy(x: self.size.height, y: 0)
transform = transform.scaledBy(x: -1, y: 1);


default:
break;
}


// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
let ctx = CGContext(
data: nil,
width: Int(self.size.width),
height: Int(self.size.height),
bitsPerComponent: self.cgImage!.bitsPerComponent,
bytesPerRow: 0,
space: self.cgImage!.colorSpace!,
bitmapInfo: UInt32(self.cgImage!.bitmapInfo.rawValue)
)






ctx!.concatenate(transform);


switch self.imageOrientation {


case .left, .leftMirrored, .right, .rightMirrored:
// Grr...
ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.height ,height:self.size.width))


default:
ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.width ,height:self.size.height))
break;
}


// And now we just create a new UIImage from the drawing context
let cgimg = ctx!.makeImage()


let img = UIImage(cgImage: cgimg!)


return img;


}

Thanks to Waseem05 for his Swift 3 translation but his method only worked for me when I wrapped it inside an extension to UIImage and placed it outside/below the parent class like so:

extension UIImage {


func fixOrientation() -> UIImage
{


if self.imageOrientation == UIImageOrientation.up {
return self
}


var transform = CGAffineTransform.identity


switch self.imageOrientation {
case .down, .downMirrored:
transform = transform.translatedBy(x: self.size.width, y: self.size.height)
transform = transform.rotated(by: CGFloat(M_PI));


case .left, .leftMirrored:
transform = transform.translatedBy(x: self.size.width, y: 0);
transform = transform.rotated(by: CGFloat(M_PI_2));


case .right, .rightMirrored:
transform = transform.translatedBy(x: 0, y: self.size.height);
transform = transform.rotated(by: CGFloat(-M_PI_2));


case .up, .upMirrored:
break
}




switch self.imageOrientation {


case .upMirrored, .downMirrored:
transform = transform.translatedBy(x: self.size.width, y: 0)
transform = transform.scaledBy(x: -1, y: 1)


case .leftMirrored, .rightMirrored:
transform = transform.translatedBy(x: self.size.height, y: 0)
transform = transform.scaledBy(x: -1, y: 1);


default:
break;
}


// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
let ctx = CGContext(
data: nil,
width: Int(self.size.width),
height: Int(self.size.height),
bitsPerComponent: self.cgImage!.bitsPerComponent,
bytesPerRow: 0,
space: self.cgImage!.colorSpace!,
bitmapInfo: UInt32(self.cgImage!.bitmapInfo.rawValue)
)






ctx!.concatenate(transform);


switch self.imageOrientation {


case .left, .leftMirrored, .right, .rightMirrored:
// Grr...
ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.height ,height:self.size.width))


default:
ctx?.draw(self.cgImage!, in: CGRect(x:0 ,y: 0 ,width: self.size.width ,height:self.size.height))
break;
}


// And now we just create a new UIImage from the drawing context
let cgimg = ctx!.makeImage()


let img = UIImage(cgImage: cgimg!)


return img;


}
}

Then called it with:

let correctedImage:UIImage = wonkyImage.fixOrientation()

And all was then well! Apple should make it easier to discard orientation when we don't need front/back camera and up/down/left/right device orientation metadata.

Swift 3.1

func fixImageOrientation(_ image: UIImage)->UIImage {
UIGraphicsBeginImageContext(image.size)
image.draw(at: .zero)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage ?? image
}

Swift 3.0 version of Tommy's answer

let imageToDisplay = UIImage.init(cgImage: originalImage.cgImage!, scale: originalImage.scale, orientation: UIImageOrientation.up)
extension UIImage {
func fixImageOrientation() -> UIImage {
UIGraphicsBeginImageContext(self.size)
self.draw(at: .zero)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage ?? self
}
}
  1. Create extension like top example.
  2. Call it: imageView.image?.fixImageOrientation() or UIImage(named: "someImage").fixImageOrientation()

  3. Good luck all!

If you need to rotate and fix the image orientation below extension would be useful.

extension UIImage {


public func imageRotatedByDegrees(degrees: CGFloat) -> UIImage {
//Calculate the size of the rotated view's containing box for our drawing space
let rotatedViewBox: UIView = UIView(frame: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
let t: CGAffineTransform = CGAffineTransform(rotationAngle: degrees * CGFloat.pi / 180)
rotatedViewBox.transform = t
let rotatedSize: CGSize = rotatedViewBox.frame.size
//Create the bitmap context
UIGraphicsBeginImageContext(rotatedSize)
let bitmap: CGContext = UIGraphicsGetCurrentContext()!
//Move the origin to the middle of the image so we will rotate and scale around the center.
bitmap.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
//Rotate the image context
bitmap.rotate(by: (degrees * CGFloat.pi / 180))
//Now, draw the rotated/scaled image into the context
bitmap.scaleBy(x: 1.0, y: -1.0)
bitmap.draw(self.cgImage!, in: CGRect(x: -self.size.width / 2, y: -self.size.height / 2, width: self.size.width, height: self.size.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}




public func fixedOrientation() -> UIImage {
if imageOrientation == UIImageOrientation.up {
return self
}


var transform: CGAffineTransform = CGAffineTransform.identity


switch imageOrientation {
case UIImageOrientation.down, UIImageOrientation.downMirrored:
transform = transform.translatedBy(x: size.width, y: size.height)
transform = transform.rotated(by: CGFloat.pi)
break
case UIImageOrientation.left, UIImageOrientation.leftMirrored:
transform = transform.translatedBy(x: size.width, y: 0)
transform = transform.rotated(by: CGFloat.pi/2)
break
case UIImageOrientation.right, UIImageOrientation.rightMirrored:
transform = transform.translatedBy(x: 0, y: size.height)
transform = transform.rotated(by: -CGFloat.pi/2)
break
case UIImageOrientation.up, UIImageOrientation.upMirrored:
break
}


switch imageOrientation {
case UIImageOrientation.upMirrored, UIImageOrientation.downMirrored:
transform.translatedBy(x: size.width, y: 0)
transform.scaledBy(x: -1, y: 1)
break
case UIImageOrientation.leftMirrored, UIImageOrientation.rightMirrored:
transform.translatedBy(x: size.height, y: 0)
transform.scaledBy(x: -1, y: 1)
case UIImageOrientation.up, UIImageOrientation.down, UIImageOrientation.left, UIImageOrientation.right:
break
}


let ctx: CGContext = CGContext(data: nil,
width: Int(size.width),
height: Int(size.height),
bitsPerComponent: self.cgImage!.bitsPerComponent,
bytesPerRow: 0,
space: self.cgImage!.colorSpace!,
bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!


ctx.concatenate(transform)


switch imageOrientation {
case UIImageOrientation.left, UIImageOrientation.leftMirrored, UIImageOrientation.right, UIImageOrientation.rightMirrored:
ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
default:
ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
break
}


let cgImage: CGImage = ctx.makeImage()!


return UIImage(cgImage: cgImage)
}
}

Inspired from @Aqua Answer.....

in Objective C

- (UIImage *)fixImageOrientation:(UIImage *)img {


UIGraphicsBeginImageContext(img.size);
[img drawAtPoint:CGPointZero];


UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();


if (newImg) {
return newImg;
}


return img;
}

I tried the checkmarked solution and it doesn't work for me. But the below solution works for fixing orientation from camera before converting to png.

Swift 5:

let imageToDisplay = originalImage.resize(new: originalImage.resize)