from http://www.nathanm.com/photoshop-blending-math/

 

Been working on programmatically blending bitmaps. Below are the macros that I’ve come up, borrowing the some of the formulas from other websites (see sources at the bottom of this post).

Channel blending

#define ChannelBlend_Normal(B,L)     ((uint8)(B))
#define ChannelBlend_Lighten(B,L)    ((uint8)((L > B) ? L:B))
#define ChannelBlend_Darken(B,L)     ((uint8)((L > B) ? B:L))
#define ChannelBlend_Multiply(B,L)   ((uint8)((B * L) / 255))
#define ChannelBlend_Average(B,L)    ((uint8)((B + L) / 2))
#define ChannelBlend_Add(B,L)        ((uint8)(min(255, (B + L))))
#define ChannelBlend_Subtract(B,L)   ((uint8)((B + L < 255) ? 0:(B + L - 255)))
#define ChannelBlend_Difference(B,L) ((uint8)(abs(B - L)))
#define ChannelBlend_Negation(B,L)   ((uint8)(255 - abs(255 - B - L)))
#define ChannelBlend_Screen(B,L)     ((uint8)(255 - (((255 - B) * (255 - L)) >> 8)))
#define ChannelBlend_Exclusion(B,L)  ((uint8)(B + L - 2 * B * L / 255))
#define ChannelBlend_Overlay(B,L)    ((uint8)((L < 128) ? (2 * B * L / 255):(255 - 2 * (255 - B) * (255 - L) / 255)))
#define ChannelBlend_SoftLight(B,L)  ((uint8)((L < 128)?(2*((B>>1)+64))*((float)L/255):(255-(2*(255-((B>>1)+64))*(float)(255-L)/255))))
#define ChannelBlend_HardLight(B,L)  (ChannelBlend_Overlay(L,B))
#define ChannelBlend_ColorDodge(B,L) ((uint8)((L == 255) ? L:min(255, ((B << 8 ) / (255 - L)))))
#define ChannelBlend_ColorBurn(B,L)  ((uint8)((L == 0) ? L:max(0, (255 - ((255 - B) << 8 ) / L))))
#define ChannelBlend_LinearDodge(B,L)(ChannelBlend_Add(B,L))
#define ChannelBlend_LinearBurn(B,L) (ChannelBlend_Subtract(B,L))
#define ChannelBlend_LinearLight(B,L)((uint8)(L < 128)?ChannelBlend_LinearBurn(B,(2 * L)):ChannelBlend_LinearDodge(B,(2 * (L - 128))))
#define ChannelBlend_VividLight(B,L) ((uint8)(L < 128)?ChannelBlend_ColorBurn(B,(2 * L)):ChannelBlend_ColorDodge(B,(2 * (L - 128))))
#define ChannelBlend_PinLight(B,L)   ((uint8)(L < 128)?ChannelBlend_Darken(B,(2 * L)):ChannelBlend_Lighten(B,(2 * (L - 128))))
#define ChannelBlend_HardMix(B,L)    ((uint8)((ChannelBlend_VividLight(B,L) < 128) ? 0:255))
#define ChannelBlend_Reflect(B,L)    ((uint8)((L == 255) ? L:min(255, (B * B / (255 - L)))))
#define ChannelBlend_Glow(B,L)       (ChannelBlend_Reflect(L,B))
#define ChannelBlend_Phoenix(B,L)    ((uint8)(min(B,L) - max(B,L) + 255))
#define ChannelBlend_Alpha(B,L,O)    ((uint8)(O * B + (1 - O) * L))
#define ChannelBlend_AlphaF(B,L,F,O) (ChannelBlend_Alpha(F(B,L),B,O))

B is the base channel and L is the blend channel. For example you to blend using Glow you simply call:

Target[i] = ChannelBlend_Glow(Base[i], Blend[i]);

The great thing about these macros is that you can apply the blending effect simply by passing in the channel value, without regard to which channel is red, green, or blue.

To use the blending along with opacity you can use the following.

