Search code examples
iosuicolor

Comparing equality of [UIColor colorWithPatternImage:]


I want to compare two UIColors that I generated using [UIColor colorWithPatternImage:] for equality. I can't seem to figure out how to do this.

[[UIColor colorWithPatternImage:[UIImage imageNamed:@"camo2"]] isEqual:
[UIColor colorWithPatternImage:[UIImage imageNamed:@"camo2"]]]

Always returns false, whether I use == or isEqual. Does anybody know if it's possible to properly compare colorWithPatternImages, or CGPatterns I suppose? I've also tried comparing CGColorGetPattern(color.CGColor) but that doesn't work either.

EDIT: The reason for this is I have a function that accepts a UIColor and gives me an NSString for displaying to the user.

+(NSString *)colorNameForColor:(UIColor *)color {

    if ([color isEqual:[UIColor whiteColor]]) {
        return @"White";
    }

    if ([color isEqual:[UIColor colorWithPatternImage:[UIImage imageNamed:@"camo"]]]) {
        return @"Camo";
    }
    ...
}

Is this just an insane thing to do? I suppose I could make my own object that has a color property and a colorName property...


Solution

  • Using Private APIs

    This took some reverse engineering of CoreGraphics but I was able to find one private method _CGPatternGetImage which appears to return the image.

    You'll need to include the following headers:

    #include <dlfcn.h>
    @import CoreGraphics;
    

    Create a function pointer:

    typedef CGImageRef (*CGPatternGetImage)(CGPatternRef pattern);
    

    And then access the function:

    -(void)comparePatterns
    {
        void *handle = dlopen("/System/Library/Frameworks/CoreGraphics.framework/CoreGraphics", RTLD_NOW);
        CGPatternGetImage getImage = (CGPatternGetImage) dlsym(handle, "CGPatternGetImage");
    
        UIColor *aColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"pattern1"]];
        UIColor *bColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"pattern1"]];
        UIColor *cColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"pattern2"]];
    
        NSData *aImageData = UIImagePNGRepresentation([UIImage imageWithCGImage:getImage(CGColorGetPattern(aColor.CGColor))]);
        NSData *bImageData = UIImagePNGRepresentation([UIImage imageWithCGImage:getImage(CGColorGetPattern(bColor.CGColor))]);
        NSData *cImageData = UIImagePNGRepresentation([UIImage imageWithCGImage:getImage(CGColorGetPattern(cColor.CGColor))]);
    
        NSLog(@"Should be true: %d",[aImageData isEqual:bImageData]);
        NSLog(@"Should be false: %d",[aImageData isEqual:cImageData]);
    }
    

    You probably don't want to access any private APIs in a production app but this might be useful for testing.

    Using Associative References

    If this is going on the App Store then a better solution could be creating a category for UIColor and give it an associative reference to store the pattern name or whatever is easiest for you to compare. This won't compare the actual images at all so it's possible that if you don't set the correct data to identify the pattern the comparison won't be accurate.

    Include the header:

    #import <objc/runtime.h>
    

    Create the category:

    @interface UIColor(CustomPatterns)
    @property (strong, nonatomic) NSString* patternName;
    @end
    
    @implementation UIColor(CustomPatterns)
    
    static char CUSTOM_PATTERNS_PATTERN_NAME_KEY;
    
    @dynamic patternName;
    
    -(void)setPatternName:(NSString *)patternName
    {
       objc_setAssociatedObject(self, &CUSTOM_PATTERNS_PATTERN_NAME_KEY, patternName, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    -(NSString *)patternName
    {
        return  (NSString*)objc_getAssociatedObject(self, &CUSTOM_PATTERNS_PATTERN_NAME_KEY);
    }
    
    @end
    

    And then you can set your custom data and compare:

    -(void)comparePatterns
    {
            UIColor *aColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"1"]];
            aColor.patternName = @"1";
    
            UIColor *bColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"1"]];
            bColor.patternName = @"1";
    
            UIColor *cColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"2"]];
            cColor.patternName = @"2";
    
            NSLog(@"Should be true: %d",[aColor.patternName isEqualToString:bColor.patternName]);
            NSLog(@"Should be false: %d",[aColor.patternName isEqualToString:cColor.patternName]);
    }