How do I get K with CMY Function?

When I have a Color, I know how to extract its amount of Cyan, Magenta and Yellow, but now I want to get its Black.

How do I achieve that ?

A Google quest returned answers about printing in CMYK, nothing about extracting K from the color value.

You don’t.

First of all, for anyone that doesn’t know, we’re talking about:
C Cyan
M Magenta
Y Yellow
K BlacK

These are the colors that are used for reproducing color on a printed page, as opposed to RGB for screens.

The Xojo properties are just inversions of one another…

C = 255 - R
M = 255 - G
Y = 255 - B

If you’ve ever mixed paints, you’ll remember that you can’t actually get black by mixing these together. You get more of a dark brown. Black ink is used to replace a portion of the places where all three are meant to be black.

If you’re still curious, read on…

The black (K) portion is difficult to quantify because how it’s calculated is dependent on the type of paper that you are printing on.

Paper is porous. That is, when a drop of ink is placed on it, the ink tends to bleed a bit. How much it bleeds is directly related to the amount of black ink that’s used. Think of the difference between the paper that’s used in a greeting card vs what’s used in a telephone book (if you remember those). Try dropping a bead of water on each of these and you’ll see what I mean.

Now, when color ink is applied to paper to make colors, they are overlaid onto the page. The problem that arises is that because colors bleed, the more ink that’s applied to the page in a particular spot, the muddier the image gets. If you tried to apply 10% of CMY you’d be fine, but 100% not so much because the paper can only absorb so much ink. Black is used to substitute a certain portion of these solid ink areas to avoid this problem.

But here’s the rub… the amount of color replacement varies based on the % of color that’s on the paper as well. So you can’t just assume that you’ll be replacing straight values either:

C 10
M 70
Y 30

C 0
M 60
Y 20
K 10

The way the black replacement of color is done is based on algorithms of how we perceive color.

TL;DR: If you want to do this accurately, you’re going to need to get into Color Profiles which is a whole other discussion, and not something that’s particularly easy to implement in Xojo. People have done it, it’s just not easy.

2 Likes

Thank you Greg for your explanation.

Here’s what I was doing (no more):

Black (CMYK) is wrong and so is HSV on this working screen shot.

On the left are the names, hex values and color from the HTML definitions; and on the right, I displayed more information about the ListBox selected color.

In relation to what though? Since there’s no way to get that value in Xojo, you must be doing some sort of calculation there. (Although it looks close to right)

I sort the Hex value Column; then select the first one, look at the black Canvas (from CMYK) and press the bottom arrow key until the 148° Row: the Black rendered color does not change very much…

I add C+M+Y values and / the result by 3… to set a value for Black (it’s an idea like any other). That value change (of course).