Target[i] = ChannelBlend_AlphaF(Base[i], Blend[i], Blend_Subtract, 0.5F)

Color blending

To add certain blend modes that utilize hue, luminosity, and saturation we have to construct a per-color interface instead of per-channel interface. For these macros we assume that A and B are buffer pointers and they point to bytes with channels red, green, and blue in that order.

#define ColorBlend_Buffer(T,B,L,M)      (T)[0] = ChannelBlend_##M((B)[0], (L)[0]), \
                                        (T)[1] = ChannelBlend_##M((B)[1], (L)[1]), \
                                        (T)[2] = ChannelBlend_##M((B)[2], (L)[2])
#define ColorBlend_Normal(T,B,L)        (ColorBlend_Buffer(T,B,L,Normal))
#define ColorBlend_Lighten(T,B,L)       (ColorBlend_Buffer(T,B,L,Lighten))
#define ColorBlend_Darken(T,B,L)        (ColorBlend_Buffer(T,B,L,Darken))
#define ColorBlend_Multiply(T,B,L)      (ColorBlend_Buffer(T,B,L,Multiply))
#define ColorBlend_Average(T,B,L)       (ColorBlend_Buffer(T,B,L,Average))
#define ColorBlend_Add(T,B,L)           (ColorBlend_Buffer(T,B,L,Add))
#define ColorBlend_Subtract(T,B,L)      (ColorBlend_Buffer(T,B,L,Subtract))
#define ColorBlend_Difference(T,B,L)    (ColorBlend_Buffer(T,B,L,Difference))
#define ColorBlend_Negation(T,B,L)      (ColorBlend_Buffer(T,B,L,Negation))
#define ColorBlend_Screen(T,B,L)        (ColorBlend_Buffer(T,B,L,Screen))
#define ColorBlend_Exclusion(T,B,L)     (ColorBlend_Buffer(T,B,L,Exclusion))
#define ColorBlend_Overlay(T,B,L)       (ColorBlend_Buffer(T,B,L,Overlay))
#define ColorBlend_SoftLight(T,B,L)     (ColorBlend_Buffer(T,B,L,SoftLight))
#define ColorBlend_HardLight(T,B,L)     (ColorBlend_Buffer(T,B,L,HardLight))
#define ColorBlend_ColorDodge(T,B,L)    (ColorBlend_Buffer(T,B,L,ColorDodge))
#define ColorBlend_ColorBurn(T,B,L)     (ColorBlend_Buffer(T,B,L,ColorBurn))
#define ColorBlend_LinearDodge(T,B,L)   (ColorBlend_Buffer(T,B,L,LinearDodge))
#define ColorBlend_LinearBurn(T,B,L)    (ColorBlend_Buffer(T,B,L,LinearBurn))
#define ColorBlend_LinearLight(T,B,L)   (ColorBlend_Buffer(T,B,L,LinearLight))
#define ColorBlend_VividLight(T,B,L)    (ColorBlend_Buffer(T,B,L,VividLight))
#define ColorBlend_PinLight(T,B,L)      (ColorBlend_Buffer(T,B,L,PinLight))
#define ColorBlend_HardMix(T,B,L)       (ColorBlend_Buffer(T,B,L,HardMix))
#define ColorBlend_Reflect(T,B,L)       (ColorBlend_Buffer(T,B,L,Reflect))
#define ColorBlend_Glow(T,B,L)          (ColorBlend_Buffer(T,B,L,Glow))
#define ColorBlend_Phoenix(T,B,L)       (ColorBlend_Buffer(T,B,L,Phoenix))
#define ColorBlend_Hue(T,B,L)            ColorBlend_Hls(T,B,L,HueL,LuminationB,SaturationB)
#define ColorBlend_Saturation(T,B,L)     ColorBlend_Hls(T,B,L,HueB,LuminationB,SaturationL)
#define ColorBlend_Color(T,B,L)          ColorBlend_Hls(T,B,L,HueL,LuminationB,SaturationL)
#define ColorBlend_Luminosity(T,B,L)     ColorBlend_Hls(T,B,L,HueB,LuminationL,SaturationB)
 
