- 要获取屏幕截图,请使用
Robot.createScreenCapture(Rectangle)
。 - 要获取许多屏幕截图,请在(Swing)调用的循环中调用它
Timer
。将它们添加到可扩展的集合中,例如ArrayList
。 - 使用将
BufferedImage
对象转换为JPEG格式ImageIO.write()
。 - 要将这些屏幕截图形成为.MOV,请使用JMF的JpegImagesToMovie(是的,JMF已经过时了,但是仍然可以正常工作的部分工作正常)。
由于找不到用于爱人或搜索的JpegImagesToMovie源的副本,因此这里有一个适合我使用的旧副本。我认为此版本是在未进行任何更改之前。
请注意,Java小程序必须经过数字签名(由您)和信任(最终用户),才能获取单个屏幕截图。它还需要信任(或插件2
JRE中的JNLP
API服务),以便将MOV保存到客户端的本地文件系统。
JpegImagesToMovie.java
import java.io.*;import java.util.*;import java.awt.Dimension;import javax.media.*;import javax.media.control.*;import javax.media.protocol.*;import javax.media.protocol.DataSource;import javax.media.datasink.*;import javax.media.format.VideoFormat;public class JpegImagesToMovie implements ControllerListener, DataSinkListener { public boolean doIt(int width, int height, int frameRate, Vector inFiles, MediaLocator outML) { ImageDataSource ids = new ImageDataSource(width, height, frameRate, inFiles); Processor p; try { System.err.println("- create processor for the image datasource ..."); p = Manager.createProcessor(ids); } catch (Exception e) { System.err.println("Yikes! Cannot create a processor from the data source."); return false; } p.addControllerListener(this); // Put the Processor into configured state so we can set // some processing options on the processor. p.configure(); if (!waitForState(p, p.Configured)) { System.err.println("Failed to configure the processor."); return false; } // Set the output content descriptor to QuickTime. p.setContentDescriptor(new ContentDescriptor(FileTypeDescriptor.QUICKTIME)); // Query for the processor for supported formats. // Then set it on the processor. TrackControl tcs[] = p.getTrackControls(); Format f[] = tcs[0].getSupportedFormats(); if (f == null || f.length <= 0) { System.err.println("The mux does not support the input format: " + tcs[0].getFormat()); return false; } tcs[0].setFormat(f[0]); System.err.println("Setting the track format to: " + f[0]); // We are done with programming the processor. Let's just // realize it. p.realize(); if (!waitForState(p, p.Realized)) { System.err.println("Failed to realize the processor."); return false; } // Now, we'll need to create a DataSink. DataSink dsink; if ((dsink = createDataSink(p, outML)) == null) { System.err.println("Failed to create a DataSink for the given output MediaLocator: " + outML); return false; } dsink.addDataSinkListener(this); fileDone = false; System.err.println("start processing..."); // OK, we can now start the actual transcoding. try { p.start(); dsink.start(); } catch (IOException e) { System.err.println("IO error during processing"); return false; } // Wait for EndOfStream event. waitForFileDone(); // Cleanup. try { dsink.close(); } catch (Exception e) {} p.removeControllerListener(this); System.err.println("...done processing."); return true; } DataSink createDataSink(Processor p, MediaLocator outML) { DataSource ds; if ((ds = p.getDataOutput()) == null) { System.err.println("Something is really wrong: the processor does not have an output DataSource"); return null; } DataSink dsink; try { System.err.println("- create DataSink for: " + outML); dsink = Manager.createDataSink(ds, outML); dsink.open(); } catch (Exception e) { System.err.println("Cannot create the DataSink: " + e); return null; } return dsink; } Object waitSync = new Object(); boolean stateTransitionOK = true; boolean waitForState(Processor p, int state) { synchronized (waitSync) { try { while (p.getState() < state && stateTransitionOK) waitSync.wait(); } catch (Exception e) {} } return stateTransitionOK; } public void controllerUpdate(ControllerEvent evt) { if (evt instanceof ConfigureCompleteEvent || evt instanceof RealizeCompleteEvent || evt instanceof PrefetchCompleteEvent) { synchronized (waitSync) { stateTransitionOK = true; waitSync.notifyAll(); } } else if (evt instanceof ResourceUnavailableEvent) { synchronized (waitSync) { stateTransitionOK = false; waitSync.notifyAll(); } } else if (evt instanceof EndOfMediaEvent) { evt.getSourceController().stop(); evt.getSourceController().close(); } } Object waitFileSync = new Object(); boolean fileDone = false; boolean fileSuccess = true; boolean waitForFileDone() { synchronized (waitFileSync) { try { while (!fileDone) waitFileSync.wait(); } catch (Exception e) {} } return fileSuccess; } public void dataSinkUpdate(DataSinkEvent evt) { if (evt instanceof EndOfStreamEvent) { synchronized (waitFileSync) { fileDone = true; waitFileSync.notifyAll(); } } else if (evt instanceof DataSinkErrorEvent) { synchronized (waitFileSync) { fileDone = true; fileSuccess = false; waitFileSync.notifyAll(); } } } public static void main(String args[]) { if (args.length == 0) prUsage(); // Parse the arguments. int i = 0; int width = -1, height = -1, frameRate = 1; Vector inputFiles = new Vector(); String outputURL = null; while (i < args.length) { if (args[i].equals("-w")) { i++; if (i >= args.length) prUsage(); width = new Integer(args[i]).intValue(); } else if (args[i].equals("-h")) { i++; if (i >= args.length) prUsage(); height = new Integer(args[i]).intValue(); } else if (args[i].equals("-f")) { i++; if (i >= args.length) prUsage(); frameRate = new Integer(args[i]).intValue(); } else if (args[i].equals("-o")) { i++; if (i >= args.length) prUsage(); outputURL = args[i]; } else { inputFiles.addElement(args[i]); } i++; } if (outputURL == null || inputFiles.size() == 0) prUsage(); // Check for output file extension. if (!outputURL.endsWith(".mov") && !outputURL.endsWith(".MOV")) { System.err.println("The output file extension should end with a .mov extension"); prUsage(); } if (width < 0 || height < 0) { System.err.println("Please specify the correct image size."); prUsage(); } // Check the frame rate. if (frameRate < 1) frameRate = 1; // Generate the output media locators. MediaLocator oml; if ((oml = createMediaLocator(outputURL)) == null) { System.err.println("Cannot build media locator from: " + outputURL); System.exit(0); } JpegImagesToMovie imageToMovie = new JpegImagesToMovie(); imageToMovie.doIt(width, height, frameRate, inputFiles, oml); System.exit(0); } static void prUsage() { System.err.println("Usage: java JpegImagesToMovie -w <width> -h <height> -f <frame rate> -o <output URL> <input JPEG file 1> <input JPEG file 2> ..."); System.exit(-1); } static MediaLocator createMediaLocator(String url) { MediaLocator ml; if (url.indexOf(":") > 0 && (ml = new MediaLocator(url)) != null) return ml; if (url.startsWith(File.separator)) { if ((ml = new MediaLocator("file:" + url)) != null) return ml; } else { String file = "file:" + System.getProperty("user.dir") + File.separator + url; if ((ml = new MediaLocator(file)) != null) return ml; } return null; } /////////////////////////////////////////////// // // Inner classes. /////////////////////////////////////////////// class ImageDataSource extends PullBufferDataSource { ImageSourceStream streams[]; ImageDataSource(int width, int height, int frameRate, Vector images) { streams = new ImageSourceStream[1]; streams[0] = new ImageSourceStream(width, height, frameRate, images); } public void setLocator(MediaLocator source) { } public MediaLocator getLocator() { return null; } public String getContentType() { return ContentDescriptor.RAW; } public void connect() { } public void disconnect() { } public void start() { } public void stop() { } public PullBufferStream[] getStreams() { return streams; } public Time getDuration() { return DURATION_UNKNOWN; } public Object[] getControls() { return new Object[0]; } public Object getControl(String type) { return null; } } class ImageSourceStream implements PullBufferStream { Vector images; int width, height; VideoFormat format; int nextImage = 0; // index of the next image to be read. boolean ended = false; public ImageSourceStream(int width, int height, int frameRate, Vector images) { this.width = width; this.height = height; this.images = images; format = new VideoFormat(VideoFormat.JPEG, new Dimension(width, height), Format.NOT_SPECIFIED, Format.byteArray, (float)frameRate); } public boolean willReadBlock() { return false; } public void read(Buffer buf) throws IOException { // Check if we've finished all the frames. if (nextImage >= images.size()) { // We are done. Set EndOfMedia. System.err.println("Done reading all images."); buf.setEOM(true); buf.setOffset(0); buf.setLength(0); ended = true; return; } String imageFile = (String)images.elementAt(nextImage); nextImage++; System.err.println(" - reading image file: " + imageFile); // Open a random access file for the next image. RandomAccessFile raFile; raFile = new RandomAccessFile(imageFile, "r"); byte data[] = null; // Check the input buffer type & size. if (buf.getData() instanceof byte[]) data = (byte[])buf.getData(); // Check to see the given buffer is big enough for the frame. if (data == null || data.length < raFile.length()) { data = new byte[(int)raFile.length()]; buf.setData(data); } // Read the entire JPEG image from the file. raFile.readFully(data, 0, (int)raFile.length()); System.err.println(" read " + raFile.length() + " bytes."); buf.setOffset(0); buf.setLength((int)raFile.length()); buf.setFormat(format); buf.setFlags(buf.getFlags() | buf.FLAG_KEY_frame); // Close the random access file. raFile.close(); } public Format getFormat() { return format; } public ContentDescriptor getContentDescriptor() { return new ContentDescriptor(ContentDescriptor.RAW); } public long getContentLength() { return 0; } public boolean endOfStream() { return ended; } public Object[] getControls() { return new Object[0]; } public Object getControl(String type) { return null; } }}


