Jump to content
You must now use your email address to sign in [click for more info] ×

Emulating Blend mode AND, OR, XOR with Affinity Photo and Apply Image Filter


Recommended Posts

Blend mode AND, OR, XOR with Affinity Photo

 

Out of the box, you won’t find the blend modes AND, OR, XOR in Affinity Photo V1 or V2. Luckily there is the option to use the “Apply Image” filter which allows to create self-defined blend formulas. As the formulas are quite complex and long, the best way is copy the formulas into your favourite text editor, and copy/paste them into the filter one-by-one.

The steps are relatively simple, but you need to follow an exact sequence of several steps to get it right.

Preparation steps

  • Have 2 pixel layers present in file, ideally of identical size (pixel x and y). I name the layers “destination” and “source” within this tutorial. The destination layer will be modified and show the result, the source layer stays unchanged.
  • If you want to use vector layers, make a copy and rasterise them.
  • Have text editor with formulas open parallel to Photo.
  • There is one formula for every colour channel. The formulas are made specifically for RGB colour model. They can be adapted for any other colour model (GREY, CMYK, LAB) by search and replacing the variable names of colour channels. I leave this task as an exercise for the reader.

Steps to blend 2 layers with your chosen formula (AND, OR, XOR)

  • Select destination layer
  • Choose Filter-> Apply Image
  • Drag the source layer (from layer stack) into source area of the filter UI. The canvas will show the selected source area, as the default formula uses 100% of the colours from the source layer. You will change the formulas in the next step
  • Activate box “Equations”
  • Copy / paste the 3 formulas for the individual colour channels DR / DG / DB
  • Click apply
  • The destination layer shows the result

Limitations

  • Unfortunately, this filter is “destructive”, meaning it will be applied to a pixel layer and stores the result as pixel layer. As of Photo 2 V 2.0.3, there is no way to have this as non-destructive live filter.
  • You can re-apply the filter, using the same formulas and source image, to other destination layers.
  • If you want to use it on different source image data, you need to apply the filter again from scratch.
  • Even worth, there is not easy way like preset to save the formulas inside Affinity.
  • If you use the macro recorder, you will be bound to the source layer used when recording the macro.
  • You can store the formulas as text layers within Affinity Photo, and optionally save / export them as Assets. The only advantage is having everything consolidated “inside” Photo, the workflows gets more complicated in case you try to use the text frames as source for copy/paste.

Formula for AND

R:

(((((((irem(idiv(SR*255,128),2)*irem(idiv(DR*255,128),2)×2+irem(idiv(SR*255,64),2)*irem(idiv(DR*255,64),2))×2+irem(idiv(SR*255,32),2)*irem(idiv(DR*255,32),2))×2+irem(idiv(SR*255,16),2)*irem(idiv(DR*255,16),2))×2+irem(idiv(SR*255,8),2)*irem(idiv(DR*255,8),2))×2+irem(idiv(SR*255,4),2)*irem(idiv(DR*255,4),2))×2+irem(idiv(SR*255,2),2)*irem(idiv(DR*255,2),2))×2+irem(idiv(SR*255,1),2)*irem(idiv(DR*255,1),2))÷255

 

G:

(((((((irem(idiv(SG*255,128),2)*irem(idiv(DG*255,128),2)×2+irem(idiv(SG*255,64),2)*irem(idiv(DG*255,64),2))×2+irem(idiv(SG*255,32),2)*irem(idiv(DG*255,32),2))×2+irem(idiv(SG*255,16),2)*irem(idiv(DG*255,16),2))×2+irem(idiv(SG*255,8),2)*irem(idiv(DG*255,8),2))×2+irem(idiv(SG*255,4),2)*irem(idiv(DG*255,4),2))×2+irem(idiv(SG*255,2),2)*irem(idiv(DG*255,2),2))×2+irem(idiv(SG*255,1),2)*irem(idiv(DG*255,1),2))÷255

 

B:

(((((((irem(idiv(SG*255,128),2)*irem(idiv(DG*255,128),2)×2+irem(idiv(SG*255,64),2)*irem(idiv(DG*255,64),2))×2+irem(idiv(SG*255,32),2)*irem(idiv(DG*255,32),2))×2+irem(idiv(SG*255,16),2)*irem(idiv(DG*255,16),2))×2+irem(idiv(SG*255,8),2)*irem(idiv(DG*255,8),2))×2+irem(idiv(SG*255,4),2)*irem(idiv(DG*255,4),2))×2+irem(idiv(SG*255,2),2)*irem(idiv(DG*255,2),2))×2+irem(idiv(SG*255,1),2)*irem(idiv(DG*255,1),2))÷255

