change color or tint of image in a button

Discussion in 'iOS Programming' started by theprizerevealed, Nov 3, 2016.

  1. theprizerevealed, Nov 3, 2016
    Last edited: Nov 3, 2016

    theprizerevealed macrumors member

    Joined:
    Feb 26, 2016
    #1
    I wish to change the color or tint of an image that is inside of a button when that button is pressed. I have learned of various code to change the tint of a UIImageView but that does not seem to work for a UIImage.

    The code for the tinting of a UIImageView seems to be this for Swift 3:

    Code:
    theImageView.image = theImageView.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
    theImageView.tintColor = UIColor.redColor()
    
    theImage.setTintColor(UIColor.redColor())
    
    but it doesn't seem to work for just an image inside a button. Can anyone suggest how to do it? I have looked at various extensions but none of them seem to work or I am not applying the code correctly. thanks for your help.
    --- Post Merged, Nov 3, 2016 ---
    I have found some code that works partially however it blots the image itself and all you can see is the color. Is there any way to fix this?

    Code:
    mybuttonname.setImage(mypicturename?.withRenderingMode(UIImageRenderingMode.alwaysTemplate), for: .normal)
            mybuttonname.tintColor = UIColor.orange 
     
  2. theprizerevealed thread starter macrumors member

    Joined:
    Feb 26, 2016
    #2
    okay, I found something that might work if only I knew how to use it properly as found here. I don't understand how to call the functions properly though.

    https://stackoverflow.com/questions/27163171/change-color-of-png-in-buttons-ios

    Code:
       
        /**
         Tint, Colorize image with given tint color<br><br>
         This is similar to Photoshop's "Color" layer blend mode<br><br>
         This is perfect for non-greyscale source images, and images that have both highlights and shadows that should be preserved<br><br>
         white will stay white and black will stay black as the lightness of the image is preserved<br><br>
         
         <img src="http://yannickstephan.com/easyhelper/tint1.png" height="70" width="120"/>
         
         **To**
         
         <img src="http://yannickstephan.com/easyhelper/tint2.png" height="70" width="120"/>
         
         - parameter tintColor: UIColor
         
         - returns: UIImage
         */
        func tintPhoto(_ tintColor: UIColor) -> UIImage {
           
            return modifiedImage { context, rect in
                // draw black background - workaround to preserve color of partially transparent pixels
                context.setBlendMode(.normal)
                UIColor.black.setFill()
                context.fill(rect)
               
                // draw original image
                context.setBlendMode(.normal)
                context.draw(cgImage!, in: rect)
               
                // tint image (loosing alpha) - the luminosity of the original image is preserved
                context.setBlendMode(.color)
                tintColor.setFill()
                context.fill(rect)
               
                // mask by alpha values of original image
                context.setBlendMode(.destinationIn)
                context.draw(context.makeImage()!, in: rect)
            }
        }
       
        /**
         Tint Picto to color
         
         - parameter fillColor: UIColor
         
         - returns: UIImage
         */
        func tintPicto(_ fillColor: UIColor) -> UIImage {
           
            return modifiedImage { context, rect in
                // draw tint color
                context.setBlendMode(.normal)
                fillColor.setFill()
                context.fill(rect)
               
                // mask by alpha values of original image
                context.setBlendMode(.destinationIn)
                context.draw(cgImage!, in: rect)
            }
        }
       
        /**
         Modified Image Context, apply modification on image
         
         - parameter draw: (CGContext, CGRect) -> ())
         
         - returns: UIImage
         */
        fileprivate func modifiedImage(_ draw: (CGContext, CGRect) -> ()) -> UIImage {
           
            // using scale correctly preserves retina images
            UIGraphicsBeginImageContextWithOptions(size, false, scale)
            let context: CGContext! = UIGraphicsGetCurrentContext()
            assert(context != nil)
           
            // correctly rotate image
            context.translateBy(x: 0, y: size.height)
            context.scaleBy(x: 1.0, y: -1.0)
           
            let rect = CGRect(x: 0.0, y: 0.0, width: size.width, height: size.height)
           
            draw(context, rect)
           
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return image!
        }
       
    }
    
    

    how do I call these extensions and functions to tint an image saved as this:
    Code:
    var image = UIImage(named: “my picture”)
    sorry for my obtuseness but it is what it is.
     
  3. bjet767 macrumors 6502a

    Joined:
    Oct 2, 2010
    #3
    OK I'll answer.

    The reason why nobody is answering is because you are really new at this and don't seem to understand much beyond the basics (no insult intended).

    The button UIImage is just that, an Image, and the original needs to be replaced with the tinted image for what ever state of the button you are trying to change.

    In your code fragment there seems to be two image modification functions that can be used and a third which is private (only used within the object it's listed in).

    Basically pass your image to either and the color for the tint or background and it will return an image with the new color in it. Then change the image of your button.

    I code in Objective C and would have to rewrite the functions for my personal use.

    Have you reviewed Apple's documentation on the UIButton? There's stuff there which might make it easier to change the tint.

    "When setting the content of a button, you must specify the title, image, and appearance attributes for each state separately. If you do not customize the content for a particular state, the button uses the values associated with the Default state and adds any appropriate customizations. For example, in the highlighted state, an image-based button draws a highlight on top of the default image if no custom image is provided."


    I went and tested what you want to do and I think the problem is you may be trying to change the tint when you press the button itself. If all you have is an action it will will default to the default image. What you have to do is subclass a UIButton to do what you want it to do when it selected or, per note from Apple documentation, set up how you want it to look per the desired state.

    Again we really don't know what you are trying to do.
     
  4. theprizerevealed thread starter macrumors member

    Joined:
    Feb 26, 2016
    #4
    thank you for your willingness to reply. I think with your input it helped me slightly to decipher the way to call the function. For other novices sake, I will post the code that I used here generally

    Code:
    let tintedimage = originalimagename?.tintphoto(UIColor.orange)
    mybuttonname.setImage(tintedimage, for: UIControlState.normal)
    
    --- Post Merged, Nov 4, 2016 ---
    huh, it doesn't seem to tint the whole image, only part of it. I'm not sure why.
     
  5. bjet767, Nov 4, 2016
    Last edited: Nov 4, 2016

    bjet767 macrumors 6502a

    Joined:
    Oct 2, 2010
    #5
    It doesn't tint the whole image because it only looks for the colors and then tints those only. If you want to convert and image to say "sepia tone" do that first and the set it like your doing.

    You would use Core Image for this.

    Here's a great example in swift:

    Code:
    override func viewDidLoad() {
        guard let image = imageView?.image, cgimg = image.CGImage else {
            print("imageView doesn't have an image!")
            return
        }
     
        let coreImage = CIImage(CGImage: cgimg)
     
        let filter = CIFilter(name: "CISepiaTone")
        filter?.setValue(coreImage, forKey: kCIInputImageKey)
        filter?.setValue(0.5, forKey: kCIInputIntensityKey)
     
        if let output = filter?.valueForKey(kCIOutputImageKey) as? CIImage {
            let filteredImage = UIImage(CIImage: output)
            imageView?.image = filteredImage
        }
         
        else {
            print("image filtering failed")
        }
    }
    
    Here's the link:https://www.appcoda.com/core-image-introduction/

    I think you want more than just a tint color and eventually you may need to write a UIButton subclass to make the behaviors you desire.

    Here's a link to someone demonstrating subclassing a UIButton in Swift: http://www.lunapip.com/programming/subclassing-uibutton-in-swift-tutorial/
     
  6. theprizerevealed thread starter macrumors member

    Joined:
    Feb 26, 2016
    #6
    well I tested this on a black and white image and it tinted the black part of the image with a color partially but it did not do it entirely. There is something related to the area of the image as the function operates which needs to be corrected. But I don't see in the code why that is so.
     
  7. bjet767 macrumors 6502a

    Joined:
    Oct 2, 2010
    #7
    The prize

    Again I'm not real sure what you're trying, tinting the button image or modifying the image and then adding it to the button.

    Coding is an on going challenge that teaches you to master the art of problem solving. Once you get the syntax down it's working through the device API and making it do what you want.

    Bottom line? Keep experimenting until you get the results you need.
     
  8. theprizerevealed thread starter macrumors member

    Joined:
    Feb 26, 2016
    #8
    I have found some code that works better but it does so slowly and with too dark a tint for my desire. Is there some way to lighten this tint?

    Code:
    func tint(image: UIImage, color: UIColor) -> UIImage
    {
    let ciImage = CIImage(image: image)
    let filter = CIFilter(name: "CIMultiplyCompositing")
    
    let colorFilter = CIFilter(name: "CIConstantColorGenerator")
    let ciColor = CIColor(color: color)
    colorFilter.setValue(ciColor, forKey: kCIInputColorKey)
    let colorImage = colorFilter.outputImage
    
    filter.setValue(colorImage, forKey: kCIInputImageKey)
    filter.setValue(ciImage, forKey: kCIInputBackgroundImageKey)
    
    return UIImage(CIImage: filter.outputImage)!
    }
    
    
    what happens is that the image will appear grayed over first and then the overlayed color will appear. How can I avoid the grayed overlay while still maintaining the color overlay?
     
  9. bjet767 macrumors 6502a

    Joined:
    Oct 2, 2010
    #9
    First images are slower because of their nature.

    It looks like you call filter twice, try only once.

    While I haven't done it you can create you own filter so look at documentation for CIFilter.
     
  10. theprizerevealed, Nov 10, 2016
    Last edited: Nov 10, 2016

    theprizerevealed thread starter macrumors member

    Joined:
    Feb 26, 2016
    #10
    well I guess I need a little help understanding why the code from post #8 works as it does. I have looked at CIColorMonochrome as an alternative but I haven't been able to make anything work yet.

    I have found what appears to be alternative simpler code that should work but doesn't for some reason. I am using a black and white image as a test input for the functions so I'm not sure if the success of the code is contingent on the original coloring of the input original image.

    From studying Apple's website here: https://developer.apple.com/library...#//apple_ref/doc/filter/ci/CIPhotoEffectTonal - it appears that some of these code tools requiring the original image to possess certain qualities.

    Here is the simpler sample code that I'm trying to use to make the image color faster and with a nicer appearance:
    Code:
    override func viewDidLoad() {
       super.viewDidLoad()
      
        // 1
        let image = UIImage(named: "dog.jpg")
        let originalImage = CIImage(image: image)
      
        // 2
        var filter = CIFilter(name: "CIPhotoEffectMono")
        filter.setDefaults()
        filter.setValue(originalImage, forKey: kCIInputImageKey)
      
        // 3
        var outputImage = filter.outputImage
        var newImage = UIImage(CIImage: outputImage)
        imageView.image = newImage
    }
    
    as found here: http://www.ioscreator.com/tutorials/core-image-tutorial-ios8-swift
    postscript - I know that CIPhotoEffectMono would not be useful with a black and white image but no other coloring filter seems to work either.
     
  11. bjet767 macrumors 6502a

    Joined:
    Oct 2, 2010
    #11

Share This Page