叠加混合模式公式是什么?

8

我有两种颜色:一种是动态设置的,另一种始终为白色0.5透明度。我想计算出结果白色,就好像它是在使用叠加混合模式时绘制在动态颜色上。

我知道叠加混合模式结合了正片叠底滤色混合模式。

正片叠底混合模式的公式为:

Result Color = (Top Color) * (Bottom Color) /255

屏幕混合模式的作用是:

Result Color = 255 - [((255 - Top Color)*(255 - Bottom Color))/255]

如何计算叠加混合模式的结果颜色?

是否存在可以直接完成此操作的UIColor扩展类?

4个回答

10

公式分为两个部分:

第一部分:如果下层值 > 127.5,则执行以下操作 -

值单位 = (255-下层值)/127.5

最小值 = 下层值 - (255-下层值)

叠加 = (上层值 * 值单位) + 最小值

第二部分:如果下层值 < 127.5,则执行以下操作 -

值单位 = 下层值/127.5

叠加 = 上层值 * 值单位

从公式中我们可以看到,最终结果在很大程度上取决于上层值。如果上层值更高(更亮),则最终结果更可能更亮。

来源:这里


太好了。这不是我最初的问题的一部分,但你知道有没有任何UIColor扩展类可以直接做到这一点? - samvermette
不是OTB实现,但这可能会对您有所帮助:https://github.com/facebook/three20/blob/master/src/Three20Style/Sources/UIColorAdditions.m - Vincent Guerci

8

接着willi的回答,这是公式转换成代码的样子:

CGFloat newComponents[4];
const CGFloat *topComponents = CGColorGetComponents([[UIColor colorWithRed:1 green:1 blue:1 alpha:1] CGColor]);
const CGFloat *components = CGColorGetComponents(self.color.CGColor);
const int n = CGColorGetNumberOfComponents(self.color.CGColor);

for(int i=0; i < n; i++) {

    if(components[i] > 0.5) {
        CGFloat value = (topComponents[i]-components[i])/0.5;
        CGFloat min = components[i]-(topComponents[i]-components[i]);
        newComponents[i] = topComponents[i]*value+min; 
    } else {
        CGFloat value = components[i]/0.5;
        newComponents[i] = topComponents[i]*value; 
    }
}

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
UIColor *resultColor = [UIColor colorWithCGColor:CGColorCreate(colorSpace, newComponents)];
CGColorSpaceRelease(colorSpace);

2

我不知道你的目标是什么,可能完全离题了,但为什么不直接使用Quartz 2D呢?

CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(ctx, kCGBlendModeOverlay);
... draw with overlay blending

CGBlendMode 可以通过 CGContextSetBlendMode 提供叠加、正片叠底、屏幕等众多模式...:

enum CGBlendMode {
    /* Available in Mac OS X 10.4 & later. */
    kCGBlendModeNormal,
    kCGBlendModeMultiply,
    kCGBlendModeScreen,
    kCGBlendModeOverlay,
    kCGBlendModeDarken,
    kCGBlendModeLighten,
    kCGBlendModeColorDodge,
    kCGBlendModeColorBurn,
    kCGBlendModeSoftLight,
    kCGBlendModeHardLight,
    kCGBlendModeDifference,
    kCGBlendModeExclusion,
    kCGBlendModeHue,
    kCGBlendModeSaturation,
    kCGBlendModeColor,
    kCGBlendModeLuminosity,

    /* Available in Mac OS X 10.5 & later. R, S, and D are, respectively,
       premultiplied result, source, and destination colors with alpha; Ra,
       Sa, and Da are the alpha components of these colors.

       The Porter-Duff "source over" mode is called `kCGBlendModeNormal':
         R = S + D*(1 - Sa)

       Note that the Porter-Duff "XOR" mode is only titularly related to the
       classical bitmap XOR operation (which is unsupported by
       CoreGraphics). */

    kCGBlendModeClear,          /* R = 0 */
    kCGBlendModeCopy,           /* R = S */
    kCGBlendModeSourceIn,       /* R = S*Da */
    kCGBlendModeSourceOut,      /* R = S*(1 - Da) */
    kCGBlendModeSourceAtop,     /* R = S*Da + D*(1 - Sa) */
    kCGBlendModeDestinationOver,    /* R = S*(1 - Da) + D */
    kCGBlendModeDestinationIn,      /* R = D*Sa */
    kCGBlendModeDestinationOut,     /* R = D*(1 - Sa) */
    kCGBlendModeDestinationAtop,    /* R = S*(1 - Da) + D*Sa */
    kCGBlendModeXOR,            /* R = S*(1 - Da) + D*(1 - Sa) */
    kCGBlendModePlusDarker,     /* R = MAX(0, (1 - D) + (1 - S)) */
    kCGBlendModePlusLighter     /* R = MIN(1, S + D) */
};
typedef enum CGBlendMode CGBlendMode; /* Available in Mac OS X 10.4 & later. */

这就是我一直在做的事情。但是我需要保留那个使用叠加混合模式绘制的带有0.5 alpha颜色的结果的引用。这样我就可以在其他地方使用它,并使用kCGBlendModeNormal进行绘制,它看起来就像是我使用kCGBlendModeOverlay进行绘制的一样。 - samvermette
啊,我明白了,我猜你可以结合几个图形来实现这个,我不想像你一样编码,但如果这样能行的话... :) - Vincent Guerci

1

为了后代(因为这是谷歌的热门搜索结果),维基百科的公式更简洁明了。

这是一个伪代码版本。如果你处理一字节颜色,可以使用255和127。

// For 'a' base layer, 'b' top layer.

if (a < 0.5) {
    result = 2 * a * b;
} else {
    result = 1 - 2 * (1 - a) * (1 - b);
}

https://en.wikipedia.org/wiki/Blend_modes#Overlay


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接