Source code: com/anotherbigidea/flash/movie/Movie.java
1 /****************************************************************
2 * Copyright (c) 2001, David N. Main, All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the
6 * following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 *
17 * 3. The name of the author may not be used to endorse or
18 * promote products derived from this software without specific
19 * prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ****************************************************************/
34 package com.anotherbigidea.flash.movie;
35
36 import java.io.*;
37 import java.util.*;
38 import com.anotherbigidea.flash.*;
39 import com.anotherbigidea.flash.interfaces.*;
40 import com.anotherbigidea.flash.writers.*;
41 import com.anotherbigidea.flash.readers.*;
42 import com.anotherbigidea.flash.structs.*;
43
44 /**
45 * A Flash Movie
46 */
47 public class Movie implements TimeLine
48 {
49 protected int width;
50 protected int height;
51 protected int frameRate;
52 protected Color backColor;
53 protected int version;
54 protected boolean isProtected;
55
56 protected Map importLibraries;
57 protected Vector exportedSymbols;
58
59 protected SortedMap frames = new TreeMap();
60 protected int frameCount = 0;
61
62 //--Table of characters defined so far in the movie - while writing out
63 protected HashMap definedSymbols = new HashMap();
64
65 protected int depth = 1; //the next available depth
66 protected int maxId = 1; //the next available symbol id
67
68 /**
69 * Create a movie with the default values -
70 * (550x400), 12 frames/sec, white backcolor, Flash version 5.
71 */
72 public Movie()
73 {
74 width = 550;
75 height = 400;
76 frameRate = 12;
77 version = 5;
78 }
79
80 /**
81 * Create a movie with the given properties
82 */
83 public Movie( int width, int height, int frameRate, int version, Color backColor )
84 {
85 this.width = width;
86 this.height = height;
87 this.frameRate = frameRate;
88 this.version = version;
89 this.backColor = backColor;
90 }
91
92 public int getWidth () { return width; }
93 public int getHeight () { return height; }
94 public int getFrameRate() { return frameRate; }
95 public int getVersion () { return version; }
96 public Color getBackColor() { return backColor; }
97
98 public void setWidth ( int width ) { this.width = width; }
99 public void setHeight ( int height ) { this.height = height; }
100 public void setFrameRate( int rate ) { this.frameRate = rate; }
101 public void setVersion ( int version ) { this.version = version; }
102 public void setBackColor( Color color ) { this.backColor = color; }
103
104 /**
105 * Return the protection flag. If true then the movie cannot be imported
106 * into the Flash Author. The existence of tools such as JavaSWF makes
107 * this kind of protection almost worthless.
108 */
109 public boolean isProtected() { return isProtected; }
110
111 public void protect( boolean isProtected ) { this.isProtected = isProtected; }
112
113 /**
114 * Get the current number of frames in the timeline.
115 */
116 public int getFrameCount()
117 {
118 return frameCount;
119 }
120
121 /**
122 * Get the Frame object for the given frame number - or create one if
123 * none exists. If the frame number is larger than the current frame count
124 * then the frame count is increased.
125 *
126 * @param frameNumber must be 1 or larger
127 */
128 public Frame getFrame( int frameNumber )
129 {
130 if( frameNumber < 1 ) return null;
131
132 Integer num = new Integer( frameNumber );
133 Frame frame = (Frame)frames.get( num );
134
135 if( frame == null )
136 {
137 frame = new Frame( frameNumber, this );
138 frames.put( num, frame );
139 if( frameNumber > frameCount ) frameCount = frameNumber;
140 }
141
142 return frame;
143 }
144
145 /**
146 * Append a frame to the end of the timeline
147 */
148 public Frame appendFrame()
149 {
150 frameCount++;
151 Frame frame = new Frame( frameCount, this );
152 frames.put( new Integer(frameCount), frame );
153 return frame;
154 }
155
156 /**
157 * Get the next available depth in the timeline
158 */
159 public int getAvailableDepth()
160 {
161 return depth;
162 }
163
164 /**
165 * Set the next available depth in the timeline
166 * @param depth must be >= 1
167 */
168 public void setAvailableDepth( int depth )
169 {
170 if( depth < 1 ) return;
171 this.depth = depth;
172 }
173
174 /**
175 * Import symbols from another movie (Flash 5 only)
176 * @return Symbols representing the imports
177 */
178 public ImportedSymbol[] importSymbols( String libraryName, String[] symbolNames )
179 {
180 if( importLibraries == null ) importLibraries = new HashMap();
181
182 ArrayList imports = (ArrayList)importLibraries.get( libraryName );
183 if( imports == null )
184 {
185 imports = new ArrayList();
186 importLibraries.put( libraryName, imports );
187 }
188
189 ImportedSymbol[] symbols = new ImportedSymbol[ symbolNames.length ];
190
191 for( int i = 0; i < symbolNames.length; i++ )
192 {
193 ImportedSymbol imp = new ImportedSymbol( 0, symbolNames[i], libraryName );
194 symbols[i] = imp;
195 imports.add( imp );
196 }
197
198 return symbols;
199 }
200
201 /**
202 * Clear all the defined library imports
203 */
204 public void clearImports()
205 {
206 if( importLibraries != null ) importLibraries.clear();
207 }
208
209 /**
210 * Access the imported symbols.
211 * @return an empty array if there are no imports
212 */
213 public ImportedSymbol[] getImportedSymbols()
214 {
215 if( importLibraries == null ) return new ImportedSymbol[0];
216
217 Vector imports = new Vector();
218
219 for( Iterator iter = importLibraries.values().iterator(); iter.hasNext(); )
220 {
221 List list = (List)iter.next();
222
223 for( Iterator i2 = list.iterator(); i2.hasNext(); )
224 {
225 imports.add( i2.next() );
226 }
227 }
228
229 ImportedSymbol[] imps = new ImportedSymbol[ imports.size() ];
230 imports.copyInto( imps );
231
232 return imps;
233 }
234
235 /**
236 * Export a number of symbols with the given names so that other movies
237 * can import and use them. Flash version 5 only.
238 */
239 public void exportSymbols( String[] exportNames, Symbol[] symbols )
240 {
241 if( exportedSymbols == null ) exportedSymbols = new Vector();
242
243 for( int i = 0; i < exportNames.length && i < symbols.length; i++ )
244 {
245 exportedSymbols.add( new ExportedSymbol( symbols[i], exportNames[i] ));
246 }
247 }
248
249 /**
250 * Get the symbols exported from the movie
251 * @return an empty array if there are no exports
252 */
253 public ExportedSymbol[] getExportedSymbols()
254 {
255 if( exportedSymbols == null ) return new ExportedSymbol[0];
256
257 ExportedSymbol[] exports = new ExportedSymbol[ exportedSymbols.size() ];
258
259 exportedSymbols.copyInto( exports );
260
261 return exports;
262 }
263
264 /**
265 * Clear all the symbol exports
266 */
267 public void clearExports()
268 {
269 if( exportedSymbols != null ) exportedSymbols.clear();
270 }
271
272 /**
273 * Write the movie in SWF format.
274 */
275 public void write( SWFTagTypes tagwriter ) throws IOException
276 {
277 //--Reset state
278 definedSymbols.clear();
279 maxId = 1;
280
281 tagwriter.header( version,
282 -1, //force length calculation
283 width * SWFConstants.TWIPS,
284 height * SWFConstants.TWIPS,
285 frameRate,
286 -1); //force frame calculation
287
288 //default backColor is white
289 if( backColor == null ) backColor = new Color(255,255,255);
290
291 tagwriter.tagSetBackgroundColor( backColor );
292
293 if( isProtected ) tagwriter.tagProtect( null );
294
295 //--Process Imports
296 if( importLibraries != null && ! importLibraries.isEmpty() )
297 {
298 for( Iterator keys = importLibraries.keySet().iterator(); keys.hasNext();)
299 {
300 String libName = (String)keys.next();
301 List imports = (List)importLibraries.get( libName );
302
303 String[] names = new String[imports.size()];
304 int[] ids = new int[imports.size()];
305
306 int i = 0;
307 for( Iterator it = imports.iterator(); it.hasNext(); )
308 {
309 ImportedSymbol imp = (ImportedSymbol)it.next();
310
311 names[i] = imp.getName();
312 ids[i] = imp.define( this, tagwriter, tagwriter );
313
314 i++;
315 }
316
317 tagwriter.tagImport( libName, names, ids );
318 }
319 }
320
321 //--Process Exports
322 if( exportedSymbols != null && ! exportedSymbols.isEmpty() )
323 {
324 String[] names = new String[exportedSymbols.size()];
325 int[] ids = new int[exportedSymbols.size()];
326
327 int i = 0;
328 for( Iterator it = exportedSymbols.iterator(); it.hasNext(); )
329 {
330 ExportedSymbol exp = (ExportedSymbol)it.next();
331
332 names[i] = exp.getExportName();
333 ids[i] = exp.getSymbol().define( this, tagwriter, tagwriter );
334
335 i++;
336 }
337
338 tagwriter.tagExport( names, ids );
339 }
340
341 int lastFrame = 0;
342 for( Iterator iter = frames.values().iterator(); iter.hasNext(); )
343 {
344 Frame frame = (Frame)iter.next();
345
346 int number = frame.getFrameNumber();
347
348 //write any intermediate empty frames
349 while( number > lastFrame + 1 )
350 {
351 tagwriter.tagShowFrame();
352 lastFrame++;
353 }
354
355 frame.write( this, tagwriter, tagwriter );
356
357 lastFrame = number;
358 }
359
360 //end of time line
361 tagwriter.tagEnd();
362 }
363
364 /**
365 * Write the movie in uncompressed SWF format to the given file.
366 */
367 public void write( String filename ) throws IOException {
368 write( filename, false );
369 }
370
371 /**
372 * Write the movie in uncompressed SWF format to the given output stream.
373 */
374 public void write( OutputStream out ) throws IOException {
375 write( out, false );
376 }
377
378 /**
379 * Write the movie in SWF format to the given file.
380 *
381 * @param compressed true for Flash MX+ compression.
382 */
383 public void write( String filename, boolean compressed ) throws IOException {
384 SWFWriter swfwriter = new SWFWriter( filename );
385 TagWriter tagwriter = new TagWriter( swfwriter );
386 swfwriter.setCompression( compressed );
387 write( tagwriter );
388 }
389
390 /**
391 * Write the movie in SWF format to the given output stream.
392 *
393 * @param compressed true for Flash MX+ compression.
394 */
395 public void write( OutputStream out, boolean compressed ) throws IOException {
396 SWFWriter swfwriter = new SWFWriter( out );
397 TagWriter tagwriter = new TagWriter( swfwriter );
398 swfwriter.setCompression( compressed );
399 write( tagwriter );
400 }
401
402
403 }