FileDocCategorySizeDatePackage
GifDecoder.javaAPI DocAndroid 1.5 API24530Wed May 06 22:41:54 BST 2009org.apache.harmony.awt.gl.image

GifDecoder

public class GifDecoder extends ImageDecoder
author
Oleg V. Khaschansky
version
$Revision$

Fields Summary
private static final int
baseHints
private static final int
interlacedHints
static final int
IMPOSSIBLE_VALUE
private static final int
BUFFER_SIZE
private byte[]
buffer
GifDataStream
gifDataStream
GifGraphicBlock
currBlock
private long
hNativeDecoder
private int
bytesConsumed
private boolean
consumersPrepared
private Hashtable
properties
private boolean
forceRGB
private byte[]
screenBuffer
private int[]
screenRGBBuffer
Constructors Summary
public GifDecoder(DecodingImageSource src, InputStream is)


         
        super(src, is);
    
Methods Summary
private native intdecode(byte[] input, int bytesInBuffer, long hDecoder, org.apache.harmony.awt.gl.image.GifDecoder$GifDataStream dataStream, org.apache.harmony.awt.gl.image.GifDecoder$GifGraphicBlock currBlock)

public voiddecodeImage()

        try {
            int bytesRead = 0;
            int needBytes, offset, bytesInBuffer = 0;
            boolean eosReached = false;
            GifGraphicBlock blockToDispose = null;

            // Create new graphic block
            if (currBlock == null) {
                currBlock = new GifGraphicBlock();
                gifDataStream.graphicBlocks.add(currBlock);
            }

            // Read from the input stream
            for (;;) {
                needBytes = BUFFER_SIZE - bytesInBuffer;
                offset = bytesInBuffer;

                bytesRead = inputStream.read(buffer, offset, needBytes);

                if (bytesRead < 0) {
                    eosReached = true;
                    bytesRead = 0;
                } // Don't break, maybe something left in buffer

                // Keep track on how much bytes left in buffer
                bytesInBuffer += bytesRead;

                // Here we pass number of new bytes read from the input stream (bytesRead)
                // since native decoder uses java buffer and doesn't have its own
                // buffer. So it adds this number to the number of bytes left
                // in buffer from the previous call.
                int numLines = decode(
                        buffer,
                        bytesRead,
                        hNativeDecoder,
                        gifDataStream,
                        currBlock);

                // Keep track on how much bytes left in buffer
                bytesInBuffer -= bytesConsumed;

                if (
                        !consumersPrepared &&
                        gifDataStream.logicalScreen.completed &&
                        gifDataStream.logicalScreen.globalColorTable.completed &&
                        (currBlock.imageData != null || // Have transparent pixel filled
                        currBlock.rgbImageData != null)
                ) {
                    prepareConsumers();
                    consumersPrepared = true;
                }

                if (bytesConsumed < 0) {
                    break; // Error exit
                }

                if (currBlock != null) {
                    if (numLines != 0) {
                        // Dispose previous image only before showing next
                        if (blockToDispose != null) {
                            blockToDispose.dispose();
                            blockToDispose = null;
                        }

                        currBlock.sendNewData(this, numLines);
                    }

                    if (currBlock.completed && hNativeDecoder != 0) {
                        blockToDispose = currBlock; // Dispose only before showing new pixels
                        currBlock = new GifGraphicBlock();
                        gifDataStream.graphicBlocks.add(currBlock);
                    }
                }

                if (hNativeDecoder == 0) {
                    break;
                }

                if (eosReached && numLines == 0) { // Maybe image is truncated...
                    releaseNativeDecoder(hNativeDecoder);
                    break;
                }
            }
        } finally {
            closeStream();
        }

        // Here all animation goes
        // Repeat image loopCount-1 times or infinitely if loopCount = 0
        if (gifDataStream.loopCount != 1) {
            if (currBlock.completed == false) {
                gifDataStream.graphicBlocks.remove(currBlock);
            }

            int numFrames = gifDataStream.graphicBlocks.size();
            // At first last block will be disposed
            GifGraphicBlock gb =
                    gifDataStream.graphicBlocks.get(numFrames-1);

            ImageLoader.beginAnimation();

            while (gifDataStream.loopCount != 1) {
                if (gifDataStream.loopCount != 0) {
                    gifDataStream.loopCount--;
                }

                // Show all frames
                for (int i=0; i<numFrames; i++) {
                    gb.dispose();
                    gb = gifDataStream.graphicBlocks.get(i);

                    // Show one frame
                    if (forceRGB) {
                        setPixels(
                                gb.imageLeft,
                                gb.imageTop,
                                gb.imageWidth,
                                gb.imageHeight,
                                ColorModel.getRGBdefault(),
                                gb.getRgbImageData(),
                                0,
                                gb.imageWidth
                        );
                    } else {
                        setPixels(
                                gb.imageLeft,
                                gb.imageTop,
                                gb.imageWidth,
                                gb.imageHeight,
                                null,
                                gb.imageData,
                                0,
                                gb.imageWidth
                        );
                    }
                }
            }
            ImageLoader.endAnimation();
        }

        imageComplete(ImageConsumer.STATICIMAGEDONE);
    
