pirags
pirags

Reputation: 125

GPUImageLightenBlendFilter with opacity

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?

Upvotes: 0

Views: 495

Answers (2)

pirags
pirags

Reputation: 125

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

Upvotes: 1

Rahul Dadhich
Rahul Dadhich

Reputation: 1221

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....

Upvotes: 1

Related Questions