How to find out the initial size (width and height) of a swf file with java?

Is there a way to find out the original width and height of a swf file with java?

int width, height; // my stream contains an image or a swf file InputStream stream = file.getInputStream(); // mediaType has been set with the help of file extension switch (mediaType) { case IMAGE: BufferedImage img = ImageIO.read(stream); width = img.getWidth(); height = img.getHeight(); break; case FLASH: // what is the code here ? break; } 
+7
source share
2 answers

I looked at the source of brooksandrus and was somewhat dissatisfied, so I wrote my own solution, "one top class". I understand that this makes a long post, but did not know how to publish it otherwise.

  package resnbl.android.swfview;

 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.zip.DataFormatException;
 import java.util.zip.Inflater;

 / **
  * This class will read just enough of a SWF file header to glean the essential
  * meta-data about the animation.
  *
  * This is based on <a href="http://www.adobe.com/devnet/swf.html">
  * SWF File Format Specification (version 10) </a>.
  *
  * @author Resnbl Software
  * @since Mar 22, 2011
  * /
 public class SWFInfo
 {
     static final int UNCOMP_HDR_LEN = 8;  // portion of header that is never compressed

     public boolean isCompressed;
     public int version;
     public long size;
     public int width, height;
     public float fps;
     public int frameCount;

     // Instantiate through getInfo () methods
     private SWFInfo ()
     {}

     / **
      * Get the header info for a (potential) SWF file specified by a file path String.
      *
      * @param path String containing path to file.
      *
      * @return {@link SWFinfo} object or null if file not found or not SWF.
      * /
     public static SWFInfo getInfo (String path)
     {
         return getInfo (new File (path));
     }

     / **
      * Get the header info for a (potential) SWF file specified by a {@link File} object.
      *
      * @param path {@link File} pointing to the desired SWF file.
      *
      * @return {@link SWFinfo} object or null if file not found or not SWF.
      * /
     public static SWFInfo getInfo (File file)
     {
         SWFInfo info = new SWFInfo ();
         byte [] hdr = getBytes (file);

         if (hdr == null)
             return null;
         info.isCompressed = hdr [0] == 'C';
         info.version = hdr [3];
         info.size = hdr [4] & 0xFF |  (hdr [5] & 0xFF) << 8 |  (hdr [6] & 0xFF) << 16 |  hdr [7] << 24;

         BitReader rdr = new BitReader (hdr, UNCOMP_HDR_LEN);

         int [] dims = decodeRect (rdr);
         info.width = (dims [1] - dims [0]) / 20;  // convert twips to pixels
         info.height = (dims [3] - dims [2]) / 20;

         info.fps = (float) rdr.uI16 () / 256f;  // 8.8 fixed-point format
         info.frameCount = rdr.uI16 ();

         return info;
     }

     / *
      * Read just enough of the file for our purposes
      * /
     private static byte [] getBytes (File file)
     {
         if (file == null ||! file.exists () || file.isDirectory ())
             return null;

         byte [] bytes = new byte [128];  // should be enough ...
         FileInputStream fis = null;

         try
         {
             fis = new FileInputStream (file);

             if (fis.read (bytes) <bytes.length)
                 bytes = null;  // too few bytes to be a SWF
             else if (bytes [0] == 'C' && bytes [1] == 'W' && bytes [2] == 'S')
                 bytes = expand (bytes, UNCOMP_HDR_LEN);  // compressed SWF
             else if (bytes [0]! = 'F' || bytes [1]! = 'W' || bytes [2]! = 'S')
                 bytes = null;  // not a SWF
             // else uncompressed SWF
         }
         catch (IOException e)
         {}
         finally
         {
             if (fis! = null)
                 try {fis.close ();  }
                 catch (IOException ee) {}
         }

         return bytes;
     }

     / *
      * All of the file past the initial {@link UNCOMP_HDR_LEN} bytes are compressed.
      * Decompress as much as is in the buffer already read and return them,
      * overlaying the original uncompressed data.
      *
      * Fortunately, the compression algorithm used by Flash is the ZLIB standard,
      * ie, the same algorithms used to compress .jar files
      * /
     private static byte [] expand (byte [] bytes, int skip)
     {
         byte [] newBytes = new byte [bytes.length - skip];
         Inflater inflater = new Inflater ();

         inflater.setInput (bytes, skip, newBytes.length);
         try
         {
             int outCount = inflater.inflate (newBytes);
             System.arraycopy (newBytes, 0, bytes, skip, outCount);
             Arrays.fill (bytes, skip + outCount, bytes.length, (byte) 0);
             return bytes;
         }
         catch (DataFormatException e)
         {}

         return null;
     }

     / **
      * Return Stage frame rectangle as 4 <code> int </code> s: LRTB
      *
      * Note the values ​​are in TWIPS (= 1 / 20th of a pixel)
      *
      * I do this to avoid a loading the <code> Rect </code> class which is an
      * <code> android.graphics </code> class, and not available if you want to
      * test this with desktop Java.
      *
      * @param rdr
      * @return
      * /
     public static int [] decodeRect (BitReader rdr)
     {
         int [] dims = new int [4];
         int nBits = rdr.uBits (5);

         dims [0] = rdr.sBits (nBits);  // X min = left always 0
         dims [1] = rdr.sBits (nBits);  // X max = right
         dims [2] = rdr.sBits (nBits);  // Y min = top always 0
         dims [3] = rdr.sBits (nBits);  // Y max = bottom

         return dims;
     }

     / **
      * This can be run from a desktop command line sitting at the ... / bin directory as:
      *
      * java resnbl.android.swfview.SWFInfo swf_file
      *
      * @param args path to swf_file to parse
      * /
 // commented out to prevent Eclipse from thinkg this is a standard Java app when used for Android!
 // public static void main (String [] args)
 // {
 // if (args.length == 0)
 // throw new IllegalArgumentException ("No swf_file parameter given");
 //
 // File file = new File (args [0]);
 // SWFInfo info = SWFInfo.getInfo (file);
 //
 // if (info! = null)
 // {
 // System.out.println ("File:" + file);
 // System.out.println ("Flash ver:" + info.version + "FPS:" + info.fps + "Frames:" + info.frameCount);
 // System.out.println ("File size:" + file.length () + "Compressed:" + info.isCompressed + "Uncompressed size:" + info.size);
 // System.out.println ("Dimensions:" + info.width + "x" + info.height);
 //}
 // else
 // System.out.println ("File not a .SWF:" + file);
 //}

     / **
      * Read an arbitrary number of bits from a byte [].
      *
      * This should be turned into a full-featured independant class (someday ...).
      * /
     static class BitReader
     {
         private byte [] bytes;
         private int byteIdx;
         private int bitIdx = 0;

         / **
          * Start reading from the beginning of the supplied array.
          * @param bytes byte [] to process
          * /
         public BitReader (byte [] bytes)
         {
             this (bytes, 0);
         }

         / **
          * Start reading from an arbitrary index into the array.
          * @param bytes byte [] to process
          * @param startIndex byte # to start at
          * /
         public BitReader (byte [] bytes, int startIndex)
         {
             this.bytes = bytes;
             byteIdx = startIndex;
         }

         / **
          * Fetch the next <code> bitCount </code> bits as an unsigned int.
          * @param bitCount # bits to read
          * @return int
          * /
         public int uBits (int bitCount)
         {
             int value = 0;

             while (--bitCount> = 0)
                 value = value << 1 |  getBit ();
             return value;
         }

         / **
          * Fetch the next <code> bitCount </code> bits as a <em> signed </em> int.
          * @param bitCount # bits to read
          * @return int
          * /
         public int sBits (int bitCount)
         {
             // First bit is the "sign" bit
             int value = getBit () == 0?  0: -1;
             --bitCount;

             while (--bitCount> = 0)
                 value = value << 1 |  getBit ();
             return value;
         }

         // Get the next bit in the array
         private int getBit ()
         {
             int value = (bytes [byteIdx] >> (7 - bitIdx)) & 0x01;

             if (++ bitIdx == 8)
             {
                 bitIdx = 0;
                 ++ byteIdx;
             }

             return value;
         }

         / **
          * Fetch the next 2 "whole" bytes as an unsigned int (little-endian).
          * @return int
          * /
         public int uI16 ()
         {
             sync ();  // back to "byte-aligned" mode
             return (bytes [byteIdx ++] & 0xff) |  (bytes [byteIdx ++] & 0xff) << 8;
         }

         / **
          * Bump indexes to the next byte boundary.
          * /
         public void sync ()
         {
             if (bitIdx> 0)
             {
                 ++ byteIdx;
                 bitIdx = 0;
             }
         }
     }
 }

Note. I made a global replacement for angle brackets with their HTML equivalents to display them correctly. If you cut and paste it, I hope you do not have to return this change.

+5
source

Well, for me it is also interesting to get the width and height of the flash file. I have not yet found an easy way to do this so far.

After a short google search, I came across this:

http://www.brooksandrus.com/blog/2006/08/11/lightweight-swf-header-reader-java-ii/

This is a library that allows you to analyze the header of a flash file, but it is several years old, and comments suggest that it does not fire for flash 7 up (which would make it almost useless now). But maybe with a little tweak, this will work.

I must say, however, that I have not tried this library.

Hope that helps

+1
source

All Articles