first version fo GIF read support
Stefan Schuermans

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