开发者

Flip UIImage Along Either Axis

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)
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