Flip UIImage Along Either Axis

☆樱花仙子☆ 提交于 2019-12-19 09:00:10

问题


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);
     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.


回答1:


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;
}



回答2:


Try the following:

UIImage* myimage = [UIImage imageNamed: @"myimage.png"];
myimage = [UIImage imageWithCGImage: myimage.CGImage scale: 1.0f orientation: UIImageOrientationUpMirrored];



回答3:


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.




回答4:


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



回答5:


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


来源:https://stackoverflow.com/questions/6462070/flip-uiimage-along-either-axis

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!