Wie stelle ich die Deckkraft / Alpha eines UIImage ein?

80

Ich weiß, dass Sie dies mit einem UIImageView tun können, aber kann es mit einem UIImage gemacht werden? Ich möchte, dass die Array-Eigenschaft für Animationsbilder eines UIImageView ein Array desselben Bildes mit unterschiedlichen Opazitäten ist. Gedanken?

Marty
quelle

Antworten:

122

Ich musste das nur tun, dachte aber, dass Stevens Lösung langsam sein würde. Dies sollte hoffentlich Grafik HW verwenden. Erstellen Sie eine Kategorie auf UIImage:

- (UIImage *)imageByApplyingAlpha:(CGFloat) alpha {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect area = CGRectMake(0, 0, self.size.width, self.size.height);

    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -area.size.height);

    CGContextSetBlendMode(ctx, kCGBlendModeMultiply);

    CGContextSetAlpha(ctx, alpha);

    CGContextDrawImage(ctx, area, self.CGImage);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return newImage;
}
Nick H247
quelle
3
Ich kann mich nicht einmal erinnern, warum ich das brauchte :)
Marty
Tolle Lösung! Danke Nick!
Christopher
1
Stellen Sie nur sicher, dass Sie UIGraphicsBeginImageContextWithOptions im Hauptthread aufrufen, da das Rendern im Hintergrund nicht vorhersehbar ist.
Steven Veltema
1
Laut Apple können Sie UIGraphicsBeginImageContextWithOptions in jedem Thread seit iOS 4 und höher aufrufen.
Ameisen
6
Funktioniert super, vielen Dank. Für andere Neulinge in der Logistik rund um die iOS-Entwicklung sind hier die Schritte zum Erstellen einer Kategorie für UIImage aufgeführt. 1. Klicken Sie mit der rechten Maustaste in den Director Ihres Projekts und wählen Sie Neue Datei. 2. Wählen Sie im angezeigten Bildschirm den Dateityp der Kategorie Objective-C aus. 3. Fügen Sie den Code der Antwort in die .m-Datei und eine Deklaration für die Methode in die .h-Datei ein. 4. Importieren Sie die Datei in die Datei, in der das Bild transparent ist. 5. Verwenden Sie die Methode imageByApplyingAlpha für eine Instanz eines UIImage.
Danny
78

Stellen Sie die Deckkraft der Ansicht ein, in der sie angezeigt wird.

UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageWithName:@"SomeName.png"]];
imageView.alpha = 0.5; //Alpha runs from 0.0 to 1.0

Verwenden Sie dies in einer Animation. Sie können das Alpha in einer Animation für eine bestimmte Dauer ändern.

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
//Set alpha
[UIView commitAnimations];
Mats Stijlaart
quelle
Ja, ich dachte, ich müsste es vielleicht so mit einem Timer machen, um die Deckkraft ständig zu ändern. Ich dachte nur, es wäre viel einfacher, ein Array für die Array-Eigenschaft der Animationsbilder zu haben, damit es von selbst animiert wird.
Marty
Sie können es mit dem Animationsdelegierten wie ein Herzschlag animieren. Verwenden Sie keinen Timer, die Animation ändert das Alpha reibungslos. Viel Glück.
Mats Stijlaart
3
Dies funktioniert nur, wenn der Entwickler eine UIImageView verwendet. Die Frage besagt eindeutig, dass dies nicht der Fall ist.
Raul Huerta
1
Dies funktioniert mit einem UIImage, das in einem CALayer dargestellt wird. Nur Sie legen die Ebene.Papazität fest, ohne das Bild ändern zu müssen. Danke Mats!
Chris
Toll! Funktioniert UIButtongenau das, was ich brauchte.
NecipAllef
50

Basierend auf Alexey Ishkovs Antwort, aber in Swift

Ich habe eine Erweiterung der UIImage-Klasse verwendet.

Swift 2:

UIImage-Erweiterung:

