概要

JPanelに明度を最大値に固定した色相環を描画します。

サンプルコード

// Colors: a Color Dialog | Java Graphics
// https://javagraphics.blogspot.com/2007/04/jcolorchooser-making-alternative.html
private BufferedImage updateImage() {
  BufferedImage image = new BufferedImage(SIZE, SIZE, BufferedImage.TYPE_INT_ARGB);
  int[] row = new int[SIZE];
  float size = (float) SIZE;
  float radius = size / 2f;

  for (int yidx = 0; yidx < SIZE; yidx++) {
    float y = yidx - size / 2f;
    for (int xidx = 0; xidx < SIZE; xidx++) {
      float x = xidx - size / 2f;
      double theta = Math.atan2(y, x) - 3d * Math.PI / 2d;
      if (theta < 0) {
        theta += 2d * Math.PI;
      }
      double r = Math.sqrt(x * x + y * y);
      float hue = (float) (theta / (2d * Math.PI));
      float sat = Math.min((float) (r / radius), 1f);
      float bri = 1f;
      row[xidx] = Color.HSBtoRGB(hue, sat, bri);
    }
    image.getRaster().setDataElements(0, yidx, SIZE, 1, row);
  }
  return image;
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、色相環をサイズ固定でJPanelの中央に描画しています。

  • 色相(hue): new Color(Color.HSBtoRGB(0f, 1f, 1f))は赤で、これを頂点に角度に応じて色相を変更
  • 彩度(saturation): 中心から外周へ0fから1fで彩度をグラデーション描画
  • 明度(brightness): 最大値の1fで明度は固定

  • 1つのピクセルごとにHSBからRGBに色変換してBufferedImageを作成しているので、円の縁でジャギーが発生する
    • このサンプルでは円ではなく正方形の色マップを描画し、あとでソフトクリッピング効果を使った円図形での切り抜きを行っている
      // Soft Clipping
      GraphicsConfiguration gc = g2.getDeviceConfiguration();
      BufferedImage buf = gc.createCompatibleImage(s, s, Transparency.TRANSLUCENT);
      Graphics2D g2d = buf.createGraphics();
      
      g2d.setComposite(AlphaComposite.Src);
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      g2d.fill(new Ellipse2D.Float(0f, 0f, s, s));
      
      g2d.setComposite(AlphaComposite.SrcAtop);
      g2d.drawImage(colorWheelImage, 0, 0, null);
      g2d.dispose();
      
      g2.drawImage(buf, null, (getWidth() - s) / 2, (getHeight() - s) / 2);
      g2.dispose();
      
  • Corretto 1.8.0_212を使用すると、色相環が特定のサイズになるとWindowの縁をソフトクリッピングでなめらかにすると同様の描画抜け?が発生する場合がある
    • SIZE192224256288320などの32の倍数にすると描画が壊れる
  • 参考元のColors: a Color Dialog | Java Graphicsでは、外周のピクセルに直接アンチエイリアスを実施しているので上記のバグは発生しない
    // antialias
    float k = 1.2f; // the number of pixels to antialias
    if (r > radius - k) {
      int alpha = (int)(255 - 255 * (r - radius + k) / k);
      if (alpha < 0) alpha = 0;
      if (alpha > 255) alpha = 255;
      row[x] = row[x] & 0xff_ff_ff + (alpha << 24);
    }
    

参考リンク

コメント