2012-11-04 62 views
3

我创建了一些自定义的Swing组件,我希望从一种颜色淡入到另一种颜色。目前我正在从RGB转换到HSB,然后在绘制之前递增Hue值并转换回RGB,工作很好。颜色衰落算法?

然而,这循环遍历所有的颜色(即试图从黄色,橙色,红色等从蓝色到绿色循环渐变)。有没有一种体面的算法/方法可以从一种颜色直接淡入另一种颜色?

编辑:我已经通过Swing Timer更新了它(我试图避开像鼠疫这样的线程触摸组件)。今晚我会告诉你,谢谢!

+0

只是增量德RGB值,会做的伎俩。 – fonZ

+3

对于[示例](http://stackoverflow.com/a/2124507/230513)。 – trashgod

+1

您可以使用Trident提供的颜色插值。这是一个[示例](http://stackoverflow.com/a/11750906/1048330) – tenorsax

回答

5

在此基础上example,下面从Color.greenColor.blueN = 32步骤回Color.green再次循环Queue<Color>。请注意,在HSB模型中,Color.green在数字上小于Color.blue。另请参阅与此相关的使用HSB的example

enter image description here

public Flash(JComponent component) { 
    this.component = component; 
    float gHue = Color.RGBtoHSB(0, 1, 0, null)[0]; 
    float bHue = Color.RGBtoHSB(0, 0, 1, null)[0]; 
    for (int i = 0; i < N; i++) { 
     clut.add(Color.getHSBColor(gHue + (i * (bHue - gHue)/N), 1, 1)); 
    } 
    for (int i = 0; i < N; i++) { 
     clut.add(Color.getHSBColor(bHue - (i * (bHue - gHue)/N), 1, 1)); 
    } 
} 
1

提示

  1. 使用Swing Timer的慢动作效果由数RGB的
  2. 递减值,说x

Tadaaaa .. :-)

更新:如果您希望,你可以打价值x

使用Math.Random()功能执行过程中产生伪随机值x

HovercraftFullOfEels & mKorbel,感谢您的输入

+0

Swing Timer比线程更适合这个工作。 –

+0

@HovercraftFullOfEels:关于秋千的小想法。我的答案完全基于我对java的了解。但我相信'Swings'会为它做点什么。 –

+3

如果您无意中使用了Thread.sleep,则可以冻结Swing事件线程,冻结整个应用程序。如果您直接使用后台线程,那么您必须注意确保所有Swing调用都在Swing事件线程上使用SwingUtilities.invokeLater(new Runnable(){...});'正确排队。由于这是一个Swing相关的问题,最好的解决方案是使用Swing已经可用于这种事情的工具,一个Swing Timer。 –

0

你可以线性插值从一开始RGB颜色转换到你想要的到最后。

这意味着,例如,你有rgb(255,255,0)为起点颜色和rgb(50,50,50)为目标,要达到5个步骤,你通过(-41 = (255-50)/5, -41, 10)在每一步都领先于下列颜色调整的最终颜色:

rgb(255,255, 0) 
rgb(214,214, 10) 
rgb(173,173, 20) 
rgb(132,132, 30) 
rgb(91, 91, 40) 
rgb(50, 50, 50) 

这就是所谓的线性渐变,并会非常容易实现,但当然存在各种其他技术来在颜色之间进行漂亮的转换。

1

最简单的方法是在每个RGB值之间进行插值。 这将是所有语言一样 - Python代码看起来像:

steps = 10 

rgb1 = [ 'AA', '08', 'C3' ] 
rgb2 = [ '03', '88', '1C' ] 

h1 = map(lambda s: int('0x'+s, 0), rgb1) 
h2 = map(lambda s: int('0x'+s, 0), rgb2) 

inc = [0, 0, 0] 
for i in range(0,3): 
    inc[i] = (h2[i] - h1[i])/(steps - 1) 

for i in range(0,steps-1): 
    print '<span style="background: #%02x%02x%02x"> &nbsp; %i &nbsp; </span>' % ( 
      h1[0] + i * inc[0], 
      h1[1] + i * inc[1], 
      h1[2] + i * inc[2], 
      i+1) 

print '<span style="background: #%02x%02x%02x"> &nbsp; %i &nbsp; </span>' % ( 
     h2[0], h2[1], h2[2], steps) 
+0

这里是代码和输出的要点:[gist.github.com/4014407](https://gist.github.com/4014407) – SammyO

3

我用相结合的办法来达到同样的效果。

Baiscally我使用一个相似的API接口作为LinearGradientPaint,其中我提供了一个分数数组和颜色数组,然后基于一个float百分比,我计算得到的混合颜色。

这使我可以通过相同的算法产生许多有效的结果。

enter image description here

虽然这个例子的目的是展示一个不同的颜色,你可以简单地提供两种颜色的{0f, 1f}两种颜色

一小部分这让我切实做好彩色动画的混合以及。

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 FadePane()); 
       frame.add(new ColorFadePane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class FadePane extends JPanel { 

     private float[] fractions = new float[]{0f, 0.25f, 0.5f, 1f}; 
     private Color[] colors = new Color[]{Color.GREEN, Color.BLUE, Color.YELLOW, Color.RED}; 
     private float direction = 0.05f; 
     private float progress = 0f; 

     public FadePane() { 
      Timer timer = new Timer(125, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        if (progress + direction > 1f) { 
         direction = -0.05f; 
        } else if (progress + direction < 0f) { 
         direction = 0.05f; 
        } 
        progress += direction; 
        repaint(); 
       } 
      }); 
      timer.setCoalesce(true); 
      timer.setRepeats(true); 
      timer.start(); 
     } 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      int width = getWidth(); 
      int height = getHeight(); 
      Color startColor = blendColors(fractions, colors, progress); 
      g2d.setColor(startColor); 
      g2d.fillRect(0, 0, width, height); 
      g2d.dispose(); 
     } 
    } 

    public class ColorFadePane extends JPanel { 

     private float[] fractions = new float[]{0f, 0.25f, 0.5f, 1f}; 
     private Color[] colors = new Color[]{Color.GREEN, Color.BLUE, Color.YELLOW, Color.RED}; 

     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; 
    } 
}