3 Replies Latest reply: May 11, 2010 3:16 PM by 843802 RSS

    Reading gif animation frame rates and such?

    843802
      Okay so I've been coding java for some time now and I mostly just make applications for fun.
      I usually don't have to get help for coding so this is my first post here...
      The current goal I have is a application that displays animations (may turn into a animation editor)

      I've tried searching on google alot for the answer but no justice :(

      Okay so I have the image loading, a semi-nice gui, the image displays and cycles through the animation.

      But the thing that I want is for the image cycle to actually know the real frame rate of the gif instead of having to define it myself.
      Is there anyway to do this? I was reading up and the only solution I found was to read the bytes of the file itself but that would take alot of work and I haven't got a clue on how to do that.


      This is my code for loading the animation:
      public void loadAnimation(String name) {
              final File imageName = new File(name);
              new Thread() {
                  @Override
                  public void run() {
                      for(int i = 0; i < animationImage.length; i++) {
                          if(animationImage[i] != null) {
                              animationImage.flush();
      }
      animationImage[i] = null;
      }
      if(lastImageDrawn != null) {
      lastImageDrawn.flush();
      }
      lastImageDrawn = null;
      lastImageIndex = 0;
      ImageReader reader = ImageIO.getImageReadersByFormatName("gif").next();
      readingImage = false;
      try {
      reader.setInput(new FileImageInputStream(imageName));
      totalImages = reader.getNumImages(true);
      imageProgressBar.setMax(totalImages);
      readingImage = true;
      int currentImage = 0;
      while(readingImage) {
      BufferedImage image = reader.read(currentImage);
      animationImage[currentImage] = image;
      currentImage++;
      imageProgressBar.setValue(currentImage);
      imageProgressBar.setText("Loaded frame: " + currentImage + " / " + totalImages + " - " + imageProgressBar.getPercent() + "%");
      repaint();
      image.flush();
      if(currentImage == reader.getNumImages(true)) {
      readingImage = false;
      reader.reset();
      reader.dispose();
      }
      }
      } catch (IOException e) {
      e.printStackTrace();
      }
      }
      }.start();
      }
      If you guys could help it'd be very appreciated.
      
      EDIT: Oh yeah, I don't want to use any library's I usually like coding things myself...
      
      Edited by: steve4448 on May 7, 2010 11:45 AM                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
        • 1. Re: Reading gif animation frame rates and such?
          843802
          Given the following declarations which completely define a GIF animation,
          //information obtained from source file/url.
          private Image[] images;
          private short[] durations; //hundredths of a second
          private short[] xOffsets;
          private short[] yOffsets;
          private Disposal[] disposalMethods;
          
          //The background color of the global pallete in the GIF file is not
          //used.  It is here merely in case you want to change the implementation
          //of RESTORE_TO_BACKGROUND disposal method.
          private Color backgroundColor;
          the following method will load all this information from a GIF file. Keep [this page|http://java.sun.com/javase/6/docs/api/javax/imageio/metadata/doc-files/gif_metadata.html] open in a web browser as you look at the code. The class referred to as "Disposal" in the code is an enum class. It's provided in my post below this one.
          /**Loads all the frames in an src from the given ImageInputStream.
           * Furthermore, if the src references a GIF file then information
           * on frame durations, offsets, and disposal methods will be extracted
           * (and stored).  The src stream is not closed at the end of the method.
           * It is the duty of the caller to close it if they so wish.*/
          private void loadFromStream(ImageInputStream imageStream)
                  throws java.io.IOException {
          
              //obtain an appropriate src reader
              java.util.Iterator<ImageReader> readers =
                      ImageIO.getImageReaders(imageStream);
          
              ImageReader reader = null;
              while(readers.hasNext()) {
                  reader = readers.next();
          
                  String metaFormat = reader.getOriginatingProvider()
                          .getNativeImageMetadataFormatName();
                  if("gif".equalsIgnoreCase(reader.getFormatName()) &&
                     !"javax_imageio_gif_image_1.0".equals(metaFormat)) {
                      continue;
                  }else {
                      break;
                  }
              }
              if(reader == null) {
                  throw new java.io.IOException("Can not read image format!");
              }
          
              boolean isGif = reader.getFormatName().equalsIgnoreCase("gif");
          
              reader.setInput(imageStream,false,!isGif);
          
              //before we get to the frames, determine if there is a background color
              IIOMetadata globalMeta = reader.getStreamMetadata();
              if(globalMeta != null && "javax_imageio_gif_stream_1.0".equals(
                      globalMeta.getNativeMetadataFormatName())) {
          
                  IIOMetadataNode root = (IIOMetadataNode)
                          globalMeta.getAsTree("javax_imageio_gif_stream_1.0");
          
                  IIOMetadataNode colorTable = (IIOMetadataNode) 
                          root.getElementsByTagName("GlobalColorTable").item(0);
          
                  if (colorTable != null) {
                      String bgIndex = colorTable.getAttribute("backgroundColorIndex");
          
                      IIOMetadataNode colorEntry = (IIOMetadataNode) colorTable.getFirstChild();
                      while (colorEntry != null) {
                          if (colorEntry.getAttribute("index").equals(bgIndex)) {
                              int red = Integer.parseInt(colorEntry.getAttribute("red"));
                              int green = Integer.parseInt(colorEntry.getAttribute("green"));
                              int blue = Integer.parseInt(colorEntry.getAttribute("blue"));
          
                              backgroundColor = new java.awt.Color(red, green, blue);
                              break;
                          }
          
                          colorEntry = (IIOMetadataNode) colorEntry.getNextSibling();
                      }
                  }
              }
          
              //now we read the images, delay times, offsets and disposal methods
              List<BufferedImage> frames    = new ArrayList<BufferedImage>();
              List<Integer>       delays    = new ArrayList<Integer>();
              List<Integer>       lOffsets  = new ArrayList<Integer>();
              List<Integer>       tOffsets  = new ArrayList<Integer>();
              List<Disposal>      disposals = new ArrayList<Disposal>();
          
              boolean unkownMetaFormat = false;
              for(int index = 0;;index++) {
                  try {
                      //read a frame and its metadata
                      javax.imageio.IIOImage frame = reader.readAll(index,null);
          
                      //add the frame to the list
                      frames.add(forceNonCustom((BufferedImage) frame.getRenderedImage()));
          
                      if(unkownMetaFormat)
                          continue;
          
                      //obtain src metadata
                      javax.imageio.metadata.IIOMetadata meta = frame.getMetadata();
          
                      IIOMetadataNode imgRootNode = null;
                      try{
                          imgRootNode = (IIOMetadataNode)
                                  meta.getAsTree("javax_imageio_gif_image_1.0");
                      }catch(IllegalArgumentException e) {
                          //unkown metadata format, can't do anyting about this
                          unkownMetaFormat = true;
                          continue;
                      }
          
                      IIOMetadataNode gce = (IIOMetadataNode)
                          imgRootNode.getElementsByTagName("GraphicControlExtension").item(0);
          
                      delays.add(Integer.parseInt(gce.getAttribute("delayTime")));
                      disposals.add(Disposal.disposalForString(gce.getAttribute("disposalMethod")));
          
                      IIOMetadataNode imgDescr = (IIOMetadataNode)
                          imgRootNode.getElementsByTagName("ImageDescriptor").item(0);
          
                      lOffsets.add(Integer.parseInt(imgDescr.getAttribute("imageLeftPosition")));
                      tOffsets.add(Integer.parseInt(imgDescr.getAttribute("imageTopPosition")));
                  } catch (IndexOutOfBoundsException e) {
                      break;
                  }
              }
          
              //clean up
              reader.dispose();
          
              //copy the source information into their respective arrays
              if(!frames.isEmpty()) {
                  images = frames.toArray(new BufferedImage[]{});
              }
              if(!delays.isEmpty()) {
                  durations = new short[delays.size()];
                  int i = 0;
                  for (int duration : delays)
                      durations[i++] = (short) (duration == 0?DEFAULT_DURATION:
                                                              duration);
              }
              if(!lOffsets.isEmpty()) {
                  xOffsets = new short[lOffsets.size()];
                  int i = 0;
                  for(int offset : lOffsets)
                      xOffsets[i++] = (short) offset;
              }
              if(!tOffsets.isEmpty()) {
                  yOffsets = new short[tOffsets.size()];
                  int i = 0;
                  for(int offset : tOffsets)
                      yOffsets[i++] = (short) offset;
              }
              if(!disposals.isEmpty()) {
                  disposalMethods = disposals.toArray(new Disposal[]{});
              }
          }
          • 2. Re: Reading gif animation frame rates and such?
            843802
            /**The GIF Frame disposal methods*/
            public static enum Disposal {
                /**Treated the same as DO_NOT_DISPOSE*/
                UNSPECIFIED ("none","undefinedDisposalMethod4","undefinedDisposalMethod5",
                                    "undefinedDisposalMethod6","undefinedDisposalMethod7"),
               /**Any pixels not covered by the next frame continues to display. However,
                * even if the last frame is marked as DO_NOT_DISPOSE, the area will be
                * cleared when the animation starts over.*/
                DO_NOT_DISPOSE("doNotDispose"),
            
               /**There exists two intepretations of this dispose method.  One
                * interpretation is that the curent frame is restored to a background
                * color before rendering the next frame.  The second interpretation
                * is that the frame is entirely cleared allowing the background of the
                * web browser to show.  The later interpretation is used in this case.*/
                RESTORE_TO_BACKGROUND("restoreToBackgroundColor"),
            
                /**Restores the src to the previous frame marked by UNSPECIFIED
                * or DO_NOT_DISPOSE*/
                RESTORE_TO_PREVIOUS("restoreToPrevious");
            
                private String[] gifMetaNames;
                private Disposal(String ... gifMetaNames) {
                    this.gifMetaNames = gifMetaNames;
                }
            
                public static Disposal disposalForString(String s) {
                    for(Disposal d : Disposal.values()) {
                        for(String validName : d.gifMetaNames) {
                            if(validName.equals(s)) {
                                return d;
                            }
                        }
                    }
                    return UNSPECIFIED;
                }
            }
            • 3. Re: Reading gif animation frame rates and such?
              843802
              Thanks for your post.
              I'm currently sick so I can't really test it but once I'm feeling better I'll test it out thanks.


              I've changed my question to answered because just reading the code seems like its going to work.

              Thanks for your code and time.