skip to Main Content

Using GPUImage I am trying to replicate Photoshop Lighten Blend Mode with opacity. Unfortunately the alpha channel has no effect using the GPUImageLightenBlendFilter.

Photoshop Lighten Blend Mode with opacity

Brad confirms there might problems with alpha:
GPUImage's GPUImageOpacityFilter not behaving as expected, doesn't change alpha channel

I have successfully replicated the PS blending using CoreImage which respects the alpha value.

CIImage *ciImage1 = [[CIImage alloc] initWithImage:input1];
CIImage *ciImage2 = [[CIImage alloc] initWithImage:input2];

// Alpha adjustment for input1
CIFilter *alphaFilter = [CIFilter filterWithName:@"CIColorMatrix"];
CGFloat rgba[4] = { 0.0, 0.0, 0.0, 0.5 };
CIVector *alphaVector = [CIVector vectorWithValues:rgba count:4];
[alphaFilter setValue:alphaVector forKey:@"inputAVector"];
[alphaFilter setValue:ciImage1 forKey:kCIInputImageKey];

// Lighten blend
CIFilter *blendFilter = [CIFilter filterWithName:@"CILightenBlendMode"];
[blendFilter setValue:alphaFilter.outputImage forKey:kCIInputImageKey];
[blendFilter setValue:ciImage2 forKey:kCIInputBackgroundImageKey];

There are 2 versions of GPUImage I have tried (they are adjusting alpha for input1 using a different method).

GPUImagePicture *input1 = [[GPUImagePicture alloc] initWithImage:input1];
GPUImagePicture *input2 = [[GPUImagePicture alloc] initWithImage:input2];

// Alpha adjustment for input1
GPUImageOpacityFilter *alphaFilter = [GPUImageOpacityFilter new];
alphaFilter.opacity = 0.5;
[input1 addTarget:alphaFilter];

// Lighten blend
GPUImageLightenBlendFilter *blendFilter = [GPUImageLightenBlendFilter new];
[alphaFilter addTarget:blendFilter];
[input2 addTarget:blendFilter];

or:

GPUImagePicture *input1 = [[GPUImagePicture alloc] initWithImage:input1];
GPUImagePicture *input2 = [[GPUImagePicture alloc] initWithImage:input2];

// Alpha adjustment for input1
GPUImageColorMatrixFilter *alphaFilter = [GPUImageColorMatrixFilter new];
alphaFilter.colorMatrix = (GPUMatrix4x4) {
  { 1.0, 0.0, 0.0, 0.0 },
  { 0.0, 1.0, 0.0, 0.0 },
  { 0.0, 0.0, 1.0, 0.0 },
  { 0.0, 0.0, 0.0, 0.5 }
};
[input1 addTarget:alphaFilter];

// Lighten blend
GPUImageLightenBlendFilter *blendFilter = [GPUImageLightenBlendFilter new];
[alphaFilter addTarget:blendFilter];
[input2 addTarget:blendFilter];

Both GPUImage implementations return output as if alpha for input1 was 1.0.

I have looked at Lighten Blending Mode documentation in different sources on the internet and they all use this formula:

max(blend, base)

Looking at the shader in implementation of GPUImageLightenBlendFilter it also uses the same formula:

lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
gl_FragColor = max(textureColor, textureColor2);

However, it seems that Photoshop and CoreImage have some extra manipulation with the alpha (probably similar to Gimp: https://github.com/GNOME/gimp/blob/783bbab8a889d4eba80b6a83f2e529937a73a471/app/operations/gimpoperationlightenonlymode.c).

Anyone has ideas how to include the alpha channel in the GPUImageLightenBlendFilter formula?

2

Answers


  1. Chosen as BEST ANSWER

    I found this Shader code the best for my case:

    lowp vec4 textureColor = texture2D(inputImageTexture, textureCoordinate);
    lowp vec4 textureColor2 = texture2D(inputImageTexture2, textureCoordinate2);
    
    textureColor.rgb *= textureColor.a;
    textureColor2.rgb *= textureColor2.a;
    lowp vec4 textureOut = max(textureColor, textureColor2);
    textureOut.rgb /= textureOut.a;
    
    gl_FragColor = textureOut;
    

    Found here: https://github.com/BradLarson/GPUImage/pull/1297


  2. Below is shader code for GPUImageLightenBlendFilter with opacity and amount.

    precision highp float;
    uniform sampler2D inputImageTexture;
    uniform sampler2D inputImageTexture2;
    uniform float alpha;   // used for opacity....
    uniform float amount;  // amount of blend....
    varying vec2 textureCoordinate;
    
    void main ()
    {
        // Get samples from both layers
        vec4 dst = texture2D(inputImageTexture, textureCoordinate);
        vec4 src = texture2D(inputImageTexture2, textureCoordinate);
    
    src.a *= alpha;
    vec4 colour = vec4(0.0, 0.0, 0.0, 0.0);
    
    colour = vec4(max(dst, src).rgb, src.a) * src.a + dst * (1.0 - src.a);
    colour = clamp(colour, 0.0, 1.0);
    gl_FragColor.xyz = mix(dst, colour, amount).rgb;
    gl_FragColor.w = 1.0;
    }
    

    Works perfectly for me….

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search