2016-09-27 3 views
0

У меня есть эта программа:Java Graphics.fillXxx() в сочетании с Graphics2D.scale()

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.geom.Rectangle2D; 

import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 
import javax.swing.WindowConstants; 


public class TestLine { 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new TestLine().start(); 
      } 
     }); 
    } 

    private static void start() { 
     JFrame frame = new JFrame(); 
     frame.setContentPane(new CarthPanel()); 
     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    private static class CarthPanel extends JComponent { 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      Graphics2D gg = (Graphics2D) g; 

      int w = gg.getClipBounds().width; 
      int h = gg.getClipBounds().height; 
      System.out.println("(w,h)=(" + w + "," + h + ")"); 

      gg.translate(w - 1, 0); // <<< when uncommenting both lines, mirroring applies 
      gg.scale(-1.0, 1.0); // 

      paintTest(gg, w, h); 
     } 

     private static void paintTest(Graphics2D g, int w, int h) { 
      // black background 
      g.setColor(Color.black); 
      g.fillRect(0, 0, w, h); 

      // colored corners 
      g.setColor(Color.RED); 
      g.drawLine(0, 0, 10, 0); 
      g.drawLine(0, 0, 0, 10); 
      g.setColor(Color.RED); 
      g.drawLine(0, 199, 10, 199); 
      g.drawLine(0, 199, 0, 189); 
      g.setColor(Color.CYAN); 
      g.drawLine(189, 0, 199, 0); 
      g.drawLine(199, 0, 199, 10); 
      g.setColor(Color.CYAN); 
      g.drawLine(189, 199, 199, 199); 
      g.drawLine(199, 199, 199, 189); 

      // yellow squares 
      g.setColor(Color.yellow); 
      g.drawRect(3, 3, 10, 10); 
      g.fillRect(186, 3, 11, 11); 
      g.fillRect(3, 186, 11, 11); 
      g.drawRect(186, 186, 10, 10); 

      String chars = "ABC"; 
      g.setFont(Font.decode("Arial 72")); 
      Rectangle2D rect = g.getFontMetrics().getStringBounds(chars, g); 
      g.drawString(chars, (int) (200 - rect.getWidth())/2, (int) (200 - rect.getHeight())); 
     } 
    } 
} 

Если запустить эту программу один раз с двумя конкретными линиями комментируемых в и затем один раз с теми же линиями закомментирована (см код), то вы получите, чтобы увидеть это:

[Graphics.scale() and Graphics.translate()[1]

Если вы не заметили эту проблему, вот увеличенное рис:

Zoomed

Можно было бы ожидать, что изображение будет полностью зеркальным. Это справедливо для всех штрихов и полых форм (= drawXxx()). Однако все заполненные фигуры (= методы fillXxx()) выводятся ровно на один пиксель слева от того, где я их ожидаю; например заполненные желтые прямоугольники, и вы также можете заметить, что черный фон сдвинулся, как видно по белой линии на правой границе.

Является ли это ошибкой или это предназначено? Я подозреваю, что у него есть что-то делать с той разницей, как «ширина» и «высота» в настоящее время обрабатываются в drawXxx() и fillXxx() методы:

  • DrawRect (х, у, ш, ч) приводит к полый прямоугольник с X-осями границ x и x + w, поэтому прямоугольник имеет ширину w + 1 пиксель.
  • fillRect (x, y, w, h) приводит к заполненному прямоугольнику с границами x и x + w-1, поэтому прямоугольник имеет ширину w пикселей.

Что мне не хватает?

ответ

-1

Это ошибка, это не функция :) Наверняка это не предназначено, зеркальное изображение должно быть идеальным, нет причин, почему этого не должно быть.

Существует способ использования BufferedImage для рендеринга на нем в обычном режиме, а затем рисование этого BufferedImage перевернулось, единственным недостатком является небольшое влияние на производительность и не очень красивый текст, нарисованный с использованием субпикселя LCD.

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.geom.Rectangle2D; 
import java.awt.image.BufferedImage; 

import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 
import javax.swing.WindowConstants; 


