Bir UIImage'ın opaklığı / alfa ayarı nasıl yapılır?


83

Bunu bir UIImageView ile yapabileceğinizi biliyorum, ancak bir UIImage'a yapılabilir mi? Bir UIImageView öğesinin animasyon görüntüleri dizi özelliğinin aynı görüntünün bir dizisi olmasına ancak farklı opaklıklara sahip olmasını istiyorum. Düşünceler?

Yanıtlar:


122

Bunu yapmam gerekiyordu ama Steven'ın çözümünün yavaş olacağını düşündüm. Bu umarım grafik HW kullanmalıdır. UIImage'da bir kategori oluşturun:

- (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;
}

3
buna neden ihtiyacım olduğunu bile hatırlayamıyorum :)
Marty

Harika çözüm! Teşekkürler Nick!
Christopher

1
Sadece ana iş parçacığı üzerinde UIGraphicsBeginImageContextWithOptions'ı çağırdığınızdan emin olun çünkü arka plan oluşturma öngörülemez olacaktır.
Steven Veltema

1
Apple'a göre, UIGraphicsBeginImageContextWithOptions'ı iOS 4 ve sonraki sürümlerden bu yana herhangi bir iş parçacığında çağırabilirsiniz.
Karıncalar

6
Harika çalışıyor, çok teşekkürler. İOS geliştirme ile ilgili lojistiğe yeni başlayanlar için, UIImage için bir kategori oluşturma adımları. 1. Projenizin yöneticisine sağ tıklayın ve Yeni Dosya'yı seçin. 2. Görünen ekranda, Amaç-C kategorisi dosya türünü seçin. 3. Yanıtlayanın kodunu .m dosyasına ve yöntem için bir bildirimi .h dosyasına ekleyin. 4. Görüntünün şeffaf olmasını sağlayan dosyada, dosyayı # içe aktarın. 5. Bir UIImage örneğinde imageByApplyingAlpha yöntemini kullanın.
Danny

79

Gösterildiği görünümün opaklığını ayarlayın.

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

Bunu bir animasyonda kullanın. Bir animasyondaki alfayı bir süre için değiştirebilirsiniz.

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
//Set alpha
[UIView commitAnimations];

evet, opaklığı sürekli olarak değiştirmek için bunu bir zamanlayıcıyla böyle yapmak zorunda kalabileceğimi düşünüyordum, sadece animasyon görüntüleri dizisi özelliği için bir diziye sahip olmanın çok daha kolay olacağını düşündüm, böylece kendi kendine canlandırabilirdi.
Marty

Animasyon temsilcisi ile bir kalp atışı gibi 'içeri' ve 'dışarı' hareketlendirebilirsiniz. Zamanlayıcı kullanmayın, animasyon alfayı sorunsuz bir şekilde değiştirecektir. İyi şanslar.
Mats Stijlaart

3
Bu yalnızca geliştirici bir UIImageView kullanıyorsa çalışır. Soru açıkça durumun böyle olmadığını söylüyor.
Raul Huerta

1
Bu, bir CALayer'da sunulan bir UIImage ile çalışır, yalnızca görüntüyü değiştirmek zorunda kalmadan layer.opacity'yi ayarlarsınız. Teşekkürler Mats!
Chris

Harika! UIButtonTam olarak ihtiyacım olan şey üzerinde çalışıyor .
NecipAllef

53

Alexey Ishkov'un cevabına göre, ancak Swift'de

UIImage sınıfının bir uzantısını kullandım.

Swift 2:

UIImage Uzantısı:

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

Kullanmak:

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

Hızlı 3/4/5:

Bu uygulamanın isteğe bağlı bir UIImage döndürdüğünü unutmayın. Bunun nedeni, Swift 3'te UIGraphicsGetImageFromCurrentImageContextartık isteğe bağlı olarak dönmesidir. Bağlam nil ise veya ne ile oluşturulmamışsa bu değer sıfır olabilirUIGraphicsBeginImageContext .

UIImage Uzantısı:

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

Kullanmak:

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

Bu Swift 3versiyonu tercih ederim .
AechoLiu

Teşekkürler. Swift 4'te de aynı şekilde çalışıyor, cevabı bunu yansıtacak şekilde güncelledim.
zeeshan

Bravo efendim, bravo
Ryan Brodie

17

çok daha kolay bir çözüm var:

- (UIImage *)tranlucentWithAlpha:(CGFloat)alpha
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

1
Muhtemelen kabul edilen cevap olmalıydı. Sonucu almanın en hızlı / en verimli yolu
Will Von Ullrich

4

Bunun oldukça geç olduğunun farkındayım ama bunun gibi bir şeye ihtiyacım vardı, bu yüzden bunu yapmak için hızlı ve kirli bir yöntem geliştirdim.

+ (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;
}

2
Daha iyi bir isimsetImage:withAlpha:
Alexander

8
set genellikle bir şekilde alıcının durumunu değiştirerek özelliklere atıfta bulunur. adını vermek daha iyi olur image:withAlpha:mu?
Jonathan.

2
Evet. Ayrıca set çağrısı, yeni bir görüntü döndürmek yerine, içeri aktarılan aynı nesneyi ayarlamayı uygular.
sistem

4

Hey hey, Xamarin kullanıcısından teşekkürler! :) Burada c # 'ye çevrilir

//***************************************************************************
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;
        }

}

Kullanım örneği:

var MySupaImage = UIImage.FromBundle("opaquestuff.png").WithAlpha(0.15f);

1

diğerleriyle aynı sonuç, farklı tarz:

extension UIImage {

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

}

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()
  }
}

0

Metal işleme ile deney yapıyorsanız ve ilk yanıtta imageByApplyingAlpha tarafından oluşturulan CGImage'ı çıkarıyorsanız, beklediğinizden daha büyük bir Metal işleme ile karşılaşabilirsiniz. Metal ile deney yaparken, imageByApplyingAlpha'da bir kod satırını değiştirmek isteyebilirsiniz:

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

İPhone 11 Pro Max gibi ölçek faktörü 3.0 olan bir cihaz kullanıyorsanız, yukarıda gösterilen 0.0 ölçek faktörü size beklediğinizden üç kat daha büyük bir CGImage verecektir. Ölçek faktörünün 1.0 olarak değiştirilmesi, herhangi bir ölçeklendirmeden kaçınmalıdır.

Umarım, bu cevap yeni başlayanları çok fazla sıkıntıdan kurtarır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.