extension UIImage {
    func imageWithAlpha(alpha: CGFloat) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        drawAtPoint(CGPointZero, blendMode: .Normal, alpha: alpha)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

Benutzen:

let image = UIImage(named: "my_image")
let transparentImage = image.imageWithAlpha(0.5)

Swift 3/4/5:

Beachten Sie, dass diese Implementierung ein optionales UIImage zurückgibt. Dies liegt daran, dass in Swift 3 UIGraphicsGetImageFromCurrentImageContextjetzt ein optionales zurückgegeben wird. Dieser Wert kann Null sein, wenn der Kontext Null ist oder was nicht mit erstellt wurdeUIGraphicsBeginImageContext .

UIImage-Erweiterung:

extension UIImage {
    func image(alpha: CGFloat) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        draw(at: .zero, blendMode: .normal, alpha: alpha)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

Benutzen:

let image = UIImage(named: "my_image")
let transparentImage = image?.image(alpha: 0.5)
Devin B.
quelle
Ich bevorzuge diese Swift 3Version.
AechoLiu
Vielen Dank. In Swift 4 funktioniert es genauso. Ich habe die Antwort aktualisiert, um dies widerzuspiegeln.
Zeeshan
Bravo Sir, Bravo
Ryan Brodie
17

Es gibt eine viel einfachere Lösung:

- (UIImage *)tranlucentWithAlpha:(CGFloat)alpha
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
Alexey Ishkov
quelle
1
Wahrscheinlich hätte die akzeptierte Antwort sein sollen. Schnellster / effizientester Weg, um das Ergebnis zu erhalten
Will Von Ullrich
4

Mir ist klar, dass dies ziemlich spät ist, aber ich brauchte so etwas, also habe ich eine schnelle und schmutzige Methode entwickelt, um dies zu tun.

+ (UIImage *) image:(UIImage *)image withAlpha:(CGFloat)alpha{

    // Create a pixel buffer in an easy to use format
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    UInt8 * m_PixelBuf = malloc(sizeof(UInt8) * height * width * 4);

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(m_PixelBuf, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    //alter the alpha
    int length = height * width * 4;
    for (int i=0; i<length; i+=4)
    {
        m_PixelBuf[i+3] =  255*alpha;
    }


    //create a new image
    CGContextRef ctx = CGBitmapContextCreate(m_PixelBuf, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGImageRef newImgRef = CGBitmapContextCreateImage(ctx);  
    CGColorSpaceRelease(colorSpace);
    CGContextRelease(ctx);  
    free(m_PixelBuf);

    UIImage *finalImage = [UIImage imageWithCGImage:newImgRef];
    CGImageRelease(newImgRef);  

    return finalImage;
}
Steven Veltema
quelle
2
Besserer Name wäresetImage:withAlpha:
Alexander
8
set beziehen sich normalerweise auf Eigenschaften, die den Status des Empfängers auf irgendeine Weise ändern. wäre es besser, es zu nennen image:withAlpha:?
Jonathan.
2
Ja. Beim Aufrufen von set wird auch dasselbe übergebene Objekt festgelegt, anstatt ein neues Bild zurückzugeben.
System
4

Hey hey danke vom Xamarin User! :) Hier wird es in c # übersetzt

//***************************************************************************
public static class ImageExtensions
//***************************************************************************
{
    //-------------------------------------------------------------
    public static UIImage WithAlpha(this UIImage image, float alpha)  
    //-------------------------------------------------------------
        {
        UIGraphics.BeginImageContextWithOptions(image.Size,false,image.CurrentScale);
        image.Draw(CGPoint.Empty, CGBlendMode.Normal, alpha);
        var newImage = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();
        return newImage;
        }

}

Anwendungsbeispiel:

var MySupaImage = UIImage.FromBundle("opaquestuff.png").WithAlpha(0.15f);
Nick Kovalsky
quelle
1

gleiches Ergebnis wie andere, anderer Stil:

extension UIImage {

    func withAlpha(_ alpha: CGFloat) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(at: .zero, blendMode: .normal, alpha: alpha)
        }
    }

}
Devin Pitcher
quelle
1

Swift 5:

extension UIImage {
  func withAlphaComponent(_ alpha: CGFloat) -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(size, false, scale)
    defer { UIGraphicsEndImageContext() }

    draw(at: .zero, blendMode: .normal, alpha: alpha)
    return UIGraphicsGetImageFromCurrentImageContext()
  }
}
Vadoff
quelle
0

Wenn Sie mit Metall-Rendering experimentieren und das von imageByApplyingAlpha in der ersten Antwort generierte CGImage extrahieren, erhalten Sie möglicherweise ein Metall-Rendering, das größer ist als erwartet. Während Sie mit Metal experimentieren, möchten Sie möglicherweise eine Codezeile in imageByApplyingAlpha ändern:

    UIGraphicsBeginImageContextWithOptions (self.size, NO, 1.0f);
//  UIGraphicsBeginImageContextWithOptions (self.size, NO, 0.0f);

Wenn Sie ein Gerät mit einem Skalierungsfaktor von 3,0 wie das iPhone 11 Pro Max verwenden, erhalten Sie mit dem oben gezeigten Skalierungsfaktor 0,0 ein CGI-Bild, das dreimal größer ist als erwartet. Durch Ändern des Skalierungsfaktors auf 1,0 sollte eine Skalierung vermieden werden.

Hoffentlich erspart diese Antwort Anfängern viel Ärger.

russes
quelle