Jak odcień przezroczystego obrazu PNG w iPhonie?

Wiem, że możliwe jest odcień prostokątnego obrazu, rysując nad nim CGContextFillRect i ustawiając tryb mieszania. Nie mogę jednak wymyślić, jak zrobić odcień na przezroczystym obrazie, takim jak ikona. Musi to być możliwe, ponieważ SDK robi to samo na paskach kart w takich. Czy ktoś mógłby podać fragment?

Aktualizacja:

Wiele wspaniałych sugestii zostały podane dla tego problemu, ponieważ pierwotnie zapytał. Pamiętaj, aby przeczytać wszystkie odpowiedzi, aby dowiedzieć się, co najbardziej Ci pasuje.

W tym celu należy skontaktować się z działem obsługi klienta.]}

Z iOS 7.0 mogę teraz po prostu wykonać następujące czynności, które zaspokoiłyby potrzeby mojego pierwotnego pytania. Ale jeśli masz bardziej skomplikowane sprawy, sprawdź wszystkie odpowiedzi.

UIImage *iconImage = [[UIImage imageNamed:@"myImageName"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];    
UIImageView *icon = [[UIImageView alloc] initWithImage:iconImage];
icon.tintColor = [UIColor redColor];
Author: anna, 2010-08-18

13 answers

Update: Oto Gist dla szybkiego rozszerzenia UIColor przy użyciu poniższego kodu.


Jeśli masz obrazek w skali szarości i chcesz Biały stać się kolorem przyciemniającym, kCGBlendModeMultiply to jest droga. Dzięki tej metodzie podświetlenia nie mogą być jaśniejsze niż kolor przyciemniania.

Przeciwnie, jeśli masz obraz bez skali szarości, lub masz pasemka i cienie które powinny być zachowany, tryb mieszaniakCGBlendModeColor to jest droga. Biały pozostanie biały, a czarny pozostanie czarny, ponieważ lekkość obrazu jest zachowana. Ten tryb jest po prostu stworzony do przyciemniania-jest taki sam jak tryb mieszania warstw w Photoshopie (zastrzeżenie: mogą się zdarzyć nieco różne wyniki).

Zauważ, że przyciemnianie pikseli alfa nie działa poprawnie ani w systemie iOS, ani w Photoshopie - pół przezroczyste czarne piksele nie pozostaną Czarne. Zaktualizowałem odpowiedź poniżej, aby obejść to problem, zajęło sporo czasu, aby dowiedzieć się.

Możesz również użyć jednego z trybów mieszania kCGBlendModeSourceIn/DestinationIn zamiast CGContextClipToMask.

Jeśli chcesz utworzyć UIImage, każda z następujących sekcji kodu może być otoczona następującym kodem:

UIGraphicsBeginImageContextWithOptions (myIconImage.size, NO, myIconImage.scale); // for correct resolution on retina, thanks @MobileVet
CGContextRef context = UIGraphicsGetCurrentContext();

CGContextTranslateCTM(context, 0, myIconImage.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

CGRect rect = CGRectMake(0, 0, myIconImage.size.width, myIconImage.size.height);

// image drawing code here

UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

Oto kod do przyciemniania przezroczystego obrazu za pomocą kCGBlendModeColor:

// draw black background to preserve color of transparent pixels
CGContextSetBlendMode(context, kCGBlendModeNormal);
[[UIColor blackColor] setFill];
CGContextFillRect(context, rect);

// draw original image
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, myIconImage.CGImage);

// tint image (loosing alpha) - the luminosity of the original image is preserved
CGContextSetBlendMode(context, kCGBlendModeColor);
[tintColor setFill];
CGContextFillRect(context, rect);

// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);

Jeśli twój obraz nie ma półprzezroczystych pikseli, możesz również zrobić to na odwrót za pomocą kCGBlendModeLuminosity:

// draw tint color
CGContextSetBlendMode(context, kCGBlendModeNormal);
[tintColor setFill];
CGContextFillRect(context, rect);

// replace luminosity of background (ignoring alpha)
CGContextSetBlendMode(context, kCGBlendModeLuminosity);
CGContextDrawImage(context, rect, myIconImage.CGImage);

// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);

Jeśli nie zależy ci na jasności, ponieważ po prostu masz obraz z kanałem alfa, który powinien być przyciemniony kolorem, możesz to zrobić w bardziej efektywny sposób]}

