5

I have been attempting this for a few days now. I'm creating a sprite sheet loader, however I must also be able to load the sprites facing the opposite direction. This involves flipping the images that I already have loaded.

I have already attempted to do this using the UIImageOrientation / UIImageOrientationUpMirrored method however this has absolutely no effect and simply draws the frame with the exact same orientation as before.

I have since attempted a slightly more complicated way which I will include below. But still, simply draws the image in exactly the same way as it is loaded into the application. (Not mirrored).

I've included the method below (along with my comments so that you can maybe follow my thought pattern), can you see what I am doing wrong?

- (UIImage*) getFlippedFrame:(UIImage*) imageToFlip
{
//create a context to draw that shizz into
UIGraphicsBeginImageContext(imageToFlip.size);
CGContextRef currentContext = UIGraphicsGetCurrentContext();



//WHERE YOU LEFT OFF. you're attempting to find a way to flip the image in imagetoflip. and return it as a new UIimage. But no luck so far.
[imageToFlip drawInRect:CGRectMake(0, 0, imageToFlip.size.width, imageToFlip.size.height)];

//take the current context with the old frame drawn in and flip it.
CGContextScaleCTM(currentContext, -1.0, 1.0);

//create a UIImage made from the flipped context. However will the transformation survive the transition to UIImage? UPDATE: Apparently not.

UIImage* flippedFrame = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return flippedFrame;
}

Thank you, Guy.

Guy Joel McLean
  • 1,019
  • 4
  • 12
  • 34

1 Answers1

6

I would have expected that you have to change the transform of the context and then draw. Also, you would need to translate because you are flipping to negative coordinates, so, replace

[imageToFlip drawInRect:CGRectMake(0, 0, imageToFlip.size.width, imageToFlip.size.height)];
CGContextScaleCTM(currentContext, -1.0, 1.0);

with (edited based on comments)

CGContextTranslateCTM(currentContext, imageToFlip.size.width, 0);      
CGContextScaleCTM(currentContext, -1.0, 1.0);
[imageToFlip drawInRect:CGRectMake(0, 0, imageToFlip.size.width, imageToFlip.size.height)];

NOTE: From comments, a category to use

@implementation UIImage (Flip) 
  - (UIImage*)horizontalFlip { 
     UIGraphicsBeginImageContext(self.size); 
     CGContextRef current_context = UIGraphicsGetCurrentContext();                           
     CGContextTranslateCTM(current_context, self.size.width, 0);
     CGContextScaleCTM(current_context, -1.0, 1.0); 
     [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; 
     UIImage *flipped_img = UIGraphicsGetImageFromCurrentImageContext(); 
     UIGraphicsEndImageContext(); 
     return flipped_img; 
  } 
@end
Lou Franco
  • 87,846
  • 14
  • 132
  • 192
  • I had previously tried something like this, however i think i got confused and translated the context in the wrong direction (-imagetoflip.size.width). I also translated THEN scaled. This made the image disappear when it was finally drawn. Your suggestion does the same, however i feel that it puts me on the right track as it as least changing the image. Maybe it is just a matter of me tweaking the translation till i find what I'm looking for. – Guy Joel McLean Apr 23 '12 at 15:16
  • Also if you know a bit about core graphics, would you mind telling me why we transform the context THEN draw into it? I would've thought you draw into the context then transform the context to transformed them both together, but this is apparently incorrect. – Guy Joel McLean Apr 23 '12 at 15:18
  • I don't know if I can answer why -- but one advantage is that you can transform, draw, transform again, draw, etc. You might want to do this to get different effects. – Lou Franco Apr 23 '12 at 15:23
  • If you figure it out, edit my answer or at least comment so I can update to the correct answer. – Lou Franco Apr 23 '12 at 15:23
  • BOOM! Turns out the CG is much like OpenGL calls to glTranslate, glRotate and glScale. In the way that you must call them in reverse order from the actions you wish to perform. (Yeah, I know way more about GL than I do Cocoa!) For Example, here we wish to scale the context by -1 in the x direction and then translate it by the width of ImageToFlip. However in practice, we code: CGContextTranslateCTM(currentContext, imageToFlip.size.width, 0); CGContextScaleCTM(currentContext, -1.0, 1.0); Before I was unknowingly translating the context and THEN scaling what was inside that (nothing). – Guy Joel McLean Apr 24 '12 at 02:42
  • Also I'm quite new to Stack Overflow and don't understand editing your answer. Plus it's 3am. I'll give it the big 'ol tick anyway as the correct answer is contained here now. – Guy Joel McLean Apr 24 '12 at 02:44
  • @LouFranco: how to make vertical ? – Maulik Sep 28 '12 at 09:21
  • In this line `CGContextScaleCTM(currentContext, -1.0, 1.0);` the -1.0 is x and the 1.0 is y, which results in a horizontal flip. Change to `1.0, -1.0`. And you need to change the translate as well, so change `CGContextTranslateCTM(currentContext, imageToFlip.size.width, 0);` to `0, imageToFlip.size.height` – Lou Franco Oct 05 '12 at 19:01
  • 2
    Works great! Here is the UIImage category based on your code: `@implementation UIImage (Flip) - (UIImage*)horizontalFlip { UIGraphicsBeginImageContext(self.size); CGContextRef current_context = UIGraphicsGetCurrentContext(); CGContextTranslateCTM(current_context, self.size.width, 0); CGContextScaleCTM(current_context, -1.0, 1.0); [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; UIImage *flipped_img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return flipped_img; } @end` – digipeople Oct 15 '13 at 06:39
  • Image quality becomes very bad – iWheelBuy Apr 14 '14 at 06:40
  • @iWheelBuy is your scale anything other than 1 and -1? – Lou Franco Apr 14 '14 at 11:10
  • I have got the iOS7 back navigation image. Its size is 25x41 and it has @2x suffix. Got it there -> http://stackoverflow.com/questions/227078/creating-a-left-arrow-button-like-uinavigationbars-back-style-on-a-uitoolba Then I tried to rotate it. – iWheelBuy Apr 15 '14 at 04:39
  • Make a new question with your code and the before and after images – Lou Franco Apr 15 '14 at 13:02