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 }