// draw tint color
CGContextSetBlendMode(context, kCGBlendModeNormal);
[tintColor setFill];
CGContextFillRect(context, rect);

// mask by alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawImage(context, rect, myIconImage.CGImage);

Lub odwrotnie:

// draw alpha-mask
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGContextDrawImage(context, rect, myIconImage.CGImage);

// draw tint color, preserving alpha values of original image
CGContextSetBlendMode(context, kCGBlendModeSourceIn);
[tintColor setFill];
CGContextFillRect(context, rect);
Baw się dobrze!
 163
Author: fabb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-18 13:09:54

Odniosłem największy sukces z tą metodą, ponieważ inne, które wypróbowałem, powodowały zniekształcone kolory dla półprzezroczystych pikseli dla pewnych kombinacji kolorów. Powinno to być również nieco lepsze od strony wydajności.

+ (UIImage *) imageNamed:(NSString *) name withTintColor: (UIColor *) tintColor {

    UIImage *baseImage = [UIImage imageNamed:name];

    CGRect drawRect = CGRectMake(0, 0, baseImage.size.width, baseImage.size.height);

    UIGraphicsBeginImageContextWithOptions(baseImage.size, NO, 0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(context, 0, baseImage.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // draw original image
    CGContextSetBlendMode(context, kCGBlendModeNormal);
    CGContextDrawImage(context, drawRect, baseImage.CGImage);

    // draw color atop
    CGContextSetFillColorWithColor(context, tintColor.CGColor);
    CGContextSetBlendMode(context, kCGBlendModeSourceAtop);
    CGContextFillRect(context, drawRect);

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return tintedImage;
}
 20
Author: cania,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-20 09:21:37

Po przeszukaniu, najlepszym rozwiązaniem, do którego doszedłem, jest użycie kombinacji trybu mieszania i maski przycinającej, aby uzyskać koloryzację / przyciemnianie przezroczystego PNG: {]}

CGContextSetBlendMode (context, kCGBlendModeMultiply);

CGContextDrawImage(context, rect, myIconImage.CGImage);

CGContextClipToMask(context, rect, myIconImage.CGImage);

CGContextSetFillColorWithColor(context, tintColor);

CGContextFillRect(context, rect);
 18
Author: anna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-19 18:13:35

Mogę uzyskać wyniki bardzo zbliżone do odcienia w pasku nawigacyjnym Apple za pomocą kCGBlendModeOverlay. Taking excelent @ fabb answer and combining @ omz approach in this post https://stackoverflow.com/a/4684876/229019 przyszedłem z takim rozwiązaniem, które trzyma wyniki oczekiwałem:

- (UIImage *)tintedImageUsingColor:(UIColor *)tintColor;
{
    UIGraphicsBeginImageContextWithOptions (self.size, NO, [[UIScreen mainScreen] scale]);

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);

    // draw original image
    [self drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0f];

    // tint image (loosing alpha). 
    // kCGBlendModeOverlay is the closest I was able to match the 
    // actual process used by apple in navigation bar 
    CGContextSetBlendMode(context, kCGBlendModeOverlay);
    [tintColor setFill];
    CGContextFillRect(context, rect);

    // mask by alpha values of original image
    [self drawInRect:rect blendMode:kCGBlendModeDestinationIn alpha:1.0f];

    UIImage *tintedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return tintedImage;
}

Oto przykład przyciemniania kilku obrazów w skali szarości przezroczystością:

