Vertical flip of CGContext
Solution 1
The CTM affects future drawing; you're capturing what you have already drawn. You need to concat that transformation before you draw, not after.
Solution 2
Here is some code that I wrote based on this answer, in case it is helpful to anyone:
#import <QuartzCore/QuartzCore.h>
...
+ (UIImage *) flipImageVertically:(UIImage *)originalImage {
UIImageView *tempImageView = [[UIImageView alloc] initWithImage:originalImage];
UIGraphicsBeginImageContext(tempImageView.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform flipVertical = CGAffineTransformMake(
1, 0, 0, -1, 0, tempImageView.frame.size.height
);
CGContextConcatCTM(context, flipVertical);
[tempImageView.layer renderInContext:context];
UIImage *flipedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[tempImageView release];
return flipedImage;
}
Solution 3
Here is the same code as above (benvolioT's answer) but in SWIFT 4.0
import QuartzCore
...
func flipImageVertically(originalImage:UIImage) -> UIImage{
let tempImageView:UIImageView = UIImageView(image: originalImage)
UIGraphicsBeginImageContext(tempImageView.frame.size)
let context:CGContext = UIGraphicsGetCurrentContext()!
let flipVertical: CGAffineTransform = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: tempImageView.frame.size.height)
context.concatenate(flipVertical)
tempImageView.layer.render(in: context)
let flippedImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return flippedImage
}
And here is an even better way in SWIFT:
func flipImageVertically(originalImage:UIImage) -> UIImage {
let image:UIImage = UIImage(CGImage: originalImage.CGImage, scale: 1.0, orientation: UIImageOrientation.RightMirrored)!
return image
}
Solution 4
Swift 4:
let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: originalImage.size.height)
ctx.concatenate(flipVertical)
Solution 5
Use this function in Swift 4:
func drawImage(image: UIImage) -> UIImage {
// Setup our context
let opaque = false
let scale: CGFloat = 0 // 0 means we use scale factor of the device’s main screen.
UIGraphicsBeginImageContextWithOptions(image.size, opaque, scale)
let context = UIGraphicsGetCurrentContext()!
let flipVertical = CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: image.size.height)
context.concatenate(flipVertical) // flip by y
// draw your another figures
//...
// Drawing complete, set context to image and finish
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
teabot
Big Data Developer at Expedia Tinkerer and Maker at the London Hackspace (my personal page)
Updated on March 07, 2021Comments
-
teabot about 3 years
I have a UIView that I am trying to render into a UIImage using [CALayer renderInContext:]. However, I find that the resultant image is flipped vertically. I kind of expect this due to the different coordinate systems. However, I then try and flip the context back to normal with an affine transform - but it doesn't have any effect:
CGAffineTransform flipVertical = CGAffineTransformMake( 1, 0, 0, -1, 0, imageContextHeight ); CGContextConcatCTM(imageContext, flipVertical); CGImageRef cgImage = CGBitmapContextCreateImage(imageContext); UIImage* uiImage = [[UIImage imageWithCGImage:cgImage] retain]; CGImageRelease(cgImage);
What am I doing wrong?
-
MindBlower3 over 5 yearsSecond method doesn't fix the issue reported in Question, but the first does
-
agurtovoy over 2 yearsNote that
CGContext.height
works only for bitmap contexts and returns 0 in other cases, so you might want to pass the height explicitly here.