Подтвердить что ты не робот

Отображение gif в android

У меня есть этот код для отображения gif-изображения с фильмом.

public class GIFView extends View{        
private Movie movie;  
private InputStream is;  
private long moviestart;  
public GIFView(Context context) {  
    super(context);
    is=getResources().openRawResource(R.drawable.anim_cerca);  
    movie=Movie.decodeStream(is);
}  

@Override  
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    long now=android.os.SystemClock.uptimeMillis();  

    if (moviestart == 0) 
        moviestart = now;  

    int relTime = (int)((now - moviestart) % movie.duration());
    movie.setTime(relTime);
    movie.draw(canvas,10,10);
    this.invalidate();
}                         

}

Моя проблема возникает при загрузке gif, она очень плохо рисуется, отображается только первый кадр, а другой подобен нарушенному. Что я могу сделать?

РЕДАКТИРОВАТЬ: ПРОБЛЕМА ЭМУЛЯТОР! ЭТО НЕ ПОКАЗЫВАЕТ GIF, НО НА УСТРОЙСТВЕ ЭТО ОК!:)

4b9b3361

Ответ 1

Я решил таким образом:

public class GIFView extends View{        
    private Movie movie;    
    private long moviestart;  
    public GIFView(Context context) throws IOException {  
        super(context);
    movie=Movie.decodeStream(getResources().getAssets().open("anim_cerca.gif"));
    }
    public GIFView(Context context, AttributeSet attrs) throws IOException{
        super(context, attrs);
    movie=Movie.decodeStream(getResources().getAssets().open("anim_cerca.gif"));
    }
    public GIFView(Context context, AttributeSet attrs, int defStyle) throws IOException {
        super(context, attrs, defStyle);
        movie=Movie.decodeStream(getResources().getAssets().open("anim_cerca.gif"));
    }
@Override  
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
    long now=android.os.SystemClock.uptimeMillis();
    Paint p = new Paint();
    p.setAntiAlias(true);
    if (moviestart == 0) 
            moviestart = now;
            int relTime;
            relTime = (int)((now - moviestart) % movie.duration());
            movie.setTime(relTime);
            movie.draw(canvas,0,0);
            this.invalidate();
       }                         
}    

и в макете я помещаю это пользовательское представление таким образом:

<spazio.digitale.com.GIFView
        android:layout_marginLeft="30dp" android:layout_gravity="center"
        android:layout_width="wrap_content" android:layout_height="220dp"
        android:id="@+id/GIFSingle">
</spazio.digitale.com.GIFView>

Ответ 2

Хорошее начало. Должен сделать его более полезным для загрузки различных gif после добавления в представление и для активов или ресурсов. Кроме того, для устройств с аппаратным ускорением я получал пустые представления, поэтому я отключил этот GIFView.

Кроме того, не забудьте разместить анимированные gif в каталоге res/drawable-xhdpi (или активы, если вы используете этот путь)

public class GIFView extends View{

    Movie movie;
    long moviestart;

    public GIFView(Context context) throws IOException { 
        super(context);
    }
    public GIFView(Context context, AttributeSet attrs) throws IOException{
        super(context, attrs);
    }
    public GIFView(Context context, AttributeSet attrs, int defStyle) throws IOException {
        super(context, attrs, defStyle);
    }

    public void loadGIFResource(Context context, int id)
    {
        //turn off hardware acceleration
        this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        InputStream is=context.getResources().openRawResource(id);
        movie = Movie.decodeStream(is);
    }

    public void loadGIFAsset(Context context, String filename)
    {
        InputStream is;
        try {
            is = context.getResources().getAssets().open(filename);
            movie = Movie.decodeStream(is);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (movie == null) {
            return;
        }

        long now=android.os.SystemClock.uptimeMillis();

        if (moviestart == 0) moviestart = now;

        int relTime;
        relTime = (int)((now - moviestart) % movie.duration());
        movie.setTime(relTime);
        movie.draw(canvas,10,10);
        this.invalidate();
    }
}

Применение:

imageView.loadGIFResource(this, R.drawable.quickguide_1);

и

<com.eyeverify.GIFView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="50dp"
        android:layout_marginTop="110dp"
        android:src="@drawable/quickguide_1"/>

Ответ 3

создать класс класса GifDecoder

