Presentation of animated gif images of downloaded from the Android network



  • Dano:

    Reference *.gif file.

    Objective:

    Imminate it in animated form. And clash.

    Attempts to decide:

    Found it. https://stackoverflow.com/a/11736861/3212712 Two classes. First responsible for decoding gif file, second heir ImageViewaccepted InputStream gif A file decoding it by first class and displaying animated image.

    The problem is, in these-your-interests, I only found a way to reflect. gif Annex resource file:

    InputStream is = context.getResources().openRawResource(R.raw.some_gif)

    I got a little thinking. InputStream and from a simple CD file:

    FileInputStream in = new FileInputStream(file);

    I mean, you can download the file from the network, put it on the disk and get it loaded. But I'd like to make a decision. For example, https://github.com/nostra13/Android-Universal-Image-Loader ,yourself loads and clashes images.

    The problem is, SimpleImageLoadingListener Ooh. UIL at the end of loading, issue the type object Bitmap♪ I didn't change it. InputStream♪ I sold this code:

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    loadedImage.compress(Bitmap.CompressFormat.PNG, 0 /*ignored for PNG*/, bos);
    byte[] bitmapdata = bos.toByteArray();
    ByteArrayInputStream bs = new ByteArrayInputStream(bitmapdata);
    

    But he's got it. ByteArrayInputStream converted to design GifDecoderView doesn't lead to pictures. The methods are called, but the image doesn't show up. It doesn't work. ByteArrayInputStream instead InputStream

    Possible solution:

    Decided it with a crutch like that: At the end of download, I get the images File Discash pictures UIL and turn it into one. FileInputStream:

    File file = DiskCacheUtils.findInCache(imageUri, imageLoader.getDiskCache());
    FileInputStream in = new FileInputStream(file);
    

    That's how it works, but I'm very embarrassed that at the end of the loading, I'm not getting anything. Bitmap My picture, she's still in it. MemoryCache kept at that moment. And I, with all this to a friend, still a picture of the CD.

    Question:

    Can I get something? InputStream of Bitmap or is there a ready solution to the very task in the form of libraries? I found a couple. https://github.com/felipecsl/GifImageView and https://github.com/facebook/fresco but he didn't try them, because it was interesting to see the solution presented, and it seemed to work well.

    P. S.:

    The decision now in use is mine. https://ru.stackoverflow.com/a/479846/17609 but still wonder how it can be improved.



  • For the display of animated gif images I found on https://stackoverflow.com/a/11736861/3212712 Two classes:

    GifDecoder.java

    public class GifDecoder
    {
        public static final int STATUS_OK = 0;
        public static final int STATUS_FORMAT_ERROR = 1;
        public static final int STATUS_OPEN_ERROR = 2;
        protected static final int MAX_STACK_SIZE = 4096;
        private static final String LOG = GifDecoder.class.getSimpleName();
        protected InputStream in;
        protected int status;
        protected int width; // full image width
        protected int height; // full image height
        protected boolean gctFlag; // global color table used
        protected int gctSize; // size of global color table
        protected int loopCount = 1; // iterations; 0 = repeat forever
        protected int[] gct; // global color table
        protected int[] lct; // local color table
        protected int[] act; // active color table
        protected int bgIndex; // background color index
        protected int bgColor; // background color
        protected int lastBgColor; // previous bg color
        protected int pixelAspect; // pixel aspect ratio
        protected boolean lctFlag; // local color table flag
        protected boolean interlace; // interlace flag
        protected int lctSize; // local color table size
        protected int ix, iy, iw, ih; // current image rectangle
        protected int lrx, lry, lrw, lrh;
        protected Bitmap image; // current frame
        protected Bitmap lastBitmap; // previous frame
        protected byte[] block = new byte[256]; // current data block
    
    protected int blockSize = 0; // block size last graphic control extension info
    protected int dispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev
    protected int lastDispose = 0;
    protected boolean transparency = false; // use transparent color
    protected int delay = 0; // delay in milliseconds
    protected int transIndex; // transparent color index
    // LZW decoder working arrays
    protected short[] prefix;
    protected byte[] suffix;
    protected byte[] pixelStack;
    protected byte[] pixels;
    protected Vector<GifFrame> frames; // frames read from current file
    protected int frameCount;
    
    public int getDelay(int n)
    {
        delay = -1;
        if ((n >= 0) && (n < frameCount))
        {
            delay = frames.elementAt(n).delay;
        }
        return delay;
    }
    
    public int getFrameCount()
    {
        return frameCount;
    }
    
    public Bitmap getBitmap()
    {
        return getFrame(0);
    }
    
    public int getLoopCount()
    {
        return loopCount;
    }
    
    protected void setPixels()
    {
    
        int[] dest = new int[width * height];
    
        if (lastDispose > 0)
        {
            if (lastDispose == 3)
            {
                // use image before last
                int n = frameCount - 2;
                if (n > 0)
                {
                    lastBitmap = getFrame(n - 1);
                }
                else
                {
                    lastBitmap = null;
                }
            }
            if (lastBitmap != null)
            {
                lastBitmap.getPixels(dest, 0, width, 0, 0, width, height);
                if (lastDispose == 2)
                {
                    // fill last image rect area with background color
                    int c = 0;
                    if (!transparency)
                    {
                        c = lastBgColor;
                    }
                    for (int i = 0; i < lrh; i++)
                    {
                        int n1 = (lry + i) * width + lrx;
                        int n2 = n1 + lrw;
                        for (int k = n1; k < n2; k++)
                        {
                            dest[k] = c;
                        }
                    }
                }
            }
        }
        int pass = 1;
        int inc = 8;
        int iline = 0;
        for (int i = 0; i < ih; i++)
        {
            int line = i;
            if (interlace)
            {
                if (iline >= ih)
                {
                    pass++;
                    switch (pass)
                    {
                        case 2:
                            iline = 4;
                            break;
                        case 3:
                            iline = 2;
                            inc = 4;
                            break;
                        case 4:
                            iline = 1;
                            inc = 2;
                            break;
                        default:
                            break;
                    }
                }
                line = iline;
                iline += inc;
            }
            line += iy;
            if (line < height)
            {
                int k = line * width;
                int dx = k + ix; // start of line in dest
                int dlim = dx + iw; // end of dest line
                if ((k + width) < dlim)
                {
                    dlim = k + width; // past dest edge
                }
                int sx = i * iw; // start of line in source
                while (dx < dlim)
                {
                    // map color and insert in destination
                    int index = ((int) pixels[sx++]) & 0xff;
                    int c = act[index];
                    if (c != 0)
                    {
                        dest[dx] = c;
                    }
                    dx++;
                }
            }
        }
        image = Bitmap.createBitmap(dest, width, height, Bitmap.Config.ARGB_4444);
    }
    
    public Bitmap getFrame(int n)
    {
        if (frameCount <= 0)
        {
            return null;
        }
        n = n % frameCount;
        return (/*(GifFrame)*/ frames.elementAt(n)).image;
    }
    
    public int read(InputStream is)
    {
        init();
        if (is != null)
        {
            in = is;
    
            readHeader();
            if (!err())
            {
                readContents();
                if (frameCount < 0)
                {
                    status = STATUS_FORMAT_ERROR;
                }
            }
        }
        else
        {
            status = STATUS_OPEN_ERROR;
        }
        try
        {
            if (is != null)
            {
                is.close();
            }
            else
            {
                Log.i(LOG, "is = NULL!" + " WTF?!");
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        return status;
    }
    
    protected void decodeBitmapData()
    {
        int nullCode = -1;
        int npix = iw * ih;
        int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;
        if ((pixels == null) || (pixels.length < npix))
        {
            pixels = new byte[npix]; // allocate new pixel array
        }
        if (prefix == null)
        {
            prefix = new short[MAX_STACK_SIZE];
        }
        if (suffix == null)
        {
            suffix = new byte[MAX_STACK_SIZE];
        }
        if (pixelStack == null)
        {
            pixelStack = new byte[MAX_STACK_SIZE + 1];
        }
        data_size = read();
        clear = 1 << data_size;
        end_of_information = clear + 1;
        available = clear + 2;
        old_code = nullCode;
        code_size = data_size + 1;
        code_mask = (1 << code_size) - 1;
        for (code = 0; code < clear; code++)
        {
            prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException
            suffix[code] = (byte) code;
        }
        datum = bits = count = first = top = pi = bi = 0;
        for (i = 0; i < npix; )
        {
            if (top == 0)
            {
                if (bits < code_size)
                {
                    // Load bytes until there are enough bits for a code.
                    if (count == 0)
                    {
                        // Read a new data block.
                        count = readBlock();
                        if (count <= 0)
                        {
                            break;
                        }
                        bi = 0;
                    }
                    datum += (((int) block[bi]) & 0xff) << bits;
                    bits += 8;
                    bi++;
                    count--;
                    continue;
                }
                code = datum & code_mask;
                datum >>= code_size;
                bits -= code_size;
                if ((code > available) || (code == end_of_information))
                {
                    break;
                }
                if (code == clear)
                {
                    // Reset decoder.
                    code_size = data_size + 1;
                    code_mask = (1 << code_size) - 1;
                    available = clear + 2;
                    old_code = nullCode;
                    continue;
                }
                if (old_code == nullCode)
                {
                    pixelStack[top++] = suffix[code];
                    old_code = code;
                    first = code;
                    continue;
                }
                in_code = code;
                if (code == available)
                {
                    pixelStack[top++] = (byte) first;
                    code = old_code;
                }
                while (code > clear)
                {
                    pixelStack[top++] = suffix[code];
                    code = prefix[code];
                }
                first = ((int) suffix[code]) & 0xff;
                if (available >= MAX_STACK_SIZE)
                {
                    break;
                }
                pixelStack[top++] = (byte) first;
                prefix[available] = (short) old_code;
                suffix[available] = (byte) first;
                available++;
                if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE))
                {
                    code_size++;
                    code_mask += available;
                }
                old_code = in_code;
            }
            // Pop a pixel off the pixel stack.
            top--;
            pixels[pi++] = pixelStack[top];
            i++;
        }
        for (i = pi; i < npix; i++)
        {
            pixels[i] = 0; // clear missing pixels
        }
    }
    
    protected boolean err()
    {
        return status != STATUS_OK;
    }
    
    protected void init()
    {
        status = STATUS_OK;
        frameCount = 0;
        frames = new Vector<>();
        gct = null;
        lct = null;
    }
    
    protected int read()
    {
        int curByte = 0;
        try
        {
            curByte = in.read();
        }
        catch (Exception e)
        {
            status = STATUS_FORMAT_ERROR;
        }
        return curByte;
    }
    
    protected int readBlock()
    {
        blockSize = read();
        int n = 0;
        if (blockSize > 0)
        {
            try
            {
                int count;// = 0;
                while (n < blockSize)
                {
                    count = in.read(block, n, blockSize - n);
                    if (count == -1)
                    {
                        break;
                    }
                    n += count;
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            if (n < blockSize)
            {
                status = STATUS_FORMAT_ERROR;
            }
        }
        return n;
    }
    
    protected int[] readColorTable(int ncolors)
    {
        int nbytes = 3 * ncolors;
        int[] tab = null;
        byte[] c = new byte[nbytes];
        int n = 0;
        try
        {
            n = in.read(c);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        if (n < nbytes)
        {
            status = STATUS_FORMAT_ERROR;
        }
        else
        {
            tab = new int[256]; // max size to avoid bounds checks
            int i = 0;
            int j = 0;
            while (i < ncolors)
            {
                int r = ((int) c[j++]) & 0xff;
                int g = ((int) c[j++]) & 0xff;
                int b = ((int) c[j++]) & 0xff;
                tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
            }
        }
        return tab;
    }
    
    protected void readContents()
    {
        // read GIF file content blocks
        boolean done = false;
        while (!(done || err()))
        {
            int code = read();
            switch (code)
            {
                case 0x2C: // image separator
                    readBitmap();
                    break;
                case 0x21: // extension
                    code = read();
                    switch (code)
                    {
                        case 0xf9: // graphics control extension
                            readGraphicControlExt();
                            break;
                        case 0xff: // application extension
                            readBlock();
                            String app = "";
                            for (int i = 0; i < 11; i++)
                            {
                                app += (char) block[i];
                            }
                            if (app.equals("NETSCAPE2.0"))
                            {
                                readNetscapeExt();
                            }
                            else
                            {
                                skip(); // don't care
                            }
                            break;
                        case 0xfe:// comment extension
                            skip();
                            break;
                        case 0x01:// plain text extension
                            skip();
                            break;
                        default: // uninteresting extension
                            skip();
                    }
                    break;
                case 0x3b: // terminator
                    done = true;
                    break;
                case 0x00: // bad byte, but keep going and see what happens break;
                default:
                    status = STATUS_FORMAT_ERROR;
            }
        }
    }
    
    protected void readGraphicControlExt()
    {
        read(); // block size
        int packed = read(); // packed fields
        dispose = (packed & 0x1c) >> 2; // disposal method
        if (dispose == 0)
        {
            dispose = 1; // elect to keep old image if discretionary
        }
        transparency = (packed & 1) != 0;
        delay = readShort() * 10; // delay in milliseconds
        transIndex = read(); // transparent color index
        read(); // block terminator
    }
    
    protected void readHeader()
    {
        String id = "";
        for (int i = 0; i < 6; i++)
        {
            id += (char) read();
        }
        if (!id.startsWith("GIF"))
        {
            status = STATUS_FORMAT_ERROR;
            return;
        }
        readLSD();
        if (gctFlag && !err())
        {
            gct = readColorTable(gctSize);
            bgColor = gct[bgIndex];
        }
    }
    
    protected void readBitmap()
    {
        ix = readShort(); // (sub)image position & size
        iy = readShort();
        iw = readShort();
        ih = readShort();
        int packed = read();
        lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace
        lctSize = (int) Math.pow(2, (packed & 0x07) + 1);
        interlace = (packed & 0x40) != 0;
        if (lctFlag)
        {
            lct = readColorTable(lctSize); // read table
            act = lct; // make local table active
        }
        else
        {
            act = gct; // make global table active
            if (bgIndex == transIndex)
            {
                bgColor = 0;
            }
        }
        int save = 0;
        if (transparency)
        {
            save = act[transIndex];
            act[transIndex] = 0; // set transparent color if specified
        }
        if (act == null)
        {
            status = STATUS_FORMAT_ERROR; // no color table defined
        }
        if (err())
        {
            return;
        }
        decodeBitmapData(); // decode pixel data
        skip();
        if (err())
        {
            return;
        }
        frameCount++;
        // create new image to receive frame data
        image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
        setPixels(); // transfer pixel data to image
        frames.addElement(new GifFrame(image, delay)); // add image to frame
        // list
        if (transparency)
        {
            act[transIndex] = save;
        }
        resetFrame();
    }
    
    protected void readLSD()
    {
        // logical screen size
        width = readShort();
        height = readShort();
        // packed fields
        int packed = read();
        gctFlag = (packed & 0x80) != 0; // 1 : global color table flag
        // 2-4 : color resolution
        // 5 : gct sort flag
        gctSize = 2 << (packed & 7); // 6-8 : gct size
        bgIndex = read(); // background color index
        pixelAspect = read(); // pixel aspect ratio
    }
    
    protected void readNetscapeExt()
    {
        do
        {
            readBlock();
            if (block[0] == 1)
            {
                // loop count sub-block
                int b1 = ((int) block[1]) & 0xff;
                int b2 = ((int) block[2]) & 0xff;
                loopCount = (b2 << 8) | b1;
            }
        } while ((blockSize > 0) && !err());
    }
    
    protected int readShort()
    {
        // read 16-bit value, LSB first
        return read() | (read() << 8);
    }
    
    protected void resetFrame()
    {
        lastDispose = dispose;
        lrx = ix;
        lry = iy;
        lrw = iw;
        lrh = ih;
        lastBitmap = image;
        lastBgColor = bgColor;
        dispose = 0;
        transparency = false;
        delay = 0;
        lct = null;
    }
    
    protected void skip()
    {
        do
        {
            readBlock();
        } while ((blockSize > 0) && !err());
    }
    
    private static class GifFrame
    {
        public Bitmap image;
        public int delay;
    
        public GifFrame(Bitmap im, int del)
        {
            image = im;
            delay = del;
        }
    }
    

    }

    GifDecoderView.java

    public class GifDecoderView extends ImageView
    {
    public static final String LOG = GifDecoderView.class.getSimpleName();

    final Handler mHandler = new Handler();
    private boolean mIsPlayingGif = false;
    private GifDecoder mGifDecoder;
    private Bitmap mTmpBitmap;
    final Runnable mUpdateResults = new Runnable()
    {
        public void run()
        {
            if (mTmpBitmap != null && !mTmpBitmap.isRecycled())
            {
                GifDecoderView.this.setImageBitmap(mTmpBitmap);
            }
        }
    };
    
    private ImageLoader imageLoader;
    
    public GifDecoderView(Context context, InputStream stream)
    {
        super(context);
        playGif(stream);
    }
    
    public GifDecoderView(Context context, String url)
    {
        super(context);
    
        imageLoader = MyUIL.get(context);
    
        imageLoader.loadImage(url, MyUIL.getSimple(), new SimpleImageLoadingListener()
        {
            @Override
            public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage)
            {
                super.onLoadingComplete(imageUri, view, loadedImage);
                Log.i(LOG, "onLoadingComplete for URI: "+imageUri);
    
                File file = DiskCacheUtils.findInCache(imageUri, imageLoader.getDiskCache());
    
                try
                {
                    FileInputStream in = new FileInputStream(file);
                    playGif(in);
                }
                catch (FileNotFoundException e)
                {
                    e.printStackTrace();
                }
            }
        });
    }
    
    private void playGif(InputStream stream)
    {
        Log.i(LOG, "playGif");
        mGifDecoder = new GifDecoder();
        mGifDecoder.read(stream);
    
        mIsPlayingGif = true;
    
        new Thread(new Runnable()
        {
            public void run()
            {
                final int n = mGifDecoder.getFrameCount();
                final int ntimes = mGifDecoder.getLoopCount();
                int repetitionCounter = 0;
                do
                {
                    for (int i = 0; i < n; i++)
                    {
                        mTmpBitmap = mGifDecoder.getFrame(i);
                        int t = mGifDecoder.getDelay(i);
                        mHandler.post(mUpdateResults);
                        try
                        {
                            Thread.sleep(t);
                        }
                        catch (InterruptedException e)
                        {
                            e.printStackTrace();
                        }
                    }
                    if (ntimes != 0)
                    {
                        repetitionCounter++;
                    }
                } while (mIsPlayingGif && (repetitionCounter <= ntimes));
            }
        }).start();
    }
    
    public void stopRendering()
    {
        mIsPlayingGif = true;
    }
    

    }

    Some improved the reference decision by adding the class. GifDecoderView Designer taking place InputStream URL Images, some loads UIL- Uh, after loading comes out of the cash, transforms into FileInputStream It's still coming.




Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2