63

I'm trying to add a UIBarButtonItem containing a UIImage to a UIToolbar. The image keeps being tinted and I can't get it to show as the original colored image - all I want to do is display an image, verbatim, in a UIBarButtonItem! I'm following the directions in the iOS 7 transition guide to set the image rendering mode to UIImageRenderingModeAlwaysOriginal.

UIImage *image = [UIImage imageNamed:@"myImage.png"];
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];

UIBarButtonItem *ratingImage = [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStyleBordered target:nil action:nil];

[toolbar setItems:[NSArray arrayWithObjects:ratingImage, nil] animated:YES];

One thing to note is that I set the tintColor for the main UIWindow of my app right when it loads...maybe this isn't important with regard to my issue, but thought I'd mention it.

DiscDev
  • 36,864
  • 20
  • 113
  • 130

5 Answers5

173

I spent an evening trying to figure this out as well. You were very close to the solution. The trick is to instantiate the UIImage with the rendering mode.

Instead of doing:

 UIImage *image = [UIImage imageNamed:@"myImage.png"];
 image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];

do this:

 UIImage *image = [[UIImage imageNamed:@"myImage.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];

and it works!

In my case, I had dragged a Navigation bar to my viewcontroller in the IB, and added the BarButtonItem. But don't provide the item an image in the IB. Make an outlet and assign it the UIImage (like we created above) by doing this:

[myCustomBarButtonItem setImage:image];

Hope this works for you.

ScorpionKing2k5
  • 2,441
  • 1
  • 16
  • 18
  • 15
    I don't see how the two statements above differ. Given everything I know about objc they shouldn't! it's just the same statement compressed into one line and without a temporary variable assignment... What am I not getting here? Is there something fundamental about the language that I've gotten wrong or is it that I'm simply missing something? – entropy Jan 16 '14 at 10:12
  • 1
    @entropy to be honest, that's exactly what I wasted my evening on. There doesn't seem to be any difference between the 2, but the latter works and the former does not. Could be a bug in the SDK. – ScorpionKing2k5 Jan 17 '14 at 08:48
  • I agree with @entropy, that is some weird voodoo. I don't see how it could be a bug in the SDK. Could it be a side-effect of ARC? – hatfinch Feb 11 '14 at 11:11
  • By the way, it looks like imageWithRenderingMode: is only available in iOS 7... if you're targeting iOS 6 or below, you'll need something else – Tim Crowley Mar 29 '14 at 21:13
  • 2
    I just experienced the same thing as @ScorpionKing2k5, in the iOS 8 GM. Crazy, but apparently still true. – janineanne Sep 16 '14 at 03:39
  • 1
    Thanks for the super useful answer @ScorpionKing2k5, I come back to this one all the time. For others out there, it may be worthwhile to create a Category on UIImage for these purposes. Then you can do [UIImage originalImageNamed:@"myImage.png"], and the implementation returns [[UIImage imageNamed:@"myImage.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; – DiscDev Feb 17 '15 at 16:57
  • Thank you for your post. That saved me a lot of time. – iphaaw Apr 04 '15 at 07:29
  • Can this be achieved through storyboard? – Ace Green May 16 '15 at 12:43
  • 1
    I cannot believe this sh*t D: This took me hours. Thank you so much :) It's still the same on Xcode 6.4/ iOS 8.4 – benjamin.ludwig Aug 18 '15 at 09:19
  • Is there is any other way ? Like special type of image which do not require setting `UIImageRenderingModeAlwaysOriginal `? – Bista Jan 23 '16 at 09:22
11

UIImageRenderingModeAlwaysOriginal can also be set by selecting the image in your Assets.xcassets "folder" in XCode and setting the "Render as" dropdown to "Original image".

andlin
  • 3,534
  • 3
  • 25
  • 43
9

For Swift 2.1+ it would look like this:

let image : UIImage? = UIImage(named:"myImage.png")!.imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)

UPDATED Swift 3

let image : UIImage? = UIImage(named:"myImage.png")!.withRenderingMode(.alwaysOriginal)
Flexicoder
  • 7,371
  • 4
  • 40
  • 52
jesses.co.tt
  • 2,558
  • 1
  • 26
  • 46
  • Is there is any other way ? Like special type of image which do not require setting `UIImageRenderingModeAlwaysOriginal `? – Bista Jan 23 '16 at 09:22
  • 1
    @jesses.co.tt my friend, you saved my day!! That was EXACTLY what I've been searching for this whole afternoon. Thanks a lot! – DccBr Jun 10 '16 at 01:33
0

The accepted answer is fine but if you placed the UIBarButtonItem in a storyboard or xib then you can just:

  • Go to the Assets catalog where the image lives
  • Select the image
  • Go to the attributes inspector (cmd-opt-4)
  • Set "Render As" to "Original Image"

Only do this if you want all instances of this image to show up without tinting.

enter image description here

John Scalo
  • 2,774
  • 1
  • 22
  • 30
-4

If you want it to work for versions of iOS less than v7, you might need to to this:

UIImage *image = [UIImage imageNamed:@"myImage.png"];
@try {
  image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
} @catch (NSException *exception) {
}

Since imageWithRenderingMode: is an iOS 7 method, you'll get an exception if you try and use it with a lesser version.

Tim Crowley
  • 331
  • 4
  • 9
  • 8
    Don't use a try-catch block... instead check on this instead [image respondsToSelector:@selector(imageWithRenderingMode:)]; – LightningStryk Aug 01 '14 at 14:24
  • 2
    @LightningStryk is right - the above example is not the recommended way to call an API that might not be available. Use the respondsToSelector method. – DiscDev Oct 06 '14 at 14:05