Ausgabe
Ich möchte die Farbe eines undurchsichtigen UIImage ändern. Mein ursprüngliches Bild ist wie folgt:
und ich möchte das Bild in das folgende Format konvertieren
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 UIImage
dazu 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 minTolerance
ist der Punkt, an dem Pixel beginnen, sich mit der Ersatzfarbe zu vermischen (anstatt ersetzt zu werden). Das maxTolerance
ist der Punkt, an dem die Pixel nicht mehr gemischt werden.
Vor:
Nach:
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)