[FIXED] So ersetzen Sie eine bestimmte Farbe durch eine andere auf einem undurchsichtigen UIImage

Ausgabe

Ich möchte die Farbe eines undurchsichtigen UIImage ändern. Mein ursprüngliches Bild ist wie folgt:

Geben Sie hier die Bildbeschreibung ein

und ich möchte das Bild in das folgende Format konvertieren

Geben Sie hier die Bildbeschreibung ein

Im Grunde möchte ich also die rote Farbe im Bild in schwarze Farbe (jede andere Farbe) umwandeln. Oben sind zwei Bilder zum besseren Verständnis hinzugefügt.

Lösung

Ich konnte keine Antworten auf die “Duplikate” sehen (diese Frage hätte nicht als Duplikat gekennzeichnet werden sollen), mit denen Sie eine bestimmte Farbe durch eine andere Farbe ersetzen und an einem undurchsichtigen Bild arbeiten können, also habe ich beschlossen, eine hinzuzufügen möchten.


Ich habe UIImagedazu eine Kategorie erstellt. Sie funktioniert im Grunde, indem sie jedes Pixel durchläuft und erkennt, wie nah es an einer bestimmten Farbe ist, und es mit Ihrer Ersatzfarbe mischt, falls dies der Fall ist.

Dies funktioniert für Bilder mit transparentem und undurchsichtigem Hintergrund .

@implementation UIImage (UIImageColorReplacement)

-(UIImage*) imageByReplacingColor:(UIColor*)sourceColor withMinTolerance:(CGFloat)minTolerance withMaxTolerance:(CGFloat)maxTolerance withColor:(UIColor*)destinationColor {

    // components of the source color
    const CGFloat* sourceComponents = CGColorGetComponents(sourceColor.CGColor);
    UInt8* source255Components = malloc(sizeof(UInt8)*4);
    for (int i = 0; i < 4; i++) source255Components[i] = (UInt8)round(sourceComponents[i]*255.0);

    // components of the destination color
    const CGFloat* destinationComponents = CGColorGetComponents(destinationColor.CGColor);
    UInt8* destination255Components = malloc(sizeof(UInt8)*4);
    for (int i = 0; i < 4; i++) destination255Components[i] = (UInt8)round(destinationComponents[i]*255.0);

    // raw image reference
    CGImageRef rawImage = self.CGImage;

    // image attributes
    size_t width = CGImageGetWidth(rawImage);
    size_t height = CGImageGetHeight(rawImage);
    CGRect rect = {CGPointZero, {width, height}};

    // bitmap format
    size_t bitsPerComponent = 8;
    size_t bytesPerRow = width*4;
    CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big;

    // data pointer
    UInt8* data = calloc(bytesPerRow, height);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // create bitmap context
    CGContextRef ctx = CGBitmapContextCreate(data, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo);
    CGContextDrawImage(ctx, rect, rawImage);

    // loop through each pixel's components
    for (int byte = 0; byte < bytesPerRow*height; byte += 4) {

        UInt8 r = data[byte];
        UInt8 g = data[byte+1];
        UInt8 b = data[byte+2];

        // delta components
        UInt8 dr = abs(r-source255Components[0]);
        UInt8 dg = abs(g-source255Components[1]);
        UInt8 db = abs(b-source255Components[2]);

        // ratio of 'how far away' each component is from the source color
        CGFloat ratio = (dr+dg+db)/(255.0*3.0);
        if (ratio > maxTolerance) ratio = 1; // if ratio is too far away, set it to max.
        if (ratio < minTolerance) ratio = 0; // if ratio isn't far enough away, set it to min.

        // blend color components
        data[byte] = (UInt8)round(ratio*r)+(UInt8)round((1.0-ratio)*destination255Components[0]);
        data[byte+1] = (UInt8)round(ratio*g)+(UInt8)round((1.0-ratio)*destination255Components[1]);
        data[byte+2] = (UInt8)round(ratio*b)+(UInt8)round((1.0-ratio)*destination255Components[2]);

    }

    // get image from context
    CGImageRef img = CGBitmapContextCreateImage(ctx);

    // clean up
    CGContextRelease(ctx);
    CGColorSpaceRelease(colorSpace);
    free(data);
    free(source255Components);
    free(destination255Components);

    UIImage* returnImage = [UIImage imageWithCGImage:img];
    CGImageRelease(img);

    return returnImage;
}

@end

Verwendungszweck:

UIImage* colaImage = [UIImage imageNamed:@"cola1.png"];
UIImage* blackColaImage = [colaImage imageByReplacingColor:[UIColor colorWithRed:1 green:0 blue:0 alpha:1] withMinTolerance:0.5 withMaxTolerance:0.6 withColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:1]];

Dies minToleranceist der Punkt, an dem Pixel beginnen, sich mit der Ersatzfarbe zu vermischen (anstatt ersetzt zu werden). Das maxToleranceist der Punkt, an dem die Pixel nicht mehr gemischt werden.

Vor:

Geben Sie hier die Bildbeschreibung ein

Nach:

Geben Sie hier die Bildbeschreibung ein

Das Ergebnis ist ein wenig aliasiert, aber bedenken Sie, dass Ihr Originalbild ziemlich klein war. Dies funktioniert viel besser mit einem Bild mit höherer Auflösung. Sie können auch mit den Toleranzen herumspielen, um noch bessere Ergebnisse zu erzielen!


Beantwortet von –
Hamish


Antwort geprüft von –
Jay B. (FixError Admin)

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like