From Rgb to Cmyk

9

Given 3 bytes or RGB as input, calculate the nearest CMYK values, and output them.

  • create either a function with parameters and return value or a program that operates on stdin/stdout
  • use the color profile of your choice, but provide a reference
  • input may be either separate numeric values in range [0;255] or a 6 digit hex string
  • output should be separate numeric values ranging either [0;1] or [0;100]
  • standard code golf: no loopholes, shortest code wins
  • extravagant ideas are welcome

sample data:

input             output
108,174,106       [0.3793103448275862, 0.0, 0.3908045977011494, 0.3176470588235294]
0,0,0             0,0,0,1
170,255,238       33,0,7,0  
0x0088ff          1,0.4667,0,0
[250,235,215]     [0,6,14,1.96]  
#123456           .7907,.3953,0,.6627
  • Uncalibrated mapping is fine and probably the easiest
  • No input validation required; floats are allowed (ranging from 0 to 255), but may also be rounded
  • Output format should be either clearly commented or obvious; i.e.:
    1. CMYK in that order
    2. does not matter if percentage [0;100] or pure numbers [0;1]
  • Testing should include the trivial example [0,0,0].

This site has the most digits of online tools that I could find. Does anyone know a tool that gives more than 4 digits?

Titus

Posted 2016-06-30T07:15:06.087

Reputation: 13 814

Can the input be floats between 0 to 1? – Leaky Nun – 2016-06-30T07:19:55.087

4Could you give some example inputs/outputs? – Kevin Cruijssen – 2016-06-30T07:21:37.050

Also, welcome to PPCG. :) Usually we put challenges first in the Sandbox for Proposed Challenges for ± 72 hours. That way people can give feedback and your challenge will overall improve before you post it here.

– Kevin Cruijssen – 2016-06-30T07:23:22.260

8@KevinCruijssen Just a side note, but I don't think that's how you use ±... – Leaky Nun – 2016-06-30T07:23:50.480

@LeakyNun In my understanding it means something like More or less / roughly in the English language see the adverb section here for some examples. I personally prefer it over ≈. Although according to Wikipedia it is mostly used in mathematics and such, in that case the usage is indeed wrong.

– Kevin Cruijssen – 2016-06-30T07:28:09.377

@KevinCruijssen Oh, thanks for teaching. – Leaky Nun – 2016-06-30T07:29:15.880

1Welcome to the site! This is a decent challenge, but it's a little bit unclear. I'm voting to close as unclear what you're asking, but if you explain the algorithm to convert them and provide some test-cases, I will retract my vote. – James – 2016-06-30T15:18:46.000

2@KevinCruijssen In the adverb section, it says South African. It's not used that way in standard English. We use ~. – mbomb007 – 2016-06-30T16:24:31.217

1The close vote message is a bit misleading, because it stems from our Q&A roots, but it was indeed "put on hold as unclear what you're asking". There were a couple of requests for clarification in the comments which weren't addressed: specifically whether inputs and outputs as floats between 0 and 1 are allowed (or whether it has to be integers from 0 to 255), how the conversion actually works, and whether you could include some test cases. – Martin Ender – 2016-07-01T13:30:32.957

Is it required to always have a 0 in at least one of CMY? – l4m2 – 2018-03-21T17:58:00.980

@l4m2 I don´t think so; but I guess that there are RGBs for which the result does not contain a 0. – Titus – 2018-03-23T15:24:06.530

Answers

8

Dyalog APL, 16 15 bytes

1-⊢(÷,255÷⍨⊢)⌈/

1 minus 1-
X divided by ÷ Y, followed by , 255 dividing 255÷⍨ Y , where
  X is itself (i.e. the list of RGB values), and
  Y is the max /⌈ (of the RGB values).

$$ \begin{cases} J = max(R,G,B)\\ C = 1-\frac{R}{J}\\ M = 1-\frac{G}{J}\\ Y = 1-\frac{B}{J}\\ K = 1-\frac{J}{255}\\ \end{cases} $$

TryAPL!

Credits:
 ∘ -1 byte by ngn.

Adám

Posted 2016-06-30T07:15:06.087

Reputation: 37 779

When is PPCG getting MathJax? – Neil – 2016-06-30T11:45:22.813

@Neil http://meta.codegolf.stackexchange.com/search?q=MathJax

– Adám – 2016-06-30T12:07:32.160

