private void readOpPackBits(final ImageInputStream pStream, final boolean hasRegion, final int pPixmapCount) throws IOException {
        // Get rowBytes
        int rowBytesRaw = pStream.readUnsignedShort();
        int rowBytes = rowBytesRaw & 0x7FFF;
        boolean isPixMap = (rowBytesRaw & 0x8000) > 0;

        if (DEBUG) {
            System.out.print(hasRegion ? "packBitsRgn" : "packBitsRect");
            System.out.print(", rowBytes: " + rowBytes);
            if (isPixMap) {
                System.out.print(", it is a PixMap");
            }
            else {
                System.out.print(", it is a BitMap");
            }
        }

        // Get bounds rectangle. THIS IS NOT TO BE SCALED BY THE RESOLUTION!
        Rectangle bounds = new Rectangle();
        int y = pStream.readUnsignedShort();
        int x = pStream.readUnsignedShort();
        bounds.setLocation(x, y);

        y = pStream.readUnsignedShort();
        x = pStream.readUnsignedShort();
        bounds.setSize(x - bounds.x, y - bounds.y);
        if (DEBUG) {
            System.out.print(", bounds: " + bounds);
        }

        ColorModel colorModel;
        int cmpSize;

        if (isPixMap) {
            // Get PixMap record version number
            int pmVersion = pStream.readUnsignedShort();
            if (DEBUG) {
                System.out.print(", pmVersion: " + pmVersion);
            }

            // Get packing format
            int packType = pStream.readUnsignedShort();
            if (DEBUG) {
                System.out.print(", packType: " + packType);
            }

            // Get size of packed data (not used for v2)
            int packSize = pStream.readInt();
            if (DEBUG) {
                System.out.println(", packSize: " + packSize);
            }

            // Get resolution info
            double hRes = PICTUtil.readFixedPoint(pStream);
            double vRes = PICTUtil.readFixedPoint(pStream);
            if (DEBUG) {
                System.out.print("hRes: " + hRes + ", vRes: " + vRes);
            }

            // Get pixel type
            int pixelType = pStream.readUnsignedShort();
            if (DEBUG) {
                if (pixelType == 0) {
                    System.out.print(", indexed pixels");
                }
                else {
                    System.out.print(", RGBDirect");
                }
            }

            // Get pixel size
            int pixelSize = pStream.readUnsignedShort();
            if (DEBUG) {
                System.out.print(", pixelSize:" + pixelSize);
            }

            // Get pixel component count
            int cmpCount = pStream.readUnsignedShort();
            if (DEBUG) {
                System.out.print(", cmpCount:" + cmpCount);
            }

            // Get pixel component size
            cmpSize = pStream.readUnsignedShort();
            if (DEBUG) {
                System.out.print(", cmpSize:" + cmpSize);
            }

            // planeBytes (ignored)
            int planeBytes = pStream.readInt();
            if (DEBUG) {
                System.out.print(", planeBytes:" + planeBytes);
            }

            // Handle to ColorTable record
            int clutId = pStream.readInt();
            if (DEBUG) {
                System.out.print(", clutId:" + clutId);
            }

            // Reserved
            pStream.readInt();

            // TODO: Seems to be packType 0 all the time?
            // packType = 0 means default....

            if (packType != 0) {
                throw new IIOException("Unknown pack type: " + packType);
            }
            if (pixelType != 0) {
                throw new IIOException("Unsupported pixel type: " + pixelType);
            }

            // Color table
            colorModel = PICTUtil.readColorTable(pStream, pixelSize);
        }
        else {
            // Old style BitMap record
            cmpSize = 1;
            colorModel = QuickDraw.MONOCHROME;
        }

        // Get source rectangle. We DO NOT scale the coordinates by the
        // resolution info, since we are in pixmap coordinates here
        // TODO: readReactangleNonScaled()
        Rectangle srcRect = new Rectangle();
        y = pStream.readUnsignedShort();
        x = pStream.readUnsignedShort();
        srcRect.setLocation(x, y);

        y = pStream.readUnsignedShort();
        x = pStream.readUnsignedShort();
        srcRect.setSize(x - srcRect.x, y - srcRect.y);

        if (DEBUG) {
            System.out.print(", srcRect:" + srcRect);
        }

        // TODO: FixMe...
        // Get destination rectangle. We DO scale the coordinates according to
        // the image resolution, since we are working in display coordinates
        Rectangle dstRect = new Rectangle();
        readRectangle(pStream, dstRect);
        if (DEBUG) {
            System.out.print(", dstRect:" + dstRect);
        }

        // Get transfer mode
        int transferMode = pStream.readUnsignedShort();
        if (DEBUG) {
            System.out.print(", mode: " + transferMode);
        }

        Rectangle regionBounds = new Rectangle();
        Area region = hasRegion ? readRegion(pStream, regionBounds) : null;

        if (DEBUG) {
            if (hasRegion) {
                verboseRegionCmd(", region", regionBounds, region);
            }
            else {
                System.out.println();
            }
        }

        // Set up pixel buffer for the RGB values
        byte[] pixArray = new byte[srcRect.height * rowBytes];
        int pixBufOffset = 0;

        // Read in the RGB arrays
        for (int scanline = 0; scanline < srcRect.height; scanline++) {
            // Read in the scanline
            if (rowBytes >= 8) {
                // Get byteCount of the scanline
                int packedBytesCount = rowBytes > 250 ? pStream.readUnsignedShort() : pStream.readUnsignedByte();

                // Unpack them all
                Decoder decoder = new PackBitsDecoder();
                DataInput unPackBits = new DataInputStream(new DecoderStream(IIOUtil.createStreamAdapter(pStream, packedBytesCount), decoder));
                unPackBits.readFully(pixArray, pixBufOffset, rowBytes);
            }
            else {
                // Uncompressed
                imageInput.readFully(pixArray, pixBufOffset, rowBytes);
            }

            // Increment pixel buffer offset
            pixBufOffset += rowBytes;

            ////////////////////////////////////////////////////
            // TODO: This works for single image PICTs only...
            // However, this is the most common case. Ok for now
            processImageProgress(scanline * 100 / srcRect.height);
            if (abortRequested()) {
                processReadAborted();

                // Skip rest of image data
                for (int skip = scanline + 1; skip < srcRect.height; skip++) {
                    // Get byteCount of the scanline
                    int packedBytesCount;

                    if (rowBytes < 8) {
                        packedBytesCount = rowBytes;
                    }
                    else if (rowBytes > 250) {
                        packedBytesCount = pStream.readUnsignedShort();
                    }
                    else {
                        packedBytesCount = pStream.readUnsignedByte();
                    }

                    pStream.readFully(new byte[packedBytesCount], 0, packedBytesCount);

                    if (DEBUG) {
                        System.out.print("Skip " + skip + ", byteCount: " + packedBytesCount);
                    }
                }

                break;
            }
            ////////////////////////////////////////////////////
        }

        // We add all new images to it. If we are just replaying, then
        // "pPixmapCount" will never be greater than the size of the vector
        if (images.size() <= pPixmapCount) {
            // Create BufferedImage and add buffer it for multiple reads
            DataBuffer db = new DataBufferByte(pixArray, pixArray.length);
            WritableRaster raster = Raster.createPackedRaster(db, (rowBytes * 8) / cmpSize, srcRect.height, cmpSize, null);
            BufferedImage img = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);

            images.add(img);
        }

        // Draw the image
        BufferedImage img = images.get(pPixmapCount);
        if (img != null) {
            srcRect.setLocation(0, 0); // Raster always start at 0,0
            context.copyBits(img, srcRect, dstRect, transferMode, region);
        }

        // Line break at the end
        if (DEBUG) {
            System.out.println();
        }
    }
