当前位置: 代码迷 >> Android >> Android银屏内容制作成GIF图方式
  详细解决方案

Android银屏内容制作成GIF图方式

热度:187   发布时间:2016-04-24 11:10:42.0
Android屏幕内容制作成GIF图方式

1.方式
1.1方式一:先把App操作过程录制成视频,然后根据视频转换成Gif
参考:http://www.jb51.net/article/78236.htm
1.2方式二:采用截屏的方式得到bitmaps数组,然后根据bitmaps数组生成gif
2.方式二举例

//截屏类package com.example.androidgifmaker;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.util.ArrayList;import android.app.Activity;import android.graphics.Bitmap;import android.graphics.Rect;import android.util.Log;public class ScreenShot {    public static String TAG = "ScreenShot";    public static ArrayList<Bitmap> bitmaps; //Add your bitmaps from internal or external storage.    // 获取指定Activity的截屏,保存到png文件    private static Bitmap takeScreenShot(Activity activity) {        // View是你需要截图的View        View view = activity.getWindow().getDecorView();        view.setDrawingCacheEnabled(true);        view.buildDrawingCache();        Bitmap b1 = view.getDrawingCache();        // 获取状态栏高度        Rect frame = new Rect();        activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);        int statusBarHeight = frame.top;        Log.i(TAG, "状态栏的高度" + statusBarHeight);        int wintop = activity.getWindow().findViewById(android.R.id.content).getTop();        int titleBarHeight = wintop-statusBarHeight;        Log.i(TAG, "标题栏的高度:"+ titleBarHeight);        // 获取屏幕长和高        int width = activity.getWindowManager().getDefaultDisplay().getWidth();        int height = activity.getWindowManager().getDefaultDisplay().getHeight();        Log.i(TAG, "屏幕的宽度:" + width);        Log.i(TAG, "屏幕的高度:" + height);        // 去掉标题栏        // Bitmap b = Bitmap.createBitmap(b1, 0, 25, 320, 455);        Bitmap b = Bitmap.createBitmap(b1, 0, statusBarHeight, width, height - statusBarHeight);        view.destroyDrawingCache();        return b;    }    // 程序入口    public static void shoot(Activity a) {        if(bitmaps!=null){            bitmaps.add(ScreenShot.takeScreenShot(a));        }    }}
//Gif生成类AnimatedGifMaker.class //开源项目:https://github.com/dilligan/AndroidGifMakerpackage com.example.androidgifmaker;import java.io.BufferedOutputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.nio.ByteBuffer;import android.graphics.Bitmap;import android.graphics.Color;public class AnimatedGifMaker{    // still logs noWRITE and noEXISTER    // use Paint for instance field transparent in the future    protected int width; // image size    protected int height;    protected Color transparent = null; // transparent color if given    protected int transIndex; // transparent index in color table    protected int repeat = -1; // no repeat    protected int delay = 0; // frame delay (hundredths)    protected boolean started = false; // ready to output frames    protected OutputStream out;    protected Bitmap image; // current frame    protected byte[] pixels; // BGR byte array from frame    protected byte[] indexedPixels; // converted frame indexed to palette    protected int colorDepth; // number of bit planes    protected byte[] colorTab; // RGB palette    protected boolean[] usedEntry = new boolean[256]; // active palette entries    protected int palSize = 7; // color table size (bits-1)    protected int dispose = -1; // disposal code (-1 = use default)    protected boolean closeStream = false; // close stream when finished    protected boolean firstFrame = true;    protected boolean sizeSet = false; // if false, get size from first frame    protected int sample = 10; // default sample interval for quantizer    /**     * Sets the delay time between each frame, or changes it for subsequent     * frames (applies to last frame added).     *      * @param ms     *            int delay time in milliseconds     */    public void setDelay(int ms) {        delay = Math.round(ms / 10.0f);    }    /**     * Sets the GIF frame disposal code for the last added frame and any     * subsequent frames. Default is 0 if no transparent color has been set,     * otherwise 2.     *      * @param code     *            int disposal code.     */    public void setDispose(int code) {        if (code >= 0) {            dispose = code;        }    }    /**     * Sets the number of times the set of GIF frames should be played. Default     * is 1; 0 means play indefinitely. Must be invoked before the first image     * is added.     *      * @param iter     *            int number of iterations.     * @return     */    public void setRepeat(int iter) {        if (iter >= 0) {            repeat = iter;        }    }    /**     * MAKES ABSOLUTE WHITE (0,0,0) THE TRANSPARENT COLOR.      *      * @param c     *            Color to be treated as transparent on display.     */    public void setTransparent(Color c) {        transparent = c;    }    /**     * Adds next GIF frame. The frame is not written immediately, but is     * actually deferred until the next frame is received so that timing data     * can be inserted. Invoking <code>finish()</code> flushes all frames. If     * <code>setSize</code> was not invoked, the size of the first image is used     * for all subsequent frames.     *      * @param im     *            BufferedImage containing frame to write.     * @return true if successful.     */    public boolean addFrame(Bitmap im) {        if ((im == null) || !started) {            return false;        }        boolean ok = true;        try {            if (!sizeSet) {                // use first frame's size                setSize(im.getWidth(), im.getHeight());            }            image = im;            getImagePixels(); // convert to correct format if necessary            analyzePixels(); // build color table & map pixels            if (firstFrame) {                writeLSD(); // logical screen descriptior                writePalette(); // global color table                if (repeat >= 0) {                    // use NS app extension to indicate reps                    writeNetscapeExt();                }            }            writeGraphicCtrlExt(); // write graphic control extension THIS IS IT            writeImageDesc(); // image descriptor            if (!firstFrame) {                writePalette(); // local color table            }            writePixels(); // encode and write pixel data            firstFrame = false;        } catch (IOException e) {            ok = false;        }        return ok;    }    /**     * Flushes any pending data and closes output file. If writing to an     * OutputStream, the stream is not closed.     */    public boolean finish() {        if (!started)            return false;        boolean ok = true;        started = false;        try {            out.write(0x3b); // gif trailer            out.flush();            if (closeStream) {                out.close();            }        } catch (IOException e) {            ok = false;        }        // reset for subsequent use        transIndex = 0;        out = null;        image = null;        pixels = null;        indexedPixels = null;        colorTab = null;        closeStream = false;        firstFrame = true;        return ok;    }    /**     * Sets frame rate in frames per second. Equivalent to     * <code>setDelay(1000/fps)</code>.     *      * @param fps     *            float frame rate (frames per second)     */    public void setFrameRate(float fps) {        if (fps != 0f) {            delay = Math.round(100f / fps);        }    }    /**     * Sets quality of color quantization (conversion of images to the maximum     * 256 colors allowed by the GIF specification). Lower values (minimum = 1)     * produce better colors, but slow processing significantly. 10 is the     * default, and produces good color mapping at reasonable speeds. Values     * greater than 20 do not yield significant improvements in speed.     *      * @param quality     *            int greater than 0.     * @return     */    public void setQuality(int quality) {        if (quality < 1)            quality = 1;        sample = quality;    }    /**     * Sets the GIF frame size. The default size is the size of the first frame     * added if this method is not invoked.     *      * @param w     *            int frame width.     * @param h     *            int frame width.     */    public void setSize(int w, int h) {        if (started && !firstFrame)            return;        width = w;        height = h;        if (width < 1)            width = 320;        if (height < 1)            height = 240;        sizeSet = true;    }    /**     * Initiates GIF file creation on the given stream. The stream is not closed     * automatically.     *      * @param os     *            OutputStream on which GIF images are written.     * @return false if initial write failed.     */    public boolean start(OutputStream os) {        if (os == null)            return false;        boolean ok = true;        closeStream = false;        out = os;        try {            writeString("GIF87a"); // header        } catch (IOException e) {            ok = false;        }        return started = ok;    }    /**     * Initiates writing of a GIF file with the specified name.     *      * @param file     *            String containing output file name.     * @return false if open or initial write failed.     */    public boolean start(String file) {        boolean ok = true;        try {            out = new BufferedOutputStream(new FileOutputStream(file));            ok = start(out);            closeStream = true;        } catch (IOException e) {            ok = false;        }        return started = ok;    }    /**     * Analyzes image colors and creates color map.     */    protected void analyzePixels() {        int len = pixels.length;        int nPix = len / 3;        indexedPixels = new byte[nPix];        NeuQuant nq = new NeuQuant(pixels, len, sample);        // initialize quantizer        colorTab = nq.process(); // create reduced palette        // convert map from BGR to RGB        for (int i = 0; i < colorTab.length; i += 3) {            byte temp = colorTab[i];            colorTab[i] = colorTab[i + 2];            colorTab[i + 2] = temp;            usedEntry[i / 3] = false;        }        // map image pixels to new palette        // HACK        int k = 0;        for (int i = 0; i < nPix; i++) {            int index = nq.map(pixels[k++] & 0xff, pixels[k++] & 0xff,                    pixels[k++] & 0xff);            usedEntry[index] = true;            indexedPixels[i] = (byte) index;        }        pixels = null;        colorDepth = 8;        palSize = 7;        // get closest match to transparent color if specified        if (transparent != null) {            transIndex = findClosest(transparent);        }    }    /**     * Returns index of palette color closest to c     *      */    protected int findClosest(Color c) {        if (colorTab == null)            return -1;        // HACK        int r = 0;        int g = 0;        int b = 0;        int minpos = 0;        int dmin = 256 * 256 * 256;        int len = colorTab.length;        for (int i = 0; i < len;) {            int dr = r - (colorTab[i++] & 0xff);            int dg = g - (colorTab[i++] & 0xff);            int db = b - (colorTab[i] & 0xff);            int d = dr * dr + dg * dg + db * db;            int index = i / 3;            if (usedEntry[index] && (d < dmin)) {                dmin = d;                minpos = index;            }            i++;        }        return minpos;    }    /**     * Extracts image pixels into byte array "pixels"     */    protected void getImagePixels() {        // calculate how many bytes our image consists of.        int bytes = image.getByteCount();        ByteBuffer buffer = ByteBuffer.allocate(bytes); // Create a new buffer        image.copyPixelsToBuffer(buffer); // Move the byte data to the buffer        byte[] inputBytes = buffer.array(); // Get the underlying array                                            // containing the data.        pixels = new byte[(3 * inputBytes.length) / 4];        for (int i = 0; i < inputBytes.length / 4; i++) {            byte r = inputBytes[4 * i];            byte g = inputBytes[4 * i + 1];            byte b = inputBytes[4 * i + 2];            // ignore alpha            pixels[3 * i] = r;            pixels[3 * i + 1] = g;            pixels[3 * i + 2] = b;        }        for (int i = 0; i < pixels.length; i += 3) {            //switch R and B            byte temp = pixels[i];            pixels[i] = pixels[i + 2];            pixels[i + 2] = temp;        }    }    /**     * Writes Graphic Control Extension     */    protected void writeGraphicCtrlExt() throws IOException {        out.write(0x21); // extension introducer        out.write(0xf9); // GCE label        out.write(4); // data block size        int transp, disp;        if (transparent == null) {            transp = 0;            disp = 0; // dispose = no action        } else {            transp = 1;            disp = 2; // force clear if using transparent color        }        if (dispose >= 0) {            disp = dispose & 7; // user override        }        disp <<= 2;        // packed fields        out.write(0 | // 1:3 reserved                disp | // 4:6 disposal                0 | // 7 user input - 0 = none                transp); // 8 transparency flag        writeShort(delay); // delay x 1/100 sec        out.write(transIndex); // transparent color index        out.write(0); // block terminator    }    /**     * Writes Image Descriptor     */    protected void writeImageDesc() throws IOException {        out.write(0x2c); // image separator        writeShort(0); // image position x,y = 0,0        writeShort(0);        writeShort(width); // image size        writeShort(height);        // packed fields        if (firstFrame) {            // no LCT - GCT is used for first (or only) frame            out.write(0);        } else {            // specify normal LCT            out.write(0x80 | // 1 local color table 1=yes                    0 | // 2 interlace - 0=no                    0 | // 3 sorted - 0=no                    0 | // 4-5 reserved                    palSize); // 6-8 size of color table        }    }    /**     * Writes Logical Screen Descriptor     */    protected void writeLSD() throws IOException {        // logical screen size        writeShort(width);        writeShort(height);        // packed fields        out.write((0x80 | // 1 : global color table flag = 1 (gct used)        0x70 | // 2-4 : color resolution = 7        0x00 | // 5 : gct sort flag = 0        palSize)); // 6-8 : gct size        out.write(0); // background color index        out.write(0); // pixel aspect ratio - assume 1:1    }    /**     * Writes Netscape application extension to define repeat count.     */    protected void writeNetscapeExt() throws IOException {        out.write(0x21); // extension introducer        out.write(0xff); // app extension label        out.write(11); // block size        writeString("NETSCAPE" + "2.0"); // app id + auth code        out.write(3); // sub-block size        out.write(1); // loop sub-block id        writeShort(repeat); // loop count (extra iterations, 0=repeat forever)        out.write(0); // block terminator    }    /**     * Writes color table     */    protected void writePalette() throws IOException {        out.write(colorTab, 0, colorTab.length);        int n = (3 * 256) - colorTab.length;        for (int i = 0; i < n; i++) {            out.write(0);        }    }    /**     * Encodes and writes pixel data     */    protected void writePixels() throws IOException {        LZWEncoder encoder = new LZWEncoder(width, height, indexedPixels,                colorDepth);        encoder.encode(out);    }    /**     * Write 16-bit value to output stream, LSB first     */    protected void writeShort(int value) throws IOException {        out.write(value & 0xff);        out.write((value >> 8) & 0xff);    }    /**     * Writes string to output stream     */    protected void writeString(String s) throws IOException {        for (int i = 0; i < s.length(); i++) {            out.write((byte) s.charAt(i));        }    }}class NeuQuant {    protected static final int netsize = 256; /* number of colours used */    /* four primes near 500 - assume no image has a length so large */    /* that it is divisible by all four primes */    protected static final int prime1 = 499;    protected static final int prime2 = 491;    protected static final int prime3 = 487;    protected static final int prime4 = 503;    protected static final int minpicturebytes = (3 * prime4);    /* minimum size for input image */    /*     * Program Skeleton ---------------- [select samplefac in range 1..30] [read     * image from input file] pic = (unsigned char*) malloc(3*width*height);     * initnet(pic,3*width*height,samplefac); learn(); unbiasnet(); [write     * output image header, using writecolourmap(f)] inxbuild(); write output     * image using inxsearch(b,g,r)     */    /*     * Network Definitions -------------------     */    protected static final int maxnetpos = (netsize - 1);    protected static final int netbiasshift = 4; /* bias for colour values */    protected static final int ncycles = 100; /* no. of learning cycles */    /* defs for freq and bias */    protected static final int intbiasshift = 16; /* bias for fractions */    protected static final int intbias = (((int) 1) << intbiasshift);    protected static final int gammashift = 10; /* gamma = 1024 */    protected static final int gamma = (((int) 1) << gammashift);    protected static final int betashift = 10;    protected static final int beta = (intbias >> betashift); /* beta = 1/1024 */    protected static final int betagamma = (intbias << (gammashift - betashift));    /* defs for decreasing radius factor */    protected static final int initrad = (netsize >> 3); /*                                                         * for 256 cols, radius                                                         * starts                                                         */    protected static final int radiusbiasshift = 6; /* at 32.0 biased by 6 bits */    protected static final int radiusbias = (((int) 1) << radiusbiasshift);    protected static final int initradius = (initrad * radiusbias); /*                                                                     * and                                                                     * decreases                                                                     * by a                                                                     */    protected static final int radiusdec = 30; /* factor of 1/30 each cycle */    /* defs for decreasing alpha factor */    protected static final int alphabiasshift = 10; /* alpha starts at 1.0 */    protected static final int initalpha = (((int) 1) << alphabiasshift);    protected int alphadec; /* biased by 10 bits */    /* radbias and alpharadbias used for radpower calculation */    protected static final int radbiasshift = 8;    protected static final int radbias = (((int) 1) << radbiasshift);    protected static final int alpharadbshift = (alphabiasshift + radbiasshift);    protected static final int alpharadbias = (((int) 1) << alpharadbshift);    /*     * Types and Global Variables --------------------------     */    protected byte[] thepicture; /* the input image itself */    protected int lengthcount; /* lengthcount = H*W*3 */    protected int samplefac; /* sampling factor 1..30 */    // typedef int pixel[4]; /* BGRc */    protected int[][] network; /* the network itself - [netsize][4] */    protected int[] netindex = new int[256];    /* for network lookup - really 256 */    protected int[] bias = new int[netsize];    /* bias and freq arrays for learning */    protected int[] freq = new int[netsize];    protected int[] radpower = new int[initrad];    /* radpower for precomputation */    /*     * Initialise network in range (0,0,0) to (255,255,255) and set parameters     * -----------------------------------------------------------------------     */    public NeuQuant(byte[] thepic, int len, int sample) {        int i;        int[] p;        thepicture = thepic;        lengthcount = len;        samplefac = sample;        network = new int[netsize][];        for (i = 0; i < netsize; i++) {            network[i] = new int[4];            p = network[i];            p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize;            freq[i] = intbias / netsize; /* 1/netsize */            bias[i] = 0;        }    }    public byte[] colorMap() {        byte[] map = new byte[3 * netsize];        int[] index = new int[netsize];        for (int i = 0; i < netsize; i++)            index[network[i][3]] = i;        int k = 0;        for (int i = 0; i < netsize; i++) {            int j = index[i];            map[k++] = (byte) (network[j][0]);            map[k++] = (byte) (network[j][1]);            map[k++] = (byte) (network[j][2]);        }        return map;    }    /*     * Insertion sort of network and building of netindex[0..255] (to do after     * unbias)     * ------------------------------------------------------------------     * -------------     */    public void inxbuild() {        int i, j, smallpos, smallval;        int[] p;        int[] q;        int previouscol, startpos;        previouscol = 0;        startpos = 0;        for (i = 0; i < netsize; i++) {            p = network[i];            smallpos = i;            smallval = p[1]; /* index on g */            /* find smallest in i..netsize-1 */            for (j = i + 1; j < netsize; j++) {                q = network[j];                if (q[1] < smallval) { /* index on g */                    smallpos = j;                    smallval = q[1]; /* index on g */                }            }            q = network[smallpos];            /* swap p (i) and q (smallpos) entries */            if (i != smallpos) {                j = q[0];                q[0] = p[0];                p[0] = j;                j = q[1];                q[1] = p[1];                p[1] = j;                j = q[2];                q[2] = p[2];                p[2] = j;                j = q[3];                q[3] = p[3];                p[3] = j;            }            /* smallval entry is now in position i */            if (smallval != previouscol) {                netindex[previouscol] = (startpos + i) >> 1;                for (j = previouscol + 1; j < smallval; j++)                    netindex[j] = i;                previouscol = smallval;                startpos = i;            }        }        netindex[previouscol] = (startpos + maxnetpos) >> 1;        for (j = previouscol + 1; j < 256; j++)            netindex[j] = maxnetpos; /* really 256 */    }    /*     * Main Learning Loop ------------------     */    public void learn() {        int i, j, b, g, r;        int radius, rad, alpha, step, delta, samplepixels;        byte[] p;        int pix, lim;        if (lengthcount < minpicturebytes)            samplefac = 1;        alphadec = 30 + ((samplefac - 1) / 3);        p = thepicture;        pix = 0;        lim = lengthcount;        samplepixels = lengthcount / (3 * samplefac);        delta = samplepixels / ncycles;        alpha = initalpha;        radius = initradius;        rad = radius >> radiusbiasshift;        if (rad <= 1)            rad = 0;        for (i = 0; i < rad; i++)            radpower[i] = alpha                    * (((rad * rad - i * i) * radbias) / (rad * rad));        // fprintf(stderr,"beginning 1D learning: initial radius=%d\n", rad);        if (lengthcount < minpicturebytes)            step = 3;        else if ((lengthcount % prime1) != 0)            step = 3 * prime1;        else {            if ((lengthcount % prime2) != 0)                step = 3 * prime2;            else {                if ((lengthcount % prime3) != 0)                    step = 3 * prime3;                else                    step = 3 * prime4;            }        }        i = 0;        while (i < samplepixels) {            b = (p[pix + 0] & 0xff) << netbiasshift;            g = (p[pix + 1] & 0xff) << netbiasshift;            r = (p[pix + 2] & 0xff) << netbiasshift;            j = contest(b, g, r);            altersingle(alpha, j, b, g, r);            if (rad != 0)                alterneigh(rad, j, b, g, r); /* alter neighbours */            pix += step;            if (pix >= lim)                pix -= lengthcount;            i++;            if (delta == 0)                delta = 1;            if (i % delta == 0) {                alpha -= alpha / alphadec;                radius -= radius / radiusdec;                rad = radius >> radiusbiasshift;                if (rad <= 1)                    rad = 0;                for (j = 0; j < rad; j++)                    radpower[j] = alpha                            * (((rad * rad - j * j) * radbias) / (rad * rad));            }        }        // fprintf(stderr,"finished 1D learning: final alpha=%f        // !\n",((float)alpha)/initalpha);    }    /*     * Search for BGR values 0..255 (after net is unbiased) and return colour     * index     * --------------------------------------------------------------------     * --------     */    public int map(int b, int g, int r) {        int i, j, dist, a, bestd;        int[] p;        int best;        bestd = 1000; /* biggest possible dist is 256*3 */        best = -1;        i = netindex[g]; /* index on g */        j = i - 1; /* start at netindex[g] and work outwards */        while ((i < netsize) || (j >= 0)) {            if (i < netsize) {                p = network[i];                dist = p[1] - g; /* inx key */                if (dist >= bestd)                    i = netsize; /* stop iter */                else {                    i++;                    if (dist < 0)                        dist = -dist;                    a = p[0] - b;                    if (a < 0)                        a = -a;                    dist += a;                    if (dist < bestd) {                        a = p[2] - r;                        if (a < 0)                            a = -a;                        dist += a;                        if (dist < bestd) {                            bestd = dist;                            best = p[3];                        }                    }                }            }            if (j >= 0) {                p = network[j];                dist = g - p[1]; /* inx key - reverse dif */                if (dist >= bestd)                    j = -1; /* stop iter */                else {                    j--;                    if (dist < 0)                        dist = -dist;                    a = p[0] - b;                    if (a < 0)                        a = -a;                    dist += a;                    if (dist < bestd) {                        a = p[2] - r;                        if (a < 0)                            a = -a;                        dist += a;                        if (dist < bestd) {                            bestd = dist;                            best = p[3];                        }                    }                }            }        }        return (best);    }    public byte[] process() {        learn();        unbiasnet();        inxbuild();        return colorMap();    }    /*     * Unbias network to give byte values 0..255 and record position i to     * prepare for sort     * ----------------------------------------------------------     * -------------------------     */    public void unbiasnet() {        int i;        for (i = 0; i < netsize; i++) {            network[i][0] >>= netbiasshift;            network[i][1] >>= netbiasshift;            network[i][2] >>= netbiasshift;            network[i][3] = i; /* record colour no */        }    }    /*     * Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in     * radpower[|i-j|]     * ----------------------------------------------------------     * -----------------------     */    protected void alterneigh(int rad, int i, int b, int g, int r) {        int j, k, lo, hi, a, m;        int[] p;        lo = i - rad;        if (lo < -1)            lo = -1;        hi = i + rad;        if (hi > netsize)            hi = netsize;        j = i + 1;        k = i - 1;        m = 1;        while ((j < hi) || (k > lo)) {            a = radpower[m++];            if (j < hi) {                p = network[j++];                try {                    p[0] -= (a * (p[0] - b)) / alpharadbias;                    p[1] -= (a * (p[1] - g)) / alpharadbias;                    p[2] -= (a * (p[2] - r)) / alpharadbias;                } catch (Exception e) {                } // prevents 1.3 miscompilation            }            if (k > lo) {                p = network[k--];                try {                    p[0] -= (a * (p[0] - b)) / alpharadbias;                    p[1] -= (a * (p[1] - g)) / alpharadbias;                    p[2] -= (a * (p[2] - r)) / alpharadbias;                } catch (Exception e) {                }            }        }    }    /*     * Move neuron i towards biased (b,g,r) by factor alpha     * ----------------------------------------------------     */    protected void altersingle(int alpha, int i, int b, int g, int r) {        /* alter hit neuron */        int[] n = network[i];        n[0] -= (alpha * (n[0] - b)) / initalpha;        n[1] -= (alpha * (n[1] - g)) / initalpha;        n[2] -= (alpha * (n[2] - r)) / initalpha;    }    /*     * Search for biased BGR values ----------------------------     */    protected int contest(int b, int g, int r) {        /* finds closest neuron (min dist) and updates freq */        /* finds best neuron (min dist-bias) and returns position */        /*         * for frequently chosen neurons, freq[i] is high and bias[i] is         * negative         */        /* bias[i] = gamma*((1/netsize)-freq[i]) */        int i, dist, a, biasdist, betafreq;        int bestpos, bestbiaspos, bestd, bestbiasd;        int[] n;        bestd = ~(((int) 1) << 31);        bestbiasd = bestd;        bestpos = -1;        bestbiaspos = bestpos;        for (i = 0; i < netsize; i++) {            n = network[i];            dist = n[0] - b;            if (dist < 0)                dist = -dist;            a = n[1] - g;            if (a < 0)                a = -a;            dist += a;            a = n[2] - r;            if (a < 0)                a = -a;            dist += a;            if (dist < bestd) {                bestd = dist;                bestpos = i;            }            biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift));            if (biasdist < bestbiasd) {                bestbiasd = biasdist;                bestbiaspos = i;            }            betafreq = (freq[i] >> betashift);            freq[i] -= betafreq;            bias[i] += (betafreq << gammashift);        }        freq[bestpos] += beta;        bias[bestpos] -= betagamma;        return (bestbiaspos);    }}class LZWEncoder {    private static final int EOF = -1;    private int imgW, imgH;    private byte[] pixAry;    private int initCodeSize;    private int remaining;    private int curPixel;    // GIFCOMPR.C - GIF Image compression routines    //    // Lempel-Ziv compression based on 'compress'. GIF modifications by    // David Rowley (mgardi@watdcsu.waterloo.edu)    // General DEFINEs    static final int BITS = 12;    static final int HSIZE = 5003; // 80% occupancy    // GIF Image compression - modified 'compress'    //    // Based on: compress.c - File compression ala IEEE Computer, June 1984.    //    // By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)    // Jim McKie (decvax!mcvax!jim)    // Steve Davies (decvax!vax135!petsd!peora!srd)    // Ken Turkowski (decvax!decwrl!turtlevax!ken)    // James A. Woods (decvax!ihnp4!ames!jaw)    // Joe Orost (decvax!vax135!petsd!joe)    int n_bits; // number of bits/code    int maxbits = BITS; // user settable max # bits/code    int maxcode; // maximum code, given n_bits    int maxmaxcode = 1 << BITS; // should NEVER generate this code    int[] htab = new int[HSIZE];    int[] codetab = new int[HSIZE];    int hsize = HSIZE; // for dynamic table sizing    int free_ent = 0; // first unused entry    // block compression parameters -- after all codes are used up,    // and compression rate changes, start over.    boolean clear_flg = false;    // Algorithm: use open addressing double hashing (no chaining) on the    // prefix code / next character combination. We do a variant of Knuth's    // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime    // secondary probe. Here, the modular division first probe is gives way    // to a faster exclusive-or manipulation. Also do block compression with    // an adaptive reset, whereby the code table is cleared when the compression    // ratio decreases, but after the table fills. The variable-length output    // codes are re-sized at this point, and a special CLEAR code is generated    // for the decompressor. Late addition: construct the table according to    // file size for noticeable speed improvement on small files. Please direct    // questions about this implementation to ames!jaw.    int g_init_bits;    int ClearCode;    int EOFCode;    // output    //    // Output the given code.    // Inputs:    // code: A n_bits-bit integer. If == -1, then EOF. This assumes    // that n_bits =< wordsize - 1.    // Outputs:    // Outputs code to the file.    // Assumptions:    // Chars are 8 bits long.    // Algorithm:    // Maintain a BITS character long buffer (so that 8 codes will    // fit in it exactly). Use the VAX insv instruction to insert each    // code in turn. When the buffer fills up empty it and start over.    int cur_accum = 0;    int cur_bits = 0;    int masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F,            0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF,            0x7FFF, 0xFFFF };    // Number of characters so far in this 'packet'    int a_count;    // Define the storage for the packet accumulator    byte[] accum = new byte[256];    // ----------------------------------------------------------------------------    LZWEncoder(int width, int height, byte[] pixels, int color_depth) {        imgW = width;        imgH = height;        pixAry = pixels;        initCodeSize = Math.max(2, color_depth);    }    // Add a character to the end of the current packet, and if it is 254    // characters, flush the packet to disk.    void char_out(byte c, OutputStream outs) throws IOException {        accum[a_count++] = c;        if (a_count >= 254)            flush_char(outs);    }    // Clear out the hash table    // table clear for block compress    void cl_block(OutputStream outs) throws IOException {        cl_hash(hsize);        free_ent = ClearCode + 2;        clear_flg = true;        output(ClearCode, outs);    }    // reset code table    void cl_hash(int hsize) {        for (int i = 0; i < hsize; ++i)            htab[i] = -1;    }    void compress(int init_bits, OutputStream outs) throws IOException {        int fcode;        int i /* = 0 */;        int c;        int ent;        int disp;        int hsize_reg;        int hshift;        // Set up the globals: g_init_bits - initial number of bits        g_init_bits = init_bits;        // Set up the necessary values        clear_flg = false;        n_bits = g_init_bits;        maxcode = MAXCODE(n_bits);        ClearCode = 1 << (init_bits - 1);        EOFCode = ClearCode + 1;        free_ent = ClearCode + 2;        a_count = 0; // clear packet        ent = nextPixel();        hshift = 0;        for (fcode = hsize; fcode < 65536; fcode *= 2)            ++hshift;        hshift = 8 - hshift; // set hash code range bound        hsize_reg = hsize;        cl_hash(hsize_reg); // clear hash table        output(ClearCode, outs);        outer_loop: while ((c = nextPixel()) != EOF) {            fcode = (c << maxbits) + ent;            i = (c << hshift) ^ ent; // xor hashing            if (htab[i] == fcode) {                ent = codetab[i];                continue;            } else if (htab[i] >= 0) // non-empty slot            {                disp = hsize_reg - i; // secondary hash (after G. Knott)                if (i == 0)                    disp = 1;                do {                    if ((i -= disp) < 0)                        i += hsize_reg;                    if (htab[i] == fcode) {                        ent = codetab[i];                        continue outer_loop;                    }                } while (htab[i] >= 0);            }            output(ent, outs);            ent = c;            if (free_ent < maxmaxcode) {                codetab[i] = free_ent++; // code -> hashtable                htab[i] = fcode;            } else                cl_block(outs);        }        // Put out the final code.        output(ent, outs);        output(EOFCode, outs);    }    // ----------------------------------------------------------------------------    void encode(OutputStream os) throws IOException {        os.write(initCodeSize); // write "initial code size" byte        remaining = imgW * imgH; // reset navigation variables        curPixel = 0;        compress(initCodeSize + 1, os); // compress and write the pixel data        os.write(0); // write block terminator    }    // Flush the packet to disk, and reset the accumulator    void flush_char(OutputStream outs) throws IOException {        if (a_count > 0) {            outs.write(a_count);            outs.write(accum, 0, a_count);            a_count = 0;        }    }    final int MAXCODE(int n_bits) {        return (1 << n_bits) - 1;    }    // ----------------------------------------------------------------------------    // Return the next pixel from the image    // ----------------------------------------------------------------------------    private int nextPixel() {        if (remaining == 0)            return EOF;        --remaining;        byte pix = pixAry[curPixel++];        return pix & 0xff;    }    void output(int code, OutputStream outs) throws IOException {        cur_accum &= masks[cur_bits];        if (cur_bits > 0)            cur_accum |= (code << cur_bits);        else            cur_accum = code;        cur_bits += n_bits;        while (cur_bits >= 8) {            char_out((byte) (cur_accum & 0xff), outs);            cur_accum >>= 8;            cur_bits -= 8;        }        // If the next entry is going to be too big for the code size,        // then increase it, if possible.        if (free_ent > maxcode || clear_flg) {            if (clear_flg) {                maxcode = MAXCODE(n_bits = g_init_bits);                clear_flg = false;            } else {                ++n_bits;                if (n_bits == maxbits)                    maxcode = maxmaxcode;                else                    maxcode = MAXCODE(n_bits);            }        }        if (code == EOFCode) {            // At EOF, write the rest of the buffer.            while (cur_bits > 0) {                char_out((byte) (cur_accum & 0xff), outs);                cur_accum >>= 8;                cur_bits -= 8;            }            flush_char(outs);        }    }}
package com.example.androidgifmaker;import java.io.File;import java.io.FileOutputStream;import android.annotation.SuppressLint;import android.app.Activity;import android.app.ProgressDialog;import android.content.Intent;import android.graphics.Color;import android.net.Uri;import android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.os.Message;import android.view.Menu;import android.view.MenuItem;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends Activity {    ProgressDialog progressBar;    private TextView tv;    private int count;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        tv = (TextView)findViewById(R.id.text);        new Thread(new TvRunnable()).start();    }    class TvRunnable implements Runnable{        @Override        public void run() {            // TODO Auto-generated method stub            while(true){                count++;                myHandler.sendEmptyMessage(1);                try {                    Thread.sleep(100);                } catch (InterruptedException e) {                    // TODO Auto-generated catch block                    e.printStackTrace();                }            }        }    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        // Inflate the menu; this adds items to the action bar if it is present.        getMenuInflater().inflate(R.menu.main, menu);        return true;    }    @Override    public boolean onOptionsItemSelected(MenuItem item) {        // TODO Auto-generated method stub        switch (item.getItemId()) {        case R.id.action_settings:            new Thread(new ShootRunnable(2)).start();            break;        default:            break;        }        return super.onOptionsItemSelected(item);    }    class ShootRunnable implements Runnable{        private int second;        private int frameNum = 0;        ShootRunnable(int second){            this.second = second;            ScreenShot.prepareShoot();        }        @Override        public void run() {            // TODO Auto-generated method stub            while(second>0){                while (frameNum<10) {                    long start = System.currentTimeMillis();                    ScreenShot.shoot(MainActivity.this);                    long offset;                    if((offset = (System.currentTimeMillis()-start))<100){                        try {                            Thread.sleep(offset);                        } catch (InterruptedException e) {                            // TODO Auto-generated catch block                            e.printStackTrace();                        }                    }                    frameNum++;                }                second--;                frameNum = 0;            }            myHandler.sendEmptyMessage(0);        }    }    Handler myHandler = new Handler(){        public void handleMessage(Message msg){            switch (msg.what) {            case 0:                makeGif();                break;            case 1:                tv.setText(count+"");                break;            default:                break;            }        };    };    public void makeGif() {        String name = "MyGif";        progressBar = ProgressDialog.show(this, "Converting...", "0%", true, false);        GifThread gt = new GifThread(name);        gt.start();        Toast.makeText(                this,                "You can access the gif in your SD Card storage, under the file Flippy. This directory is: "                        + Environment.getExternalStorageDirectory().toString()                        + "/Gifs",                Toast.LENGTH_LONG).show();    }    private class GifThread extends Thread{        private String name;         private int i;        public GifThread(String proj) { // ONLY WORKS AFTER SAVING                name=proj;        }        @Override         public void run(){            String root = Environment.getExternalStorageDirectory().toString();            File myDir = new File(root + "/Gifs/");            if(!myDir.exists())                myDir.mkdirs();            String fname = name;            File file = new File(myDir, fname + ".gif");            if (file.exists()){                file.delete();            }            try {                FileOutputStream out = new FileOutputStream(file);                AnimatedGifMaker gifs = new AnimatedGifMaker();                gifs.start(out);                gifs.setFrameRate(10);                gifs.setRepeat(0);                gifs.setTransparent(new Color());                for (i = 0; i < ScreenShot.bitmaps.size(); i++) {                    gifs.addFrame(ScreenShot.bitmaps.get(i));                    handler.sendEmptyMessage(1);                }                gifs.finish();                sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,                        Uri.parse("file://"                                + Environment.getExternalStorageDirectory()))); // uM                                                                                // HACK            } catch (Exception e) {                e.printStackTrace();            }            handler.sendEmptyMessage(0);        }        @SuppressLint("HandlerLeak")        private Handler handler = new Handler() {            @Override            public void handleMessage(Message msg) {                switch (msg.what) {                case 0:                    progressBar.dismiss();                    break;                case 1:                    progressBar.setMessage(i*100/(ScreenShot.bitmaps.size()-1)+"%");                    break;                default:                    break;                }            }        };    }}
//AndroidManifest.xml权限声明<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>

3.结果
3.1运行时
这里写图片描述
3.2生成的gif图
这里写图片描述
3.3备注
项目生成2秒,每秒10帧的gif图,存储目录在SD卡的Gifs文件夹
4.总结:
4.1完成对当前的activity的内容制作成gif图,甚至可以指定view进行制作,但是制作时不可切换activity
4.2制作时间是根据截图的文件大小决定,由于此处采用原图进行制作,所以耗时较长,可以采用压缩原图方式进行制作,减少制作时间
5.工程源码:https://github.com/HQlin/AndroidGifMaker

  相关解决方案