1 /*
2
3 dsh-piccolo-sprite Piccolo2D sprite nodes and supporting classes.
4 Copyright (c) 2006-2013 held jointly by the individual authors.
5
6 This library is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 3 of the License, or (at
9 your option) any later version.
10
11 This library is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this library; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19
20 > http://www.fsf.org/licensing/licenses/lgpl.html
21 > http://www.opensource.org/licenses/lgpl-license.php
22
23 */
24 package org.dishevelled.piccolo.sprite;
25
26 import java.awt.Graphics2D;
27 import java.awt.Image;
28 import java.awt.RenderingHints;
29
30 import java.awt.image.BufferedImage;
31
32 import java.awt.geom.AffineTransform;
33
34 import java.io.File;
35 import java.io.InputStream;
36 import java.io.IOException;
37
38 import java.net.MalformedURLException;
39 import java.net.URL;
40
41 import java.util.ArrayList;
42 import java.util.Collections;
43 import java.util.List;
44
45 import javax.imageio.ImageIO;
46
47 /**
48 * Static utility methods for creating animations.
49 *
50 * @author Michael Heuer
51 * @version $Revision$ $Date$
52 */
53 public final class Animations
54 {
55
56 /**
57 * Private no-arg constructor.
58 */
59 private Animations()
60 {
61 // empty
62 }
63
64
65 // single frame animations
66
67 /**
68 * Create and return a new single frame animation from the specified image input stream.
69 *
70 * @param image image input stream
71 * @return a new single frame animation from the specified image
72 * @throws IOException if an IO error occurs
73 */
74 public static SingleFrameAnimation createAnimation(final InputStream image)
75 throws IOException
76 {
77 BufferedImage bufferedImage = ImageIO.read(image);
78 return createAnimation(bufferedImage);
79 }
80
81 /**
82 * Create and return a new single frame animation from the specified image file.
83 *
84 * @param image image file
85 * @return a new single frame animation from the specified image
86 * @throws IOException if an IO error occurs
87 */
88 public static SingleFrameAnimation createAnimation(final File image)
89 throws IOException
90 {
91 BufferedImage bufferedImage = ImageIO.read(image);
92 return createAnimation(bufferedImage);
93 }
94
95 /**
96 * Create and return a new single frame animation from the specified image URL.
97 *
98 * @param image image URL
99 * @return a new single frame animation from the specified image
100 * @throws IOException if an IO error occurs
101 */
102 public static SingleFrameAnimation createAnimation(final URL image)
103 throws IOException
104 {
105 BufferedImage bufferedImage = ImageIO.read(image);
106 return createAnimation(bufferedImage);
107 }
108
109 /**
110 * Create and return a new single frame animation from the specified image.
111 *
112 * @param image image
113 * @return a new single frame animation from the specified image
114 */
115 public static SingleFrameAnimation createAnimation(final Image image)
116 {
117 return new SingleFrameAnimation(image);
118 }
119
120
121 // multiple frame animations from base image
122
123 /**
124 * Create and return a new multiple frames animation containing all the frame images
125 * specified from <code>baseImage</code>.
126 *
127 * @param baseImage base image file or URL name
128 * @param suffix image suffix
129 * @param frames number of frames
130 * @return a new multiple frames animation containing all the frame images
131 * specified from <code>baseImage</code>
132 * @throws IOException if an IO error occurs
133 */
134 public static MultipleFramesAnimation createAnimation(final String baseImage, final String suffix, final int frames)
135 throws IOException
136 {
137 return new MultipleFramesAnimation(createFrameList(baseImage, suffix, frames));
138 }
139
140 /**
141 * Create and return a new multiple frames animation containing all the frame images
142 * specified from <code>baseImage</code>.
143 *
144 * @param baseImage base image file
145 * @param suffix image suffix
146 * @param frames number of frames
147 * @return a new multiple frames animation containing all the frame images
148 * specified from <code>baseImage</code>
149 * @throws IOException if an IO error occurs
150 */
151 public static MultipleFramesAnimation createAnimation(final File baseImage, final String suffix, final int frames)
152 throws IOException
153 {
154 return new MultipleFramesAnimation(createFrameList(baseImage, suffix, frames));
155 }
156
157 /**
158 * Create and return a new multiple frames animation containing all the frame images
159 * specified from <code>baseImage</code>.
160 *
161 * @param baseImage base image URL
162 * @param suffix image suffix
163 * @param frames number of frames
164 * @return a new multiple frames animation containing all the frame images
165 * specified from <code>baseImage</code>
166 * @throws IOException if an IO error occurs
167 */
168 public static MultipleFramesAnimation createAnimation(final URL baseImage, final String suffix, final int frames)
169 throws IOException
170 {
171 return new MultipleFramesAnimation(createFrameList(baseImage, suffix, frames));
172 }
173
174
175 // looped frame animations from base image
176
177 /**
178 * Create and return a new looped frames animation containing all the frame images
179 * specified from <code>baseImage</code>.
180 *
181 * @param baseImage base image file or URL name
182 * @param suffix image suffix
183 * @param frames number of frames
184 * @return a new looped frames animation containing all the frame images
185 * specified from <code>baseImage</code>
186 * @throws IOException if an IO error occurs
187 */
188 public static LoopedFramesAnimation createLoopedAnimation(final String baseImage,
189 final String suffix,
190 final int frames)
191 throws IOException
192 {
193 return new LoopedFramesAnimation(createFrameList(baseImage, suffix, frames));
194 }
195
196 /**
197 * Create and return a new looped frames animation containing all the frame images
198 * specified from <code>baseImage</code>.
199 *
200 * @param baseImage base image file
201 * @param suffix image suffix
202 * @param frames number of frames
203 * @return a new looped frames animation containing all the frame images
204 * specified from <code>baseImage</code>
205 * @throws IOException if an IO error occurs
206 */
207 public static LoopedFramesAnimation createLoopedAnimation(final File baseImage,
208 final String suffix,
209 final int frames)
210 throws IOException
211 {
212 return new LoopedFramesAnimation(createFrameList(baseImage, suffix, frames));
213 }
214
215 /**
216 * Create and return a new looped frames animation containing all the frame images
217 * specified from <code>baseImage</code>.
218 *
219 * @param baseImage base image URL
220 * @param suffix image suffix
221 * @param frames number of frames
222 * @return a new looped frames animation containing all the frame images
223 * specified from <code>baseImage</code>
224 * @throws IOException if an IO error occurs
225 */
226 public static LoopedFramesAnimation createLoopedAnimation(final URL baseImage,
227 final String suffix,
228 final int frames)
229 throws IOException
230 {
231 return new LoopedFramesAnimation(createFrameList(baseImage, suffix, frames));
232 }
233
234
235 // multiple frame animations from sprite sheet
236
237 /**
238 * Create and return a new multiple frames animation containing all the frame images
239 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
240 * and read horizontally the specified number of frames.
241 *
242 * @param spriteSheet sprite sheet input stream
243 * @param x starting location x
244 * @param y starting location y
245 * @param width frame width
246 * @param height frame height
247 * @param frames number of frames
248 * @return a new multiple frames animation containing all the frame images
249 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
250 * and read horizontally the specified number of frames
251 * @throws IOException if an IO error occurs
252 */
253 public static MultipleFramesAnimation createAnimation(final InputStream spriteSheet, final int x, final int y,
254 final int width, final int height, final int frames)
255 throws IOException
256 {
257 return new MultipleFramesAnimation(createFrameList(spriteSheet, x, y, width, height, frames));
258 }
259
260 /**
261 * Create and return a new multiple frames animation containing all the frame images
262 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
263 * and read horizontally the specified number of frames.
264 *
265 * @param spriteSheet sprite sheet file
266 * @param x starting location x
267 * @param y starting location y
268 * @param width frame width
269 * @param height frame height
270 * @param frames number of frames
271 * @return a new multiple frames animation containing all the frame images
272 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
273 * and read horizontally the specified number of frames
274 * @throws IOException if an IO error occurs
275 */
276 public static MultipleFramesAnimation createAnimation(final File spriteSheet, final int x, final int y,
277 final int width, final int height, final int frames)
278 throws IOException
279 {
280 return new MultipleFramesAnimation(createFrameList(spriteSheet, x, y, width, height, frames));
281 }
282
283 /**
284 * Create and return a new multiple frames animation containing all the frame images
285 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
286 * and read horizontally the specified number of frames.
287 *
288 * @param spriteSheet sprite sheet URL
289 * @param x starting location x
290 * @param y starting location y
291 * @param width frame width
292 * @param height frame height
293 * @param frames number of frames
294 * @return a new multiple frames animation containing all the frame images
295 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
296 * and read horizontally the specified number of frames
297 * @throws IOException if an IO error occurs
298 */
299 public static MultipleFramesAnimation createAnimation(final URL spriteSheet, final int x, final int y,
300 final int width, final int height, final int frames)
301 throws IOException
302 {
303 return new MultipleFramesAnimation(createFrameList(spriteSheet, x, y, width, height, frames));
304 }
305
306 /**
307 * Create and return a new multiple frames animation containing all the frame images
308 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
309 * and read horizontally the specified number of frames.
310 *
311 * @param spriteSheet sprite sheet image
312 * @param x starting location x
313 * @param y starting location y
314 * @param width frame width
315 * @param height frame height
316 * @param frames number of frames
317 * @return a new multiple frames animation containing all the frame images
318 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
319 * and read horizontally the specified number of frames
320 */
321 public static MultipleFramesAnimation createAnimation(final BufferedImage spriteSheet, final int x, final int y,
322 final int width, final int height, final int frames)
323 {
324 return new MultipleFramesAnimation(createFrameList(spriteSheet, x, y, width, height, frames));
325 }
326
327
328 // looped frame animations from sprite sheet
329
330 /**
331 * Create and return a new looped frames animation containing all the frame images
332 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
333 * and read horizontally the specified number of frames.
334 *
335 * @param spriteSheet sprite sheet input stream
336 * @param x starting location x
337 * @param y starting location y
338 * @param width frame width
339 * @param height frame height
340 * @param frames number of frames
341 * @return a new looped frames animation containing all the frame images
342 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
343 * and read horizontally the specified number of frames
344 * @throws IOException if an IO error occurs
345 */
346 public static LoopedFramesAnimation createLoopedAnimation(final InputStream spriteSheet, final int x, final int y,
347 final int width, final int height, final int frames)
348 throws IOException
349 {
350 return new LoopedFramesAnimation(createFrameList(spriteSheet, x, y, width, height, frames));
351 }
352
353 /**
354 * Create and return a new looped frames animation containing all the frame images
355 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
356 * and read horizontally the specified number of frames.
357 *
358 * @param spriteSheet sprite sheet file
359 * @param x starting location x
360 * @param y starting location y
361 * @param width frame width
362 * @param height frame height
363 * @param frames number of frames
364 * @return a new looped frames animation containing all the frame images
365 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
366 * and read horizontally the specified number of frames
367 * @throws IOException if an IO error occurs
368 */
369 public static LoopedFramesAnimation createLoopedAnimation(final File spriteSheet, final int x, final int y,
370 final int width, final int height, final int frames)
371 throws IOException
372 {
373 return new LoopedFramesAnimation(createFrameList(spriteSheet, x, y, width, height, frames));
374 }
375
376 /**
377 * Create and return a new looped frames animation containing all the frame images
378 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
379 * and read horizontally the specified number of frames.
380 *
381 * @param spriteSheet sprite sheet URL
382 * @param x starting location x
383 * @param y starting location y
384 * @param width frame width
385 * @param height frame height
386 * @param frames number of frames
387 * @return a new looped frames animation containing all the frame images
388 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
389 * and read horizontally the specified number of frames
390 * @throws IOException if an IO error occurs
391 */
392 public static LoopedFramesAnimation createLoopedAnimation(final URL spriteSheet, final int x, final int y,
393 final int width, final int height, final int frames)
394 throws IOException
395 {
396 return new LoopedFramesAnimation(createFrameList(spriteSheet, x, y, width, height, frames));
397 }
398
399 /**
400 * Create and return a new looped frames animation containing all the frame images
401 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
402 * and read horizontally the specified number of frames.
403 *
404 * @param spriteSheet sprite sheet image
405 * @param x starting location x
406 * @param y starting location y
407 * @param width frame width
408 * @param height frame height
409 * @param frames number of frames
410 * @return a new looped frames animation containing all the frame images
411 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
412 * and read horizontally the specified number of frames
413 */
414 public static LoopedFramesAnimation createLoopedAnimation(final BufferedImage spriteSheet, final int x, final int y,
415 final int width, final int height, final int frames)
416 {
417 return new LoopedFramesAnimation(createFrameList(spriteSheet, x, y, width, height, frames));
418 }
419
420
421 // multiple frame animations from frame list
422
423 /**
424 * Create and return a new multiple frames animation containing the specified frame images.
425 *
426 * @param images list of frame images, must not be null
427 * @return a new multiple frames animation containing the specified frame images
428 */
429 public static MultipleFramesAnimation createAnimation(final List<Image> images)
430 {
431 return new MultipleFramesAnimation(images);
432 }
433
434
435 // looped frame animations from frame list
436
437 /**
438 * Create and return a new looped frames animation containing the specified frame images.
439 *
440 * @param images list of frame images, must not be null
441 * @return a new looped frames animation containing the specified frame images
442 */
443 public static LoopedFramesAnimation createLoopedAnimation(final List<Image> images)
444 {
445 return new LoopedFramesAnimation(images);
446 }
447
448
449 // create frame lists
450
451 /**
452 * Create and return an unmodifiable list of images containing all the frame images
453 * specified from <code>baseImage</code>.
454 *
455 * @param baseImage base image file or URL name
456 * @param suffix image suffix
457 * @param frames number of frames
458 * @return a new unmodifiable list of images containing all the frame images
459 * specified from <code>baseImage</code>
460 * @throws IOException if an IO error occurs
461 */
462 public static List<Image> createFrameList(final String baseImage, final String suffix, final int frames)
463 throws IOException
464 {
465 if (baseImage == null)
466 {
467 throw new IllegalArgumentException("baseImage must not be null");
468 }
469 List<Image> frameList = null;
470 try
471 {
472 frameList = createFrameList(new URL(baseImage), suffix, frames);
473 }
474 catch (MalformedURLException e)
475 {
476 frameList = createFrameList(new File(baseImage), suffix, frames);
477 }
478 return frameList;
479 }
480
481 /**
482 * Create and return an unmodifiable list of images containing all the frame images
483 * specified from <code>baseImage</code>.
484 *
485 * @param baseImage base image file
486 * @param suffix image suffix
487 * @param frames number of frames
488 * @return a new unmodifiable list of images containing all the frame images
489 * specified from <code>baseImage</code>
490 * @throws IOException if an IO error occurs
491 */
492 public static List<Image> createFrameList(final File baseImage, final String suffix, final int frames)
493 throws IOException
494 {
495 if (baseImage == null)
496 {
497 throw new IllegalArgumentException("baseImage must not be null");
498 }
499 int leadingZeros = (int) (frames / 10) + 1; // is this math correct?
500 String format = "%s%0" + leadingZeros + "d%s";
501 List<Image> images = new ArrayList<Image>(frames);
502 for (int frame = 0; frame < frames; frame++)
503 {
504 File file = new File(String.format(format, new Object[] { baseImage.getPath(), frame, suffix }));
505 Image image = ImageIO.read(file);
506 images.add(image);
507 }
508 return Collections.unmodifiableList(images);
509 }
510
511 /**
512 * Create and return an unmodifiable list of images containing all the frame images
513 * specified from <code>baseImage</code>.
514 *
515 * @param baseImage base image URL
516 * @param suffix image suffix
517 * @param frames number of frames
518 * @return a new unmodifiable list of images containing all the frame images
519 * specified from <code>baseImage</code>
520 * @throws IOException if an IO error occurs
521 */
522 public static List<Image> createFrameList(final URL baseImage, final String suffix, final int frames)
523 throws IOException
524 {
525 if (baseImage == null)
526 {
527 throw new IllegalArgumentException("baseImage must not be null");
528 }
529 int leadingZeros = (int) (frames / 10) + 1; // is this math correct?
530 String format = "%s%0" + leadingZeros + "d%s";
531 List<Image> images = new ArrayList<Image>(frames);
532 for (int frame = 0; frame < frames; frame++)
533 {
534 URL url = new URL(String.format(format, new Object[] { baseImage.getPath(), frame, suffix }));
535 Image image = ImageIO.read(url);
536 images.add(image);
537 }
538 return Collections.unmodifiableList(images);
539 }
540
541 /**
542 * Create and return an unmodifiable list of frame images containing all the frame images
543 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
544 * and read horizontally the specified number of frames.
545 *
546 * @param spriteSheet sprite sheet input stream
547 * @param x starting location x
548 * @param y starting location y
549 * @param width frame width
550 * @param height frame height
551 * @param frames number of frames
552 * @return an unmodifiable list of frame images containing all the frame images
553 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
554 * and read horizontally the specified number of frames
555 * @throws IOException if an IO error occurs
556 */
557 public static List<Image> createFrameList(final InputStream spriteSheet, final int x, final int y,
558 final int width, final int height, final int frames)
559 throws IOException
560 {
561 BufferedImage bufferedImage = ImageIO.read(spriteSheet);
562 return createFrameList(bufferedImage, x, y, width, height, frames);
563 }
564
565 /**
566 * Create and return an unmodifiable list of frame images containing all the frame images
567 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
568 * and read horizontally the specified number of frames.
569 *
570 * @param spriteSheet sprite sheet file
571 * @param x starting location x
572 * @param y starting location y
573 * @param width frame width
574 * @param height frame height
575 * @param frames number of frames
576 * @return an unmodifiable list of frame images containing all the frame images
577 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
578 * and read horizontally the specified number of frames
579 * @throws IOException if an IO error occurs
580 */
581 public static List<Image> createFrameList(final File spriteSheet, final int x, final int y,
582 final int width, final int height, final int frames)
583 throws IOException
584 {
585 BufferedImage bufferedImage = ImageIO.read(spriteSheet);
586 return createFrameList(bufferedImage, x, y, width, height, frames);
587 }
588
589 /**
590 * Create and return an unmodifiable list of frame images containing all the frame images
591 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
592 * and read horizontally the specified number of frames.
593 *
594 * @param spriteSheet sprite sheet file
595 * @param x starting location x
596 * @param y starting location y
597 * @param width frame width
598 * @param height frame height
599 * @param frames number of frames
600 * @return an unmodifiable list of frame images containing all the frame images
601 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
602 * and read horizontally the specified number of frames
603 * @throws IOException if an IO error occurs
604 */
605 public static List<Image> createFrameList(final URL spriteSheet, final int x, final int y,
606 final int width, final int height, final int frames)
607 throws IOException
608 {
609 BufferedImage bufferedImage = ImageIO.read(spriteSheet);
610 return createFrameList(bufferedImage, x, y, width, height, frames);
611 }
612
613 /**
614 * Create and return an unmodifiable list of frame images containing all the frame images
615 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
616 * and read horizontally the specified number of frames.
617 *
618 * @param spriteSheet sprite sheet image
619 * @param x starting location x
620 * @param y starting location y
621 * @param width frame width
622 * @param height frame height
623 * @param frames number of frames
624 * @return an unmodifiable list of frame images containing all the frame images
625 * from <code>spriteSheet</code> as specified by the starting location <code>(x, y)</code>
626 * and read horizontally the specified number of frames
627 */
628 public static List<Image> createFrameList(final BufferedImage spriteSheet, final int x, final int y,
629 final int width, final int height, final int frames)
630 {
631 if (spriteSheet == null)
632 {
633 throw new IllegalArgumentException("spriteSheet must not be null");
634 }
635 List<Image> images = new ArrayList<Image>(frames);
636 for (int frame = 0; frame < frames; frame++)
637 {
638 Image subimage = spriteSheet.getSubimage(x + (frame * width), y, width, height);
639 images.add(subimage);
640 }
641 return Collections.unmodifiableList(images);
642 }
643
644
645 // sprite sheet utility methods
646
647 /**
648 * Create and return a new sprite sheet image containing all of the specified frame images
649 * assembled horizontally.
650 *
651 * @param frameImages frame images, must not be null
652 * @return a new sprite sheet image containing all of the specified frame images
653 * assembled horizontally
654 */
655 public static BufferedImage createSpriteSheet(final List<Image> frameImages)
656 {
657 if (frameImages == null)
658 {
659 throw new IllegalArgumentException("frameImages must not be null");
660 }
661 int width = 0;
662 int height = 0;
663 for (Image image : frameImages)
664 {
665 if (image.getWidth(null) > width)
666 {
667 width = image.getWidth(null);
668 }
669 if (image.getHeight(null) > height)
670 {
671 height = image.getHeight(null);
672 }
673 }
674 BufferedImage spriteSheet = new BufferedImage(width * frameImages.size(), height, BufferedImage.TYPE_INT_ARGB);
675 Graphics2D graphics = spriteSheet.createGraphics();
676 graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
677 for (int i = 0, size = frameImages.size(); i < size; i++)
678 {
679 Image image = frameImages.get(i);
680 int x = width * i + (width / 2) - (image.getWidth(null) / 2);
681 int y = (height / 2) - (image.getHeight(null) / 2);
682 graphics.drawImage(image, x, y, null);
683 }
684 graphics.dispose();
685 return spriteSheet;
686 }
687
688 /**
689 * Create and return a new sprite sheet image containing all of the specified frame images
690 * specified from <code>baseImage</code> assembled horizontally.
691 *
692 * @param baseImage base image file or URL name
693 * @param suffix image suffix
694 * @param frames number of frames
695 * @return a new sprite sheet image containing all of the specified frame images
696 * specified from <code>baseImage</code> assembled horizontally
697 * @throws IOException if an IO error occurs
698 */
699 public static BufferedImage createSpriteSheet(final String baseImage, final String suffix, final int frames)
700 throws IOException
701 {
702 return createSpriteSheet(createFrameList(baseImage, suffix, frames));
703 }
704
705 /**
706 * Create and return a new sprite sheet image containing all of the specified frame images
707 * specified from <code>baseImage</code> assembled horizontally.
708 *
709 * @param baseImage base image file
710 * @param suffix image suffix
711 * @param frames number of frames
712 * @return a new sprite sheet image containing all of the specified frame images
713 * specified from <code>baseImage</code> assembled horizontally
714 * @throws IOException if an IO error occurs
715 */
716 public static BufferedImage createSpriteSheet(final File baseImage, final String suffix, final int frames)
717 throws IOException
718 {
719 return createSpriteSheet(createFrameList(baseImage, suffix, frames));
720 }
721
722 /**
723 * Create and return a new sprite sheet image containing all of the specified frame images
724 * specified from <code>baseImage</code> assembled horizontally.
725 *
726 * @param baseImage base image URL
727 * @param suffix image suffix
728 * @param frames number of frames
729 * @return a new sprite sheet image containing all of the specified frame images
730 * specified from <code>baseImage</code> assembled horizontally
731 * @throws IOException if an IO error occurs
732 */
733 public static BufferedImage createSpriteSheet(final URL baseImage, final String suffix, final int frames)
734 throws IOException
735 {
736 return createSpriteSheet(createFrameList(baseImage, suffix, frames));
737 }
738
739 /**
740 * Create and return an unmodifiable list of frame images containing all the frame images
741 * from <code>frameImages</code> in the same order flipped horizontally.
742 *
743 * @param frameImages list of frame images, must not be null
744 * @return an unmodifiable list of frame images containing all the frame images
745 * from <code>frameImages</code> in the same order flipped horizontally
746 */
747 public static List<Image> flipHorizontally(final List<Image> frameImages)
748 {
749 if (frameImages == null)
750 {
751 throw new IllegalArgumentException("frameImages must not be null");
752 }
753 int width = 0;
754 int height = 0;
755 for (Image image : frameImages)
756 {
757 if (image.getWidth(null) > width)
758 {
759 width = image.getWidth(null);
760 }
761 if (image.getHeight(null) > height)
762 {
763 height = image.getHeight(null);
764 }
765 }
766 BufferedImage spriteSheet = new BufferedImage(width * frameImages.size(), height, BufferedImage.TYPE_INT_ARGB);
767 Graphics2D graphics = spriteSheet.createGraphics();
768 graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
769 for (int i = 0, size = frameImages.size(); i < size; i++)
770 {
771 Image image = frameImages.get(i);
772 double cx = image.getWidth(null) / 2.0d;
773 double cy = image.getHeight(null) / 2.0d;
774 double x = width * i + (width / 2.0d) - cx;
775 double y = (height / 2.0d) - cy;
776
777 AffineTransform rotate = new AffineTransform();
778 rotate.translate(cx, cy);
779 rotate.concatenate(new AffineTransform(new double[] { 1.0d, 0.0d, 0.0d, -1.0d }));
780 rotate.translate(-cx, -cy);
781 graphics.setTransform(rotate);
782 graphics.drawImage(image, (int) x, (int) y, null);
783 }
784 graphics.dispose();
785 return createFrameList(spriteSheet, 0, 0, width, height, frameImages.size());
786 }
787
788 /**
789 * Create and return an unmodifiable list of frame images containing all the frame images
790 * from <code>frameImages</code> in the same order flipped vertically.
791 *
792 * @param frameImages list of frame images, must not be null
793 * @return an unmodifiable list of frame images containing all the frame images
794 * from <code>frameImages</code> in the same order flipped vertically
795 */
796 public static List<Image> flipVertically(final List<Image> frameImages)
797 {
798 if (frameImages == null)
799 {
800 throw new IllegalArgumentException("frameImages must not be null");
801 }
802 int width = 0;
803 int height = 0;
804 for (Image image : frameImages)
805 {
806 if (image.getWidth(null) > width)
807 {
808 width = image.getWidth(null);
809 }
810 if (image.getHeight(null) > height)
811 {
812 height = image.getHeight(null);
813 }
814 }
815 BufferedImage spriteSheet = new BufferedImage(width * frameImages.size(), height, BufferedImage.TYPE_INT_ARGB);
816 Graphics2D graphics = spriteSheet.createGraphics();
817 graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
818 for (int i = 0, size = frameImages.size(); i < size; i++)
819 {
820 Image image = frameImages.get(i);
821 double cx = image.getWidth(null) / 2.0d;
822 double cy = image.getHeight(null) / 2.0d;
823 double x = width * i + (width / 2.0d) - cx;
824 double y = (height / 2.0d) - cy;
825
826 AffineTransform rotate = new AffineTransform();
827 rotate.translate(cx, cy);
828 rotate.concatenate(new AffineTransform(new double[] { -1.0d, 0.0d, 0.0d, 1.0d }));
829 rotate.translate(-cx, -cy);
830 graphics.setTransform(rotate);
831 graphics.drawImage(image, (int) x, (int) y, null);
832 }
833 graphics.dispose();
834 return createFrameList(spriteSheet, 0, 0, width, height, frameImages.size());
835 }
836
837 /**
838 * Create and return an unmodifiable list of frame images created by
839 * rotating around the center of specified image 2π/steps times.
840 *
841 * @param image image to rotate, must not be null
842 * @param steps number of steps
843 * @return an unmodifiable list of frame images created by
844 * rotating around the center of specified image 2π/steps times
845 */
846 public static List<Image> rotate(final BufferedImage image, final int steps)
847 {
848 if (image == null)
849 {
850 throw new IllegalArgumentException("image must not be null");
851 }
852 int width = image.getWidth(null);
853 int height = image.getHeight(null);
854 int size = Math.max(width, height);
855 BufferedImage spriteSheet = new BufferedImage(size * steps, size, BufferedImage.TYPE_INT_ARGB);
856 Graphics2D graphics = spriteSheet.createGraphics();
857 graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
858 double x = width / 2.0d;
859 double y = height / 2.0d;
860 double r = (2.0d / (double) steps) * Math.PI;
861 for (int i = 0; i < steps; i++)
862 {
863 AffineTransform rotate = new AffineTransform();
864 rotate.translate(size * i, 0.0d);
865 rotate.rotate(i * r, x, y);
866 graphics.drawRenderedImage(image, rotate);
867 }
868 graphics.dispose();
869 return createFrameList(spriteSheet, 0, 0, size, size, steps);
870 }
871 }