#define ColorBlend_Hls(T,B,L,O1,O2,O3) {                                        \
    float64 HueB, LuminationB, SaturationB;                                     \
    float64 HueL, LuminationL, SaturationL;                                     \
    Color_RgbToHls((B)[2],(B)[1],(B)[0], &HueB, &LuminationB, &SaturationB);    \
    Color_RgbToHls((L)[2],(L)[1],(L)[0], &HueL, &LuminationL, &SaturationL);    \
    Color_HlsToRgb(O1,O2,O3,&(T)[2],&(T)[1],&(T)[0]);                           \
    }
 
int32 Color_HueToRgb(float64 M1, float64 M2, float64 Hue, float64 *Channel)
{
    if (Hue < 0.0)
        Hue += 1.0;
    else if (Hue > 1.0)
        Hue -= 1.0;
 
    if ((6.0 * Hue) < 1.0)
        *Channel = (M1 + (M2 - M1) * Hue * 6.0);
    else if ((2.0 * Hue) < 1.0)
        *Channel = (M2);
    else if ((3.0 * Hue) < 2.0)
        *Channel = (M1 + (M2 - M1) * ((2.0F / 3.0F) - Hue) * 6.0);
    else
        *Channel = (M1);
 
    return TRUE;
}
 
int32 Color_RgbToHls(uint8 Red, uint8 Green, uint8 Blue, float64 *Hue, float64 *Lumination, float64 *Saturation)
{
    float64 Delta;
    float64 Max, Min;
    float64 Redf, Greenf, Bluef;
 
    Redf    = ((float64)Red   / 255.0F);
    Greenf  = ((float64)Green / 255.0F);
    Bluef   = ((float64)Blue  / 255.0F);
 
    Max     = max(max(Redf, Greenf), Bluef);
    Min     = min(min(Redf, Greenf), Bluef);
 
    *Hue        = 0;
    *Lumination = (Max + Min) / 2.0F;
    *Saturation = 0;
 
    if (Max == Min)
        return TRUE;
 
    Delta = (Max - Min);
 
    if (*Lumination < 0.5)
        *Saturation = Delta / (Max + Min);
    else
        *Saturation = Delta / (2.0 - Max - Min);
 
    if (Redf == Max)
        *Hue = (Greenf - Bluef) / Delta;
    else if (Greenf == Max)
        *Hue = 2.0 + (Bluef - Redf) / Delta;
    else
        *Hue = 4.0 + (Redf - Greenf) / Delta;
 
    *Hue /= 6.0;
 
    if (*Hue < 0.0)
        *Hue += 1.0;      
 
    return TRUE;
}
 
int32 Color_HlsToRgb(float64 Hue, float64 Lumination, float64 Saturation, uint8 *Red, uint8 *Green, uint8 *Blue)
{
    float64 M1, M2;
    float64 Redf, Greenf, Bluef;
 
    if (Saturation == 0)
        {
        Redf    = Lumination;
        Greenf  = Lumination;
        Bluef   = Lumination;
        }
    else
        {
        if (Lumination <= 0.5)
            M2 = Lumination * (1.0 + Saturation);
        else
            M2 = Lumination + Saturation - Lumination * Saturation;
 
        M1 = (2.0 * Lumination - M2);
 
        Color_HueToRgb(M1, M2, Hue + (1.0F / 3.0F), &Redf);
        Color_HueToRgb(M1, M2, Hue, &Greenf);
        Color_HueToRgb(M1, M2, Hue - (1.0F / 3.0F), &Bluef);
        }
 
    *Red    = (uint8)(Redf * 255);
    *Blue   = (uint8)(Bluef * 255);
    *Green  = (uint8)(Greenf * 255);
 
    return TRUE;
}

So now we can use the hue, saturation, color, and luminosity blend modes along with the rest of the blend modes. To use the ColorBlend macros we just position our bitmap’s pointers to the next RGB iteration and call,

