2

When you use following loop to generate all the possible colors.

for (int red = 0; red < 256; red++) {
  for (int green = 0; green < 256; green++) {
    for (int blue = 0; blue < 256; blue++) {
    }
  }
}

It generates something like thisenter image description here

I want a loop such that color is gradually changing (i.e. gradient must not repeat. For instance all the possible shades of green are together, then all the possible shades of blue and so on) and all the possible colors are covered in the loop.

Mathias G.
  • 4,875
  • 3
  • 39
  • 60
Surabhi Mundra
  • 377
  • 1
  • 12
  • [`LinearGradientPaint`](https://docs.oracle.com/javase/8/docs/api/java/awt/LinearGradientPaint.html) would be my first port of call, if that doesn't quite meet your requirements then maybe something like [this](https://stackoverflow.com/questions/13223065/color-fading-algorithm/13223818#13223818) would be better suited – MadProgrammer Aug 10 '18 at 06:01

2 Answers2

2

This is part of a "color blending" algorithm I've been using for awhile. It basically takes a series of colors and series of normalised points and calculates the "blending" between those colors/points automatically

So, at the heart of the solution, we have the colors, from black to fully "coloured" (ie green/blue/red)

private Color[] colors = new Color[]{
    new Color(0, 0, 0), new Color(0, 255, 0), // Green
    new Color(0, 0, 0), new Color(0, 0, 255), // Blue
    new Color(0, 0, 0), new Color(255, 0, 0), // Red
};

We then have the fraction of the area we want those colors to cover, note, there is a point for each color change, the algorithm then blends the color from the start to end point automatically.

private float[] fractions = new float[]{
    0f, 0.33f, 
    0.34f, 0.66f,
    0.67f,1f};

The example simply then generates a number of bands (100 in this case) to "fake" the blending effect

Fady

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ColorFade {

    public static void main(String[] args) {
        new ColorFade();
    }

    public ColorFade() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new ColorFadePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ColorFadePane extends JPanel {

        private float[] fractions = new float[]{
            0f, 0.33f, 
            0.34f, 0.66f,
            0.67f,1f};
        private Color[] colors = new Color[]{
            new Color(0, 0, 0), new Color(0, 255, 0),
            new Color(0, 0, 0), new Color(0, 0, 255),
            new Color(0, 0, 0), new Color(255, 0, 0),
        };

        public ColorFadePane() {
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 100);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g.create();
            int width = getWidth();
            int height = getHeight();
            int bandWidth = width / 100;
            for (int index = 0; index < 100; index++) {
                float progress = (float) index / (float) 100;
                Color color = blendColors(fractions, colors, progress);

                int x = bandWidth * index;
                int y = 0;
                g2d.setColor(color);
                g2d.fillRect(x, y, bandWidth, height);
            }
            g2d.dispose();
        }
    }

    public static Color blendColors(float[] fractions, Color[] colors, float progress) {
        Color color = null;
        if (fractions != null) {
            if (colors != null) {
                if (fractions.length == colors.length) {
                    int[] indicies = getFractionIndicies(fractions, progress);

                    float[] range = new float[]{fractions[indicies[0]], fractions[indicies[1]]};
                    Color[] colorRange = new Color[]{colors[indicies[0]], colors[indicies[1]]};

                    float max = range[1] - range[0];
                    float value = progress - range[0];
                    float weight = value / max;

                    color = blend(colorRange[0], colorRange[1], 1f - weight);
                } else {
                    throw new IllegalArgumentException("Fractions and colours must have equal number of elements");
                }
            } else {
                throw new IllegalArgumentException("Colours can't be null");
            }
        } else {
            throw new IllegalArgumentException("Fractions can't be null");
        }
        return color;
    }

    public static int[] getFractionIndicies(float[] fractions, float progress) {
        int[] range = new int[2];

        int startPoint = 0;
        while (startPoint < fractions.length && fractions[startPoint] <= progress) {
            startPoint++;
        }

        if (startPoint >= fractions.length) {
            startPoint = fractions.length - 1;
        }

        range[0] = startPoint - 1;
        range[1] = startPoint;

        return range;
    }

    public static Color blend(Color color1, Color color2, double ratio) {
        float r = (float) ratio;
        float ir = (float) 1.0 - r;

        float rgb1[] = new float[3];
        float rgb2[] = new float[3];

        color1.getColorComponents(rgb1);
        color2.getColorComponents(rgb2);

        float red = rgb1[0] * r + rgb2[0] * ir;
        float green = rgb1[1] * r + rgb2[1] * ir;
        float blue = rgb1[2] * r + rgb2[2] * ir;

        if (red < 0) {
            red = 0;
        } else if (red > 255) {
            red = 255;
        }
        if (green < 0) {
            green = 0;
        } else if (green > 255) {
            green = 255;
        }
        if (blue < 0) {
            blue = 0;
        } else if (blue > 255) {
            blue = 255;
        }

        Color color = null;
        try {
            color = new Color(red, green, blue);
        } catch (IllegalArgumentException exp) {
            NumberFormat nf = NumberFormat.getNumberInstance();
            System.out.println(nf.format(red) + "; " + nf.format(green) + "; " + nf.format(blue));
            exp.printStackTrace();
        }
        return color;
    }
}

LinearGradientPaint

Now, if you want to be really boring, you could just use a LinearGradientPaint instead...

LinearGradientPaint

public class ColorFadePane extends JPanel {

    private float[] fractions = new float[]{
        0f, 0.33f,
        0.34f, 0.66f,
        0.67f, 1f};
    private Color[] colors = new Color[]{
        new Color(0, 0, 0), new Color(0, 255, 0),
        new Color(0, 0, 0), new Color(0, 0, 255),
        new Color(0, 0, 0), new Color(255, 0, 0),};

    public ColorFadePane() {
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(200, 100);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D g2d = (Graphics2D) g.create();
        int width = getWidth();
        int height = getHeight();
        LinearGradientPaint lgp = new LinearGradientPaint(new Point(0, 0), new Point(width, 0), fractions, colors);
        g2d.setPaint(lgp);
        g2d.fillRect(0, 0, width, height);
        g2d.dispose();
    }
}

But I need to generate the result as a image/file

Okay, fine, so, create a BufferedImage and paint to it instead and save it using ImageIO.write

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
1

If you really want to show a total of 16 million colors, then you have to give up some of your criteria. You can't have all the shades of red then all the shades of green then all the shades of blue because that doesn't explain the mixing of the colors. All the shades of red and green mixed together -- is that all the shades of red or all the shades of green. Expecially because now you're going to add some blue to the mix.

You also said you want it gradually shifting, so what you could do is (in metacode):

for (int red = 0; red < 256; ++red) {
    bool redIsEven = (red % 2) == 0;
    int greenStart = redIsEven ? 0 : 255;
    int greenEnd = redIsEven ? 256 : -1;
    int greenDirection = redIsEven ? 1 : -1;
    for (int green = greenStart; green != greenEnd; green += greenDirection) {
         ... similar code for blue, but based on green, not red
    }
}

That is... you'll do red = 0 and green will go from 0 to 255. For green = 0, blue also goes 0...255, but when it's 1, it goes backwards, so it's flowing evenly. Then green counts downwards, then upwards, then downwards...

So you get a smooth flow with none of the 16 million choices repeated.

Is that what you're trying to do?

Joseph Larson
  • 8,530
  • 1
  • 19
  • 36