 import java.io.InputStream;
 import java.util.Vector;
 import android.graphics.Bitmap;  
 import android.graphics.Bitmap.Config;
 public class GifDecoder
{


public static final int STATUS_OK = 0;
/**
 * File read status: Error decoding file (may be partially decoded)
 */

public static final int STATUS_FORMAT_ERROR = 1;
/**
 * File read status: Unable to open source.
 */

public static final int STATUS_OPEN_ERROR = 2;
protected static final int MAX_STACK_SIZE = 4096*2;
public static final    int MIN_DELAY                   = 100;
public static final    int MIN_DELAY_ENFORCE_THRESHOLD = 20;
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; 
protected int frameCount;
private boolean readComplete;

public GifDecoder()
{
    readComplete = false;
}

private static class GifFrame {
    public GifFrame(Bitmap im, int del) {
        image = im;
        delay = del;
    }

    public Bitmap image;
    public int delay;
}

/**
 * Gets display duration for specified frame.
 *
 * @param n
 *          int index of frame
 * @return delay in milliseconds
 */
public int getDelay(int n) {
    delay = -1;
    if ((n >= 0) && (n < frameCount)) {
        delay = frames.elementAt(n).delay;
        //meets browser compatibility standards
        if (delay < MIN_DELAY_ENFORCE_THRESHOLD) delay = MIN_DELAY;
    }
    return delay;
}

/**
 * Gets the number of frames read from file.
 *
 * @return frame count
 */
public int getFrameCount() {
    return frameCount;
}

/**
 * Gets the first (or only) image read.
 *
 * @return BufferedBitmap containing first frame, or null if none.
 */
public Bitmap getBitmap() {
    return getFrame(0);
}

/**
 * Gets the "Netscape" iteration count, if any. A count of 0 means repeat indefinitiely.
 *
 * @return iteration count if one was specified, else 1.
 */
public int getLoopCount() {
    return loopCount;
}

/**
 * Creates new frame image from current data (and previous frames as specified by their disposition codes).
 */
protected void setPixels() {
    // expose destination image pixels as int array
    int[] dest = new int[width * height];
    // fill in starting image contents based on last image dispose code
    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);
            // copy pixels
            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;
                    }
                }
            }
        }
    }
    // copy each source line to the appropriate place in the destination
    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, Config.ARGB_4444);
}

/**
 * Gets the image contents of frame n.
 *
 * @return BufferedBitmap representation of frame, or null if n is invalid.
 */
public Bitmap getFrame(int n) {
    if (frameCount <= 0)
        return null;
    n = n % frameCount;
    return ((GifFrame) frames.elementAt(n)).image;
}

/**
 * Reads GIF image from stream
 *
 * @param is
 *          containing GIF file.
 * @return read status code (0 = no errors)
 */
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;
    }
    readComplete = true;
    return status;
}

public void complete()
{
    readContents();
    try {
        in.close();
    } catch (Exception e) {
    }
}

/**
 * Decodes LZW image data into pixel array. Adapted from John Cristy BitmapMagick.
 */
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];
    }
    // Initialize GIF data stream decoder.
    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;
    }
    // Decode GIF pixel stream.
    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;
            }
            // Get the next code.
            code = datum & code_mask;
            datum >>= code_size;
                bits -= code_size;
                // Interpret the code
                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;
                // Add a new string to the string table,
                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
    }
}

/**
 * Returns true if an error was encountered during reading/decoding
 */
protected boolean err() {
    return status != STATUS_OK;
}

/**
 * Initializes or re-initializes reader
 */
protected void init() {
    status = STATUS_OK;
    frameCount = 0;
    frames = new Vector<GifFrame>();
    gct = null;
    lct = null;
}

/**
 * Reads a single byte from the input stream.
 */
protected int read() {
    int curByte = 0;
    try {
        curByte = in.read();
    } catch (Exception e) {
        status = STATUS_FORMAT_ERROR;
    }
    return curByte;
}

/**
 * Reads next variable length block from input.
 *
 * @return number of bytes stored in "buffer"
 */
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;
}

/**
 * Reads color table as 256 RGB integer values
 *
 * @param ncolors
 *          int number of colors to read
 * @return int array containing 256 colors (packed ARGB with full alpha)
 */
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;
}

/**
 * Main file parser. Reads GIF content blocks.
 */
protected void readContents() {
    // read GIF file content blocks
    boolean done = false;
    while (!(done || err())) {
        int code = read();
        switch (code) {
        case 0x2C: // image separator
        readBitmap();
        if(!readComplete) return;
        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;
        }
    }
}

