IOS - UIImageView - как обрабатывать ориентацию изображения UIImage
Можно ли настроить UIImageView для обработки ориентации изображения? Когда я устанавливаю изображение UIImageView с ориентацией ПРАВО (это фотография из рулона камеры), изображение поворачивается вправо, но я хочу показать его в правильной ориентации, как это было принято.
Я знаю, что могу повернуть данные изображения, но можно сделать его более элегантным?
Спасибо
Ответы
Ответ 1
Если я понимаю, что вы хотите сделать, это игнорировать ориентацию UIImage? Если это так, вы можете сделать это:
UIImage *originalImage = [... whatever ...];
UIImage *imageToDisplay =
[UIImage imageWithCGImage:[originalImage CGImage]
scale:[originalImage scale]
orientation: UIImageOrientationUp];
Итак, вы создаете новый UIImage с теми же пиксельными данными, что и оригинал (с помощью его свойства CGImage), но вы указываете ориентацию, которая не вращает данные.
Ответ 2
Вы можете полностью отказаться от выполнения преобразований и масштабирования вручную, как это предложено в этом ответе a0 в здесь:
- (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 явно заявляет, что они учитывают ориентацию.
Ответ 3
Я преобразовал код в Anomie answer here (скопированный выше с помощью suvish valsan) в 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;
}
(я заменил все вхождения параметра 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, но не тестировали его на самом деле. Там может быть опечатка где-то, смешанная ширина/высота и т.д. Не стесняйтесь указывать/исправлять любые ошибки).
Ответ 4
Этот метод сначала проверяет текущую ориентацию UIImage, а затем изменяет ориентацию по часовой стрелке и возвращает UIImage. Вы можете показать это изображение как
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
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
}
Ответ 5
здесь является допустимой пробной треской, учитывая ориентацию изображения:
#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;
}
Ответ 6
Расширение UIImage в Swift. На самом деле вам не нужно делать все это. Objective-C оригинал здесь, но я добавил бит, который уважает альфа исходного изображения (грубо, но он работает, чтобы отличать непрозрачные изображения от прозрачных изображений).
// 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
}
Ответ 7
Swift 3.1
func fixImageOrientation(_ image: UIImage)->UIImage {
UIGraphicsBeginImageContext(image.size)
image.draw(at: .zero)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage ?? image
}
Ответ 8
Я преобразовал код из @Nicolas Miari в ответ на 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;
}
Ответ 9
Благодаря 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 должна упростить отключение ориентации, когда нам не нужны передние/задние камеры и метаданные ориентации устройства вверх/вниз/влево/вправо.
Ответ 10
Swift 3.0 версия ответа Томми
let imageToDisplay = UIImage.init(cgImage: originalImage.cgImage!, scale: originalImage.scale, orientation: UIImageOrientation.up)
Ответ 11
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()
-
Всем удачи!