2013-04-25 2 views
1

Предположим, у меня есть BufferedImage типа TYPE_4BYTE_ABGR в Swing, и я хочу нарисовать только его часть. Например, я хотел бы рисовать только левую половину или какую-то треугольную форму или что-то более сложное.Как эффективно нарисовать подчасти изображения в Swing

Причина в том, что окончательное изображение должно быть составлено из частей отдельных изображений, которые у меня есть.

Каков наилучший способ сделать это?

Я бы предпочел определить многоугольник, а затем использовать эту форму в качестве маски для рисования, если это возможно.

Моя текущая идея: сделайте копию отдельного изображения и сделайте все пиксели за пределами желаемой формы прозрачными, затем нарисуйте все изображение. Я думаю, что это может сработать, но может быть слишком медленным с копированием и всеми.

редактировать:

Я проверил решение Гийома и обнаружил, что она работает и не очень замедлит картину. Использование клипа привело к увеличению времени рисования с 14 мс до 35 мс, но эти времена очень неточно. Я использовал профилирование EDT от here. Вот код.

import java.awt.AWTEvent; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Toolkit; 
import java.awt.image.BufferedImage; 
import java.io.IOException; 
import java.net.URL; 
import javax.imageio.ImageIO; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

/** 
* 
*/ 
public class ClipTilesTest { 

    // tile size and number of tiles in each row/column 
    private static int TILE_SIZE = 100; 
    private static int TILE_NUM = 6; 

    // taken from https://stackoverflow.com/questions/5541493/how-do-i-profile-the-edt-in-java-swing 
    public static class TimedEventQueue extends EventQueue { 

     @Override 
     protected void dispatchEvent(AWTEvent event) { 
      long startNano = System.nanoTime(); 
      super.dispatchEvent(event); 
      long endNano = System.nanoTime(); 

      if (endNano - startNano > 5000000) { 
       System.out.println(((endNano - startNano)/1000000) + "ms : " + event); 
      } 
     } 
    } 

    private static void initUI() { 

     Toolkit.getDefaultToolkit().getSystemEventQueue().push(new TimedEventQueue()); 

     // download image 
     BufferedImage image; 
     try { 
      image = ImageIO.read(new URL("http://download.chip.eu//ii/163859211_4b28e1e687.jpg")); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
      return; 
     } 
     // take out small chunk 
     final BufferedImage tile = image.getSubimage(0, 0, TILE_SIZE, TILE_SIZE); 

     JFrame frame = new JFrame(); 
     frame.setTitle(ClipTilesTest.class.getSimpleName()); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 

     // the panel containing some tiles 
     JPanel view = new JPanel() { 
      @Override 
      public void paint(Graphics g) { 
       super.paint(g); 
       Graphics2D g2d = (Graphics2D) g; 

       for (int i = 0; i < TILE_NUM; i++) { 
        for (int j = 0; j < TILE_NUM; j++) { 

         // version 1 
         /* 
         g2d.setClip(i * TILE_SIZE, j * TILE_SIZE , (i+1)*TILE_SIZE, (j+1)*TILE_SIZE); 
         g2d.drawImage(tile, i * TILE_SIZE, j * TILE_SIZE, null); 
         */ 

         // version 2 

         g2d.setClip(i * TILE_SIZE, j * TILE_SIZE , i*TILE_SIZE + TILE_SIZE/2, (j+1)*TILE_SIZE); 
         g2d.drawImage(tile, i * TILE_SIZE, j * TILE_SIZE, null); 
         g2d.setClip(i * TILE_SIZE + TILE_SIZE/2, j * TILE_SIZE , (i+1)*TILE_SIZE , (j+1)*TILE_SIZE); 
         g2d.drawImage(tile, i * TILE_SIZE, j * TILE_SIZE, null); 

        } 
       } 

      } 
     }; 
     view.setPreferredSize(new Dimension(TILE_SIZE * TILE_NUM, TILE_SIZE * TILE_NUM)); 

     // add, pack, set visible 
     frame.add(view); 
     frame.pack(); 
     frame.setVisible(true); 

     // now make a repaint event, so we can start measuring 
     view.repaint(); 
    } 

    /** 
    * @param args the command line arguments 
    */ 
    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       ClipTilesTest.initUI(); 
      } 
     }); 

    } 
} 
+0

ты пытался getSubimage (заметьте, что я никогда не использовал) – mKorbel

+0

нет, но может быть полезно в сочетании с другими вещами, чтобы получить непрямоугольные подразделы – Trilarion

+0

В этом [примере] (http://stackoverflow.com/a/3078354/230513) используется 'getSubimage()', который «Возвращает субимость, определенную указанной прямоугольной областью». – trashgod

ответ

4

Один простой способ добиться этого эффекта, чтобы изменить «клип» в Graphics объекта и установить его в форму, которую вы хотите нарисовать.

Я не знаю, насколько это эффективно, но вы можете подумать о кешировании обрезанного изображения, а затем нарисовать все кешированное изображение.

Вот небольшой демо-код:

result

import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Image; 
import java.awt.Rectangle; 
import java.awt.Shape; 
import java.awt.geom.Ellipse2D; 
import java.net.MalformedURLException; 
import java.net.URL; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.Random; 

import javax.swing.ImageIcon; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

public class TestClippedPanel { 

    private static class ClippedPanel extends JPanel { 

     private ImageIcon image; 

     private List<Shape> shapes; 

     public ClippedPanel() throws MalformedURLException { 
      shapes = new ArrayList<Shape>(); 
      image = new ImageIcon(new URL("http://download.chip.eu//ii/163859211_4b28e1e687.jpg")); 
      Random random = new Random(); 
      for (int i = 0; i < 10; i++) { 
       int x = random.nextInt(image.getIconWidth() - 1); 
       int y = random.nextInt(image.getIconHeight() - 1); 
       int w = random.nextInt(image.getIconWidth() - x) + 1; 
       int h = random.nextInt(image.getIconHeight() - y) + 1; 
       shapes.add(new Rectangle(x, y, w, h)); 
      } 
      for (int i = 0; i < 10; i++) { 
       int x = random.nextInt(image.getIconWidth() - 1); 
       int y = random.nextInt(image.getIconHeight() - 1); 
       int w = random.nextInt(image.getIconWidth() - x) + 1; 
       int h = random.nextInt(image.getIconHeight() - y) + 1; 
       shapes.add(new Ellipse2D.Double(x, y, w, h)); 
      } 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Image img = image.getImage(); 
      for (Shape shape : shapes) { 
       ((Graphics2D) g).setClip(shape); 
       g.drawImage(img, 0, 0, this); 
      } 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(image.getIconWidth(), image.getIconHeight()); 
     } 

    } 

    protected void initUI() throws MalformedURLException { 
     final JFrame frame = new JFrame(TestClippedPanel.class.getSimpleName()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     final ClippedPanel panel = new ClippedPanel(); 
     frame.add(panel); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

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

      @Override 
      public void run() { 
       try { 
        new TestClippedPanel().initUI(); 
       } catch (MalformedURLException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 
} 
+0

спасибо за код, я проверю его, а затем отчитаю. это требует немного переосмысления на моей стороне, потому что клип находится на стороне холста, а не на стороне изображения. – Trilarion

+0

Я тестировал его, и он работает, однако использование клипа замедляет рисование. Я не мог надежно определить, есть ли у картины за пределами отсечения дополнительные расходы. Помечено как решение. – Trilarion

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