We built this for one of our projects, Spectral Grove, so we could easily test gradients using Tiger’s Drylac available RAL colors. The top row of swatches shows the actual RGB interpolation between the two colors for reference. You can download a windows executable file here to create your own gradients or the source code here if you want to customize it a bit. If you do run it in processing then the print button will print a selectable list of the RAL numbers to the console. The source code is also available below, but you will need the spreadsheet of colors we compiled that is in the source code download.

/**
 * Created by SOFTlab 10.05.2019
**/
 
 import controlP5.*;

Table table;

ControlP5 cp5;

IntList pnum = new IntList();
IntList pick = new IntList();

IntList c1 = new IntList();
IntList c2 = new IntList();

int nearnum = 8;
int number_colors = 8;

ArrayList <PVector> crgb = new ArrayList<PVector>();
ArrayList <PVector> selected = new ArrayList<PVector>();
ArrayList <PVector> ccolors = new ArrayList<PVector>();

IntList  cid = new IntList();

int spacingx = 60;
int spacingy = 30;

int cspace = 0;

void setup(){
   size(1600,800);
   //fullScreen();
  table = loadTable("color_swatches.csv","header");
  
  for (TableRow row : table.rows()) {
    String id = row.getString("Number");
    String rr = row.getString("R");
    String gg = row.getString("G");
    String bb = row.getString("B");
    pnum.append(int(id));
    pick.append(0);
    crgb.add(new PVector(float(rr),float(gg),float(bb)));
  }
  
  cspace = int(crgb.size()*spacingy/(height-120))+2;
  println(cspace);
  cspace = cspace * spacingx + 150;
  println(cspace);
  
  cp5 = new ControlP5(this);
  
  cp5.addSlider("number_colors")
     .setPosition(cspace,50)
     .setRange(2,20)
     .setSize(240,20)
     .setValue(6)
     .setNumberOfTickMarks(18)
     .setColorForeground(color(200,200,200))
     .setColorLabel(color(255))
     .setColorBackground(color(70,70,70))
     .setColorValue(color(0,0,0))
     .setColorActive(color(255,255,255))
    ;
    
   cp5.addButton("Clear_Selection")
     .setValue(0)
     .setPosition(cspace,90)
     .setSize(80,20)
     .setColorForeground(color(200,200,200))
     .setColorLabel(color(255))
     .setColorBackground(color(70,70,70))
     .setColorValue(color(0,0,0))
     .setColorActive(color(255,255,255))
     ;
     
   cp5.addButton("Print_RGB")
     .setValue(0)
     .setPosition(cspace,120)
     .setSize(80,20)
     .setColorForeground(color(200,200,200))
     .setColorLabel(color(255))
     .setColorBackground(color(70,70,70))
     .setColorValue(color(0,0,0))
     .setColorActive(color(255,255,255))
     ;
  
}


void draw(){
  background(0);
  nearnum = number_colors;
  selected = new ArrayList<PVector>();
  ccolors = new ArrayList<PVector>();
  cid = new IntList();
  int xc = 0;
  int yc = 0;
  for(int i = 0; i < crgb.size(); i++){
    PVector cc = crgb.get(i);
    fill(cc.x,cc.y,cc.z);
    if(pick.get(i) == 1){
      stroke(255);
    }else{
      noStroke();
    }
    rect(xc*(spacingx+5)+50, yc * (spacingy+5)+50, spacingx,spacingy);
    fill(255);
    text(pnum.get(i), xc*(spacingx+5)+52, yc * (spacingy+5)+50 + spacingy-5); 
    yc++;
    if(yc * (spacingy+5) > height-120){
      yc = 0;
      xc++;
    }
    if(pick.get(i) == 1){
      selected.add(crgb.get(i));
      cid.append(pnum.get(i));
    }
  }
  if(selected.size() < 2){
    for(int i = 0; i < nearnum; i++){
      fill(0);
      stroke(255);
      rect(cspace+(i*55),height/2-105,50,100);
      rect(cspace+(i*55),height/2+5,50,100);
    }
  }
  noStroke();
  if(selected.size() == 2){
    for(int i = 0; i < nearnum; i++){
        PVector c1 = selected.get(0);
        PVector c2 = selected.get(1);
        int R = int((c2.x-c1.x) * i/(nearnum-1) + c1.x);
        int G = int((c2.y-c1.y) * i/(nearnum-1) + c1.y);
        int B = int((c2.z-c1.z) * i/(nearnum-1) + c1.z);
        fill(R,G,B);
        rect(cspace+(i*55),height/2-105,50,100);
        PVector nc = new PVector(R,G,B);
        float dd = 99999;
        PVector fc = new PVector(0,0,0);
        int id = 0;
        for(int j = 0; j < crgb.size(); j++){
          PVector cc = crgb.get(j);
          float nd = cc.dist(nc);
          if(nd < dd){
            dd = nd;
            fc = cc;
            id = j;
          }
        }
        fill(fc.x,fc.y,fc.z);
        ccolors.add(fc);
        rect(cspace+(i*55),height/2+5,50,100);
        fill(255);
        text(pnum.get(id), cspace+(i*55)+5, height/2+5+95); 
        text("R: " + int(fc.x), cspace+(i*55)+5, height/2+25+95); 
        text("G: " + int(fc.y), cspace+(i*55)+5, height/2+40+95); 
        text("B: " + int(fc.z), cspace+(i*55)+5, height/2+55+95); 
        
        text("R: " + R, cspace+(i*55)+5, height/2-140); 
        text("G: " + G, cspace+(i*55)+5, height/2-125); 
        text("B: " + B, cspace+(i*55)+5, height/2-110); 
        
        
    }
  }
}

void mousePressed() {
  int pc = 0;
  for(int i = 0; i < crgb.size(); i++){
    if(pick.get(i) > 0){
      pc++;
    }
  }
    int xc = 0;
    int yc = 0;
    for(int i = 0; i < crgb.size(); i++){
      if(mouseX > xc*(spacingx+5)+50 
         && mouseX < xc*(spacingx+5)+50 + spacingx 
         && mouseY > yc * (spacingy+5)+50 
         && mouseY < yc * (spacingy+5)+50 + spacingy){
        if(pick.get(i) == 0 && pc < 2){
          pick.set(i,1);
        }else{
          pick.set(i,0);
        }
      }
      yc++;
      if(yc * (spacingy+5) > height-120){
        yc = 0;
        xc++;
      }
    }
}

void keyPressed() {
  if (key == ' ') {
    for(int i = 0; i < crgb.size(); i++){
      pick.set(i,0);
    }
  }
}

public void Clear_Selection(){
  for(int i = 0; i < crgb.size(); i++){
      pick.set(i,0);
    }
}

public void Print_RGB(){
  if(cid.size() > 1){
    println(cid.get(0));
    println(cid.get(1));
  }
  for(int i = 0; i < ccolors.size(); i++){
      PVector c1 = ccolors.get(i);
      println(c1.x + "," + c1.y + "," + c1.z);
    }
    
  println("--------------------------------");
}