import ij.*; import ij.process.*; import ij.gui.*; import ij.plugin.*; import ij.util.*; import ij.text.*; import ij.macro.Interpreter; import java.awt.*; import java.io.*; import java.util.*; import java.awt.event.*; import quicktime.*; import quicktime.std.sg.*; import quicktime.std.*; import quicktime.qd.*; import quicktime.util.*; import quicktime.io.*; import quicktime.std.image.*; /** Previews and captures a single video frame using QuickTime for Java. Press the space bar to stop previewing. Press the shift or alt key to capture a frame and continue previewing. While previewing, type "+" to zoom in, "-" to zoom out, and "h" to display a histogram. Captures and displays a single frame if called with the argument "grab". Based on the LiveCam example posted to the QuickTime for Java mailing list by Jochen Broz. http://lists.apple.com/archives/quicktime-java/2005/Feb/msg00062.html */ public class QuickTime_Capture implements PlugIn { SequenceGrabber grabber; SGVideoChannel channel; QDRect cameraSize; QDGraphics gWorld; public int[] pixelData; ImagePlus imp; int intsPerRow; int width, height; boolean grabbing = true; int frame; boolean grabMode; boolean showDialog; public void run(String arg) { if (IJ.is64Bit() && IJ.isMacintosh()) { IJ.error("This plugin requires a 32-bit version of Java"); return; } String options = Macro.getOptions(); if (options!=null && options.indexOf("grab")!=-1) arg = "grab"; grabMode = arg.equals("grab"); showDialog = IJ.altKeyDown() || (options!=null && options.indexOf("dialog")!=-1); if (IJ.altKeyDown()) IJ.setKeyUp(KeyEvent.VK_ALT); IJ.resetEscape(); try { QTSession.open(); initSequenceGrabber(); width = cameraSize.getWidth(); height = cameraSize.getHeight(); intsPerRow = gWorld.getPixMap().getPixelData().getRowBytes()/4; ImageProcessor ip = new ColorProcessor(width, height); imp = new ImagePlus("Live (press space bar to stop)", ip); imp.show(); pixelData = new int[intsPerRow*height]; IJ.setKeyUp(KeyEvent.VK_ALT); IJ.setKeyUp(KeyEvent.VK_SHIFT); IJ.setKeyUp(KeyEvent.VK_SPACE); if (IJ.debugMode) { IJ.log("Size: "+width+"x"+height); IJ.log("intsPerRow: "+intsPerRow); } preview(); } catch(Exception e) { printStackTrace(e); } finally { QTSession.close(); } } /** * Initializes the SequenceGrabber. Gets it's source video bounds, creates a gWorld with that size. * Configures the video channel for grabbing, previewing and playing during recording. */ private void initSequenceGrabber() throws Exception{ grabber = new SequenceGrabber(); SGVideoChannel channel = new SGVideoChannel(grabber); if (showDialog) channel.settingsDialog(); cameraSize = channel.getSrcVideoBounds(); Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); //if (cameraSize.getHeight()>screen.height-40) // iSight camera claims to 1600x1200! // cameraSize.resize(640, 480); gWorld =new QDGraphics(cameraSize); grabber.setGWorld(gWorld, null); channel.setBounds(cameraSize); channel.setUsage(quicktime.std.StdQTConstants.seqGrabRecord | quicktime.std.StdQTConstants.seqGrabPreview | quicktime.std.StdQTConstants.seqGrabPlayDuringRecord); channel.setFrameRate(0); channel.setCompressorType( quicktime.std.StdQTConstants.kComponentVideoCodecType); } /** * This is a bit tricky. We do not start Previewing, but recording. By setting the output to a * dummy file (which will never be created (hope so)) with the * quicktime.std.StdQTConstants.seqGrabDontMakeMovie flag set. This seems to be equivalent to * preview mode with the advantage, that it refreshes correctly. */ void preview() throws Exception { QTFile movieFile = new QTFile(new java.io.File("NoFile")); grabber.setDataOutput( null, quicktime.std.StdQTConstants.seqGrabDontMakeMovie); grabber.prepare(true, true); grabber.startRecord(); while(grabbing) { grabber.idle(); grabber.update(null); displayFrame(); } } void displayFrame() { gWorld.getPixMap().getPixelData().copyToArray(0, pixelData, 0, pixelData.length); ImageProcessor ip = imp.getProcessor(); int[] pixels = ip!=null?(int[])ip.getPixels():null; ImageWindow win = imp.getWindow(); if (pixels==null || (win==null&&!Interpreter.isBatchMode()) || IJ.spaceBarDown() || IJ.escapePressed()) { grabbing = false; imp.setTitle("Untitled"); return; } if (IJ.shiftKeyDown() || IJ.altKeyDown()) { IJ.setKeyUp(KeyEvent.VK_SHIFT); IJ.setKeyUp(KeyEvent.VK_ALT); addSlice(); } if (intsPerRow!=width) { for (int i=0; i=0) IJ.error("QT Capture", "QuickTime compatible camera not found"); else if (e.toString().indexOf("userCanceledErr")>=0) ; // ignore else { CharArrayWriter caw = new CharArrayWriter(); PrintWriter pw = new PrintWriter(caw); e.printStackTrace(pw); String s = caw.toString(); if (IJ.isMacintosh()) s = Tools.fixNewLines(s); new TextWindow("Exception", s, 500, 300); } } }