Як встановити непрозорість / альфа-зображення UIImage?


83

Я знаю, що ви можете зробити це за допомогою UIImageView, але чи можна це зробити для UIImage? Я хочу, щоб властивість масиву анімаційних зображень UIImageView була масивом того самого зображення, але з різною непрозорістю. Думки?

Відповіді:


122

Мені просто потрібно було це зробити, але думав, що рішення Стівена буде повільним. Сподіваємось, тут слід використовувати графіку HW. Створіть категорію на 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;
}

3
навіть не можу згадати, навіщо мені це було потрібно :)
Марті

Чудове рішення! Дякую Ніку!
Крістофер,

1
Тільки переконайтеся, що ви викликаєте UIGraphicsBeginImageContextWithOptions в основному потоці, оскільки фонове відтворення буде непередбачуваним.
Steven Veltema

1
За словами Apple, ви можете викликати UIGraphicsBeginImageContextWithOptions у будь-якому потоці, починаючи з iOS 4 і пізніших версій.
Мурахи

6
Чудово працює, спасибі тонна. Для інших новачків у логістиці навколо розробки iOS, ось кроки для створення категорії для UIImage. 1. Клацніть правою кнопкою миші в режисері проекту та виберіть Новий файл. 2. На екрані, що з’явиться, виберіть тип файлу категорії Objective-C. 3. Додайте код відповіді у файл .m та декларацію методу у файл .h. 4. У файлі, в якому зображення використовується прозорим, # імпортуйте файл. 5. Використовуйте метод imageByApplyingAlpha на екземплярі UIImage.
Денні

79

Встановіть непрозорість його вигляду, на якому воно показано.

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

Використовуйте це в анімації. Ви можете змінювати альфа в анімації на час.

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

так, я думав, що мені, можливо, доведеться робити це так за допомогою таймера, щоб постійно змінювати непрозорість, просто думав, що буде набагато простіше мати масив для властивості масиву анімаційних зображень, щоб він анімував сам по собі.
Марті

Ви можете анімувати це "в" і "назовні", як серцебиття за допомогою делегата анімації. Не використовуйте таймер, анімація плавно змінить альфу. Удачі.
Mats Stijlaart

3
Це працює, лише якщо розробник використовує UIImageView. Питання чітко говорить, що це не так.
Raul Huerta

1
Це працює з UIImage, представленим у CALayer, лише ви встановлюєте layer.opacity, не змінюючи зображення взагалі. Дякую Матс!
Кріс

Чудово! Працює над тим UIButton, що саме мені було потрібно.
NecipAllef

53

Засноване на відповіді Олексія Ішкова, але на швидкому

Я використовував розширення класу UIImage.

Свіфт 2:

Розширення UIImage:

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

Використовувати:

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

Стрім 3/4/5:

Зверніть увагу, що ця реалізація повертає необов’язковий UIImage. Це тому, що в Swift 3 UIGraphicsGetImageFromCurrentImageContextтепер повертається необов’язковий. Це значення може бути нульовим, якщо контекст нульовий або те, що не створено за допомогоюUIGraphicsBeginImageContext .

Розширення UIImage:

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

Використовувати:

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

Я віддаю перевагу цій Swift 3версії.
AechoLiu

Дякую. Це працює так само в Swift 4, я оновив відповідь, щоб це відобразити.
zeeshan

Браво, сер, браво
Райан Броді

17

є набагато простіше рішення:

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

1
Можливо, це мала бути прийнята відповідь. Найшвидший / найефективніший спосіб отримати результат
Уілл Фон Улріх

4

Я розумію, що це досить пізно, але мені потрібно було щось подібне, тому я підготував швидкий і брудний спосіб зробити це.

+ (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
Краще буде ім'яsetImage:withAlpha:
Олександр

8
набір зазвичай відноситься до властивостей, певним чином змінюючи стан приймача. краще б його назвати image:withAlpha:?
Джонатан.

2
Ага. Також для виклику набору застосовується встановлення того самого об'єкта, який передано, а не повернення нового зображення.
системний

4

Привіт, привіт, дякую користувачеві Xamarin! :) Ось це перекладається на c #

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

}

Приклад використання:

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

1

той самий результат, що й інші, інший стиль:

extension UIImage {

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

}

1

Свіфт 5:

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

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

0

Якщо ви експериментуєте з візуалізацією металу і ви витягуєте CGImage, сформований imageByApplyingAlpha у першій відповіді, у вас може вийти візуалізація металу, яка більша, ніж ви очікуєте. Під час експериментів з Metal ви можете змінити один рядок коду в imageByApplyingAlpha:

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

Якщо ви використовуєте пристрій із коефіцієнтом масштабу 3,0, наприклад iPhone 11 Pro Max, показаний вище коефіцієнт 0,0 дасть вам CGImage, який у три рази перевищує очікуваний. Змінюючи коефіцієнт масштабу до 1,0, слід уникати масштабування.

Сподіваємось, ця відповідь позбавить початківців значного загострення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.