ColorBlend_Glow(Target + iTarget, Base + iBase, Blend + iBlend);

Color macros

Here are some color macros for combining and extracting channels colors out of an integer. One macro that I find a lot of use for is HexToRgb. With it I can copy and paste a hex color value out of the Photoshop color dialog and use the macro to do all the conversion for me to an rgb value.

#define COLOR_OPAQUE                (0)
#define COLOR_TRANSPARENT           (127)
 
#define RGB_SIZE                    (3)
#define RGB_BPP                     (24)
#define RGB_MAXRED                  (255)
#define RGB_MAXGREEN                (255)
#define RGB_MAXBLUE                 (255)
 
#define ARGB_SIZE                   (4)
#define ARGB_BPP                    (32)
#define ARGB_MAXALPHA               (127)
#define ARGB_MAXRED                 (RGB_MAXRED)
#define ARGB_MAXGREEN               (RGB_MAXGREEN)
#define ARGB_MAXBLUE                (RGB_MAXBLUE)
 
/*********************************************************************/
 
#define Color_GetChannel(c,shift)   ((uint8)((c) >> (shift)))
#define Color_Reverse(c,bpp)        ((((uint8)(c) << 24) | ((uint8)((c) >> 8 ) << 16) | ((uint8)((c) >> 16) << 8 ) | \
                                    ((uint8)((c) >> 24))) >> (32 - (bpp)))
 
#define Rgb_ByteWidth(width)        ((width) * RGB_SIZE)
#define Rgb_PixelWidth(width)       ((width) / RGB_SIZE)
 
#define Rgb_GetRed(rgb)             (Color_GetChannel(rgb, 0))
#define Rgb_GetGreen(rgb)           (Color_GetChannel(rgb, 8))
#define Rgb_GetBlue(rgb)            (Color_GetChannel(rgb, 16))
 
#define Rgba_GetRed(rgba)           (Color_GetChannel(rgba, 24))
#define Rgba_GetGreen(rgba)         (Color_GetChannel(rgba, 16))
#define Rgba_GetBlue(rgba)          (Color_GetChannel(rgba, 8))
#define Rgba_GetAlpha(rgba)         (Color_GetChannel(rgba, 0))
 
#define Argb_GetAlpha(argb)         (Color_GetChannel(argb, 24))
#define Argb_GetRed(argb)           (Color_GetChannel(argb, 16))
#define Argb_GetGreen(argb)         (Color_GetChannel(argb, 8))
#define Argb_GetBlue(argb)          (Color_GetChannel(argb, 0))
 
#define MakeRgb(r,g,b)              (((uint32)(uint8)(b) << 16) | ((uint16)(uint8)(g) << 8 ) | (uint8)(r))
#define MakeRgba(r,g,b,a)           (((uint32)(uint8)(r) << 24) | ((uint16)(uint8)(g) << 16) | ((uint16)(uint8)(b) << 8 ) | (uint8)(a))
#define MakeArgb(a,r,g,b)           (((uint32)(uint8)(a) << 24) | ((uint32)(uint8)(r) << 16) | ((uint16)(uint8)(g) << 8 ) | (uint8)(b))
 
#define HexToRgb(hex)               (MakeRgb(((hex & 0xFF0000) >> 16), ((hex & 0x00FF00) >> 8 ), (hex & 0xFF)))

Image blending

To show you what each effect does I’ve blended the following two photos.


[zt]Photoshop Blend Mode Math
Base Layer
Source
[zt]Photoshop Blend Mode Math
Blend Layer
Source

And the results..