/**
 * Reads Graphics Control Extension values
 */
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
}

/**
 * Reads GIF file header information.
 */
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];
    }
}

/**
 * Reads next frame image
 */
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);
    // 3 - sort flag
    // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color
    // table size
    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, 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();
}

/**
 * Reads Logical Screen Descriptor
 */
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
}

/**
 * Reads Netscape extenstion to obtain iteration count
 */
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());
}

/**
 * Reads next 16-bit value, LSB first
 */
protected int readShort() {
    // read 16-bit value, LSB first
    return read() | (read() << 8);
}

/**
 * Resets frame state for reading next image.
 */
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;
}

/**
 * Skips variable length blocks up to and including next zero length block.
 */
protected void skip() {
    do {
        readBlock();
    } while ((blockSize > 0) && !err());
}

}

создать другой класс GifAnimationDrawable

 import java.io.File;
 import java.io.FileInputStream;
 import java.io.BufferedInputStream;
 import java.io.IOException;
 import java.io.InputStream;

 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.Bitmap;

  public class GifAnimationDrawable extends AnimationDrawable
  {
  private boolean decoded;

private GifDecoder mGifDecoder;

private Bitmap mTmpBitmap;

private int height, width;

public GifAnimationDrawable(File f) throws IOException
{
    this(f, false);
}

public GifAnimationDrawable(InputStream is) throws IOException
{
    this(is, false);
}

public GifAnimationDrawable(File f, boolean inline) throws IOException
{
    this(new BufferedInputStream(new FileInputStream(f), 32768), inline);
}

public GifAnimationDrawable(InputStream is, boolean inline) throws IOException
{
    super();
    InputStream bis = is;
    if(!BufferedInputStream.class.isInstance(bis)) bis = new BufferedInputStream(is, 32768);
    decoded = false;
    mGifDecoder = new GifDecoder();
    mGifDecoder.read(bis);
    mTmpBitmap = mGifDecoder.getFrame(0);
    height = mTmpBitmap.getHeight();
    width = mTmpBitmap.getWidth();
    addFrame(new BitmapDrawable(mTmpBitmap), mGifDecoder.getDelay(0));
    setOneShot(mGifDecoder.getLoopCount() != 0);
    setVisible(true, true);
    if(inline){
        loader.run();
    }else{
        new Thread(loader).start();
    }
}

public boolean isDecoded(){ return decoded; }

private Runnable loader = new Runnable(){
    public void run() 
    {
        mGifDecoder.complete();
        int i, n = mGifDecoder.getFrameCount(), t;
        for(i=1;i<n;i++){
            mTmpBitmap = mGifDecoder.getFrame(i);
            t = mGifDecoder.getDelay(i);
            addFrame(new BitmapDrawable(mTmpBitmap), t);
        }
        decoded = true;
        mGifDecoder = null;
    }
};

public int getMinimumHeight(){ return height; }
public int getMinimumWidth(){ return width; }
public int getIntrinsicHeight(){ return height; }
public int getIntrinsicWidth(){ return width; }

}

в классе Mainactivity создайте объект GifAnimationDrawable

 GifAnimationDrawable gif;
 try {
        gif = new GifAnimationDrawable(getResources().openRawResource(
                R.drawable.prof));
    } catch (Exception e) {
        e.printStackTrace();
    }
    ImageView im1 = (ImageView) findViewById(R.id.imageView1);
    gif.setOneShot(false);
    im1.setImageDrawable(gif);
    gif.setVisible(true, true);

используя эти классы, вы можете добавить gif файл в любое представление

Ответ 4

в вашем AndroidManifest.xml, установите для вашего приложения следующий атрибут:

Android: hardwareAccelerated = "ложь"

Ответ 5

Или вы можете просто добавить WebView в свой xml и загрузить изображение gif внутри webview. Вам не нужно ничего делать. Изображение будет автоматически зацикливаться внутри webview

Ответ 6

Самый простой способ - использовать WebView.

Сохраните свой анимированный GIF в папке активы. Затем загрузите GIF, используя следующий код:

WebView wv = (WebView) findViewById(R.id.webView1); wv.loadUrl("file:///android_asset/anim5.gif");

webView1 - ваш идентификатор WebView, а anim5.gif - ваше имя GIF.