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 there. Here is the code I have so far:
- (UIImage *)flippedImageByAxis:(MVImageFlip)axis{
UIGraphicsBeginImageContext(self.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform verticalFlip = CGAffineTransformMake(1, 0, 0, -1, 0, self.size.height);
开发者_C百科 CGAffineTransform horizFlip = CGAffineTransformMake(-1.0, 0.0, 0.0, 1.0, self.size.width, 0.0);
if(axis == MVImageFlipXAxis || axis == MVImageFlipXAxisAndYAxis)
CGContextConcatCTM(context, horizFlip);
if(axis == MVImageFlipYAxis || axis == MVImageFlipXAxisAndYAxis)
CGContextConcatCTM(context, verticalFlip);
CGContextDrawImage(context, CGRectMake(0.0, 0.0, self.size.width, self.size.height), [self CGImage]);
UIImage *flipedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return flipedImage;
}
This flips the image but not properly. The Y-flipped image doesn't get flipped at all, the X flipped image looks like the XY image should look like, and the XY image looks like what the Y image should look like. Combining the transforms and getting them to work properly is making my head hurt.
The MVImageFlip enum is just the three you see in the code. Nothing special.
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;
}
Try the following:
UIImage* myimage = [UIImage imageNamed: @"myimage.png"];
myimage = [UIImage imageWithCGImage: myimage.CGImage scale: 1.0f orientation: UIImageOrientationUpMirrored];
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.
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)
}
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)
}
精彩评论