iOS-UIImageView - как обрабатывать ориентацию изображения UIImage
можно ли настроить UIImageView для обработки ориентации изображения? Когда я установил UIImageView изображение с ориентацией право (это фото с камеры ролл), изображение поворачивается вправо, но я хочу, чтобы показать его в правильной ориентации, как это было сделано.
Я знаю, что могу вращать данные изображения, но можно сделать это более элегантно?
спасибо
11 ответов:
Если я понимаю, что вы хотите сделать, это игнорировать ориентацию UIImage? Если это так, то вы могли бы сделать это:
UIImage *originalImage = [... whatever ...]; UIImage *imageToDisplay = [UIImage imageWithCGImage:[originalImage CGImage] scale:[originalImage scale] orientation: UIImageOrientationUp];
таким образом, вы создаете новый UIImage с теми же данными пикселей, что и оригинал (на который ссылается его свойство CGImage), но вы указываете ориентацию, которая не поворачивает данные.
вы можете полностью избежать ручного выполнения преобразований и масштабирования самостоятельно, как это было предложено an0 в этом ответе здесь:
- (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; }
документация для методов UIImage в размере и drawInRect явно заявляет, что они учитывают ориентацию.
я преобразовал код в ответ аномии здесь (копия вставлена выше suvish valsan) в Свифт:
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; }
(Я заменил все вхождения параметра
image
Сself
, потому что мой код является расширением наUIImage
).
EDIT: Swift 3 версия.
метод возвращает необязательный, потому что многие из промежуточных вызовов могут завершиться неудачей, и я не люблю использовать
!
.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; }
(Примечание: Swift 3 версия odes компилируется под Xcode 8.1, но не тестировал его на самом деле работает. Где-то может быть опечатка, перепутанная ширина/высота и т. д. Не стесняйтесь указывать / исправлять любые ошибки).
этот метод сначала проверяет текущую ориентацию UIImage, а затем изменяет ориентацию по часовой стрелке и возвращает UIImage.Вы можете показать это изображение как
self.просмотрщик фото.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
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 }
вот работоспособный образец трески, учитывая ориентацию изображения:
#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; }
расширение UIImage в Swift. Вам вообще не нужно делать все это переворачивание, на самом деле. Цель-С Оригинал здесь, но я добавил бит, который уважает Альфа исходного изображения (грубо, но он работает, чтобы отличать непрозрачные изображения от прозрачных изображений).
// 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 }
Swift 3.1
func fixImageOrientation(_ image: UIImage)->UIImage { UIGraphicsBeginImageContext(image.size) image.draw(at: .zero) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage ?? image }
я преобразовал код из @Nicolas Miari answer в Swift 3 в случае, если кому-то это нужно
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; }
спасибо Waseem05 за его перевод Swift 3, но его метод работал только для меня, когда я завернул его в расширение для UIImage и поместил его снаружи / ниже родительского класса следующим образом:
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; } }
затем назвал его с:
let correctedImage:UIImage = wonkyImage.fixOrientation()
и все было тогда хорошо! Apple должна упростить отказ от ориентации, когда нам не нужны метаданные ориентации передней/задней камеры и вверх/вниз/влево/вправо.
Swift 3.0 версия ответа Томми
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 } }
- создать расширение как пример.
называем это:
imageView.image?.fixImageOrientation()
илиUIImage(named: "someImage").fixImageOrientation()
удачи всем!