/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