J'ai essayé d'utiliser la méthode drawOval avec une hauteur et une largeur égales, mais à mesure que le diamètre augmente, le cercle devient de moins en moins beau. Que puis-je faire pour avoir un cercle d'apparence décent, peu importe la taille. Comment pourrais-je implémenter l'anticrénelage dans Java ou une autre méthode.
En fin de compte, Java2D (que je suppose être ce que vous utilisez) est déjà assez bon dans ce domaine! Il y a un tutoriel décent ici: http://www.javaworld.com/javaworld/jw-08-1998/jw-08-media.html
La ligne importante est:
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
vous pouvez définir des indices de rendu:
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Deux choses qui peuvent aider:
Graphics2D.draw(Shape)
avec une instance de Java.awt.geom.Ellipse2D
au lieu de Graphics.drawOval
Graphics2D.setRenderingHint
pour activer l'anticrénelageExemple
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);
}
Voir la réponse de Josef pour un exemple de setRenderingHint
Bien sûr, vous définissez votre rayon sur ce dont vous avez besoin:
@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);
}
Merci à Oleg Estekhin d'avoir signalé le rapport de bogue, car il explique comment le faire.
Voici quelques petits cercles avant et après. Agrandie plusieurs fois pour voir la grille de pixels.
En descendant d'une rangée, ils se déplacent légèrement de sous-pixels.
La première colonne est sans indice de rendu. Le second concerne uniquement les antialias. Le troisième est avec antialias et mode pur.
Notez comment avec les astuces anti-crénelage uniquement, les trois premiers cercles sont identiques et les deux derniers sont également identiques. Il semble y avoir une transition discrète. Arrondi probablement à un moment donné.
Voici le code. Il est en Jython pour la lisibilité, mais il pilote la bibliothèque d'exécution Java en dessous et peut être porté sans perte vers une source équivalente Java, avec exactement le même effet).
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"))
Résumé: vous avez besoin des deux VALUE_ANTIALIAS_ON
et VALUE_STROKE_PURE
pour obtenir des cercles d'aspect corrects avec une précision de sous-pixel.
L'incapacité à dessiner un "cercle d'apparence décent" est liée au très ancien bug 6431487 .
L'activation de l'anticrénelage n'aide pas beaucoup - il suffit de vérifier le type de "cercle" produit par drawOval () ou drawShape (Eclipse) lorsque la taille de cercle requise est de 16 pixels (toujours assez courante pour la taille de l'icône) et que l'anticrénelage est activé. Les cercles anti-crénelés plus grands auront une meilleure apparence, mais ils sont toujours asymétriques, si quelqu'un veut bien les regarder de près.
Il semble que pour dessiner un "cercle décent", il faut en dessiner un manuellement. Sans anticrénelage, ce sera l'algorithme du cercle médian (cette question a une réponse avec un joli Java pour cela).