b = (((*p)) & 0xff) << netbiasshift;
这句话在gifflen中经常出错,发现原来是源码的一个bug,修正如下:
if (p >= (unsigned int *)lim) p -= lengthcount;
变为:
if (p >= (unsigned int *)lim) p = (unsigned int*)thepicture;
原文:http://blog.leepood.com/the-android-gif-maker
最近做项目有个需求就是将若干张图片合成Gif动画,大家都知道在Android平台上目前是不支持Gif的,所以利用本地的Api是不可能达到目的的,于是上网查资料,得知用NDK可以达到目的OK,折腾一番搞定,下面分享下:
首先NDK的环境搭建我就不讲了,这些可以查网上的,首选去http://jiggawatt.org/badc0de/android/index.html#gifflen下载gifflen的源码来编译。
下载到源码之后我们要做的就是修改下方法名称,NDK里面书写方法的名称需同你native 类的包名相同,举个例子我的native方法类的完整路径是:
1
|
com.leepood.gifmaker.GifUtil
|
那么我需要将下载回来的源码里面的jni call的方法名称改为以Java_com_leepood_gifmaker_GitUtil_开头,这样一切就OK拉,于是NDK编译得到libgifflen.so文件。(注意:修改有六个地方:声明和实现总共6处,都要修改)
于是在java里面调用,上我写的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
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();
}
}
|
以上是原文。
但是在具体运行的时候,会发现有如下错误:
1
|
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中出了问题:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
/* 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<rad; 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 < samplepixels) {
/*b = p[0] << netbiasshift;
g = p[1] << netbiasshift;
r = p[2] << netbiasshift;*/
b = (((*p)) & 0xff) << netbiasshift;
g = (((*p) >> 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<rad; 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了,不会出问题了。