Renderowany Przykład:

  • pierwsza linia to pasek narzędzi Apple tinted [uicolor orangeColor].
  • druga linia to ten sam gradient zabarwiony na kilka kolorów, zaczynając od przezroczystego koloru (=rzeczywisty gradient), a kończąc na tym samym pomarańczowym.
  • trzeci jest prostym okręgiem z przezroczystością (len jest kolorem tła)
  • czwarta linia jest złożoną ciemną hałaśliwą fakturą
 16
Author: tozevv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:15

Możesz utworzyć kategorię UIImage i zrobić to tak:

- (instancetype)tintedImageWithColor:(UIColor *)tintColor {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGRect rect = (CGRect){ CGPointZero, self.size };
    CGContextSetBlendMode(context, kCGBlendModeNormal);
    [self drawInRect:rect];

    CGContextSetBlendMode(context, kCGBlendModeSourceIn);
    [tintColor setFill];
    CGContextFillRect(context, rect);

    UIImage *image  = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
 8
Author: kkodev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-26 10:46:02

W iOS7 wprowadzono właściwość Tintcolor w UIImageView i renderingMode w UIImage. Zobacz mój przykład na https://stackoverflow.com/a/19125120/1570970

 8
Author: Toland Hon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:33:15

Zauważ, że w zaakceptowanej odpowiedzi przez fabb, kod" otaczający " do tworzenia UIImage dał mi złą rozdzielczość obrazów na ekranie siatkówki. Aby naprawić, zmień:

UIGraphicsBeginImageContext (myIconImage.Rozmiar);

Do:

UIGraphicsBeginImageContextWithOptions (myIconImage.size, NO, 0.0);

Ostatnim parametrem, który jest ustawiony na 0.0 jest scale, i zgodnie z dokumentacją Apple: "Jeśli podasz wartość 0.0, współczynnik skali jest ustawiony na współczynnik skali ekran główny urządzenia".

Nie mam uprawnień do komentowania, a edycja wydaje się nieco niegrzeczna, więc wspominam o tym w odpowiedzi. Na wypadek, gdyby ktoś napotkał ten sam problem.

 3
Author: lxl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-11 13:08:12

W systemie iOS 7.0 możesz to zrobić również, aby odcień podstawowego interfejsu UIImageView:

UIImage *iconImage = [[UIImage imageNamed:@"myImageName"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];    
UIImageView *icon = [[UIImageView alloc] initWithImage:iconImage];
icon.tintColor = [UIColor redColor];
 3
Author: anna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-30 11:50:50

UIImageView (lub dowolny Widok) ma kolor tła, który jest RGBA. Alfa w kolorze może zrobić to, czego potrzebujesz, bez wymyślania czegoś nowego.

 2
Author: NWCoder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-18 18:56:12

Nie Moja praca, ale z powodzeniem zastosowałem takie podejście:

Http://coffeeshopped.com/2010/09/iphone-how-to-dynamically-color-a-uiimage

 1
Author: Dermot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-14 07:46:47

Chciałem przyciemnić moje widoki w mojej niestandardowej podklasie UIButton, a inne rozwiązania nie robiły tego, co chciałem. Musiałem przyciemnić" odcień " koloru obrazu. Oto jak zmienić jasność za pomocą CoreImage.

Niestandardowe przyciski z cieniowanymi obrazami po naciśnięciu przycisku

  1. Upewnij się, że dodałeś CoreImage.framework do bibliotek twojego projektu. (Link binarny z bibliotekami)

  2. UIImage shade method

    - (UIImage *)shadeImage:(UIImage *)image {
     CIImage *inputImage = [CIImage imageWithCGImage:image.CGImage];
    
     CIContext *context = [CIContext contextWithOptions:nil];
    
     CIFilter *filter = [CIFilter filterWithName:@"CIColorControls"
                                  keysAndValues:kCIInputImageKey, inputImage,
                        @"inputBrightness", [NSNumber numberWithFloat:-.5], nil];
     CIImage *outputImage = [filter outputImage];
    
     CGImageRef cgImage = [context createCGImage:outputImage fromRect:[outputImage extent]];
     UIImage *newImage = [UIImage imageWithCGImage:cgImage scale:image.scale orientation:image.imageOrientation];
     CGImageRelease(cgImage);
    
     return newImage;
    }
    
  3. Będziesz chciał przechowywać kopię kontekstu jako ivar, a nie odtworzyć.

 1
Author: Paul Solt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-24 16:51:38

Żadne odpowiedzi nie pomogą mi w przepełnieniu stosu: nasi projektanci rysują elementy interfejsu użytkownika o różnych formach, różnych wartościach alfa (i "otworach Alfa"). W większości przypadków jest to 32-bitowy plik PNG z kanałem alfa, który zawiera czarno-białe piksele (wszystkich możliwych intensywności). Po przyciemnieniu takiego zdjęcia musiałem uzyskać taki przyciemniony wynik: białe piksele-przyciemnione więcej, a ciemne piksele-mniej. A wszystko to w świetle kanału alfa. I napisałem tę metodę dla mojej kategorii UIImage. Może nie jest wysoka wydajny, ale działa jak zegar:) tutaj jest:

- (UIImage *)imageTintedWithColor:(UIColor *)color {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);

    CGContextSetBlendMode(context, kCGBlendModeCopy);
    [color setFill];
    CGContextFillRect(context, rect);

    [self drawInRect:rect blendMode:kCGBlendModeXOR alpha:1.0];

    CGContextSetBlendMode(context, kCGBlendModeXOR);
    CGContextFillRect(context, rect);

    [self drawInRect:rect blendMode:kCGBlendModeMultiply alpha:1.0];

    UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return coloredImage;
}
 1
