Algorithm for displaying n different shades of the same color in descending order of darkness

The requirement is as follows:

We need to match the color values. Thus, each discrete value will have a color.

We allow the user to specify maxColor , but NO minColor , but allow them to specify the number of cells representing the number of shades. Therefore, if maxColor Color.GREEN and bins= 5 , we would like to have 5 shades of green with the selected color, since max is the darkest and the other four will be in order of increasing brightness.

 //Give me a list of 5 shades of Green with the first argument being the darkest. List<Color> greenShades = calculateShades(Color.GREEN,5); //Give me a list of 7 shades of RED with the first argument being the darkest. List<Color> greenShades = calculateShades(Color.RED,7); 

I marked the question as Java since I am coding in Java. But I understand that this is just an algorithm. The implementation / idea of ​​this implementation in other languages, such as JavaScript, will also be implemented.

+4
source share
4 answers

The basic concept revolves around the idea of ​​generating color based on the proportion of the source ...

That is, if you want 5 bands, each strip will be 1/5 of the intensity of the last ...

 public List<Color> getColorBands(Color color, int bands) { List<Color> colorBands = new ArrayList<>(bands); for (int index = 0; index < bands; index++) { colorBands.add(darken(color, (double) index / (double) bands)); } return colorBands; } public static Color darken(Color color, double fraction) { int red = (int) Math.round(Math.max(0, color.getRed() - 255 * fraction)); int green = (int) Math.round(Math.max(0, color.getGreen() - 255 * fraction)); int blue = (int) Math.round(Math.max(0, color.getBlue() - 255 * fraction)); int alpha = color.getAlpha(); return new Color(red, green, blue, alpha); } 

As a quick and unpleasant example ...

enter image description here

 import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class ColorBands { public static void main(String[] args) { new ColorBands(); } public ColorBands() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { } JFrame frame = new JFrame("Testing"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(new TestPane()); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } public class TestPane extends JPanel { private JPanel bandsPane; private JSlider slider; private Timer changeTimer; public TestPane() { bandsPane = new JPanel(new GridBagLayout()); slider = new JSlider(1, 100); setLayout(new BorderLayout()); add(new JScrollPane(bandsPane)); add(slider, BorderLayout.SOUTH); slider.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { changeTimer.restart(); } }); changeTimer = new Timer(250, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int bands = slider.getValue(); List<Color> bandsList = getColorBands(Color.RED, bands); bandsPane.removeAll(); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets = new Insets(1, 1, 1, 1); for (Color color : bandsList) { bandsPane.add(new ColorBand(color), gbc); } gbc.weighty = 1; bandsPane.add(new JPanel(), gbc); revalidate(); repaint(); } }); changeTimer.setRepeats(false); slider.setValue(1); } @Override public Dimension getPreferredSize() { return new Dimension(200, 200); } } public List<Color> getColorBands(Color color, int bands) { List<Color> colorBands = new ArrayList<>(bands); for (int index = 0; index < bands; index++) { colorBands.add(darken(color, (double) index / (double) bands)); } return colorBands; } public static Color darken(Color color, double fraction) { int red = (int) Math.round(Math.max(0, color.getRed() - 255 * fraction)); int green = (int) Math.round(Math.max(0, color.getGreen() - 255 * fraction)); int blue = (int) Math.round(Math.max(0, color.getBlue() - 255 * fraction)); int alpha = color.getAlpha(); return new Color(red, green, blue, alpha); } public class ColorBand extends JPanel { public ColorBand(Color color) { setBackground(color); } @Override public Dimension getPreferredSize() { return new Dimension(100, 20); } } } 
+10
source

The basic idea is that you want each color component (RGB) to select the color that you gave Color.WHITE (R = 255, G = 255, B = 255) in increments of size. Here is some code that will do this.

 public List<Color> calculateShades(Color baseColor, int numberShades) { //decompose color into RGB int redMax = baseColor.getRed(); int greenMax = baseColor.getGreen(); int blueMax = baseColor.getBlue(); //Max color component in RGB final int MAX_COMPONENT = 255; //bin sizes for each color component int redDelta = (MAX_COMPONENT - redMax) / numberShades; int greenDelta = (MAX_COMPONENT - greenMax) / numberShades; int blueDelta = (MAX_COMPONENT - blueMax) / numberShades; List<Color> colors = new ArrayList<Color>(); int redCurrent = redMax; int greenCurrent = greenMax; int blueCurrent = blueMax; //now step through each shade, and decrease darkness by adding color to it for(int i = 0; i < numberShades; i++) { //step up by the bin size, but stop at the max color component (255) redCurrent = (redCurrent+redDelta) < MAX_COMPONENT ? (redCurrent + redDelta ) : MAX_COMPONENT; greenCurrent = (greenCurrent+greenDelta) < MAX_COMPONENT ? (greenCurrent + greenDelta ) : MAX_COMPONENT; blueCurrent = (blueCurrent+blueDelta) < MAX_COMPONENT ? (blueCurrent + blueDelta ) : MAX_COMPONENT; Color nextShade = new Color(redCurrent, greenCurrent, blueCurrent); colors.add(nextShade); } return colors; } 
0
source

Take a look at the Java sources for Color#darker() , apply the same logic with different FACTOR

 public Color darker() { return new Color(Math.max((int)(getRed() *FACTOR), 0), Math.max((int)(getGreen()*FACTOR), 0), Math.max((int)(getBlue() *FACTOR), 0)); } 
0
source

The RGB color system easily identifies color proportions, but lacks the flexibility to manage colors. using averages or odds will give you unwanted results. Simply put, you cannot achieve the desired results using the RGB color system.

the solution will be to convert the color to HSV or HSL (HSL perfered) and manipulate the value / brightness to get the result.

Look at the conversion algorithms:

Convert HSL colors to RGB

Mathematically, let's say you have the color R, G, B, and then:

The required number of boxes = 5

 Hue = <some value h> Saturation = <some value s> Luminosity = (max(R,G,B) + min (R,G,B))/2 

Now for the same h, s you will have 5 L values:

 L1 = 0 L2 = ((1 * 100) / 4) L3 = ((2 * 100) / 4) L4 = ((3 * 100) / 4) L5 = 100 

Here, since the first and last bit will be black and white, we used 4 instead of 5.

Now return HSL to RGB to get your desired RGB color.

(help me if you like my answer)

0
source

Source: https://habr.com/ru/post/1500429/


All Articles