private int[]getScreenRGBBuffer()

        if (screenRGBBuffer == null) {
            if (screenBuffer != null) {
                int transparentColor =
                        gifDataStream.logicalScreen.globalColorTable.cm.getTransparentPixel();
                transparentColor = transparentColor > 0 ? transparentColor : IMPOSSIBLE_VALUE;
                screenRGBBuffer =
                        toRGB(
                                screenBuffer,
                                gifDataStream.logicalScreen.globalColorTable.colors,
                                transparentColor
                        );
            } else {
                int size = gifDataStream.logicalScreen.logicalScreenHeight *
                        gifDataStream.logicalScreen.logicalScreenWidth;
                screenRGBBuffer = new int[size];
            }
        }

        return screenRGBBuffer;
    
private static native voidinitIDs()

private voidprepareConsumers()

        GifLogicalScreen gls = gifDataStream.logicalScreen;
        setDimensions(gls.logicalScreenWidth,
                gls.logicalScreenHeight);
        setProperties(properties);

        currBlock = gifDataStream.graphicBlocks.get(0);
        if (forceRGB) {
            setColorModel(ColorModel.getRGBdefault());
        } else {
            setColorModel(gls.globalColorTable.getColorModel(currBlock.transparentColor));
        }

        // Fill screen buffer with the background or transparent color
        if (forceRGB) {
            int fillColor = 0xFF000000;
            if (gls.backgroundColor != IMPOSSIBLE_VALUE) {
                fillColor = gls.backgroundColor;
            }

            Arrays.fill(getScreenRGBBuffer(), fillColor);
        } else {
            int fillColor = 0;

            if (gls.backgroundColor != IMPOSSIBLE_VALUE) {
                fillColor = gls.backgroundColor;
            } else {
                fillColor = gls.globalColorTable.cm.getTransparentPixel();
            }

            screenBuffer = new byte[gls.logicalScreenHeight*gls.logicalScreenWidth];
            Arrays.fill(screenBuffer, (byte) fillColor);
        }

        setHints(interlacedHints); // XXX - always random pixel order
    
private static native voidreleaseNativeDecoder(long hDecoder)

voidsetComment(java.lang.String newComment)

        Object currComment = properties.get("comment"); //$NON-NLS-1$

        if (currComment == null) {
            properties.put("comment", newComment); //$NON-NLS-1$
        } else {
            properties.put("comment", (String) currComment + "\n" + newComment); //$NON-NLS-1$ //$NON-NLS-2$
        }

        setProperties(properties);
    
private static native int[]toRGB(byte[] imageData, byte[] colormap, int transparentColor)