смешать два пользовательских изображения на основе альфа / прозрачности верхнего изображения

Я пытаюсь смешать фон с изображением переднего плана, где изображение переднего плана представляет собой прозрачное изображение с линиями на нем.

Я пытаюсь сделать это так.

UIGraphicsBeginImageContext(CGSizeMake(320, 480));
CGContextRef context = UIGraphicsGetCurrentContext();   

// create rect that fills screen
CGRect bounds = CGRectMake( 0,0, 320, 480);

// This is my bkgnd image
CGContextDrawImage(context, bounds, [UIImage imageNamed:@"bkgnd.jpg"].CGImage);

CGContextSetBlendMode(context, kCGBlendModeSourceIn);

// This is my image to blend in
CGContextDrawImage(context, bounds, [UIImage imageNamed:@"over.png"].CGImage);

UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();

UIImageWriteToSavedPhotosAlbum(outputImage, self, nil, nil);
// clean up drawing environment
//
UIGraphicsEndImageContext();

но вроде не работает.

Любые предложения будут оценены.


person Community    schedule 21.08.2009    source источник
comment
Техническое примечание: это относится к альфа-смешиванию (составлению двух изображений на основе альфа-канала в одном из изображений), не к использованию режимов наложения Core Graphics - повторите поиск, если это то, что вам нужно. Фактически, ответ Эрика вкратце показывает использование одного режима наложения; вы можете заменить там другой режим наложения и удалить параметр alpha: 0.8.   -  person ToolmakerSteve    schedule 10.03.2017


Ответы (7)


Это то, что я сделал в своем приложении, похожем на приложение Тайлера, но без UIImageView:

UIImage *bottomImage = [UIImage imageNamed:@"bottom.png"];
UIImage *image = [UIImage imageNamed:@"top.png"];

CGSize newSize = CGSizeMake(width, height);
UIGraphicsBeginImageContext( newSize );

// Use existing opacity as is
[bottomImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
// Apply supplied opacity
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height) blendMode:kCGBlendModeNormal alpha:0.8];

UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

Если у изображения уже есть непрозрачность, вам не нужно ее устанавливать (как в bottomImage), иначе вы можете установить ее (как в image).

person Eric    schedule 06.07.2010
comment
Спасибо за этот ответ ... Это сработало как шарм ... Но я хочу сделать то же самое для двух слоев .... - person Alfa; 21.04.2014
comment
Для поддержки дисплеев Retina и без Retina используйте UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0f);, который сообщает UIKit о необходимости получить и использовать масштабный коэффициент главного экрана устройства. - person Mr. T; 13.06.2014

мой ответ основан на ответе Эрика, но позволяет изображениям @ 2x сохранять свое разрешение после слияния изображений. Обратите внимание на URL-адрес REF в моих комментариях, так как я подтверждаю источники, которые помогли мне в разработке этой функции, которую я использовал в своих приложениях для iOS.

- (UIImage*) mergeTwoImages : (UIImage*) topImage : (UIImage*) bottomImage
{
    // URL REF: http://iphoneincubator.com/blog/windows-views/image-processing-tricks
    // URL REF: https://stackoverflow.com/questions/1309757/blend-two-uiimages?answertab=active#tab-top
    // URL REF: http://www.waterworld.com.hk/en/blog/uigraphicsbeginimagecontext-and-retina-display

    int width = bottomImage.size.width;
    int height = bottomImage.size.height;

    CGSize newSize = CGSizeMake(width, height);
    static CGFloat scale = -1.0;

    if (scale<0.0)
    {
        UIScreen *screen = [UIScreen mainScreen];

        if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 4.0)
        {
            scale = [screen scale];
        }
        else
        {
            scale = 0.0;    // Use the standard API
        }
    }

    if (scale>0.0)
    {
        UIGraphicsBeginImageContextWithOptions(newSize, NO, scale);
    }
    else
    {
        UIGraphicsBeginImageContext(newSize);
    }

    [bottomImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
    [topImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height) blendMode:kCGBlendModeNormal alpha:1.0];

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

    return newImage;
}
person Jason TEPOORTEN    schedule 12.02.2012

Смешивание с альфа

