diff --git a/src/main/jni/bitmap.c b/src/main/jni/bitmap.c index 90ff293f..79a10036 100644 --- a/src/main/jni/bitmap.c +++ b/src/main/jni/bitmap.c @@ -65,6 +65,8 @@ Java_pl_droidsonroids_gif_GifInfoHandle_renderFrame(JNIEnv *env, jclass __unused return 0; } DDGifSlurp(info, true); + if (info->currentIndex == 0) + prepareCanvas(pixels, info); const uint_fast32_t frameDuration = getBitmap((argb *) pixels, info); unlockPixels(env, jbitmap); return calculateInvalidationDelay(info, renderStartTime, frameDuration); diff --git a/src/main/jni/control.c b/src/main/jni/control.c index 201c4cee..c29bad21 100644 --- a/src/main/jni/control.c +++ b/src/main/jni/control.c @@ -31,6 +31,24 @@ Java_pl_droidsonroids_gif_GifInfoHandle_setSpeedFactor(JNIEnv __unused *env, jcl info->speedFactor = factor; } +static uint_fast32_t seek(GifInfo *info, JNIEnv *env, jint desiredIndex, jobject jbitmap) { + uint_fast32_t lastFrameDuration = info->infos[info->currentIndex].DelayTime; + if (info->currentIndex < desiredIndex) { + void *pixels; + if (lockPixels(env, jbitmap, info, &pixels) != 0) { + return 0; + } + if (info->currentIndex == 0) + prepareCanvas(pixels, info); + while (info->currentIndex < desiredIndex) { + DDGifSlurp(info, true); + lastFrameDuration = getBitmap((argb *) pixels, info); + } + unlockPixels(env, jbitmap); + } + return lastFrameDuration; +} + __unused JNIEXPORT void JNICALL Java_pl_droidsonroids_gif_GifInfoHandle_seekToTime(JNIEnv *env, jclass __unused handleClass, jlong gifInfo, jint desiredPos, jobject jbitmap) { @@ -60,17 +78,7 @@ Java_pl_droidsonroids_gif_GifInfoHandle_seekToTime(JNIEnv *env, jclass __unused info->lastFrameRemainder > info->infos[desiredIndex].DelayTime) info->lastFrameRemainder = info->infos[desiredIndex].DelayTime; } - if (info->currentIndex < desiredIndex) { - void *pixels; - if (lockPixels(env, jbitmap, info, &pixels) != 0) { - return; - } - while (info->currentIndex < desiredIndex) { - DDGifSlurp(info, true); - getBitmap((argb *) pixels, info); - } - unlockPixels(env, jbitmap); - } + seek(info, env, desiredIndex, jbitmap); info->nextStartTime = getRealTime() + (long) (info->lastFrameRemainder / info->speedFactor); } @@ -90,18 +98,7 @@ Java_pl_droidsonroids_gif_GifInfoHandle_seekToFrame(JNIEnv *env, jclass __unused if (desiredIndex >= info->gifFilePtr->ImageCount) desiredIndex = (jint) (info->gifFilePtr->ImageCount - 1); - uint_fast32_t lastFrameDuration = info->infos[info->currentIndex].DelayTime; - if (info->currentIndex < desiredIndex) { - void *pixels; - if (lockPixels(env, jbitmap, info, &pixels) != 0) { - return; - } - while (info->currentIndex < desiredIndex) { - DDGifSlurp(info, true); - lastFrameDuration = getBitmap((argb *) pixels, info); - } - unlockPixels(env, jbitmap); - } + uint_fast32_t lastFrameDuration = seek(info, env, desiredIndex, jbitmap); info->nextStartTime = getRealTime() + (long) (lastFrameDuration / info->speedFactor); if (info->lastFrameRemainder != -1) diff --git a/src/main/jni/drawing.c b/src/main/jni/drawing.c index a36ca41f..a5f4fd3c 100644 --- a/src/main/jni/drawing.c +++ b/src/main/jni/drawing.c @@ -10,7 +10,7 @@ #define MEMSET_ARGB(dst, value, count) memset(dst, value, count * sizeof(argb)) #endif -static void blitNormal(argb *bm, GifInfo *info, SavedImage *frame, ColorMapObject *cmap) { +static inline void blitNormal(argb *bm, GifInfo *info, SavedImage *frame, ColorMapObject *cmap) { unsigned char *src = info->rasterBits; argb *dst = GET_ADDR(bm, info->stride, frame->ImageDesc.Left, frame->ImageDesc.Top); @@ -135,21 +135,22 @@ static inline void disposeFrameIfNeeded(argb *bm, GifInfo *info) { memcpy(backup, bm, info->stride * fGif->SHeight * sizeof(argb)); } -uint_fast32_t const getBitmap(argb *bm, GifInfo *info) { - if (info->currentIndex == 0) { - if (info->gifFilePtr->SColorMap && info->infos[0].TransparentColor == NO_TRANSPARENT_COLOR) { - argb bgColArgb; - bgColArgb.rgb = info->gifFilePtr->SColorMap->Colors[info->gifFilePtr->SBackGroundColor]; - bgColArgb.alpha = 0xFF; - MEMSET_ARGB((uint32_t *) bm, *(uint32_t *) &bgColArgb, info->stride * info->gifFilePtr->SHeight); - } - else { - MEMSET_ARGB((uint32_t *) bm, 0, info->stride * info->gifFilePtr->SHeight); - } +inline void prepareCanvas(argb *bm, GifInfo *info){ + if (info->gifFilePtr->SColorMap && info->infos->TransparentColor == NO_TRANSPARENT_COLOR) { + argb bgColArgb; + bgColArgb.rgb = info->gifFilePtr->SColorMap->Colors[info->gifFilePtr->SBackGroundColor]; + bgColArgb.alpha = 0xFF; + MEMSET_ARGB((uint32_t *) bm, *(uint32_t *) &bgColArgb, info->stride * info->gifFilePtr->SHeight); } else { - disposeFrameIfNeeded(bm, info); + MEMSET_ARGB((uint32_t *) bm, 0, info->stride * info->gifFilePtr->SHeight); } +} + +uint_fast32_t getBitmap(argb *bm, GifInfo *info) { + if (info->currentIndex > 0) + disposeFrameIfNeeded(bm, info); + drawFrame(bm, info, info->gifFilePtr->SavedImages + info->currentIndex); uint_fast32_t frameDuration = info->infos[info->currentIndex].DelayTime; diff --git a/src/main/jni/gif.c b/src/main/jni/gif.c index 1dc88a3d..d1952777 100644 --- a/src/main/jni/gif.c +++ b/src/main/jni/gif.c @@ -50,7 +50,7 @@ static uint_fast8_t streamReadFun(GifFileType *gif, GifByteType *bytes, uint_fas (*env)->DeleteGlobalRef(env, sc->buffer); jbyteArray buffer = (*env)->NewByteArray(env, size); - if (buffer == NULL){ + if (buffer == NULL) { sc->buffer = NULL; return 0; } @@ -117,7 +117,7 @@ Java_pl_droidsonroids_gif_GifInfoHandle_openFile(JNIEnv *env, jclass __unused cl return NULL; } - const char *const filename = (*env)->GetStringUTFChars(env, jfname, 0); + const char *const filename = (*env)->GetStringUTFChars(env, jfname, NULL); if (filename == NULL) { throwException(env, ILLEGAL_STATE_EXCEPTION_BARE, "GetStringUTFChars failed"); return NULL; @@ -360,7 +360,7 @@ JNI_OnLoad(JavaVM *vm, void *__unused reserved) { defaultCmap = GifMakeMapObject(8, NULL); if (defaultCmap != NULL) { uint_fast16_t iColor; - for (iColor = 0; iColor < 256; iColor++) { + for (iColor = 1; iColor < 256; iColor++) { defaultCmap->Colors[iColor].Red = (GifByteType) iColor; defaultCmap->Colors[iColor].Green = (GifByteType) iColor; defaultCmap->Colors[iColor].Blue = (GifByteType) iColor; diff --git a/src/main/jni/gif.h b/src/main/jni/gif.h index 6e6c123c..c98a0bb3 100644 --- a/src/main/jni/gif.h +++ b/src/main/jni/gif.h @@ -186,7 +186,7 @@ void throwGifIOException(int errorCode, JNIEnv *env); jobject createGifHandle(GifSourceDescriptor *descriptor, JNIEnv *env, jboolean justDecodeMetaData); -static void blitNormal(argb *bm, GifInfo *info, SavedImage *frame, ColorMapObject *cmap); +static inline void blitNormal(argb *bm, GifInfo *info, SavedImage *frame, ColorMapObject *cmap); static void drawFrame(argb *bm, GifInfo *info, SavedImage *frame); @@ -194,7 +194,7 @@ static bool checkIfCover(const SavedImage *target, const SavedImage *covered); static void disposeFrameIfNeeded(argb *bm, GifInfo *info); -uint_fast32_t const getBitmap(argb *bm, GifInfo *info); +uint_fast32_t getBitmap(argb *bm, GifInfo *info); bool reset(GifInfo *info); @@ -207,3 +207,5 @@ long calculateInvalidationDelay(GifInfo *info, long renderStartTime, uint_fast32 jint restoreSavedState(GifInfo *info, JNIEnv *env, jlongArray state, void *pixels); void releaseSurfaceDescriptor(SurfaceDescriptor *surfaceDescriptor, JNIEnv *pConst); + +inline void prepareCanvas(argb *bm, GifInfo *info); diff --git a/src/main/jni/metadata.c b/src/main/jni/metadata.c index bc6bbab6..aca5e59d 100644 --- a/src/main/jni/metadata.c +++ b/src/main/jni/metadata.c @@ -156,6 +156,8 @@ jint restoreSavedState(GifInfo *info, JNIEnv *env, jlongArray state, void *pixel uint_fast32_t lastFrameDuration = info->infos[info->currentIndex].DelayTime; if (info->currentIndex < savedIndex) { + if (info->currentIndex == 0) + prepareCanvas(pixels, info); while (info->currentIndex < savedIndex) { DDGifSlurp(info, true); lastFrameDuration = getBitmap((argb *) pixels, info); diff --git a/src/main/jni/surface.c b/src/main/jni/surface.c index 6898ee03..334bbe2c 100644 --- a/src/main/jni/surface.c +++ b/src/main/jni/surface.c @@ -160,9 +160,10 @@ Java_pl_droidsonroids_gif_GifInfoHandle_bindSurface(JNIEnv *env, jclass __unused oldBufferBits = buffer.bits; THROW_AND_BREAK_ON_NONZERO_RESULT(ANativeWindow_lock(window, &buffer, NULL), "Window lock failed"); - if (info->currentIndex > 0) { + if (info->currentIndex == 0) + prepareCanvas(buffer.bits, info); + else memcpy(buffer.bits, oldBufferBits, bufferSize); - } pthread_mutex_lock(&info->surfaceDescriptor->renderMutex); while (info->surfaceDescriptor->renderHelper == 0) { diff --git a/src/main/jni/time.c b/src/main/jni/time.c index ffa255b4..616b567c 100644 --- a/src/main/jni/time.c +++ b/src/main/jni/time.c @@ -7,9 +7,10 @@ long calculateInvalidationDelay(GifInfo *info, long renderStartTime, uint_fast32 invalidationDelay /= info->speedFactor; } const long renderingTime = getRealTime() - renderStartTime; - invalidationDelay -= renderingTime; - if (invalidationDelay < 0) + if (renderingTime >= invalidationDelay) invalidationDelay = 0; + else + invalidationDelay -= renderingTime; info->nextStartTime = renderStartTime + invalidationDelay; return invalidationDelay; }