[zt]Photoshop Blend Mode Math
Blend_Lighten
[zt]Photoshop Blend Mode Math
Blend_Darken
[zt]Photoshop Blend Mode Math
Blend_Multiply
[zt]Photoshop Blend Mode Math
Blend_Average
[zt]Photoshop Blend Mode Math
Blend_Add
[zt]Photoshop Blend Mode Math
Blend_Subtract
[zt]Photoshop Blend Mode Math
Blend_Difference
[zt]Photoshop Blend Mode Math
Blend_Negation
[zt]Photoshop Blend Mode Math
Blend_Screen
[zt]Photoshop Blend Mode Math
Blend_Exclusion
[zt]Photoshop Blend Mode Math
Blend_Overlay
[zt]Photoshop Blend Mode Math
Blend_SoftLight
[zt]Photoshop Blend Mode Math
Blend_HardLight
[zt]Photoshop Blend Mode Math
Blend_ColorDodge
[zt]Photoshop Blend Mode Math
Blend_ColorBurn
[zt]Photoshop Blend Mode Math
Blend_LinearDodge
[zt]Photoshop Blend Mode Math
Blend_LinearBurn
[zt]Photoshop Blend Mode Math
Blend_LinearLight
[zt]Photoshop Blend Mode Math
Blend_VividLight
[zt]Photoshop Blend Mode Math
Blend_PinLight
[zt]Photoshop Blend Mode Math
Blend_HardMix
[zt]Photoshop Blend Mode Math
Blend_Reflect
[zt]Photoshop Blend Mode Math
Blend_Glow
[zt]Photoshop Blend Mode Math
Blend_Phoenix
[zt]Photoshop Blend Mode Math
Blend_Hue
[zt]Photoshop Blend Mode Math
Blend_Saturation
[zt]Photoshop Blend Mode Math
Blend_Color
[zt]Photoshop Blend Mode Math
Blend_Luminosity


And the gradients..


[zt]Photoshop Blend Mode Math
Base Layer
[zt]Photoshop Blend Mode Math
Blend Layer

And the results..


[zt]Photoshop Blend Mode Math
Blend_Lighten
[zt]Photoshop Blend Mode Math
Blend_Darken
[zt]Photoshop Blend Mode Math
Blend_Multiply
[zt]Photoshop Blend Mode Math
Blend_Average
[zt]Photoshop Blend Mode Math
Blend_Add
[zt]Photoshop Blend Mode Math
Blend_Subtract
[zt]Photoshop Blend Mode Math
Blend_Difference
[zt]Photoshop Blend Mode Math
Blend_Negation
[zt]Photoshop Blend Mode Math
Blend_Screen
[zt]Photoshop Blend Mode Math
Blend_Exclusion
[zt]Photoshop Blend Mode Math
Blend_Overlay
[zt]Photoshop Blend Mode Math
Blend_SoftLight
[zt]Photoshop Blend Mode Math
Blend_HardLight
[zt]Photoshop Blend Mode Math
Blend_ColorDodge
[zt]Photoshop Blend Mode Math
Blend_ColorBurn
[zt]Photoshop Blend Mode Math
Blend_LinearDodge
[zt]Photoshop Blend Mode Math
Blend_LinearBurn
[zt]Photoshop Blend Mode Math
Blend_LinearLight
[zt]Photoshop Blend Mode Math
Blend_VividLight
[zt]Photoshop Blend Mode Math
Blend_PinLight
[zt]Photoshop Blend Mode Math
Blend_HardMix
[zt]Photoshop Blend Mode Math
Blend_Reflect
[zt]Photoshop Blend Mode Math
Blend_Glow
[zt]Photoshop Blend Mode Math
Blend_Phoenix
[zt]Photoshop Blend Mode Math
Blend_Hue
[zt]Photoshop Blend Mode Math
Blend_Saturation
[zt]Photoshop Blend Mode Math
Blend_Color
[zt]Photoshop Blend Mode Math
Blend_Luminosity


More blending resources

PegTop blend modes
Forensic Photoshop
Insight into Photoshop 7.0 Blending Modes
SF – Basics – Blending Modes
finish the blend() modes
Romz blog
ReactOS RGB/HLS conversion fucntions

Photoshop math with GLSL shaders

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-07-03
  • 2021-05-26
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-08-28
  • 2022-12-23
  • 2022-12-23
  • 2021-09-17
  • 2022-01-18
相关资源
相似解决方案