+1 for ! Nice emoticon – programmer5000 – 2017-05-09T20:47:33.203

1@programmer5000 Thank you. You'll find that one in pretty much all my code-golfs. It swaps the arguments of the function to its left. Other APL emoticons are and . I hope we'll get and soon. – Adám – 2017-05-09T20:49:49.540

@Adám would make me happy! – programmer5000 – 2017-05-09T20:52:03.637

@programmer5000 J is the master emoticon language though (albeit they face the opposite way of normal smilies). Check the third column here.

– Adám – 2017-05-09T20:52:20.830

@programmer5000 NARS2000 APL has . Good enough?

– Adám – 2017-05-09T20:57:10.643

8

C#, 88 86 85 84 bytes

(r,g,b)=>{float[]a={r,g,b,1};var j=a.Max();a[3]=j*j/255;return a.Select(x=>1-x/j);};

output for 108,174,106:

0.3793104
0
0.3908046
0.3176471

Since OP allows function I submitted only the lambda. You can find a running demo on .NetFiddle. I am not a golfer, I post for fun. Also, it is my first answer \o/. Feel free to comment any improvement :)

Kudos to Leaky Nun for the formula.

caveat: it doesn´t work for [0,0,0] (thank you Titus)

aloisdg moving to codidact.com

Posted 2016-06-30T07:15:06.087

Reputation: 1 767

11.0-x/j? You surely can't do 1-x/j? – Erik the Outgolfer – 2016-06-30T11:18:06.320

@EʀɪᴋᴛʜᴇGᴏʟғᴇʀ yes I can! It was a rest from an experience. The goal was to auto cast to double. I remove it. – aloisdg moving to codidact.com – 2016-06-30T11:20:10.123

1You don't need it for subtraction anyways. Also, you don't seem to re-use a[3], and you don't seem to specify a fixed size for a, so you can do {r,g,b} and a[3]=j*j (because, anyways, 1 * a = a). – Erik the Outgolfer – 2016-06-30T11:25:01.507

@EʀɪᴋᴛʜᴇGᴏʟғᴇʀ I am reusing a with the select(). If I use a[3] like this I will out of range and throw, wont I? – aloisdg moving to codidact.com – 2016-06-30T11:29:49.827

I mean, assigning it first. – Erik the Outgolfer – 2016-06-30T11:31:00.943

Like this a[3]=j*j/255;? Indeed it works. – aloisdg moving to codidact.com – 2016-06-30T11:33:16.153

Yeah that one, and removing the ,1 in {r,g,b,1}? I don't think assigning first will cause any "out of range" errors. – Erik the Outgolfer – 2016-06-30T11:34:25.537

If I write double[]a={r,g,b};, it throws. – aloisdg moving to codidact.com – 2016-06-30T11:36:04.743

Welcome to PPCG! Nice first post! – Rɪᴋᴇʀ – 2016-06-30T12:24:26.477

1Great first answer and welcome to PPCG! If you want to display your language and bytes in a larger font like the other answers (which is usually the standard here), you can add a # in front of the line. :) – Kevin Cruijssen – 2016-06-30T14:15:05.127

@KevinCruijssen Thank you :) – aloisdg moving to codidact.com – 2016-06-30T14:55:00.027

nice approach; though it doesn´t work for [0,0,0] – Titus – 2017-02-10T10:17:21.933

@Titus Indeed. I forgot it! – aloisdg moving to codidact.com – 2017-02-15T16:22:25.767

4

Python, 46 bytes

lambda*c:[1-i/max(c)for i in c]+[1-max(c)/255]

Requires input to be floats in Python 2, fairly sure it doesn't in 3.

Arfie

Posted 2016-06-30T07:15:06.087

Reputation: 1 230

3

JavaScript (ES6), 58 51 bytes

a=>[...a.map(e=>1-e/m||1,m=Math.max(...a)),1-m/255]

Accepts an array [R, G, B] (add 7 bytes for separate parameters) and returns an array [C, M, Y, K] using the uncalibrated colour mapping.

Neil

Posted 2016-06-30T07:15:06.087

Reputation: 95 035

Are you sure with the order CYMK on your second answer? looks like CMYK to me. – Titus – 2016-07-01T18:09:07.570