Formula for XOR

(((((((1-abs(irem(idiv(SR*255,128),2)+irem(idiv(DR*255,128),2)-1)×2+1-abs(irem(idiv(SR*255,64),2)+irem(idiv(DR*255,64),2)-1))×2+1-abs(irem(idiv(SR*255,32),2)+irem(idiv(DR*255,32),2)-1))×2+1-abs(irem(idiv(SR*255,16),2)+irem(idiv(DR*255,16),2)-1))×2+1-abs(irem(idiv(SR*255,8),2)+irem(idiv(DR*255,8),2)-1))×2+1-abs(irem(idiv(SR*255,4),2)+irem(idiv(DR*255,4),2)-1))×2+1-abs(irem(idiv(SR*255,2),2)+irem(idiv(DR*255,2),2)-1))×2+1-abs(irem(idiv(SR*255,1),2)+irem(idiv(DR*255,1),2)-1))÷255

(((((((1-abs(irem(idiv(SG*255,128),2)+irem(idiv(DG*255,128),2)-1)×2+1-abs(irem(idiv(SG*255,64),2)+irem(idiv(DG*255,64),2)-1))×2+1-abs(irem(idiv(SG*255,32),2)+irem(idiv(DG*255,32),2)-1))×2+1-abs(irem(idiv(SG*255,16),2)+irem(idiv(DG*255,16),2)-1))×2+1-abs(irem(idiv(SG*255,8),2)+irem(idiv(DG*255,8),2)-1))×2+1-abs(irem(idiv(SG*255,4),2)+irem(idiv(DG*255,4),2)-1))×2+1-abs(irem(idiv(SG*255,2),2)+irem(idiv(DG*255,2),2)-1))×2+1-abs(irem(idiv(SG*255,1),2)+irem(idiv(DG*255,1),2)-1))÷255

(((((((1-abs(irem(idiv(SB*255,128),2)+irem(idiv(DB*255,128),2)-1)×2+1-abs(irem(idiv(SB*255,64),2)+irem(idiv(DB*255,64),2)-1))×2+1-abs(irem(idiv(SB*255,32),2)+irem(idiv(DB*255,32),2)-1))×2+1-abs(irem(idiv(SB*255,16),2)+irem(idiv(DB*255,16),2)-1))×2+1-abs(irem(idiv(SB*255,8),2)+irem(idiv(DB*255,8),2)-1))×2+1-abs(irem(idiv(SB*255,4),2)+irem(idiv(DB*255,4),2)-1))×2+1-abs(irem(idiv(SB*255,2),2)+irem(idiv(DB*255,2),2)-1))×2+1-abs(irem(idiv(SB*255,1),2)+irem(idiv(DB*255,1),2)-1))÷255

Formula for OR

((((((clamp(irem(idiv(SR*255,128),2)+irem(idiv(DR*255,128),2))×2+clamp(irem(idiv(SR*255,64),2)+irem(idiv(DR*255,64),2)))×2+clamp(irem(idiv(SR*255,32),2)+irem(idiv(DR*255,32),2)))×2+clamp(irem(idiv(SR*255,16),2)+irem(idiv(DR*255,16),2)))×2+clamp(irem(idiv(SR*255,8),2)+irem(idiv(DR*255,8),2)))×2+clamp(irem(idiv(SR*255,4),2)+irem(idiv(DR*255,4),2)))×2+clamp(irem(idiv(SR*255,2),2)+irem(idiv(DR*255,2),2)))×2+clamp(irem(idiv(SR*255,1),2)+irem(idiv(DR*255,1),2)))÷255

(((((((clamp(irem(idiv(SG*255,128),2)+irem(idiv(DG*255,128),2))×2+clamp(irem(idiv(SG*255,64),2)+irem(idiv(DG*255,64),2)))×2+clamp(irem(idiv(SG*255,32),2)+irem(idiv(DG*255,32),2)))×2+clamp(irem(idiv(SG*255,16),2)+irem(idiv(DG*255,16),2)))×2+clamp(irem(idiv(SG*255,8),2)+irem(idiv(DG*255,8),2)))×2+clamp(irem(idiv(SG*255,4),2)+irem(idiv(DG*255,4),2)))×2+clamp(irem(idiv(SG*255,2),2)+irem(idiv(DG*255,2),2)))×2+clamp(irem(idiv(SG*255,1),2)+irem(idiv(DG*255,1),2)))÷255

