/*
http://my.oschina.net/lifj/blog/233670
*/
最近做项目有个需求就是将若干张图片合成Gif动画,大家都知道在Android平台上目前是不支持Gif的,所以利用本地的Api是不可能达到目的的,于是上网查资料,得知用NDK可以达到目的OK,折腾一番搞定,下面分享下:
下载到源码之后我们要做的就是修改下方法名称,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.so
I/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.so
I/DEBUG(95): #10 pc 000272e0 /system/lib/libdvm.so
I/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.so
I/DEBUG(95): #14 pc 00048581 /system/lib/libandroid_runtime.so
I/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
radpower[i] = alpha*(((rad*rad - i*i)*radbias)/(rad*rad));
//fprintf(stderr,"beginning 1D learning: initial radius=%d\n", rad);
sprintf(s, "samplepixels = %d, rad = %d, a=%d, ad=%d, d=%d", samplepixels, rad, alpha, alphadec, delta);
__android_log_write(ANDROID_LOG_VERBOSE, "gifflen",s);
if ((lengthcount%prime1) != 0) step = prime1;
else {
if ((lengthcount%prime2) !=0) step = prime2;
else {
if ((lengthcount%prime3) !=0) step = prime3;
else step = prime4;
}
}
i = 0;
while (i
/*b = p[0] <
g = p[1] <
r = p[2] <
b = (((*p)) & 0xff) <
g = (((*p) >> 8) & 0xff) <
r = (((*p) >> 16) & 0xff) <
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
radpower[j] = alpha*(((rad*rad - j*j)*radbias)/(rad*rad));
}
}
sprintf(s, "final alpha = %f", ((float)alpha)/initalpha);
__android_log_write(ANDROID_LOG_VERBOSE, "gifflen",s);
}
我改变了:
if (p >= (unsigned int *)lim)
p -= lengthcount;
变为:
if (p >= (unsigned int *)lim)
p = (unsigned int*)thepicture;
这样就OK了,不会出问题了。