Stefan Schuermans commited on 2018-09-04 21:21:39
Showing 2 changed files, with 187 additions and 2 deletions.
| ... | ... |
@@ -1,11 +1,11 @@ |
| 1 | 1 |
# BlinkenLib |
| 2 |
-# Copyright (C) 2004-2011: Stefan Schuermans <stefan@schuermans.info> |
|
| 2 |
+# Copyright (C) 2004-2018: Stefan Schuermans <stefan@schuermans.info> |
|
| 3 | 3 |
# Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html |
| 4 | 4 |
# a blinkenarea.org project |
| 5 | 5 |
|
| 6 | 6 |
VERSION_MAJOR=0 |
| 7 | 7 |
VERSION_MINOR=1 |
| 8 |
-VERSION_REVISION=5 |
|
| 8 |
+VERSION_REVISION=6 |
|
| 9 | 9 |
|
| 10 | 10 |
JAVAC=javac |
| 11 | 11 |
JAR=jar |
| ... | ... |
@@ -9,6 +9,12 @@ package org.blinkenarea.BlinkenLib; |
| 9 | 9 |
import java.util.*; |
| 10 | 10 |
import java.util.regex.*; |
| 11 | 11 |
import java.io.*; |
| 12 |
+import java.awt.*; |
|
| 13 |
+import java.awt.image.*; |
|
| 14 |
+import javax.imageio.*; |
|
| 15 |
+import javax.imageio.metadata.*; |
|
| 16 |
+import javax.imageio.stream.*; |
|
| 17 |
+import org.w3c.dom.*; |
|
| 12 | 18 |
import org.blinkenarea.BlinkenLib.*; |
| 13 | 19 |
|
| 14 | 20 |
public class BlinkenMovie |
| ... | ... |
@@ -880,6 +886,183 @@ public class BlinkenMovie |
| 880 | 886 |
return false; |
| 881 | 887 |
} |
| 882 | 888 |
|
| 889 |
+ public boolean loadGif( String filename ) |
|
| 890 |
+ {
|
|
| 891 |
+ //delete all frames |
|
| 892 |
+ deleteInfos( ); |
|
| 893 |
+ deleteFrames( ); |
|
| 894 |
+ resize( 0, 0, 0, 0 ); |
|
| 895 |
+ |
|
| 896 |
+ //try to read file |
|
| 897 |
+ try |
|
| 898 |
+ {
|
|
| 899 |
+ //load file |
|
| 900 |
+ ImageReader reader = (ImageReader)ImageIO.getImageReadersByFormatName( "gif").next( ); |
|
| 901 |
+ ImageInputStream inStrm = ImageIO.createImageInputStream( new File( filename ) ); |
|
| 902 |
+ reader.setInput( inStrm, false ); |
|
| 903 |
+ |
|
| 904 |
+ //get global metadata |
|
| 905 |
+ IIOMetadata meta = reader.getStreamMetadata( ); |
|
| 906 |
+ Node tree = meta.getAsTree( "javax_imageio_gif_stream_1.0" ); |
|
| 907 |
+ NodeList children = tree.getChildNodes( ); |
|
| 908 |
+ |
|
| 909 |
+ //parse global metadata |
|
| 910 |
+ Color bgColor = Color.BLACK; |
|
| 911 |
+ for( int chi = 0; chi < children.getLength(); ++chi ) |
|
| 912 |
+ {
|
|
| 913 |
+ Node child = children.item( chi ); |
|
| 914 |
+ |
|
| 915 |
+ if( child.getNodeName( ).equals( "GlobalColorTable" ) ) |
|
| 916 |
+ {
|
|
| 917 |
+ NamedNodeMap attr = child.getAttributes(); |
|
| 918 |
+ Node bgIdxNode = attr.getNamedItem( "backgroundColorIndex" ); |
|
| 919 |
+ if( bgIdxNode != null ) |
|
| 920 |
+ {
|
|
| 921 |
+ int bgIdx = Integer.valueOf( bgIdxNode.getNodeValue( ) ); |
|
| 922 |
+ |
|
| 923 |
+ NodeList entries = child.getChildNodes( ); |
|
| 924 |
+ for( int ent = 0; ent < entries.getLength( ); ++ent ) |
|
| 925 |
+ {
|
|
| 926 |
+ Node entry = entries.item( ent ); |
|
| 927 |
+ if( entry.getNodeName( ).equals( "ColorTableEntry" ) ) |
|
| 928 |
+ {
|
|
| 929 |
+ NamedNodeMap entryAttr = entry.getAttributes(); |
|
| 930 |
+ int index = Integer.valueOf( entryAttr.getNamedItem( |
|
| 931 |
+ "index" ).getNodeValue( ) ); |
|
| 932 |
+ if( index == bgIdx ) |
|
| 933 |
+ {
|
|
| 934 |
+ int red = Integer.valueOf( entryAttr.getNamedItem( |
|
| 935 |
+ "red" ).getNodeValue( ) ); |
|
| 936 |
+ int green = Integer.valueOf( entryAttr.getNamedItem( |
|
| 937 |
+ "green" ).getNodeValue( ) ); |
|
| 938 |
+ int blue = Integer.valueOf( entryAttr.getNamedItem( |
|
| 939 |
+ "blue" ).getNodeValue( ) ); |
|
| 940 |
+ bgColor = new Color(red, green, blue); |
|
| 941 |
+ break; |
|
| 942 |
+ } //if index |
|
| 943 |
+ } //if entry |
|
| 944 |
+ } //for ent |
|
| 945 |
+ } //if bgIdxNode |
|
| 946 |
+ } //if child |
|
| 947 |
+ } //for chi |
|
| 948 |
+ |
|
| 949 |
+ //iterate through all frames |
|
| 950 |
+ int frameCnt = reader.getNumImages( true ); |
|
| 951 |
+ int movieWidth = 0; |
|
| 952 |
+ int movieHeight = 0; |
|
| 953 |
+ BufferedImage canvas = null, backup = null; |
|
| 954 |
+ for( int frame = 0; frame < frameCnt; ++frame ) |
|
| 955 |
+ {
|
|
| 956 |
+ //get image |
|
| 957 |
+ BufferedImage img = reader.read( frame ); |
|
| 958 |
+ |
|
| 959 |
+ //get image metadata |
|
| 960 |
+ meta = reader.getImageMetadata( frame ); |
|
| 961 |
+ tree = meta.getAsTree( "javax_imageio_gif_image_1.0" ); |
|
| 962 |
+ children = tree.getChildNodes( ); |
|
| 963 |
+ |
|
| 964 |
+ //parse metadata for this image |
|
| 965 |
+ int left = -1, top = -1, width = -1, height = -1; |
|
| 966 |
+ int duration = 100; |
|
| 967 |
+ boolean restoreToPrevious = false; |
|
| 968 |
+ boolean restoreToBackgroundColor = false; |
|
| 969 |
+ for( int chi = 0; chi < children.getLength( ); ++chi ) |
|
| 970 |
+ {
|
|
| 971 |
+ Node child = children.item( chi ); |
|
| 972 |
+ |
|
| 973 |
+ if( child.getNodeName( ).equals( "ImageDescriptor" ) ) |
|
| 974 |
+ {
|
|
| 975 |
+ NamedNodeMap attr = child.getAttributes(); |
|
| 976 |
+ left = Integer.valueOf( attr.getNamedItem( |
|
| 977 |
+ "imageLeftPosition" ).getNodeValue( ) ); |
|
| 978 |
+ top = Integer.valueOf( attr.getNamedItem( |
|
| 979 |
+ "imageTopPosition" ).getNodeValue( ) ); |
|
| 980 |
+ width = Integer.valueOf( attr.getNamedItem( |
|
| 981 |
+ "imageWidth" ).getNodeValue( ) ); |
|
| 982 |
+ height = Integer.valueOf( attr.getNamedItem( |
|
| 983 |
+ "imageHeight" ).getNodeValue( ) ); |
|
| 984 |
+ } //if ImageDescriptor |
|
| 985 |
+ if( child.getNodeName( ).equals( "GraphicControlExtension" ) ) |
|
| 986 |
+ {
|
|
| 987 |
+ NamedNodeMap attr = child.getAttributes(); |
|
| 988 |
+ Node disposalMethod = attr.getNamedItem( "disposalMethod" ); |
|
| 989 |
+ if( disposalMethod != null ) |
|
| 990 |
+ {
|
|
| 991 |
+ String disposalMethodStr = disposalMethod.getNodeValue( ); |
|
| 992 |
+ if( disposalMethodStr.equals( "restoreToPrevious" ) ) |
|
| 993 |
+ restoreToPrevious = true; |
|
| 994 |
+ else if( disposalMethodStr.equals( "restoreToBackgroundColor" ) ) |
|
| 995 |
+ restoreToBackgroundColor = true; |
|
| 996 |
+ } |
|
| 997 |
+ Node durationNode = attr.getNamedItem( "delayTime" ); |
|
| 998 |
+ if( durationNode != null ) |
|
| 999 |
+ duration = Integer.valueOf( durationNode.getNodeValue( ) ) * 10; |
|
| 1000 |
+ } //if GraphicControlExtension |
|
| 1001 |
+ } //for chi |
|
| 1002 |
+ |
|
| 1003 |
+ //no position -> ignore this frame |
|
| 1004 |
+ if (left < 0 || top < 0 || width < 0 || height < 0) |
|
| 1005 |
+ continue; |
|
| 1006 |
+ |
|
| 1007 |
+ //first frame determines movie size |
|
| 1008 |
+ if( canvas == null ) |
|
| 1009 |
+ {
|
|
| 1010 |
+ movieWidth = width; |
|
| 1011 |
+ movieHeight = height; |
|
| 1012 |
+ resize( movieHeight, movieWidth, 3, 255 ); |
|
| 1013 |
+ canvas = new BufferedImage( movieWidth, movieHeight, |
|
| 1014 |
+ BufferedImage.TYPE_INT_ARGB ); |
|
| 1015 |
+ backup = new BufferedImage( movieWidth, movieHeight, |
|
| 1016 |
+ BufferedImage.TYPE_INT_ARGB ); |
|
| 1017 |
+ } |
|
| 1018 |
+ |
|
| 1019 |
+ // keep backup if needed |
|
| 1020 |
+ if( restoreToPrevious ) |
|
| 1021 |
+ {
|
|
| 1022 |
+ Graphics g = backup.getGraphics(); |
|
| 1023 |
+ g.drawImage(canvas, 0, 0, null); |
|
| 1024 |
+ g.dispose(); |
|
| 1025 |
+ } |
|
| 1026 |
+ |
|
| 1027 |
+ // draw new image to canvas |
|
| 1028 |
+ Graphics g = canvas.getGraphics( ); |
|
| 1029 |
+ g.drawImage( img, left, top, null ); |
|
| 1030 |
+ g.dispose(); |
|
| 1031 |
+ |
|
| 1032 |
+ // convert canvas to new frame and append to movie |
|
| 1033 |
+ BlinkenFrame newFrame = new BlinkenFrame( movieHeight, movieWidth, |
|
| 1034 |
+ 3, 255, duration ); |
|
| 1035 |
+ for( int y = 0; y < movieHeight; y++ ) |
|
| 1036 |
+ for( int x = 0; x < movieWidth; x++ ) |
|
| 1037 |
+ newFrame.setColor( y, x, new Color( canvas.getRGB( x, y ) ) ); |
|
| 1038 |
+ appendFrame( newFrame ); |
|
| 1039 |
+ |
|
| 1040 |
+ // disposal of image on canvas |
|
| 1041 |
+ if( restoreToPrevious ) |
|
| 1042 |
+ {
|
|
| 1043 |
+ g = canvas.getGraphics(); |
|
| 1044 |
+ g.drawImage(backup, 0, 0, null); |
|
| 1045 |
+ g.dispose(); |
|
| 1046 |
+ } |
|
| 1047 |
+ if( restoreToBackgroundColor ) |
|
| 1048 |
+ {
|
|
| 1049 |
+ Graphics2D g2d = canvas.createGraphics(); |
|
| 1050 |
+ g2d.setColor(bgColor); |
|
| 1051 |
+ g2d.fill(new Rectangle(left, top, width, height)); |
|
| 1052 |
+ g2d.dispose(); |
|
| 1053 |
+ } |
|
| 1054 |
+ |
|
| 1055 |
+ } //for frame |
|
| 1056 |
+ |
|
| 1057 |
+ //success |
|
| 1058 |
+ return true; |
|
| 1059 |
+ } |
|
| 1060 |
+ catch( IOException e ) { }
|
|
| 1061 |
+ |
|
| 1062 |
+ //some error |
|
| 1063 |
+ return false; |
|
| 1064 |
+ } |
|
| 1065 |
+ |
|
| 883 | 1066 |
public boolean load( String filename ) |
| 884 | 1067 |
{
|
| 885 | 1068 |
if( filename.endsWith( ".blm" ) ) |
| ... | ... |
@@ -890,6 +1073,8 @@ public class BlinkenMovie |
| 890 | 1073 |
return loadBml( filename ); |
| 891 | 1074 |
if( filename.endsWith( ".bbm" ) ) |
| 892 | 1075 |
return loadBbm( filename ); |
| 1076 |
+ if( filename.endsWith( ".gif" ) ) |
|
| 1077 |
+ return loadGif( filename ); |
|
| 893 | 1078 |
deleteFrames( ); |
| 894 | 1079 |
return false; |
| 895 | 1080 |
} |
| 896 | 1081 |