Czy można skonfigurować UIImageView
obsługę orientacji obrazu? Kiedy ustawiam UIImageView
obraz z orientacją PRAWĄ (jest to zdjęcie z rolki aparatu), obraz jest obracany w prawo, ale chcę pokazać go w odpowiedniej orientacji, tak jak został zrobiony.
Wiem, że mogę obracać dane obrazu, ale czy można to zrobić bardziej elegancko?
ios
uiimageview
uiimage
orientation
Martin Pilch
źródło
źródło
CGContext
withCGBitmapContextCreate
(lub zeUIGraphicsBeginImageContext
skrótem), użyjCGContextRotateCTM
do ustawienia obrotu, użyjdrawInRect:
naUIImage
lubCGContextDrawImage
z właściwością obrazuCGImage
, a następnie przekonwertuj kontekst na obraz za pomocąUIGraphicsGetImageFromCurrentImageContext
(a następnieUIGraphicsEndImageContext
), jeśli użył UIKit do stworzenia kontekstu lubCGBitmapContextCreateImage
jeśli trzymałeś się Core Graphics. UIKit nie jest bardzo bezpieczny dla wątków, ale kod byłby schludniejszy.Można całkowicie uniknąć ręcznego zmywania przekształca i skalowanie siebie, jak sugeruje an0 w tej odpowiedzi tutaj :
- (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; }
Dokumentacja dla metod UIImage size i drawInRect wyraźnie stwierdza, że uwzględniają one orientację.
źródło
Przekształciłem kod w odpowiedzi Anomie tutaj (skopiowany i wklejony powyżej przez suvish valsan) na 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; }
(Wymieniłem wszystkie occurencies parametru
image
zself
, ponieważ mój kod jest rozszerzeniem naUIImage
).EDYCJA: Wersja Swift 3.
Metoda zwraca wartość opcjonalną, ponieważ wiele wywołań pośrednich może się nie powieść, a ja nie lubię używać
!
.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; }
(Uwaga: odes wersji Swift 3 kompiluje się pod Xcode 8.1, ale nie przetestowano tego, że faktycznie działa. Może gdzieś być literówka, pomieszana szerokość / wysokość itp. Możesz wskazać / naprawić wszelkie błędy).
źródło
func viewDidLoad
. To zdjęcie pochodzi z telefonu samsung photos.google.com/share/ i ma dane exif o orientacji 270 CW. Oto jak go używamlet background: UIImage? = UIImage(named: "background_image")?.fixOrientation() backgroundImage.image = background
Ta metoda najpierw sprawdza aktualną orientację UIImage, a następnie zmienia orientację zgodnie z ruchem wskazówek zegara i zwraca UIImage. Możesz pokazać ten obraz jako
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; }
Wersja Swift 4
func rotateImage(image:UIImage) -> UIImage { var rotatedImage = UIImage() switch image.imageOrientation { case .right: rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .down) case .down: rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .left) case .left: rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .up) default: rotatedImage = UIImage(cgImage: image.cgImage!, scale: 1.0, orientation: .right) } return rotatedImage }
źródło
Swift 3.1
func fixImageOrientation(_ image: UIImage)->UIImage { UIGraphicsBeginImageContext(image.size) image.draw(at: .zero) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage ?? image }
źródło
Rozszerzenie UIImage w Swift. Tak naprawdę wcale nie musisz robić tego całego przewracania. Oryginał Objective-C jest tutaj , ale dodałem bit, który szanuje alfa oryginalnego obrazu (prymitywnie, ale działa, aby odróżnić nieprzezroczyste obrazy od przezroczystych).
// 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 }
źródło
tutaj jest praktyczny przykładowy kod, biorąc pod uwagę orientację obrazu:
#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; }
źródło
Przekonwertowałem kod z odpowiedzi @Nicolas Miari na Swift 3 na wypadek, gdyby ktoś tego potrzebował
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; }
źródło
imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any] let imageCaptured:UIImage = info[UIImagePickerControllerOriginalImage] as! UIImage
obraz jest zawsze właściwyOrientation i ta metoda zwraca obraz :(Dziękuję Waseem05 za tłumaczenie Swift 3, ale jego metoda zadziałała dla mnie tylko wtedy, gdy zawinąłem ją do rozszerzenia do UIImage i umieściłem ją na zewnątrz / poniżej klasy nadrzędnej w następujący sposób:
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; } }
Następnie nazwał to z:
let correctedImage:UIImage = wonkyImage.fixOrientation()
I wszystko było wtedy dobrze! Apple powinno ułatwić odrzucanie orientacji, gdy nie potrzebujemy przedniej / tylnej kamery i metadanych dotyczących orientacji urządzenia w górę / w dół / w lewo / w prawo.
źródło
Jeśli potrzebujesz obrócić i naprawić orientację obrazu poniżej rozszerzenie byłoby przydatne.
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) } }
źródło
extension UIImage { func fixImageOrientation() -> UIImage { UIGraphicsBeginImageContext(self.size) self.draw(at: .zero) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage ?? self } }
Nazwij to:
imageView.image?.fixImageOrientation()
lubUIImage(named: "someImage").fixImageOrientation()
Powodzenia wszystkim!
źródło
Swift 3.0 wersja odpowiedzi Tommy'ego
let imageToDisplay = UIImage.init(cgImage: originalImage.cgImage!, scale: originalImage.scale, orientation: UIImageOrientation.up)
źródło
Zainspirowany @Aqua Answer .....
w celu C
- (UIImage *)fixImageOrientation:(UIImage *)img { UIGraphicsBeginImageContext(img.size); [img drawAtPoint:CGPointZero]; UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); if (newImg) { return newImg; } return img; }
źródło