/Users/lyon/j4p/src/video/NeuquantCapture.java
|
1 package video;
2
3 import futils.Futil;
4 import gui.In;
5 import gui.dialogs.ProgressDialog;
6 import ip.gif.neuquantAnimation.AnimatedGifEncoder;
7 import j2d.ImageUtils;
8
9 import java.awt.*;
10 import java.awt.image.BufferedImage;
11 import java.io.File;
12 import java.util.Vector;
13
14 /**
15 * Copyright DocJava, inc. User: lyon
16 * <p/>
17 * Date: Nov 26, 2004
18 * <p/>
19 * Time: 9:05:43 AM
20 */
21 public class NeuquantCapture {
22 public static void main(String[] args) {
23 streamScreenNeuquantImagesToAFile();
24 }
25
26 /**
27 * This is very memory efficient, and, if it works fast enough, it
28 * should be ok for your application. However, it is slow, for large
29 * images. Todo: build a nice interface, with a cool dialog Even though
30 * it is small in size, a rectangular area takes way too long to
31 * digitize in a stream. Generally around 3 or 4 seconds per image.
32 * Streaming generally results in an image that is 40k per image at
33 * 800x600. This is a 12:1 compression ratio. There is more work for
34 * the algorithm when the image changes more. A threaded stream for the
35 * output might be a good way to handle this.
36 */
37 public static void streamScreenNeuquantImagesToAFile() {
38 File f = Futil.getWriteFile("select gif output file");
39 Rectangle inputRect = ImageUtils.getScreenSize();
40
41 if (!In.getBoolean("capture whole screen?"))
42 inputRect = In.getRectangle("select active area");
43 int n = In.getInt("how many frames?");
44 long d = In.getInt("enter delay in ms");
45 AnimatedGifEncoder age = new AnimatedGifEncoder();
46 if (In.getBoolean("loop on playback?"))
47 age.setRepeat(0);
48 age.setDelay((int) d);
49 age.start(f.toString());
50 boolean isBuffered = In.getBoolean("buffer before save");
51 Dimension outputDim = getOutputSize(inputRect);
52 In.message("click to begin");
53
54 try {
55 neuquantImageStreamToAFile(d,
56 n,
57 inputRect,
58 outputDim,
59 age,
60 isBuffered);
61 } catch (AWTException e) {
62 e.printStackTrace();
63
64 }
65
66 age.finish();
67 System.out.println("done!");
68 In.message("done with capture");
69
70 }
71
72 private static Dimension getOutputSize(Rectangle inputRect) {
73 boolean b = In.getBoolean("would you to scale the output?");
74 Dimension output = new Dimension((int) inputRect.getWidth(),
75 (int) inputRect.getHeight());
76 if (!b) return output;
77 b = In.getBoolean("would you like fixed-size resampling?");
78 if (!b) {
79 Rectangle outputRect = In.getRectangle("select new output Height");
80 return new Dimension(-1, (int) outputRect.getHeight());
81 }
82 String options[] = {"1/2","1/4","1/8"};
83 String selected =
84 (String)In.multiPrompt(options,"scale width and height by","scale dialog");
85 int h = (int) inputRect.getHeight();
86 if (selected.equals("1/2")) h = h / 2;
87 if (selected.equals("1/4")) h = h / 4;
88 if (selected.equals("1/8")) h = h / 8;
89 return new Dimension(-1, h);
90 }
91
92 /**
93 * Call this method to save images to a file, slowly, compressing as we
94 * go. It is typical for the process to take 13 seconds per frame on a
95 * 800 Mhz mac. Wow.
96 *
97 * @param delayBetweenFrames used on playback. Also, if the capture
98 * program actually takes less time than the
99 * delay, it will add the different to the
100 * sleep time between frames.
101 * @param numberOfFrames total number of frames to capture
102 * @param inputRect size of the capture area.
103 * @param age neuquant codec.
104 * @throws java.awt.AWTException
105 */
106 public static void neuquantImageStreamToAFile(long delayBetweenFrames,
107 int numberOfFrames,
108 Rectangle inputRect,
109 Dimension outputDim,
110 AnimatedGifEncoder age,
111 boolean isBuffered)
112 throws AWTException {
113 Robot robot = new Robot();
114 long delta = 0;
115 long now = 0;
116 BufferedImage bi = null;
117 Vector v = new Vector();
118 for (int i = 0; i < numberOfFrames; i++) {
119 now = System.currentTimeMillis();
120
121 bi = grabScreen(robot, inputRect);
122 bi =
123 ImageUtils.scaleFast(bi,
124 outputDim.width,
125 outputDim.height);
126 if (isBuffered)
127 v.addElement(bi);
128 else
129 addImageToEncoder(age, bi);
130 delta = delayBetweenFrames -
131 (System.currentTimeMillis() - now);
132 System.out.println("delta is" + delta);
133 if (delta < 0) continue; // can't keep up!
134 sleep(delta);
135 }
136 if (isBuffered) {
137 ProgressDialog pd = new ProgressDialog();
138 pd.setTitle("saving images...");
139 pd.setVisible(true);
140 final int n = v.size();
141 for (int i = 0; i < n; i++) {
142 pd.setValue(i * 100 / n);
143 addImageToEncoder(age, (BufferedImage) v.elementAt(i));
144 }
145 pd.setVisible(false);
146 }
147 }
148
149 private static void addImageToEncoder(AnimatedGifEncoder age,
150 BufferedImage bi) {
151 long now = System.currentTimeMillis();
152 if (age.addFrame(bi) == false)
153 In.message("problem adding image");
154 long delay = System.currentTimeMillis() - now;
155 System.out.println("screen encoding took:" + delay);
156 }
157
158 public static BufferedImage grabScreen(Robot robot, Rectangle rect) {
159 BufferedImage bi;
160 long now = System.currentTimeMillis();
161 bi = robot.createScreenCapture(rect);
162 long delay = System.currentTimeMillis() - now;
163 System.out.println("screen capture took:" + delay);
164 return bi;
165 }
166
167 /**
168 * @param d the number of seconds to sleep.
169 */
170 public static void sleep(long d) {
171 try {
172 Thread.sleep(d);
173 } catch (InterruptedException e) {
174 e.printStackTrace();
175
176 }
177
178 }
179 }
180