JPanelに色相環を描画する
Total: 3468
, Today: 2
, Yesterday: 2
Posted by aterai at
Last-modified:
概要
JPanel
に明度を最大値に固定した色相環を描画します。
Screenshot
Advertisement
サンプルコード
// 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 - radius;
for (int xidx = 0; xidx < SIZE; xidx++) {
float x = xidx - radius;
double theta = Math.atan2(y, x) - 3d * Math.PI / 2d;
if (theta < 0) {
theta += 2d * Math.PI;
}
double r = Math.hypot(x, y); // 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の縁をソフトクリッピングでなめらかにすると同様の描画抜け?が発生する場合があるSIZE
を192
、224
、256
、288
、320
などの32
の倍数にすると描画が壊れるRenderingHints.KEY_ANTIALIASING
を使用しなければ発生しない- Backport JDK-8048782: OpenJDK: PiscesCache : xmax/ymax rounding up can cause RasterFormatException by sci-aws · Pull Request #94 · corretto/corretto-8が原因?なら
1.8.0_222
で修正される予定だが、すこし違うような気もする...これに関連したリグレッションだった模様
- Java2D rendering may break when using soft clipping effects · Issue #127 · corretto/corretto-8で報告済み、
1.8.0_222
で修正済 - 参考元の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); }
参考リンク
- Colors: a Color Dialog | Java Graphics
- カラーピッカー機能付きだが、このサンプルでは描画機能部分を参考にした
- java.netが無くなってリポジトリが参照不可になっているので、githubのクローンやJava Source Code: colorpicker.swing.ColorPickerPanelなどでソースを参照
- Color.HSBtoRGB(...) (Java Platform SE 8)