package fr.unistra.pelican.gui; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.Raster; import java.awt.image.SampleModel; import javax.media.jai.RasterFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JTextField; import javax.swing.ScrollPaneConstants; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import com.sun.media.jai.widget.DisplayJAI; import fr.unistra.pelican.ByteImage; import fr.unistra.pelican.Image; import fr.unistra.pelican.algorithms.conversion.AverageChannels; /** * This class creates a JFrame for the visualization of byte valued * videos in motion. Only the case of videos with exactly 3 * channels and the parameter "color" set, results in color. * * @author Jonathan Weber */ public class FrameVideo extends JFrame implements ActionListener{ private static final long serialVersionUID = 200807081535L; private Image video; private boolean color; private JTextField statusBar; private JSlider frameSld; private JButton playPause; private JScrollPane scroll; private Timer timer; private double frameRate; private boolean onLoop=true; public JScrollPane getScroll() { return this.scroll; } /** * * @param img * image to show * @param title * window title * @param color * whether it should be shown in color or not */ public FrameVideo(fr.unistra.pelican.Image img, String title, boolean color, double frameRate,boolean onLoop) { this(img, color, frameRate,onLoop); // yes, color must be added to the constructor! if (title != null) this.setTitle(title); } /** * * @param video * image to show * @param color * whether it should be shown in color or not */ public FrameVideo(fr.unistra.pelican.Image video, boolean color, final double frameRate,boolean onLoop) { if(video.getZDim()!=1) video=(ByteImage)video.getImage4D(0, Image.Z); if(video.getBDim()!=3&&video.getBDim()!=1) video=(ByteImage)AverageChannels.exec(video); final int bdim = video.getBDim(); final int tdim = video.getTDim(); this.frameRate=frameRate; this.video=video; final FrameVideo ben = this; // yes its ugly this.color = color; this.onLoop=onLoop; if (this.color == true && bdim != 3) { System.err.println("Only " + bdim + " channel" + ((bdim > 1) ? "s " : " ") + "found. Color visualisation cancelled"); this.color = false; } if(this.color == false && bdim !=1) { this.video = (ByteImage) this.video.getImage4D(0, Image.B); } this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); JPanel root = new JPanel(); Toolkit k = Toolkit.getDefaultToolkit(); Dimension tailleEcran = k.getScreenSize(); root.setPreferredSize(new Dimension(Math.min(tailleEcran.width - 3, video .getXDim() + 3), Math.min(tailleEcran.height - 49, video.getYDim() + 49))); root.setLayout(new BorderLayout()); this.setContentPane(root); scroll = new JScrollPane(null, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); root.add(scroll, BorderLayout.CENTER); if (this.color == false) { makeCurrentFrameDisplayed(0); } else { makeColorCurrentFrameDisplayed(0); } JPanel bottomPanel = new JPanel(); bottomPanel.setLayout(new BorderLayout()); statusBar = new JTextField(); statusBar.setEnabled(false); bottomPanel.add(statusBar, BorderLayout.SOUTH); root.add(bottomPanel, BorderLayout.SOUTH); // frames JPanel frameBox = new JPanel(); frameBox.setLayout(new BoxLayout(frameBox, BoxLayout.X_AXIS)); playPause = new JButton("PLAY "); playPause.addActionListener(this); frameBox.add(playPause); frameSld = new JSlider(SwingConstants.HORIZONTAL, 1, tdim, 1); frameSld.setSnapToTicks(true); frameBox.add(frameSld); frameSld.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { statusBar.setText(" Frame : " + Integer.toString(frameSld.getValue()) + "/" + tdim + " | Time : "+ Double.toString(frameSld.getValue()/frameRate)+" sec"); int t = frameSld.getValue() - 1; if (ben.color == false) { makeCurrentFrameDisplayed(t); } else { makeColorCurrentFrameDisplayed(t); } if(frameSld.getValue()==frameSld.getMaximum()) { if(!ben.onLoop) { timer.stop(); playPause.setText("PLAY "); } } } }); bottomPanel.add(frameBox, BorderLayout.CENTER); pack(); setVisible(true); timer = createTimer (); if(onLoop) { playPause.setText("PAUSE"); timer.start(); } } private void makeCurrentFrameDisplayed(int t) { DataBufferByte dbb; SampleModel s; Raster r; BufferedImage bimg = null; int xDim = video.getXDim(); int yDim = video.getYDim(); int frameDim = xDim*yDim; byte[] byteVal = new byte[frameDim]; int shift = t*frameDim; for(int i=0;i<frameDim;i++) { byteVal[i]=(byte)video.getPixelByte(shift++); } dbb = new DataBufferByte(byteVal, byteVal.length); s = RasterFactory.createBandedSampleModel(DataBuffer.TYPE_BYTE, xDim, yDim, 1); r = RasterFactory.createWritableRaster(s, dbb, new Point(0, 0)); bimg = new BufferedImage(xDim, yDim, BufferedImage.TYPE_BYTE_GRAY); bimg.setData(r); scroll.setViewportView(new DisplayJAI(bimg)); } private void makeColorCurrentFrameDisplayed(int t) { DataBufferByte dbb; SampleModel s; Raster r; BufferedImage bimg = null; int[] bandOffsets = { 0, 1, 2 }; int xDim = video.getXDim(); int yDim = video.getYDim(); int frameDim = xDim*yDim*3; byte[] byteVal = new byte[frameDim]; int shift=t*frameDim; for(int i =0;i<frameDim;i++) { byteVal[i]=(byte)video.getPixelByte(shift++); } dbb = new DataBufferByte(byteVal, byteVal.length); s = RasterFactory.createPixelInterleavedSampleModel( DataBuffer.TYPE_BYTE, xDim, yDim, 3, 3 * xDim, bandOffsets); r = RasterFactory.createWritableRaster(s, dbb, new Point(0, 0)); bimg = new BufferedImage(xDim, yDim, BufferedImage.TYPE_3BYTE_BGR); bimg.setData(r); scroll.setViewportView(new DisplayJAI(bimg)); } private Timer createTimer() { // Listener linked to the timer ActionListener action = new ActionListener () { public void actionPerformed (ActionEvent event) { if(frameSld.getValue()!=frameSld.getMaximum()) { frameSld.setValue(frameSld.getValue()+1); } else { if(onLoop) { frameSld.setValue(1); } } } }; return new Timer ((int)Math.round(1000/frameRate), action); } void statusBarMsg(String s) { SwingUtilities.invokeLater(new MainFrameRunnable(this, s) { public void run() { frameVideo.statusBar.setText((String) obj); } }); } class MainFrameRunnable implements Runnable { FrameVideo frameVideo; Object obj; /** * * @param frv * @param obj */ public MainFrameRunnable(FrameVideo frv, Object obj) { frameVideo = frv; this.obj = obj; } public void run() { } } public void actionPerformed(ActionEvent e) { if(e.getSource()==playPause) { if(playPause.getText()=="PLAY ") { playPause.setText("PAUSE"); timer.start(); } else { timer.stop(); playPause.setText("PLAY "); } } } }