start="2">

  • Do you know why spreading of a mixes up its content? This is weird. 3) Have you tested [0,0,0]? No exception in ES, but looks like a division by zero.
  • < – Titus – 2016-07-01T18:22:59.913

    Sorry, they were both CMY, that was my fault. Now also fixed the [0,0,0] cases. – Neil – 2016-07-01T20:17:55.300

    start="4">

  • Try [...a,m=Math.max(...a)] in your array solution. 5) Can you golf the other one further using an array as input? Consider using a.0 etc. instead of .map.
  • < – Titus – 2016-07-01T20:22:11.343

    @Titus I've come up with a completely new approach now which actually prefers CMYK order and saves 7 bytes too! – Neil – 2016-07-01T20:38:20.807

    >

  • Do I get it right that ||1 replaces infinity with 1? ES is wicked! 2) Does m really stay defined outside the map call? 3) I accept the array; but what would it look with separate parameters?
  • < – Titus – 2016-07-01T22:56:39.870

    @Titus 1) 0/0 is NaN, which counts as falsy 2) Yes, it sets the global variable m (so invalid in strict mode) 3) ([...a])=> etc. – Neil – 2016-07-01T23:23:46.117

    3

    Mathematica, 36 28 33 bytes

    List@@ColorConvert[{##}/255,"CMYK"]&
    

    After liberalization of I/O formats, golfed further: List@@#~ColorConvert~"CMYK"&

    Anonymous function, that does what is asked.

    The old function takes three arguments from 0 to 255 (anything beyond this range will be automatically clipped to this range) and returns an array of "CMYK" values between 0. and 1.

    Example (for old function):

    List @@ ColorConvert[{##}/255, "CMYK"] &[108, 174, 106]
    
    {0.37931, 0., 0.390805, 0.320313}
    

    Since arrays are allowed as input, 33 bytes:

    List@@ColorConvert[#/255,"CMYK"]&
    

    Of course the built-in function handles {0, 0, 0} properly and returns {0, 0, 0, 1}.

    LLlAMnYP

    Posted 2016-06-30T07:15:06.087

    Reputation: 361

    >

  • To clarify: input values must be in [0;255]. will edit the question in a minute, 2) Please test [0,0,0]. 3) Shouldn´t that be /255?
  • < – Titus – 2016-07-01T19:00:47.413

    @Titus you're right, its 255, can't address all issues at the moment though, I'll fix things at earliest convenience – LLlAMnYP – 2016-07-01T19:12:47.770

    @Titus fixed it – LLlAMnYP – 2016-07-04T07:07:26.687

    2

    SmileBASIC, 73 72 bytes

    INPUT R,G,B
    J=MAX(R,G,B)IF!J THEN?0,0,0,1 ELSE?1-R/J,1-G/J,1-B/J,1-J/255
    

    Could be much shorter.

    12Me21

    Posted 2016-06-30T07:15:06.087

    Reputation: 6 110

    Did you mean to write J=MAX(R,G,B) ? – Andrakis – 2017-02-09T11:46:36.720

    Yes, thank you. – 12Me21 – 2017-02-09T15:44:51.330

    2

    Lithp, 114 bytes

    #R,G,B::((var J(max R G B))(if(!= 0 J)((list(- 1(/ R J))(- 1(/ G J))(- 1(/ B J))(- 1(/ J 255))))((list 0 0 0 1))))
    

    Try it online!

    • Saved 6 bytes (forgot that max takes any number of arguments)

    I'm not quite sure this is right. The first two results with the sample data are correct, but the rest are not (see the Try it online.)

    Uses the implementation described nicely as follows:

    $$ \begin{cases} J = max(R,G,B)\\ C = 1-\frac{R}{J}\\ M = 1-\frac{G}{J}\\ Y = 1-\frac{B}{J}\\ K = 1-\frac{J}{255}\\ \end{cases} $$

    Andrakis

    Posted 2016-06-30T07:15:06.087

    Reputation: 361

    2

    Pyth, 24 21 18 24 21 bytes

    Life is a round trip, indeed.

    =cR255Q+mc--1dK-1JeSQJQK
    =cR255Q+mc-JeSQdJQ-1J
    +mc-JeSQdJQ-1cJ255
    +mc-JeSQd+J^T_15Q-1cJ255
    +m-1?JeSQcdJ1Q-1cJ255
    

    Test suite.

    Sample input: 108,174,106

    Sample output: [0.3793103448275862, 0.0, 0.3908045977011494, 0.3176470588235294]

    Sample input: 0,0,0

    Sample output: [0, 0, 0, 1.0]

    Formula used:

    $$ \begin{cases} J = max(R,G,B)\\ C = 1-\frac{R}{J}\\ M = 1-\frac{G}{J}\\ Y = 1-\frac{B}{J}\\ K = 1-\frac{J}{255}\\ \end{cases} $$

    Old formula: http://i.stack.imgur.com/ZtPD6.gif

    Old formula: http://i.stack.imgur.com/Nqi9F.gif

    Leaky Nun

    Posted 2016-06-30T07:15:06.087

    Reputation: 45 011

    nice golfing. care for a breakdown? – Titus – 2016-09-02T07:30:59.057

    2

    Bash + ImageMagick, 69 bytes

    convert "xc:$1[1x1]" -colorspace cmyk txt:-|grep -o '([^)]*)'|head -1
    

    Example:

    $ ./rgb2cmyk.sh "#6CAE6A"
    (38%,0%,39%,32%)
    
    $ ./rgb2cmyk.sh "#000000"
    (0%,0%,0%,100%)
    
    $ ./rgb2cmyk.sh "#AAFFEE"
    (33%,0%,7%,0%)
    
    $ ./rgb2cmyk.sh "#0088ff"
    (100%,47%,0%,0%)
    
    $ ./rgb2cmyk.sh "#FAEBD7"
    (0%,6%,14%,2%)
    
    $ ./rgb2cmyk.sh "#123456"
    (79%,40%,0%,66%)
    

    Marco

    Posted 2016-06-30T07:15:06.087

    Reputation: 581

    1

    PHP 7, 123 110 105 bytes

    Input as RGB color 100 240 75

    $j=max($h=$argv);echo strtr(@(1-$h[1]/$j).",".@(1-$h[2]/$j).",".@(1-$h[3]/$j).",".(1-$j/255),["NAN"=>0]);
    

    Outputs CMYK values as decimal in 0...1 range.

    Saved lots of bytes thanks to Titus.

    Sample usage:

    php -r '$j=max($h=$argv...' 100 240 75
    0.58333333333333,0,0.6875,0.058823529411765
    
    php -r '$j=max($h=$argv...' 255 255 255
    0,0,0,0
    
    php -r '$j=max($h=$argv...' 0 255 0
    1,0,1,0
    
    php -r '$j=max($h=$argv...' 0 0 0 
    0,0,0,1
    

    Test online


    Input as HEX color #123456, 202 bytes

    $h=str_split(substr($argv[1],-6),2);$j=max($r=hexdec($h[0]),$g=hexdec($h[1]),$b=hexdec($h[2]));echo z($r,$j),",",z($g,$j),",",z($b,$j),",",1-$j/255;function z($c,$y){return is_nan(@($c/$y))?0:1-$c/$y;}
    

    54 bytes for function to prevent division by zero, probably golfable or removable.

    Gets as input RGB color as HEX #123456 and outputs CMYK as decimal in 0...1 range.

    Sample usage:

    php -r '$h=str_split...' '#000000'
    0,0,0,1
    
    php -r '$h=str_split...' '#ffffff'
    0,0,0,0
    
    php -r '$h=str_split...' '#123456'
    0.7906976744186,0.3953488372093,0,0.66274509803922
    
    php -r '$h=str_split...' '#ffff00'
    0,0,1,0
    

    Mario

    Posted 2016-06-30T07:15:06.087

    Reputation: 3 043

    separate numeric values means you can just take $h=$argv; and use $h[1] instead of $h[0] etc. I like the NAN trick; but doesn´t that yield warnings? strtr is probably shorter than str_replace, and NAN needs no qotation (will yield Notices, but those are not displayed in the default config). – Titus – 2017-02-09T15:49:26.563

    Also, please provide the PHP version this works in. It does not in PHP 7 (where 1/0 results in INF) nor in PHP 5 (1/0 => false). – Titus – 2017-02-09T15:53:56.687

    @Titus Thanks for the very interesting $argv array tip in command line! I added the PHP version. It works with NAN because when you use str_replace it converts implicitly the number to string so it outputs NAN, in fact if you check at this link, you will see that it outputs NAN because of str_replace("INF" instead of str_replace("NAN". I couldn't make it work using strtr. I added the @ to suppress the warnings.

    – Mario – 2017-02-10T14:19:57.963

    I found my mistake: $n/0 is INF, but 0/0 is NAN (also in PHP 7.0). You can save 4 bytes with str_replace(NAN,0,$s) or 6 bytes with strtr($s,["NAN"=>0). – Titus – 2017-02-10T15:08:51.843

    @Titus great thanks, I couldn't figure out how to properly use strtr(); – Mario – 2017-02-10T16:11:37.813

    1

    PHP, not competing

    I was just too tempted to post my own.

    RGB input, 74 bytes

    for(;$i++<4;)echo$i<4?($j=max($argv))?1-$argv[$i]/$j:0:1-$j/255,","[$i>3];
    

    or 68 bytes with a trailing comma in the output: remove [$i>3].

    Run with php -r '<code>' <red-value> <green-value> <blue-value>.

    HEX input, 100 bytes

    foreach($a=array_map(hexdec,str_split($argv[1],2))as$c)echo($j=max($a))?1-$c/$j:0,",";echo 1-$j/255;  
    

    Run with php -nr '<code>' RRGGBB.

    That approach would take 75 bytes for RGB input:
    replace foreach($a=array_map...as$c) with foreach($a=$argv as$c)if($i++).

    Titus

    Posted 2016-06-30T07:15:06.087

    Reputation: 13 814

    0

    Hoon, 110 bytes

    =>
    rs
    |*
    a/*
    =+
    [s=(cury sub .1) j=(roll a max)]
    (welp (turn a |*(* (s (min .1 (div +< j))))) (s (div j .255)))
    

    Use the single precision floating-point library. Create a new generic function that takes a. Set s to sub curried with .1 for later, and j to folding over a with max.

    Map over a by dividing each element with j, finding the minimum of that and 1 to normalize NaN, then subtract 1 with s. Add 1-j/255 to the end of that list.

    > =f =>
      rs
      |*
      a/*
      =+
      [s=(cury sub .1) j=(roll a max)]
      (welp (turn a |*(* (s (min .1 (div +< j))))) (s (div j .255)))
    > (f (limo ~[.108 .174 .106]))
    [i=.3.7931037e-1 t=[i=.0 t=[i=.3.908046e-1 .3.1764704e-1]]]
    > (f (limo ~[.0 .0 .0]))
    [i=.0 t=[i=.0 t=[i=.0 .1]]]
    

    RenderSettings

    Posted 2016-06-30T07:15:06.087

    Reputation: 620

    Can you provide a TiO please. – Titus – 2017-02-11T10:29:43.520

    @Titus: Hoon doesn't have a TiO site, unfortunately. – RenderSettings – 2017-02-12T02:03:06.220

    0

    C, 155 bytes

    #define C(x) 1-x/(j>0?j:1)
    #define F float
    i=0;F j;f(F r,F g,F b){j=(r>g?r:g)>b?(r>g?r:g):b;for(;i++<4;)printf("%f\n",i>1?i>2?i>3?1-j/255:C(b):C(g):C(r));}
    

    I'm trying to figure out how it's possible golf more.

    Usage:

    #define C(x) 1-x/(j>0?j:1)
    #define F float
    i=0;F j;f(F r,F g,F b){j=(r>g?r:g)>b?(r>g?r:g):b;for(;i++<4;)printf("%f\n",i>1?i>2?i>3?1-j/255:C(b):C(g):C(r));}
    main(){
        f(108,174,106);
    }
    

    Output:

    0.379310
    0.000000
    0.390805
    0.317647
    

    Giacomo Garabello

    Posted 2016-06-30T07:15:06.087

    Reputation: 1 419

    >

  • +3: mistake: function should return the result, not print it. (sorry I just saw that)
  • +4: error: i is not declared.
  • +0: error: your ternary operators seem off. shouldn´t that be i>0?i>1?i>2
  • < – Titus – 2016-07-01T22:25:07.233

    but there is some golfing potential; I found -25 bytes in ANSI C, and another -19 in C99. 2 bytes are here: j>0?,17 in getting rid of the loop, and 6 in splitting up the j definition. – Titus – 2016-07-01T22:35:46.190

    add another +3 for the function: it returns something else than int, so a return type is required (F *). But I found another byte to golf away in C99. – Titus – 2016-07-02T00:24:38.553

    @Titus If I'm not mistaken, j>0?j:1 can be j+!j to achieve -3 bytes. – Albert Renshaw – 2017-02-08T23:52:01.537

    And I think the C macro is incorrect: 1-x/1 for j==0? I think that should be 1-(j>0?x/j:1). – Titus – 2017-02-11T10:34:34.710