web-dev-qa-db-ja.com

Javaで適切に見える円を描く方法

高さと幅が等しいdrawOvalメソッドを使用してみましたが、直径が大きくなると、円の見た目が悪くなります。サイズに関係なく、まともな円を描くにはどうすればよいですか。 Javaまたはその他の方法でアンチエイリアスをどのように実装しますか?.

24
soldier.moth

結局のところ、Java2D(私があなたが使用しているものと想定しています)はすでにこれでかなり優れています!ここにはまともなチュートリアルがあります: http://www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html

重要な行は次のとおりです。

graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                          RenderingHints.VALUE_ANTIALIAS_ON);
43

レンダリングのヒントを設定できます:

Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
    RenderingHints.VALUE_ANTIALIAS_ON);
28
Josef Pfleger

役立つ2つのこと:

  1. _Java.awt.geom.Ellipse2D_ではなく_Graphics.drawOval_のインスタンスでGraphics2D.draw(Shape)を使用します
  2. それでも結果が満足できない場合は、_Graphics2D.setRenderingHint_を使用してアンチエイリアスを有効にしてください

_public void Paint(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    Shape theCircle = new Ellipse2D.Double(centerX - radius, centerY - radius, 2.0 * radius, 2.0 * radius);
    g2d.draw(theCircle);
}
_

setRenderingHintの例については、Josefの回答を参照してください

12
finnw

もちろん、半径を必要なものに設定します。

@Override
public void Paint(Graphics g) {
    Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    Ellipse2D.Double hole = new Ellipse2D.Double();
    hole.width = 28;
    hole.height = 28;
    hole.x = 14;
    hole.y = 14;
    g2d.draw(hole);
}
6
Clint

バグレポートを指摘してくれたOleg Estekhinに感謝します。方法を説明しているからです。

これは前後の小さな円です。ピクセルグリッドを表示するために数倍に拡大します。

Circles before and after

行を下に行くと、サブピクセルの量だけわずかに移動しています。

最初の列には、レンダリングのヒントがありません。 2つ目はアンチエイリアスのみです。 3つ目は、アンチエイリアスと純粋モードです。

アンチエイリアスのヒントのみで、最初の3つの円は同じで、最後の2つの円も同じであることに注意してください。いくつかの個別の遷移が発生しているようです。おそらくある時点で丸められます。

これがコードです。読みやすくするためにJythonにありますが、Javaランタイムライブラリを下に駆動し、同等のJavaソースにロスレスで移植できます。まったく同じ効果があります。

from Java.lang import *
from Java.io import *
from Java.awt import *
from Java.awt.geom import *
from Java.awt.image import *
from javax.imageio import *

bim = BufferedImage(30, 42, BufferedImage.TYPE_INT_ARGB)
g = bim.createGraphics()
g.fillRect(0, 0, 100, 100)
g.setColor(Color.BLACK)
for i in range(5):
    g.draw(Ellipse2D.Double(2+0.2*i, 2+8.2*i, 5, 5))

g.setRenderingHint( RenderingHints.  KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON)

for i in range(5):
    g.draw(Ellipse2D.Double(12+0.2*i, 2+8.2*i, 5, 5))

g.setRenderingHint( RenderingHints.  KEY_STROKE_CONTROL,
                    RenderingHints.VALUE_STROKE_PURE)

for i in range(5):
    g.draw(Ellipse2D.Double(22+0.2*i, 2+8.2*i, 5, 5))

#You'll probably want this too later on:
#g.setRenderingHint( RenderingHints.  KEY_INTERPOLATION,
#                    RenderingHints.VALUE_INTERPOLATION_BICUBIC)
#g.setRenderingHint( RenderingHints.  KEY_RENDERING, 
#                    RenderingHints.VALUE_RENDER_QUALITY)

ImageIO.write(bim, "PNG", File("test.png"))

概要:両方が必要ですVALUE_ANTIALIAS_ONおよびVALUE_STROKE_PUREサブピクセル精度で描かれた適切に見える円を取得します。

4
Evgeni Sergeev

「まともな円」を描画できないことは、非常に古いバグ 6431487 に関連しています。

アンチエイリアスをオンにしてもあまり効果はありません。必要な円のサイズが16ピクセル(アイコンのサイズとしてかなり一般的)で、アンチエイリアスがオンになっているときに、drawOval()またはdrawShape(Eclipse)によって生成される「円」の種類を確認してください。アンチエイリアス処理された大きな円は見栄えがよくなりますが、誰かがそれらを注意深く見たい場合は、非対称です。

「まともな円」を描くには、手動で描く必要があるようです。アンチエイリアスを使用しない場合、中点円アルゴリズムになります(この 質問 は、かなりのJavaコードを使用して)回答します)。

3
Oleg Estekhin