Yesterday evening, I checked with TextEdit Color windoid, CMYK and moved the K value: no change in each of the three C, M & Y values (of course).
Edit: I just checked, and the amount of K changes. I do not say it have a correct value, but both the computed value and the rendered Black change (depending on the selected color in the ListBox.

I have to think at what I will do with this project. (Remove K and share it ?)

Perhaps you may find what you need in an open source color management engine like the LITTLE CMS OPEN SOURCE COLOR ENGINE.

Since CMYK is a device specific color space probably the best general CMYK color profile to use is the Idealliance GRACOL G7 ICC Profile which has become a standard for the print industry. If the RGB colors you are using are Web colors then the SRGB Profile would be the one to use for profile to profile conversion.

1 Like

In my experience, there are no systems that do this. Black is added to a color while parts of CYAN, Magenta and Yellow are removed, but they are not equal parts because black tends to be a cool color all on its own.

If you want to do this “correctly,” you’re going to have to use declares.

My point is, don’t guess. The people who work with CMYK will immediately realize that your app is broken.

You can use MBS Plugins to convert. We have classes for this and here is some example code

dim ct as LCMS2TransformMBS
			dim mi,mo as MemoryBlock
			dim pi as LCMS2ProfileMBS
			dim po as LCMS2ProfileMBS
			dim f as FolderItem
			
			// you find this profiles on Mac OS X in /System/Library/ColorSync/Profiles
			f = FindFile("Generic RGB Profile.icc")
			pi = LCMS2ProfileMBS.OpenProfileFromFile(F)
			
			if pi = nil then
				MsgBox "Failed to find the profile."+EndOfLine+EndOfLine+f.Name
			end if
			
			f = FindFile("Generic CMYK Profile.icc")
			po = LCMS2ProfileMBS.OpenProfileFromFile(F)
			
			if po = nil then
				MsgBox "Failed to find the profile."+EndOfLine+EndOfLine+f.Name
			end if
			
			// get data format for 8 bit integers
			dim pif as integer = pi.FormatterForColorspace(1, false)
			dim pof as integer = po.FormatterForColorspace(1, false)
			
			dim flags as integer = LCMS2MBS.kcmsFLAGS_BLACKPOINTCOMPENSATION
			
			ct = LCMS2TransformMBS.CreateTransform(pi, pif, po, pof, intent, flags)
			
			canvas1.Backdrop = NewColorPicture(c)
			
			' ... fill c
			mi=NewMemoryBlock(3) // RGB
			mo=NewMemoryBlock(4) // CMYK
			
			mi.UInt8Value(0)=c.red
			mi.UInt8Value(1)=c.green
			mi.UInt8Value(2)=c.blue
			
			if ct.Transform(mi,mo,1) then
				'ok
				
				dim cc as integer = mo.UInt8Value(0) // C
				dim mm as integer = mo.UInt8Value(1) // M
				dim yy as integer = mo.UInt8Value(2) // Y
				dim kk as integer = mo.UInt8Value(3) // K
				
				// convert back
				ct = LCMS2TransformMBS.CreateTransform(po, pof, pi, pif, intent)
				
				if ct.Transform(mo,mi,1) then
					dim rr as integer = mi.UInt8Value(0) // R
					dim gg as integer = mi.UInt8Value(1) // G
					dim bb as integer = mi.UInt8Value(2) // B
					
					info.text = str(c.red)+" "+str(c.Green)+" "+str(c.Blue)+EndOfLine+_
							str(cc)+" "+str(mm)+" "+str(yy)+" "+str(kk)+EndOfLine+_
							str(rr)+" "+str(gg)+" "+str(bb)+EndOfLine
					
					canvas2.Backdrop = NewColorPicture(rgb(rr,gg,bb))
					
				end if
				
			end if

RGB to CMYK conversion formula

The R,G,B values are divided by 255 to change the range from 0…255 to 0…1:

R’ = R/255

G’ = G/255

B’ = B/255

The black key (K) color is calculated from the red (R’), green (G’) and blue (B’) colors:

K = 1-max(R’, G’, B’)

The cyan color (C) is calculated from the red (R’) and black (K) colors:

C = (1-R’-K) / (1-K)

The magenta color (M) is calculated from the green (G’) and black (K) colors:

M = (1-G’-K) / (1-K)

The yellow color (Y) is calculated from the blue (B’) and black (K) colors:

Y = (1-B’-K) / (1-K)

Yes, but that simple formula is usually wrong as you need proper color profiles to describe what your RGB is and what CMYK should be.

That formula is very useful if you are not concerned about ink-soaked paper or accurate color reproduction. :grin:

If you don’t care about accurate colour reproduction why bother with CMYK at all? :grinning:

3 Likes

Well. The formula you listed above is incorrect. With the correct formula there would not be anything wrong the conversations. If conversion calculations in general are the correct way of converting color from a math perspective. It’s just without a proper color profile for a particular output method, for a given printer or ink/paper or display, the colors will just be perceived differently. so rgb(0,23,26) without a profile versus rgb(0,23,26) with an SRGB profile with still be the same values but display differently. So it might look different but the values making a math conversion from rgb would be cmyk is correct. Especially since CMYK contains less colors than RGB.

FYI. Find a better rgb to CMYK formula.