UIGraphicsBeginImageContext(area.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextRetain(context);

// mirroring context
CGContextTranslateCTM(context, 0.0, area.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

for (...) {
    CGContextBeginTransparencyLayer(context, nil);
    CGContextSetAlpha( context, alpha );
    CGContextDrawImage(context, area, tempimg.CGImage);
    CGContextEndTransparencyLayer(context);
}

// get created image
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGContextRelease(context);
UIGraphicsEndImageContext();
person Volodymyr B.    schedule 06.07.2010
comment
Пожалуйста, объясните, чем это лучше по сравнению с предыдущими ответами / или при каких обстоятельствах вы бы его использовали / или почему эта альтернатива может быть полезна. Спасибо. - person ToolmakerSteve; 10.03.2017

Swift 3

Эта функция возьмет два изображения и CGSize и вернет необязательный UIImage. Лучше всего работает, когда оба изображения имеют одинаковый размер. Если ваше верхнее изображение имеет альфа-канал, через него будет отображаться нижнее изображение.

// composit two images
func compositeTwoImages(top: UIImage, bottom: UIImage, newSize: CGSize) -> UIImage? {
    // begin context with new size
    UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0)
    // draw images to context
    bottom.draw(in: CGRect(origin: CGPoint.zero, size: newSize))
    top.draw(in: CGRect(origin: CGPoint.zero, size: newSize))
    // return the new image
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    // returns an optional
    return newImage
}

Использование

let outputSize = CGSize(width: 100, height: 100)
if let topImage = UIImage(named: "myTopImage") {
    if let bottomImage = UIImage(named: "myBottomImage") {
        // composite both images
        if let finalImage = compositeTwoImages(top: topImage, bottom: bottomImage, newSize: outputSize) {
            // do something with finalImage
        }
    }
}
person skymook    schedule 12.11.2016

Не могли бы вы подробно объяснить, что вы имеете в виду под «похоже, не работает»? Рисует ли он только одно изображение или другое? Нарисуйте черным? Шум? Крушение? Почему вы выбрали kCGBlendModeSourceIn; какого эффекта вы пытаетесь достичь (есть десятки способов смешать изображения)? У любого из ваших изображений уже есть альфа-канал?

Я предполагаю, что вы пытаетесь смешать два изображения с непрозрачностью 50%? Используйте для этого CGContextSetAlpha(), а не CGContextSetBlendMode().

person Rob Napier    schedule 21.08.2009
comment
Спасибо за ваши ответы .... Оба моих изображения имеют 100% непрозрачность .... когда я смешиваю оба изображения ... мой контекст рисует только второе изображение ... в macosx ... я использую фильтр вместо источника для составьте оба изображения .... и второе изображение, которое я хочу смешать, уже имеет альфа-канал. - person ; 22.08.2009
comment
Я считаю, что вы хотите вернуться и изучить основы рисования кварца. Я считаю, что вы не понимаете, что значит рисовать различные слои с их собственным альфа-каналом по сравнению с тем, что значит смешивать (что связано, но отличается от того, как это реализовано). Перейдите к руководству по программированию Quartz 2D; он научит вас базовой графике, которая вам нужна, чтобы вы могли делать то, что хотите, легко, с хорошей производительностью, предсказуемостью и гибкостью. developer.apple.com/documentation/graphicsimaging/conceptual/ - person Rob Napier; 24.08.2009

Вы можете использовать drawInRect: или drawAtPoint: UIImage вместо CGContextDrawImage (они рисуют в текущем контексте). Приводит ли их использование к разнице в результатах?

Также может быть полезно убедиться, что UIImage* значения, которые вы получаете обратно от imageNamed:, действительны.

person fbrereto    schedule 21.08.2009

person    schedule
comment
Спасибо за ваши ответы .... но это не то же самое, что иметь 50% непрозрачности ... может быть, я неправильно сформулировал свой вопрос ... может, я скажу, что хочу объединить 2 UIImages ... и изображение сверху имеет альфа-значения. - person ; 22.08.2009
comment
Если в файле png верхнего изображения есть альфа-значения, просто опустите subView.alpha = 0.5; линия, и он будет рисовать верхнее изображение, включая его пользовательские значения альфа, поверх нижнего изображения. - person Tyler; 23.08.2009