BoltBait's Pages - CMYK Filter

Sarcasm, just one of the services I offer.


Paint.NET CMYK Filter

According to this Wikipedia article: ...

    "conversions here are best described as "nominal". They will produce an invertible conversion between RGB and a subset of CMYK; that is, one can take an RGB color and convert to certain CMYK colors, and from these CMYK colors obtain the corresponding, original RGB equivalents. However, conversion of CMYK colors in general to RGB colors is not invertible; that is, given a CMYK color which is converted to RGB, performing the former conversion may not give the original CMYK color. In addition, CMYK colors may print wildly differently from how the RGB colors display on a monitor. There is no single "good" conversion rule between RGB and CMYK."

    "Use of four-color printing generates a good final printed result with greater contrast. However, the color seen on a computer screen is often different from the color of the same object on a printout since CMYK and RGB have different gamuts. For example, pure blue (rgb 0, 0, 100%) is impossible to produce in CMYK. The nearest equivalent in CMYK is a dissimilar shade of blue-violet."

But, I wanted to see what it would look like to split a picture into its Cyan, Magenta, Yellow, and Black components.  I understand that it won't be perfect given the CMYK limitations.


The Idea

The algorithm is given in the Wikipedia article so I just decided to code it up and see what happened.  It turned out pretty bad, so I added a slider to control the intensity of the CMY color conversions.  That helped if I set the intensity to about 75 or so.


The Effect DLL

You can download the effect DLL here: RGB2CMYK.dll

Just drop this DLL file in your \program files\Paint.NET\effects directory and you should be all set.

If you need help installing effects, read this page: Installing Effects 


Instructions for Use

OK, taking this source picture (which I found on the Wiki page):

1. Open your image.

Effects in Paint.NET can not create new layers or images, so you will have to do a little "leg work" in order to prepare for this effect.

2. Duplicate it 3 times. You should now have 4 copies. Name them "C", "M", "Y", and "K" respectively.

3. Create a new layer and fill it with white.

4. Move the white layer to the bottom.  (This will simulate the paper that we will be printing on.)

5. Select the "C" layer and run the effect. Move the slider to the first position (Cyan) and press OK.

6. Select the "M" layer and run the effect. Move the slider to the second position (Magenta) and press OK.

7. Select the "Y" layer and run the effect. Move the slider to the third position (Yellow) and press OK.

8. Select the "K" layer and run the effect. Move the slider to the last position (blacK) and press OK.

Here is the result:


Source Code

And, here is the CodeLab script:

int Amount1=0;  //[0,3] Cyan   Magenta  Yellow    blacK 
int Amount2=75; //[0,255] CMY Intensity

void Render(Surface dst, Surface src, Rectangle rect)
    PdnRegion selectionRegion = EnvironmentParameters.GetSelection(src.Bounds);
    float R=0,G=0,B=0;
    float C=0,M=0,Y=0,K=0;
    byte A=0;

    ColorBgra CurrentPixel;
    for(int y = rect.Top; y < rect.Bottom; y++)
        for (int x = rect.Left; x < rect.Right; x++)
            if (selectionRegion.IsVisible(x, y))
                CurrentPixel = src[x,y];
                // Convert to RGB (float)
                R = (float)CurrentPixel.R / 255;
                G = (float)CurrentPixel.G / 255;
                B = (float)CurrentPixel.B / 255;
                // Convert to MYC
                M = 1-G;
                Y = 1-B;
                C = 1-R;
                // Convert to CMYK
                if ((C==1) && (M==1) && (Y==1))
                    if (K > M) K=M;
                    if (K > Y) K=Y;
                    case 0:   // Cyan
                       A = (byte)(C*Amount2);
                    case 1:   // Magenta
                       A = (byte)(M*Amount2);
                    case 2:   // Yellow
                       A = (byte)(Y*Amount2);
                    case 3:   // Black
                       A = (byte)(K*255);
                dst[x,y] = ColorBgra.FromBgra(

Tuesday, April 24, 2007