private void readOpPackBits ( final ImageInputStream pStream , final boolean hasRegion , final int pPixmapCount ) throws IOException { int rowBytesRaw = pStream . readUnsignedShort ( ) ; int rowBytes = rowBytesRaw & 0x7FFF ; boolean isPixMap = ( rowBytesRaw & 0x8000 ) > 0 ; if ( DEBUG ) { System . out . print ( hasRegion ? "packBitsRgn" : "packBitsRect" ) ; System . out . print ( ", rowBytes: " + rowBytes ) ; if ( isPixMap ) { System . out . print ( ", it is a PixMap" ) ; } else { System . out . print ( ", it is a BitMap" ) ; } } Rectangle bounds = new Rectangle ( ) ; int y = pStream . readUnsignedShort ( ) ; int x = pStream . readUnsignedShort ( ) ; bounds . setLocation ( x , y ) ; y = pStream . readUnsignedShort ( ) ; x = pStream . readUnsignedShort ( ) ; bounds . setSize ( x - bounds . x , y - bounds . y ) ; if ( DEBUG ) { System . out . print ( ", bounds: " + bounds ) ; } ColorModel colorModel ; int cmpSize ; if ( isPixMap ) { int pmVersion = pStream . readUnsignedShort ( ) ; if ( DEBUG ) { System . out . print ( ", pmVersion: " + pmVersion ) ; } int packType = pStream . readUnsignedShort ( ) ; if ( DEBUG ) { System . out . print ( ", packType: " + packType ) ; } int packSize = pStream . readInt ( ) ; if ( DEBUG ) { System . out . println ( ", packSize: " + packSize ) ; } double hRes = PICTUtil . readFixedPoint ( pStream ) ; double vRes = PICTUtil . readFixedPoint ( pStream ) ; if ( DEBUG ) { System . out . print ( "hRes: " + hRes + ", vRes: " + vRes ) ; } int pixelType = pStream . readUnsignedShort ( ) ; if ( DEBUG ) { if ( pixelType == 0 ) { System . out . print ( ", indexed pixels" ) ; } else { System . out . print ( ", RGBDirect" ) ; } } int pixelSize = pStream . readUnsignedShort ( ) ; if ( DEBUG ) { System . out . print ( ", pixelSize:" + pixelSize ) ; } int cmpCount = pStream . readUnsignedShort ( ) ; if ( DEBUG ) { System . out . print ( ", cmpCount:" + cmpCount ) ; } cmpSize = pStream . readUnsignedShort ( ) ; if ( DEBUG ) { System . out . print ( ", cmpSize:" + cmpSize ) ; } int planeBytes = pStream . readInt ( ) ; if ( DEBUG ) { System . out . print ( ", planeBytes:" + planeBytes ) ; } int clutId = pStream . readInt ( ) ; if ( DEBUG ) { System . out . print ( ", clutId:" + clutId ) ; } pStream . readInt ( ) ; if ( packType != 0 ) { throw new IIOException ( "Unknown pack type: " + packType ) ; } if ( pixelType != 0 ) { throw new IIOException ( "Unsupported pixel type: " + pixelType ) ; } colorModel = PICTUtil . readColorTable ( pStream , pixelSize ) ; } else { cmpSize = 1 ; colorModel = QuickDraw . MONOCHROME ; } Rectangle srcRect = new Rectangle ( ) ; y = pStream . readUnsignedShort ( ) ; x = pStream . readUnsignedShort ( ) ; srcRect . setLocation ( x , y ) ; y = pStream . readUnsignedShort ( ) ; x = pStream . readUnsignedShort ( ) ; srcRect . setSize ( x - srcRect . x , y - srcRect . y ) ; if ( DEBUG ) { System . out . print ( ", srcRect:" + srcRect ) ; } Rectangle dstRect = new Rectangle ( ) ; readRectangle ( pStream , dstRect ) ; if ( DEBUG ) { System . out . print ( ", dstRect:" + dstRect ) ; } int transferMode = pStream . readUnsignedShort ( ) ; if ( DEBUG ) { System . out . print ( ", mode: " + transferMode ) ; } Rectangle regionBounds = new Rectangle ( ) ; Area region = hasRegion ? readRegion ( pStream , regionBounds ) : null ; if ( DEBUG ) { if ( hasRegion ) { verboseRegionCmd ( ", region" , regionBounds , region ) ; } else { System . out . println ( ) ; } } byte [ ] pixArray = new byte [ srcRect . height * rowBytes ] ; int pixBufOffset = 0 ; for ( int scanline = 0 ; scanline < srcRect . height ; scanline ++ ) { if ( rowBytes >= 8 ) { int packedBytesCount = rowBytes > 250 ? pStream . readUnsignedShort ( ) : pStream . readUnsignedByte ( ) ; Decoder decoder = new PackBitsDecoder ( ) ; DataInput unPackBits = new DataInputStream ( new DecoderStream ( IIOUtil . createStreamAdapter ( pStream , packedBytesCount ) , decoder ) ) ; unPackBits . readFully ( pixArray , pixBufOffset , rowBytes ) ; } else { imageInput . readFully ( pixArray , pixBufOffset , rowBytes ) ; } pixBufOffset += rowBytes ; processImageProgress ( scanline * 100 / srcRect . height ) ; if ( abortRequested ( ) ) { processReadAborted ( ) ; for ( int skip = scanline + 1 ; skip < srcRect . height ; skip ++ ) { int packedBytesCount ; if ( rowBytes < 8 ) { packedBytesCount = rowBytes ; } else if ( rowBytes > 250 ) { packedBytesCount = pStream . readUnsignedShort ( ) ; } else { packedBytesCount = pStream . readUnsignedByte ( ) ; } pStream . readFully ( new byte [ packedBytesCount ] , 0 , packedBytesCount ) ; if ( DEBUG ) { System . out . print ( "Skip " + skip + ", byteCount: " + packedBytesCount ) ; } } break ; } } if ( images . size ( ) <= pPixmapCount ) { DataBuffer db = new DataBufferByte ( pixArray , pixArray . length ) ; WritableRaster raster = Raster . createPackedRaster ( db , ( rowBytes * 8 ) / cmpSize , srcRect . height , cmpSize , null ) ; BufferedImage img = new BufferedImage ( colorModel , raster , colorModel . isAlphaPremultiplied ( ) , null ) ; images . add ( img ) ; } BufferedImage img = images . get ( pPixmapCount ) ; if ( img != null ) { srcRect . setLocation ( 0 , 0 ) ; context . copyBits ( img , srcRect , dstRect , transferMode , region ) ; } if ( DEBUG ) { System . out . println ( ) ; } }
/*
http://devworld.apple.com/documentation/QuickTime/RM/CompressDecompress/ImageComprMgr/B-Chapter/chapter_1000_section_5.html:

Field name      Description                             Data size (in bytes)

Opcode          Uncompressed picture data               2
Size            Size in bytes of data for this opcode   4
Version         Version of this opcode                  2
Matrix          3 by 3 fixed transformation matrix      36
MatteSize       Size of matte data in bytes             4
MatteRect       Rectangle for matte data                8