(((((((clamp(irem(idiv(SB*255,128),2)+irem(idiv(DB*255,128),2))×2+clamp(irem(idiv(SB*255,64),2)+irem(idiv(DB*255,64),2)))×2+clamp(irem(idiv(SB*255,32),2)+irem(idiv(DB*255,32),2)))×2+clamp(irem(idiv(SB*255,16),2)+irem(idiv(DB*255,16),2)))×2+clamp(irem(idiv(SB*255,8),2)+irem(idiv(DB*255,8),2)))×2+clamp(irem(idiv(SB*255,4),2)+irem(idiv(DB*255,4),2)))×2+clamp(irem(idiv(SB*255,2),2)+irem(idiv(DB*255,2),2)))×2+clamp(irem(idiv(SB*255,1),2)+irem(idiv(DB*255,1),2)))÷255

 

Source layer

615107120_blendmodesource.png.2fd2e5861f68c49796147f138d7aff28.png

Destination Layer

1987034904_blendmodedestination.png.285ffcc62d56ee7d413e57afba181cf2.png

Blend Mode AND

1187372951_blendmodeand.png.ac3a208662ffac8c37d9ee9d16e99a44.png

Blend Mode OR

844753338_blendmodeOR.png.48b72d40994bbe3f318feb00756bdc7c.png

Blend Mode XOR

1688152964_blendmodeXOR.png.02a87c3a6cc7f78596aed9623191c569.png

Mac mini M1 A2348 | Windows 10 - AMD Ryzen 9 5900x - 32 GB RAM - Nvidia GTX 1080

LG34WK950U-W, calibrated to DCI-P3 with LG Calibration Studio / Spider 5

iPad Air Gen 5 (2022) A2589

Special interest into procedural texture filter, edit alpha channel, RGB/16 and RGB/32 color formats, stacking, finding root causes for misbehaving files, finding creative solutions for unsolvable tasks, finding bugs in Apps.

 

Link to comment
Share on other sites

  • 1 year later...

I now  have an idea for a live filter version to create these blend modes. It will get messy as we need to create huge amounts of helper layers but should work:

  • for 1 bit of color depth, you can use blend modes lighten to implement OR, and darken to implement AND.
  • XOR based on Blend modes subtract over result from (lighten, darken)
  • For 2 or more bit of color depth, we need to use linked layers or symbols to create one group per bit.
    • isolate the corresponding bit from both layers, and store it as 0 or 1. 
    • Shift back the result (after blending) to the correct bit position (/ 2 ^ position)
    • combine the results of each group using blend mode add

@Ldinaare you interested into trying this as exercise?

Mac mini M1 A2348 | Windows 10 - AMD Ryzen 9 5900x - 32 GB RAM - Nvidia GTX 1080

LG34WK950U-W, calibrated to DCI-P3 with LG Calibration Studio / Spider 5

iPad Air Gen 5 (2022) A2589

Special interest into procedural texture filter, edit alpha channel, RGB/16 and RGB/32 color formats, stacking, finding root causes for misbehaving files, finding creative solutions for unsolvable tasks, finding bugs in Apps.

 

Link to comment
Share on other sites

And here the formula for a pure live version for the bitwise blend modes:

for RGB: var n1=vec3(pow(2,n)); var n255=vec3(255); irem (trunc (vec3(R,G,B)*n255 /n1), vec3(2)) *n1 /n255

Input: n (from 7 to 0)

You need one high level group per pit of color depth, blend mode add.

In every HL group,

  • one group for top layer, with blend mode "lighten" or "darken" and optionally "invert adjustment" (same for all 8 groups of course in one file)
  • one group for bottom layer, blend more "normal"
  • a PT filter, and input n set to the bit depth.

The demo file uses two symbol layers borrowed from Designer to  simplify the usage as you could drop any layer content into the symbols, and resize the document to any x/y dimension.

Could be extended to 16 bit color depth

Could be extended to CMYK, GRAY, LAB color modes by adjusting the channel names (and using vec4 instead of vec3 for CMYK and scalars for GREY)

 

Screenshot 2024-01-20 at 22.45.01.png

 

blend mode binary OR symbol.afdesign

Mac mini M1 A2348 | Windows 10 - AMD Ryzen 9 5900x - 32 GB RAM - Nvidia GTX 1080

LG34WK950U-W, calibrated to DCI-P3 with LG Calibration Studio / Spider 5

iPad Air Gen 5 (2022) A2589

Special interest into procedural texture filter, edit alpha channel, RGB/16 and RGB/32 color formats, stacking, finding root causes for misbehaving files, finding creative solutions for unsolvable tasks, finding bugs in Apps.

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...

Important Information

Terms of Use | Privacy Policy | Guidelines | We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.