2013-01-08 7 views
1

시간이 지남에 따라 너비가 증가하는 이미지를 그릴 응용 프로그램이 있습니다. 특히, 응용 프로그램은 마이크를 청취하고 매 6 밀리 초마다 스펙트로 그램을 계산하며, 업데이트 된 스펙트로 그램을 그려야합니다. java.awt.image.BufferedImage을 사용하여 스펙트로 그램을 그리지 만 미리 녹음 된 파일 만 사용할 수 있습니다. 이미지의 너비가 고정되어 있어야합니다. 스트리밍 응용 프로그램에 대해이 작업을 수행하는 가장 좋은 방법은 무엇입니까? 이미지의 너비는 알 수 없습니다.Java에서 커지는 크기의 이미지를 그립니다.

한 가지 가능성은 오른쪽에 여분의 픽셀 1 개가있는 새로운 BufferedImage를 만들고 데이터를 복사하는 것입니다.하지만 초당 수백 번 수행하는 것은 비효율적입니다. 또는 비교적 큰 너비로 시작하여 채울 때까지 오른쪽을 공백으로 유지하고, ArrayList가 크기를 상각하는 것과 비슷한 폭을 두 배로 늘릴 수 있습니다. 초당 몇 번만 데이터를 복사하면됩니다. , 또는 몇 초마다 한 번 정도. 더 나은 옵션이 있습니까?

답변

2

당신이 제안한 것의 조합과 전체 이미지의 부분 이미지 만 칠하고 적절한 기본 크기를 반환하는 무시 구성 요소를 사용합니다. 여기

무슨 뜻인지 보여주는 데모 코드 :

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Graphics; 
import java.awt.Rectangle; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.image.BufferedImage; 
import java.util.Random; 

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.SwingUtilities; 
import javax.swing.Timer; 

public class TestRecording { 

    public static class MyPanel extends JPanel { 

     private BufferedImage buffer = new BufferedImage(3000, 100, BufferedImage.TYPE_INT_RGB); 

     private int width = 0; 

     private int lastY = 50; 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 

      if (width > 0) { 
       BufferedImage sub = buffer.getSubimage(0, 0, width, buffer.getHeight()); 
       g.drawImage(sub, 0, Math.max(0, (getHeight() - buffer.getHeight())/2), this); 
      } 

     } 

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

     protected void drawSomething() { 
      // Here need to handle growing image 
      Graphics g = buffer.getGraphics(); 
      g.setColor(Color.GREEN); 
      int y = new Random().nextInt(buffer.getHeight()); 
      g.drawLine(width, lastY, width + 1, y); 
      lastY = y; 
      width += 1; 
      Rectangle r = new Rectangle(); 
      r.x = getWidth(); 
        // Lame hack to auto-scroll to the end 
      scrollRectToVisible(r); 
      revalidate(); 
      repaint(); 
     } 
    } 

    protected void initUI() { 
     JFrame frame = new JFrame(TestRecording.class.getSimpleName()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     final MyPanel p = new MyPanel(); 
     JScrollPane scrollpane = new JScrollPane(p); 
     frame.add(scrollpane); 
     frame.setSize(400, 200); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
     Timer t = new Timer(20, new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       p.drawSomething(); 
      } 
     }); 
     t.start(); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new TestRecording().initUI(); 
      } 
     }); 
    } 
} 

그리고 여기 결과입니다

Result

1

원본 이미지의 크기를 원하는 크기로 조정할 수 있습니다.

ImagegetScaledInstance(int width, int height, int hints) 방법이

+0

난 그냥, 같은 크기로 이미지의 내용을 원하는 들어오는 데이터를 더 많이 그리기위한 여분의 컬럼을 가지는 것입니다.'getScaledInstance'가 그것을 처리합니까? 나는 보았고 내가 제공 할 수있는 힌트 중 하나가 내가 원하는 것을하지 않는 것처럼 보였다. – mattg

1

당신이 그것을 그릴 위치를 1) GUI가 있습니까, 또는 2))는 출력 이미지 파일 (또는 스트림을 정말해야합니까?

if 1) 보이는 것을 그립니다. JComponent를 확장하려면 보통 JPanel을 사용하고 paintComponent를 재정 의하여 표시되는 내용을 페인트합니다. 더 효율적으로 만들려면 "타일"- 예를 들어 목록을 만듭니다. 일정한 폭의 BufferedImage를 만들고 들어오는 데이터에서 생성하고 gui에만 그려줍니다.

2) 비슷하지만 비교적 낮은 너비의 이미지 하나를 사용하여 새 데이터를 그릴 수 있습니다. 가득 차면, 지금까지 "왼쪽"이미지 (처음에는 비어 있음)에 "추가"하십시오. 이렇게하면 자주 작은 이미지와 큰 이미지를 자주 수정하게됩니다. 전체 이미지를 채우기 전에 끝이 오면 채워진 부분 만 왼쪽으로 결합하십시오.

더 많은 메모리를 사용하는 비용으로 합치는 이미지의 수를 줄이려면 오른쪽 이미지 (* X, 예 : * 1.5 또는 * 2)의 크기를 점차적으로 늘릴 수 있습니다.

이러한 "이미지"를 바이트 (또는 int) 배열 (2D를 나타내는 1D 배열로 저장할 수 있지만 효율적인 수정을 위해 행이 아닌 열로 저장)을 사용하면이 방법으로 더 효율적으로 저장할 수 있습니다. 일부 색상은 결과 이미지에 나타나지 않기 때문에 픽셀 당 비트 수가 비정상적으로 필요하다는 것을 알고 있어야합니다.

이미지가 너무 커지면 이미지를 디스크에 저장하고 왼쪽 이미지를 지우고 나중에 함께 결합하거나 별도로 사용하십시오.

+0

이미지를 파일로 출력 할 필요없이 화면에 표시 만하면됩니다.전 JScrollPane을 사용하여 전체 이미지를 표시하고 잠시 동안 너무 커지면 메모리에 맞지 않게됩니다. 나는 타일의 아이디어를 좋아한다. 예를 들어, BufferedImages를 아이콘으로 사용하는 일련의 JLabel을 컨테이너에 서로 옆에 배치하면 올바르게 정렬됩니까 (예 : 간격 없음)? – mattg

+0

조금 더 생각해 보면, 필자는 이전 칼럼으로 돌아가서 스펙트로 그램에 마크 업을 그려야합니다. 하나의 이미지를 사용하면 꽤 쉽습니다. 그러나 마크 업이이 목록에서 참조해야하는 이미지를 추적해야한다면 두통이 될 것입니다. 그러나 여전히, 당신의 대답에 새로운 아이디어가 마음에 들지만, 더 좋은 것을 얻지 못하면 받아 들일 것입니다. – mattg

+0

일렬로 늘어서 : 원칙적으로 작동해야하지만, 말했듯이, 나는 그 이미지를 paintComponent에 그리고 그 위에 그림을 그릴 것이고, 그 위에 페인트 마크 업을 칠할 것이다. 이렇게하면 그림을 그릴 책임이 훨씬 커집니다. 그리고 손으로 그린 ​​그림, affinetransformations 또는 그림을 다른 좌표로 이동하는 방법은 두 가지가 있습니다. – Alpedar

관련 문제