public class TestLine { 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new TestLine().start(); 
      } 
     }); 
    } 

    private static void start() { 
     JFrame frame = new JFrame(); 
     frame.setContentPane(new CarthPanel()); 
     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    private static class CarthPanel extends JComponent { 

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

     @Override 
     protected void paintComponent(Graphics g) { 
      Graphics2D gg = (Graphics2D) g; 

//   System.out.println("(w,h)=(" + w + "," + h + ")"); 

      gg.translate(getWidth(), 0); // <<< when uncommenting both lines, mirroring applies 
      gg.scale(-1.0, 1.0); // 

      BufferedImage img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB); 

      try { 
       paintTest(img.createGraphics()); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 

      g.drawImage(img, 0, 0, null); 
     } 



     private void paintTest(Graphics2D g) { 
      // black background 
      g.setColor(Color.black); 
      g.fillRect(0, 0, getWidth(), getHeight()); 

      // colored corners 
      g.setColor(Color.RED); 
      g.drawLine(0, 0, 10, 0); 
      g.drawLine(0, 0, 0, 10); 
      g.setColor(Color.RED); 
      g.drawLine(0, 199, 10, 199); 
      g.drawLine(0, 199, 0, 189); 
      g.setColor(Color.CYAN); 
      g.drawLine(189, 0, 199, 0); 
      g.drawLine(199, 0, 199, 10); 
      g.setColor(Color.CYAN); 
      g.drawLine(189, 199, 199, 199); 
      g.drawLine(199, 199, 199, 189); 

      // yellow squares 
      g.setColor(Color.yellow); 
      g.drawRect(3, 3, 10, 10); 
      g.fillRect(186, 3, 11, 11); 
      g.fillRect(3, 186, 11, 11); 
      g.drawRect(186, 186, 10, 10); 

      String chars = "ABC"; 
      g.setFont(Font.decode("Arial 72")); 
      Rectangle2D rect = g.getFontMetrics().getStringBounds(chars, g); 
      g.drawString(chars, (int) (200 - rect.getWidth())/2, (int) (200 - rect.getHeight())); 
     } 
    } 
} 
+0

Что вы имеете в виду, «все drawXXX ошибочны»? Из моих тестов ясно, что заполненные фигуры сдвинуты, а не очерченные фигуры. Вы правы, что графический контекст BufferedImage работает! Так что это должно быть ошибкой в ​​графическом контексте Java-компонента. – Timmos

+0

Я думаю, что ваш пример почти прав, 'g.drawImage (img, 0, 0, null);' должен быть 'gg.drawImage (img, 0, 0, null);'. – Timmos

+0

Я думаю, что ваш ответ не совсем правильный.Всякий раз, когда вы берете графический контекст из BufferedImage, а затем масштабируете/переводите его, методы fillXxx() также приводят к сдвигам пикселей. В вашем примере вы напрямую нарисовали все на BufferedImage (без каких-либо преобразований), а затем масштабировали/переводили всю вещь за один раз при рисовании изображения на графический объект Java Component. Это действительно работает, но ваше предположение о том, что это связано с самим графическим контекстом, неверно: ошибка возникает всякий раз, когда вы рисуете масштабированный/переведенный контекст. DrawXxx() сдвигается в пикселях. – Timmos

0

Не ответ, а скорее гипотеза - «содержит (х, у)» прямоугольник будет true для сторон, которая образует (х, у) угла прямоугольника и false для сторон делая (maxx, maxy) угол. Демонстрация:

Rectangle r=new Rectangle(0, 0, 10, 10); 
System.out.println(r.contains(0, 5)); // true 
System.out.println(r.contains(5, 0)); // true 
System.out.println(r.contains(10, 5)); // false 
System.out.println(r.contains(5, 10)); // false 

Гипотеза состоит в том, что fillRect не будет рассматривать «Max стороны», как внутри точки должны быть заполнены.

Чтобы оценить гипотезу, я предлагаю вам попробовать использовать GeneralPath, который определяет один и тот же прямоугольник и видит, что есть какая-либо разница в его заполнении. GeneralPath должно быть запрещено делать какие-либо предположения о том, что «правые верхние границы выходят из формы»

Смежные вопросы