I\'m trying to create a method which flips a UIImage along the X axis, Y axis, or both. I keep getting close but my transform knowledge isn\'t good enough to get all the way
Try the following:
UIImage* myimage = [UIImage imageNamed: @"myimage.png"];
myimage = [UIImage imageWithCGImage: myimage.CGImage scale: 1.0f orientation: UIImageOrientationUpMirrored];
This is merely a slightly fixed and 'updated to Swift' version of the old answer by @ultramiraculous. Just in case it helps someone.
Vertical Flip (reflection over x-axis):
func flipV(im:UIImage)->UIImage {
var newOrient:UIImageOrientation
switch im.imageOrientation {
case .Up:
newOrient = .DownMirrored
case .UpMirrored:
newOrient = .Down
case .Down:
newOrient = .UpMirrored
case .DownMirrored:
newOrient = .Up
case .Left:
newOrient = .LeftMirrored
case .LeftMirrored:
newOrient = .Left
case .Right:
newOrient = .RightMirrored
case .RightMirrored:
newOrient = .Right
}
return UIImage(CGImage: im.CGImage, scale: im.scale, orientation: newOrient)
}
Horizontal Flip (reflection over y-axis)
func flipH(im:UIImage)->UIImage {
var newOrient:UIImageOrientation
switch im.imageOrientation {
case .Up:
newOrient = .UpMirrored
case .UpMirrored:
newOrient = .Up
case .Down:
newOrient = .DownMirrored
case .DownMirrored:
newOrient = .Down
case .Left:
newOrient = .RightMirrored
case .LeftMirrored:
newOrient = .Right
case .Right:
newOrient = .LeftMirrored
case .RightMirrored:
newOrient = .Left
}
return UIImage(CGImage: im.CGImage, scale: im.scale, orientation: newOrient)
}
If you're intending to just display the image and not save it, you probably don't want to create a second CGContext. It's far more efficient to just use the already-loaded CGImage in the UIImage, and change the orientation like so:
- (UIImage *)flippedImageByFlippingAlongXAxis:(BOOL)flipOnX andAlongYAxis:(BOOL)flipOnY
{
UIImageOrientation currentOrientation = self.imageOrientation;
UIImageOrientation newOrientation = currentOrientation;
if (flipOnX == YES) {
switch (newOrientation) {
case UIImageOrientationUp:
newOrientation = UIImageOrientationUpMirrored;
break;
case UIImageOrientationDown:
newOrientation = UIImageOrientationMirrored;
break;
case UIImageOrientationUpMirrored:
newOrientation = UIImageOrientationUp;
break;
case UIImageOrientationDownMirrored:
newOrientation = UIImageOrientationDown;
break;
case UIImageOrientationLeft:
newOrientation = UIImageOrientationLeftMirrored;
break;
case UIImageOrientationRight:
newOrientation = UIImageOrientationRightMirrored;
break;
case UIImageOrientationLeftMirrored:
newOrientation = UIImageOrientationLeft;
break;
case UIImageOrientationRightMirrored:
newOrientation = UIImageOrientationRight;
break;
}
}
if (flipOnY == YES) {
switch (newOrientation) {
case UIImageOrientationUp:
newOrientation = UIImageOrientationDownMirrored;
break;
case UIImageOrientationDown:
newOrientation = UIImageOrientationUpMirrored;
break;
case UIImageOrientationUpMirrored:
newOrientation = UIImageOrientationDown;
break;
case UIImageOrientationDownMirrored:
newOrientation = UIImageOrientationUp;
break;
case UIImageOrientationLeft:
newOrientation = UIImageOrientationRightMirrored;
break;
case UIImageOrientationRight:
newOrientation = UIImageOrientationLeftMirrored;
break;
case UIImageOrientationLeftMirrored:
newOrientation = UIImageOrientationRight;
break;
case UIImageOrientationRightMirrored:
newOrientation = UIImageOrientationLeft;
break;
}
}
return [UIImage imageWithCGImage:self.CGImage scale:self.scale orientation:newOrientation];
}
When you start a new CGContext and doing flip using CGContextDrawImage, you're allocating another block of memory to hold the same bytes in a different order. By changing the UIImage orientation, you're able to avoid another allocation. The same image data is used, just drawn in a different orientation.
I finally was able to figure this out. Here is the code that works for anyone else who might need it.
- (UIImage *)flippedImageByAxis:(MVImageFlip)axis{
UIGraphicsBeginImageContext(self.size);
CGContextRef context = UIGraphicsGetCurrentContext();
if(axis == MVImageFlipXAxis){
// Do nothing, X is flipped normally in a Core Graphics Context
} else if(axis == MVImageFlipYAxis){
// fix X axis
CGContextTranslateCTM(context, 0, self.size.height);
CGContextScaleCTM(context, 1.0f, -1.0f);
// then flip Y axis
CGContextTranslateCTM(context, self.size.width, 0);
CGContextScaleCTM(context, -1.0f, 1.0f);
} else if(axis == MVImageFlipXAxisAndYAxis){
// just flip Y
CGContextTranslateCTM(context, self.size.width, 0);
CGContextScaleCTM(context, -1.0f, 1.0f);
}
CGContextDrawImage(context, CGRectMake(0.0, 0.0, self.size.width, self.size.height), [self CGImage]);
UIImage *flipedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return flipedImage;
}
Swift 3 version:
func flipV(im:UIImage)->UIImage {
var newOrient:UIImageOrientation
switch im.imageOrientation {
case .up:
newOrient = .downMirrored
case .upMirrored:
newOrient = .down
case .down:
newOrient = .upMirrored
case .downMirrored:
newOrient = .up
case .left:
newOrient = .leftMirrored
case .leftMirrored:
newOrient = .left
case .right:
newOrient = .rightMirrored
case .rightMirrored:
newOrient = .right
}
return UIImage(cgImage: im.cgImage!, scale: im.scale, orientation: newOrient)
}
func flipH(im:UIImage)->UIImage {
var newOrient:UIImageOrientation
switch im.imageOrientation {
case .up:
newOrient = .upMirrored
case .upMirrored:
newOrient = .up
case .down:
newOrient = .downMirrored
case .downMirrored:
newOrient = .down
case .left:
newOrient = .rightMirrored
case .leftMirrored:
newOrient = .right
case .right:
newOrient = .leftMirrored
case .rightMirrored:
newOrient = .left
}
return UIImage(cgImage: im.cgImage!, scale: im.scale, orientation: newOrient)
}