/*http://my.oschina.net/lifj/blog/233670*/
原文:
最近做项目有个需求就是将若干张图片合成Gif动画,大家都知道在Android平台上目前是不支持Gif的,所以利用本地的Api是不可能达到目的的,于是上网查资料,得知用NDK可以达到目的OK,折腾一番搞定,下面分享下:
首先NDK的环境搭建我就不讲了,这些可以查网上的,首选去下载gifflen的源码来编译。
下载到源码之后我们要做的就是修改下方法名称,NDK里面书写方法的名称需同你native 类的包名相同,举个例子我的native方法类的完整路径是:
com.leepood.gifmaker.GifUtil
那么我需要将下载回来的源码里面的jni call的方法名称改为以Java_com_leepood_gifmaker_GitUtil_开头,这样一切就OK拉,于是NDK编译得到libgifflen.so文件。(注意:修改有六个地方:声明和实现总共6处,都要修改)
于是在java里面调用,上我写的代码:
package com.leepood.gifmaker;import android.graphics.Bitmap;import android.util.Log;public class GifUtil { private final String TAG=this.getClass().getName(); static { System.loadLibrary("gifflen"); } /** * Init the gif file * @param gifName name * @param w width * @param h height * @param numColors colors * @param quality * @param frameDelay times * @return */ public native int Init(String gifName, int w, int h, int numColors, int quality, int frameDelay); public native void Close(); public native int AddFrame(int[] pixels); /** * encode the bitmaps to gif * @param fileName * @param bitmaps * @param delay */ public void Encode(String fileName,Bitmap[] bitmaps,int delay) { if(bitmaps==null||bitmaps.length==0) { throw new NullPointerException("Bitmaps should have content!!!"); } int width=bitmaps[0].getWidth(); int height=bitmaps[0].getHeight(); if(Init(fileName,width,height,256,100,delay)!=0) { Log.e(TAG, "GifUtil init failed"); return; } for(Bitmap bp:bitmaps) { int pixels[]=new int[width*height]; bp.getPixels(pixels, 0, width, 0, 0, width, height); AddFrame(pixels); } Close(); }}
以上是原文。
但是在具体运行的时候,会发现有如下错误:
Fatal signal 11 (SIGSEGV) at 0x5c1f2258 (code=2), thread 12065 (Thread-99423)
致命的信号 11 和在应用程序重新启动。
日志如下:
I/DEBUG(95): backtrace:I/DEBUG(95): #00 pc 00002a04 /lib/libgifflen.so (NeuQuant::learn()+239)I/DEBUG(95): #01 pc 00002b9d /lib/libgifflen.so (NeuQuant::quantise(DIB*, DIB*, int, int, int)+84)I/DEBUG(95): #02 pc 00002d41 lib/libgifflen.so (Java_com_stay_gif_GifEncoder_addFrame+208)I/DEBUG(95): #03 pc 0001deb0 /system/lib/libdvm.so (dvmPlatformInvoke+112)I/DEBUG(95): #04 pc 0004d103 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+394)I/DEBUG(95): #05 pc 0004f21f /system/lib/libdvm.so (dvmResolveNativeMethod(unsigned int const*, JValue*, Method const*, Thread*)+174)I/DEBUG(95): #06 pc 000272e0 /system/lib/libdvm.soI/DEBUG(95): #07 pc 0002bbe8 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+180)I/DEBUG(95): #08 pc 0005fb37 /system/lib/libdvm.so (dvmInvokeMethod(Object*, Method const*, ArrayObject*, ArrayObject*, ClassObject*, bool)+374)I/DEBUG(95): #09 pc 000670e5 /system/lib/libdvm.soI/DEBUG(95): #10 pc 000272e0 /system/lib/libdvm.soI/DEBUG(95): #11 pc 0002bbe8 /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+180)I/DEBUG(95): #12 pc 0005f871 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+272)I/DEBUG(95): #13 pc 000496f3 /system/lib/libdvm.soI/DEBUG(95): #14 pc 00048581 /system/lib/libandroid_runtime.soI/DEBUG(95): #15 pc 00049637 /system/lib/libandroid_runtime.so (android::AndroidRuntime::start(char const*, char const*)+390)I/DEBUG(95): #16 pc 00000dcf /system/bin/app_process
看到是在learn中出了问题:
/* Main Learning Loop ------------------ */void NeuQuant::learn(){int i,j,b,g,r;int radius,rad,alpha,step,delta,samplepixels;//unsigned char *p;unsigned int *p;unsigned char *lim;alphadec = 30 + ((samplefac-1)/3);p = (unsigned int*)thepicture;lim = thepicture + lengthcount;samplepixels = lengthcount/(PIXEL_SIZE*samplefac);delta = samplepixels/ncycles;alpha = initalpha;radius = initradius;rad = radius >> radiusbiasshift;if (rad <= 1) rad = 0;for (i=0; i> 8) & 0xff) << netbiasshift;r = (((*p) >> 16) & 0xff) << netbiasshift;j = contest(b,g,r);altersingle(alpha,j,b,g,r);if (rad) alterneigh(rad,j,b,g,r); /* alter neighbours */p += step;if (p >= (unsigned int *)lim) p -= lengthcount; //这里有问题i++;if (i%delta == 0) {alpha -= alpha / alphadec;radius -= radius / radiusdec;rad = radius >> radiusbiasshift;if (rad <= 1) rad = 0;for (j=0; j
我改变了:
if (p >= (unsigned int *)lim) p -= lengthcount;
变为:
if (p >= (unsigned int *)lim) p = (unsigned int*)thepicture;
这样就OK了,不会出问题了。