Quillion
Quillion

Reputation: 6476

Java Smooth Color Transition

Let's say I am given two colors.

public final static Color FAR = new Color(237, 237, 30);
public final static Color CLOSE = new Color(58, 237, 221);

How would I transition from one color to the next without dipping into dark colors?

I have come up with ideas such as

    double ratio = diff / range; // goes from 1 to 0
    int red = (int)Math.abs((ratio * FAR.getRed()) - ((1 - ratio) * CLOSE.getRed()));
    int green = (int)Math.abs((ratio * FAR.getGreen()) - ((1 - ratio) * CLOSE.getGreen()));
    int blue = (int)Math.abs((ratio * FAR.getBlue()) - ((1 - ratio) * CLOSE.getBlue()));

OR

    double ratio = diff / range; // goes from 1 to 0
    int red = (int) ((1 - (diff / range)) * FAR.getRed() + CLOSE.getRed() - FAR.getRed());
    int green = (int) ((1 - (diff / range)) * FAR.getGreen() + CLOSE.getGreen() - FAR.getGreen());
    int blue = (int) ((1 - (diff / range)) * FAR.getBlue() + CLOSE.getBlue() - FAR.getBlue());

But unfortunately none of them smoothly transition from one color to the next. Would anyone know how to do so while keeping the color bright and not dipping into darker colors, or how to ensure that gradient transition is smooth rather than slow at first then fast and then slow again?

I really ca not come up with any formula.

Upvotes: 5

Views: 8932

Answers (3)

OldCurmudgeon
OldCurmudgeon

Reputation: 65811

This works nicely for me:

// Steps between fading from one colour to another.
private static final int FadeSteps = 25;

private void fade(Label panel, Color colour) throws InterruptedException {
  final Color oldColour = panel.getBackground();
  final int dRed = colour.getRed() - oldColour.getRed();
  final int dGreen = colour.getGreen() - oldColour.getGreen();
  final int dBlue = colour.getBlue() - oldColour.getBlue();
  // No point if no difference.
  if (dRed != 0 || dGreen != 0 || dBlue != 0) {
    // Do it in n steps.
    for (int i = 0; i <= FadeSteps; i++) {
      final Color c = new Color(
              oldColour.getRed() + ((dRed * i) / FadeSteps),
              oldColour.getGreen() + ((dGreen * i) / FadeSteps),
              oldColour.getBlue() + ((dBlue * i) / FadeSteps));
      panel.setBackground(c);
      Thread.sleep(10);
    }
  }
}

Not the neatest bit of code but it works.

Upvotes: 1

Alex Walker
Alex Walker

Reputation: 2356

You're using the wrong sign in the calcuations. Should be plus, not minus, to apply the ratio properly.

int red = (int)Math.abs((ratio * FAR.getRed()) + ((1 - ratio) * CLOSE.getRed()));
int green = (int)Math.abs((ratio * FAR.getGreen()) + ((1 - ratio) * CLOSE.getGreen()));
int blue = (int)Math.abs((ratio * FAR.getBlue()) + ((1 - ratio) * CLOSE.getBlue()));

The reason you are getting dark colours with your existing implementation is that with (-), they would often fall close to zero (less than 50? or negative but greater than -50?) and in the negative case, well, you are taking the absolute value so it becomes a small positive number, i.e. a dark colour.

Upvotes: 7

kajacx
kajacx

Reputation: 12939

(ratio * FAR.getGreen()) + ((1 - ratio) * CLOSE.getGreen())

if ratio goest from 0 to 1, then this is weighted average, lets say ratio = 1/2, then it would be aritmetical average, if ratio = 1/3, then it is weighted average where FAR has weight 1 and CLOSE has weight 2

Upvotes: 1

Related Questions