Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIButton image rotation issue

I have a [UIButton buttonWithType:UIButtonTypeCustom] that has an image (or a background image - same problem) created by [UIImage imageWithContentsOfFile:] pointing to a JPG file taken by the camera and saved in the documents folder by the application.

If I define the image for UIControlStateNormal only, then when I touch the button the image gets darker as expected, but it also rotates either 90 degrees or 180 degrees. When I remove my finger it returns to normal.

This does not happen if I use the same image for UIControlStateHighlighted, but then I lose the touch indication (darker image).

This only happens with an image read from a file. It does not happen with [UIImage ImageNamed:].

I tried saving the file in PNG format rather than as JPG. In this case the image shows up in the wrong orientation to begin with, and is not rotated again when touched. This is not a good solution anyhow because the PNG is far too large and slow to handle.

Is this a bug or am I doing something wrong?

like image 468
Amiram Stark Avatar asked Aug 29 '11 13:08

Amiram Stark


2 Answers

I was not able to find a proper solution to this and I needed a quick workaround. Below is a function which, given a UIImage, returns a new image which is darkened with a dark alpha fill. The context fill commands could be replaced with other draw or fill routines to provide different types of darkening.

This is un-optimized and was made with minimal knowledge of the graphics api.

You can use this function to set the UIControlStateHighlighted state image so that at least it will be darker.

+ (UIImage *)darkenedImageWithImage:(UIImage *)sourceImage
{
    UIImage * darkenedImage = nil;

    if (sourceImage)
    {
        // drawing prep
        CGImageRef source = sourceImage.CGImage;
        CGRect drawRect = CGRectMake(0.f,
                                     0.f,
                                     sourceImage.size.width, 
                                     sourceImage.size.height);
        CGContextRef context = CGBitmapContextCreate(NULL, 
                                                     drawRect.size.width, 
                                                     drawRect.size.height,
                                                     CGImageGetBitsPerComponent(source),
                                                     CGImageGetBytesPerRow(source),
                                                     CGImageGetColorSpace(source),
                                                     CGImageGetBitmapInfo(source)
                                                     );

        // draw given image and then darken fill it
        CGContextDrawImage(context, drawRect, source);
        CGContextSetBlendMode(context, kCGBlendModeOverlay);
        CGContextSetRGBFillColor(context, 0.f, 0.f, 0.f, 0.5f);
        CGContextFillRect(context, drawRect);

        // get context result
        CGImageRef darkened = CGBitmapContextCreateImage(context);
        CGContextRelease(context);

        // convert to UIImage and preserve original orientation
        darkenedImage = [UIImage imageWithCGImage:darkened
                                                      scale:1.f
                                                orientation:sourceImage.imageOrientation];
        CGImageRelease(darkened);
    }

    return darkenedImage;
}
like image 149
Edward Avatar answered Oct 17 '22 16:10

Edward


To fix this you need additional normalization function like this:

public extension UIImage {

    func normalizedImage() -> UIImage! {

        if self.imageOrientation == .Up {
            return self
        }

        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        self.drawInRect(CGRectMake(0, 0, self.size.width, self.size.height))
        let normalized = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return normalized
    }
}

then you can use it like that:

self.photoButton.sd_setImageWithURL(avatarURL, 
forState: .Normal, 
placeholderImage: UIImage(named: "user_avatar_placeholder")) {

    [weak self] (image, error, cacheType, url) in

    guard let strongSelf = self else {

        return
    }

    strongSelf.photoButton.setImage(image.normalizedImage(), forState: .Normal
}
like image 22
Marcin Małysz Avatar answered Oct 17 '22 15:10

Marcin Małysz