Author: Dmitry Evglevsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-26 15:32:10

Najpierw chcę podziękować fabbowi za jego wyjątkowe rozwiązanie, które pomogło mi wykonać moje zadanie polegające na odbarwianiu ikon w połowie przezroczystych. Ponieważ potrzebowałem rozwiązania dla C# (Monotouch) musiałem przetłumaczyć jego kod. Oto, co wymyśliłem. Po prostu skopiuj wklej to do kodu i dodaj swój półprzezroczysty obraz i gotowe.

/ Align = "left" / To jest tylko po to, aby uruchomić użytkowników C#:)
//TINT COLOR IMAGE
UIImageView iImage = new UIImageView(new RectangleF(12, 14, 24,24));
iImage.ContentMode = UIViewContentMode.ScaleAspectFit;
iImage.Image = _dataItem.Image[0] as UIImage;

UIGraphics.BeginImageContextWithOptions(iImage.Bounds.Size, false, UIScreen.MainScreen.Scale);
CGContext context = UIGraphics.GetCurrentContext();

context.TranslateCTM(0, iImage.Bounds.Size.Height);
context.ScaleCTM(1.0f, -1.0f);

RectangleF rect = new RectangleF(0,0, iImage.Bounds.Width, iImage.Bounds.Height);

// draw black background to preserve color of transparent pixels
context.SetBlendMode(CGBlendMode.Normal);
UIColor.Black.SetFill();
context.FillRect(rect);

// draw original image
context.SetBlendMode(CGBlendMode.Normal);
context.DrawImage(rect, iImage.Image.CGImage);

// tint image (loosing alpha) - the luminosity of the original image is preserved
context.SetBlendMode(CGBlendMode.Color);
UIColor.Orange.SetFill();
context.FillRect(rect);

// mask by alpha values of original image
context.SetBlendMode(CGBlendMode.DestinationIn);
context.DrawImage(rect, iImage.Image.CGImage);

UIImage coloredImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();

iImage = new UIImageView(coloredImage);
iImage.Frame = new RectangleF(12, 14, 24,24);
//END TINT COLOR IMAGE

cell.Add(iImage);
 0
Author: Henning Schulz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-07 04:10:19