Compare commits

..
6 Commits
Author SHA1 Message Date
tarsin b221bf8e52 Release 1.8.0.1
CI / Build (push) Has been cancelled
Releases / Build (push) Has been cancelled
2022-07-25 19:16:07 +08:00
tarsin ab9a89685c Code clean 2022-07-25 19:02:10 +08:00
tarsin 41ccb16227 Code clean 2022-07-25 18:42:18 +08:00
tarsin f6bf7b1ba6 No need to thanks image decs anymore 2022-07-25 13:06:24 +08:00
tarsin 09e7113df1 Fix a dirty dealloc 2022-07-25 12:23:52 +08:00
tarsin 62a7e283a4 Should be able to support all format now 2022-07-25 10:51:57 +08:00
19 changed files with 163 additions and 775 deletions

No files matched your search

-4
View File
@@ -54,12 +54,8 @@ Here is the libraries
- [material-components-android](https://github.com/material-components/material-components-android)
- [material-design-icons](https://github.com/google/material-design-icons)
- [Apache Commons Lang](https://commons.apache.org/proper/commons-lang/)
- [apng](http://apng.sourceforge.net/)
- [giflib](http://giflib.sourceforge.net)
- [greenDAO](https://github.com/greenrobot/greenDAO)
- [jsoup](https://github.com/jhy/jsoup)
- [libjpeg-turbo](https://libjpeg-turbo.org/)
- [libpng](http://www.libpng.org/pub/png/libpng.html)
- [okhttp](https://github.com/square/okhttp)
- [roaster](https://github.com/forge/roaster)
- [TapTargetView](https://github.com/KeepSafe/TapTargetView)
+2 -2
View File
@@ -34,8 +34,8 @@ android {
applicationId "moe.tarsin.ehviewer"
minSdkVersion 31
targetSdkVersion 33
versionCode 180000
versionName "1.8.0.0"
versionCode 180001
versionName "1.8.0.1"
resConfigs 'zh', 'zh-rCN', 'zh-rHK', 'zh-rTW', 'es', 'ja', 'ko', 'fr', 'de', 'th'
}
+19 -53
View File
@@ -20,9 +20,7 @@ import android.graphics.Bitmap;
import androidx.annotation.Nullable;
import java.io.BufferedInputStream;
import java.io.FileDescriptor;
import java.io.InputStream;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -54,7 +52,7 @@ public final class Image {
*/
@Nullable
public static Image decode(FileDescriptor fd, boolean partially) {
return nativeDecode(fd, partially);
return nativeDecode(fd);
}
/**
@@ -62,7 +60,7 @@ public final class Image {
*/
@Nullable
public static Image decode(Integer fd, boolean partially) {
return nativeDecodeFdInt(fd, partially);
return nativeDecodeFdInt(fd);
}
/**
@@ -70,7 +68,7 @@ public final class Image {
*/
@Nullable
public static Image decodeAddr(Long addr, boolean partially) {
return nativeDecodeAddr(addr, partially);
return nativeDecodeAddr(addr);
}
/**
@@ -89,34 +87,27 @@ public final class Image {
return sImageCount.get();
}
private static native Image nativeDecode(FileDescriptor fd, boolean partially);
private static native Image nativeDecode(FileDescriptor fd);
private static native Image nativeDecodeFdInt(int fd, boolean partially);
private static native Image nativeDecodeFdInt(int fd);
private static native Image nativeDecodeAddr(long addr, boolean partially);
private static native Image nativeDecodeAddr(long addr);
private static native Image nativeCreate(Bitmap bitmap);
private static native int nativeGetByteCount(long nativePtr, int format);
private static native void nativeRender(long nativePtr, int format,
private static native void nativeRender(long nativePtr,
int srcX, int srcY, Bitmap dst, int dstX, int dstY,
int width, int height, boolean fillBlank, int defaultColor);
int width, int height);
private static native void nativeTexImage(long nativePtr, int format,
boolean init, int offsetX, int offsetY, int width, int height);
private static native void nativeTexImage(long nativePtr, boolean init, int offsetX, int offsetY, int width, int height);
private static native void nativeAdvance(long nativePtr, int format);
private static native void nativeAdvance(long nativePtr);
private static native int nativeGetDelay(long nativePtr, int format);
private static native int nativeGetDelay(long nativePtr);
private static native boolean nativeIsOpaque(long nativePtr, int format);
private static native boolean nativeIsOpaque(long nativePtr);
private static native boolean nativeIsGray(long nativePtr, int format, int error);
private static native void nativeClahe(long nativePtr, int format, boolean toGray);
private static native void nativeRecycle(long nativePtr, int format);
private static native void nativeRecycle(long nativePtr);
/**
* Return the format of the image
@@ -139,14 +130,6 @@ public final class Image {
return mHeight;
}
/**
* Return the minimum number of bytes that can be used to store this image's pixels.
*/
public int getByteCount() {
checkRecycled();
return nativeGetByteCount(mNativePtr, mFormat);
}
private void checkRecycled() {
if (mNativePtr == 0) {
if (mRecycleTracker != null) {
@@ -163,8 +146,7 @@ public final class Image {
public void render(int srcX, int srcY, Bitmap dst, int dstX, int dstY,
int width, int height, boolean fillBlank, int defaultColor) {
checkRecycled();
nativeRender(mNativePtr, mFormat, srcX, srcY, dst, dstX, dstY,
width, height, fillBlank, defaultColor);
nativeRender(mNativePtr, srcX, srcY, dst, dstX, dstY, width, height);
}
/**
@@ -174,7 +156,7 @@ public final class Image {
*/
public void texImage(boolean init, int offsetX, int offsetY, int width, int height) {
checkRecycled();
nativeTexImage(mNativePtr, mFormat, init, offsetX, offsetY, width, height);
nativeTexImage(mNativePtr, init, offsetX, offsetY, width, height);
}
/**
@@ -182,7 +164,7 @@ public final class Image {
*/
public void advance() {
checkRecycled();
nativeAdvance(mNativePtr, mFormat);
nativeAdvance(mNativePtr);
}
/**
@@ -190,7 +172,7 @@ public final class Image {
*/
public int getDelay() {
checkRecycled();
int delay = nativeGetDelay(mNativePtr, mFormat);
int delay = nativeGetDelay(mNativePtr);
return delay <= 10 ? 100 : delay;
}
@@ -199,23 +181,7 @@ public final class Image {
*/
public boolean isOpaque() {
checkRecycled();
return nativeIsOpaque(mNativePtr, mFormat);
}
/**
* Return {@code true} if the image is gray.
*/
public boolean isGray(int error) {
checkRecycled();
return nativeIsGray(mNativePtr, mFormat, error);
}
/**
* Improves contrast in this image with CLAHE.
*/
public void clahe(boolean toGray) {
checkRecycled();
nativeClahe(mNativePtr, mFormat, toGray);
return nativeIsOpaque(mNativePtr);
}
/**
@@ -225,7 +191,7 @@ public final class Image {
*/
public void recycle() {
if (mNativePtr != 0) {
nativeRecycle(mNativePtr, mFormat);
nativeRecycle(mNativePtr);
mNativePtr = 0;
sImageCount.getAndDecrement();
@@ -45,7 +45,6 @@ public final class ImageBitmap implements Animatable, Runnable {
private final Bitmap mBitmap;
private final int mFormat;
private final boolean mIsOpaque;
private final int mByteCount;
private final Set<WeakReference<Callback>> mCallbackSet = new LinkedHashSet<>();
@Nullable
private Image mImage;
@@ -60,7 +59,6 @@ public final class ImageBitmap implements Animatable, Runnable {
image.render(0, 0, mBitmap, 0, 0, width, height, false, 0);
mFormat = image.getFormat();
mIsOpaque = image.isOpaque();
mByteCount = image.getByteCount();
if (mFormat == 1) {
// For animated image, save image object
@@ -75,7 +73,6 @@ public final class ImageBitmap implements Animatable, Runnable {
mFormat = Image.FORMAT_NORMAL;
mBitmap = bitmap;
mIsOpaque = !bitmap.hasAlpha();
mByteCount = bitmap.getRowBytes() * bitmap.getHeight();
}
/**
@@ -221,13 +218,6 @@ public final class ImageBitmap implements Animatable, Runnable {
return mIsOpaque;
}
/**
* Return byte count of image
*/
public int getByteCount() {
return mByteCount;
}
/**
* Return image is animated
*/
+19 -13
View File
@@ -43,21 +43,27 @@ static char *passwd = NULL;
static void *archiveAddr = NULL;
static jlong archiveSize = 0;
const char supportExt[9][6] = {
"jpeg",
"jpg",
"png",
"gif",
"webp",
"bmp",
"ico",
"wbmp",
"heif"
};
static int filename_is_playable_file(const char *name) {
const char *dotptr = strrchr(name, '.');
if (dotptr++) {
switch (*dotptr) {
case 'j':
return (strcmp(dotptr, "jpg") == 0) || (strcmp(dotptr, "jpeg") == 0);
case 'p':
return strcmp(dotptr, "png") == 0;
case 'g':
return strcmp(dotptr, "gif") == 0;
default:
return 0;
}
}
return 0;
if (!dotptr++)
return false;
int i;
for (i=0; i<9; i++)
if (strcmp(dotptr, supportExt[i]) == 0)
return true;
return false;
}
static long archive_list_all_entries() {
-2
View File
@@ -18,8 +18,6 @@ project(image C)
set(IMAGE_SOURCES
image.c
image_utils.c
filter/clahe.c
filter/gray.c
java_wrapper.c
)
set(IMAGE_INCLUDES
-186
View File
@@ -1,186 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "clahe.h"
#include "pixel.h"
#include "../utils.h"
#include "../log.h"
#define TILE_BLOCK 8
#define LIMIT_MULTIPLE 4
#define CL_MAX_LOOP_NUMBER 4
static BYTE clamp(int t) {
t = t > 255 ? 255 : t;
t = t < 0 ? 0 : t;
return (BYTE) t;
}
void IMAGE_clahe(void *data, int width, int height, bool to_gray) {
if (width < TILE_BLOCK || height < TILE_BLOCK) {
return;
}
PIXEL *pixels = data;
if (to_gray) {
for (int i = 0; i < width * height; ++i) {
PIXEL *p = pixels + i;
int t1 = (int) (p->c1 * 0.299f + p->c2 * 0.587f + p->c3 * 0.114f);
p->c1 = clamp(t1);
}
} else {
// RGBA to YUVA
for (int i = 0; i < width * height; ++i) {
PIXEL *p = pixels + i;
int t1 = (int) (p->c1 * 0.299f + p->c2 * 0.587f + p->c3 * 0.114f);
int t2 = (int) (p->c1 * -0.169f + p->c2 * -0.331f + p->c3 * 0.5f + 128);
int t3 = (int) (p->c1 * 0.5f + p->c2 * -0.419f + p->c3 * -0.081f + 128);
p->c1 = clamp(t1);
p->c2 = clamp(t2);
p->c3 = clamp(t3);
}
}
int tile_width = width / TILE_BLOCK;
int tile_height = height / TILE_BLOCK;
int histogram[TILE_BLOCK * TILE_BLOCK][256] = {0};
float accumulation[TILE_BLOCK * TILE_BLOCK][256] = {0.0f};
// Build histogram and accumulation
for (int i = 0; i < TILE_BLOCK; i++) {
for (int j = 0; j < TILE_BLOCK; j++) {
int x_start = tile_width * i;
int x_end = i == TILE_BLOCK - 1 ? width : x_start + tile_width;
int y_start = tile_height * j;
int y_end = j == TILE_BLOCK - 1 ? height : y_start + tile_height;
int tile_size = (x_end - x_start) * (y_end - y_start);
int tile_index = i + TILE_BLOCK * j;
// Count
for (int x = x_start; x < x_end; x++) {
for (int y = y_start; y < y_end; y++) {
PIXEL *p = pixels + x + y * width;
histogram[tile_index][p->c1] += 1;
}
}
// CL
int limit = tile_size * LIMIT_MULTIPLE / 256;
for (int m = 0; m < CL_MAX_LOOP_NUMBER; m++) {
int steal = 0;
for (int n = 0; n < 256; n++) {
if (histogram[tile_index][n] > limit) {
steal += histogram[tile_index][n] - limit;
histogram[tile_index][n] = limit;
}
}
int bonus = steal / 256;
if (bonus == 0 && steal != 0 && m == 0) {
bonus = 1;
}
if (bonus == 0) {
break;
}
for (int n = 0; n < 256; n++) {
histogram[tile_index][n] += bonus;
}
}
// accumulation
for (int n = 0; n < 256; n++) {
accumulation[tile_index][n] = (float) histogram[tile_index][n] / tile_size;
if (n != 0) {
accumulation[tile_index][n] += accumulation[tile_index][n - 1];
}
}
}
}
// Interpolation
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
PIXEL *p = pixels + x + y * width;
// top-left corner
if (x <= tile_width / 2 && y <= tile_height / 2) {
p->c1 = clamp((int) (accumulation[0][p->c1] * 255));
continue;
}
// top-right corner
if (x > width - tile_width / 2 && y <= tile_height / 2) {
p->c1 = clamp((int) (accumulation[TILE_BLOCK - 1][p->c1] * 255));
continue;
}
// bottom-left corner
if (x <= tile_width / 2 && y > height - tile_height / 2) {
p->c1 = clamp((int) (accumulation[TILE_BLOCK * (TILE_BLOCK - 1)][p->c1] * 255));
continue;
}
// bottom-right corner
if (x > width - tile_width / 2 && y > height - tile_height / 2) {
p->c1 = clamp((int) (accumulation[TILE_BLOCK * TILE_BLOCK - 1][p->c1] * 255));
continue;
}
int tile_x_index = (x - tile_width / 2) / tile_width;
int tile_y_index = (y - tile_height / 2) / tile_height;
int tile_index1 = tile_x_index + TILE_BLOCK * tile_y_index;
int tile_index2 = tile_index1 + 1;
float u = (float) (x - (tile_x_index * tile_width + tile_width / 2)) / tile_width;
// top side and bottom side
if (y <= tile_height / 2 || y > height - tile_height / 2) {
p->c1 = clamp((int) (255 * (accumulation[tile_index1][p->c1] * (1 - u) +
accumulation[tile_index2][p->c1] * u)));
continue;
}
int tile_index3 = tile_index1 + TILE_BLOCK;
float v = (float) (y - (tile_y_index * tile_height + tile_height / 2)) / tile_height;
// left side and right side
if (x <= tile_width / 2 || x > width - tile_width / 2) {
p->c1 = clamp((int) (255 * (accumulation[tile_index1][p->c1] * (1 - v) +
accumulation[tile_index3][p->c1] * v)));
continue;
}
int tile_index4 = tile_index2 + TILE_BLOCK;
p->c1 = clamp((int) (255 * (
accumulation[tile_index1][p->c1] * (1 - u) * (1 - v)
+ accumulation[tile_index2][p->c1] * u * (1 - v)
+ accumulation[tile_index3][p->c1] * (1 - u) * v
+ accumulation[tile_index4][p->c1] * u * v)));
}
}
if (to_gray) {
for (int i = 0; i < width * height; ++i) {
PIXEL *p = pixels + i;
p->c2 = p->c1;
p->c3 = p->c1;
}
} else {
// YUVA to RGBA
for (int i = 0; i < width * height; ++i) {
PIXEL *p = pixels + i;
int t1 = (int) (p->c1 + (p->c2 - 128) * -0.00093f + (p->c3 - 128) * 1.401687f);
int t2 = (int) (p->c1 + (p->c2 - 128) * -0.3437f + (p->c3 - 128) * -0.71417f);
int t3 = (int) (p->c1 + (p->c2 - 128) * 1.77216f + (p->c3 - 128) * 0.00099f);
p->c1 = clamp(t1);
p->c2 = clamp(t2);
p->c3 = clamp(t3);
}
}
}
-24
View File
@@ -1,24 +0,0 @@
/*
* Copyright 2018 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef IMAGE_CLAHE_H
#define IMAGE_CLAHE_H
#include <stdbool.h>
void IMAGE_clahe(void *data, int width, int height, bool to_gray);
#endif //IMAGE_CLAHE_H
-36
View File
@@ -1,36 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "gray.h"
#include "pixel.h"
bool IMAGE_is_gray(void *data, int width, int height, int error) {
PIXEL *p = data;
for (int i = 0, n = width * height; i < n; i++, p++) {
int e1 = p->c1 - p->c2;
int e2 = p->c1 - p->c3;
int e3 = p->c2 - p->c3;
if (e1 > error || e1 < -error
|| e2 > error || e2 < -error
|| e3 > error || e3 < -error) {
return false;
}
}
return true;
}
-24
View File
@@ -1,24 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef IMAGE_GRAY_H
#define IMAGE_GRAY_H
#include <stdbool.h>
bool IMAGE_is_gray(void *data, int width, int height, int error);
#endif //IMAGE_GRAY_H
-29
View File
@@ -1,29 +0,0 @@
/*
* Copyright 2019 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef IMAGE_PIXEL_H
#define IMAGE_PIXEL_H
typedef unsigned char BYTE;
typedef struct {
BYTE c1;
BYTE c2;
BYTE c3;
BYTE c4;
} PIXEL;
#endif //IMAGE_PIXEL_H
+40 -121
View File
@@ -14,23 +14,17 @@
* limitations under the License.
*/
//
// Created by Hippo on 12/27/2015.
//
#include <android/data_space.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "image.h"
#include "image_utils.h"
#include "filter/clahe.h"
#include "filter/gray.h"
#include "log.h"
void decodeCommon(IMAGE *image) {
AImageDecoder *decoder = image->decoder;
void decodeCommon(IMAGE *image, SOURCE *src) {
image->src = src;
AImageDecoder *decoder = src->decoder;
image->isAnimated = AImageDecoder_isAnimated(decoder);
AImageDecoder_setDataSpace(decoder, ADATASPACE_SRGB);
AImageDecoder_setAndroidBitmapFormat(decoder, ANDROID_BITMAP_FORMAT_RGBA_8888);
const AImageDecoderHeaderInfo *headerInfo = AImageDecoder_getHeaderInfo(decoder);
@@ -38,155 +32,80 @@ void decodeCommon(IMAGE *image) {
image->width = AImageDecoderHeaderInfo_getWidth(headerInfo);
image->alpha =
AImageDecoderHeaderInfo_getAlphaFlags(headerInfo) == ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
image->stride = AImageDecoder_getMinimumStride(decoder);
image->bufferLen = image->height * image->stride;
src->stride = AImageDecoder_getMinimumStride(decoder);
image->bufferLen = image->height * src->stride;
image->buffer = malloc(image->bufferLen);
if (image->isAnimated) {
AImageDecoder_setInternallyHandleDisposePrevious(decoder, false);
image->frameInfo = AImageDecoderFrameInfo_create();
AImageDecoder_getFrameInfo(decoder, image->frameInfo);
src->frameInfo = AImageDecoderFrameInfo_create();
AImageDecoder_getFrameInfo(decoder, src->frameInfo);
}
AImageDecoder_decodeImage(decoder, image->buffer, src->stride, image->bufferLen);
if (!image->isAnimated) {
recycleSource(image->src);
image->src = NULL;
}
AImageDecoder_decodeImage(decoder, image->buffer, image->stride, image->bufferLen);
}
IMAGE *createFromFd(JNIEnv *env, int fd, bool partially, int *format) {
IMAGE *createFromFd(JNIEnv *env, int fd) {
AImageDecoder *decoder;
int r = AImageDecoder_createFromFd(fd, &decoder);
LOGD("%s%d", "Create ImageDecoder with ret ", r);
if (r)
return NULL;
AImageDecoder_createFromFd(fd, &decoder);
IMAGE *image = calloc(1, sizeof(IMAGE));
image->isAnimated = *format = AImageDecoder_isAnimated(decoder);
image->decoder = decoder;
decodeCommon(image);
SOURCE *src = calloc(1, sizeof(SOURCE));
src->decoder = decoder;
src->fd = fd;
decodeCommon(image, src);
return image;
}
IMAGE *createFromAddr(JNIEnv *env, void *addr, long size, bool partially, int *format) {
IMAGE *createFromAddr(JNIEnv *env, void *addr, long size) {
AImageDecoder *decoder;
int r = AImageDecoder_createFromBuffer((const void *) addr, size, &decoder);
LOGD("%s%d", "Create ImageDecoder with ret ", r);
if (r)
return NULL;
AImageDecoder_createFromBuffer((const void *) addr, size, &decoder);
IMAGE *image = calloc(1, sizeof(IMAGE));
image->isAnimated = *format = AImageDecoder_isAnimated(decoder);
image->decoder = decoder;
image->srcBuffer = addr;
decodeCommon(image);
SOURCE *src = calloc(1, sizeof(SOURCE));
src->decoder = decoder;
src->srcBuffer = addr;
decodeCommon(image, src);
return image;
}
void *create(int32_t width, int32_t height, const void *data) {
IMAGE *plain = NULL;
IMAGE *create(int32_t width, int32_t height, const void *data) {
IMAGE *plain = calloc(1, sizeof(IMAGE));
void *buffer = NULL;
size_t length;
plain = malloc(sizeof(IMAGE));
if (plain == NULL) {
WTF_OM;
return NULL;
}
length = (size_t) (width * height * 4);
size_t length = width * height * 4;
buffer = malloc(length);
if (buffer == NULL) {
WTF_OM;
free(plain);
return NULL;
}
memcpy(buffer, data, length);
plain->width = width;
plain->height = height;
plain->buffer = buffer;
plain->bufferLen = length;
plain->decoder = NULL;
return plain;
}
int get_width(IMAGE *image, int format) {
return image->width;
}
int get_height(IMAGE *image, int format) {
return image->height;
}
int get_byte_count(IMAGE *image, int format) {
return image->bufferLen;
}
void render(IMAGE *image, int format, int src_x, int src_y,
void render(IMAGE *image, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color) {
int width, int height) {
copy_pixels(image->buffer, image->width, image->height, src_x, src_y, dst, dst_w, dst_h, dst_x,
dst_y, width, height, fill_blank, default_color);
dst_y, width, height);
}
void advance(IMAGE *image, int format) {
if (format) {
AImageDecoder_advanceFrame(image->decoder);
if (AImageDecoder_decodeImage(image->decoder, image->buffer, image->stride,
void advance(IMAGE *image) {
if (image->isAnimated) {
AImageDecoder_advanceFrame(image->src->decoder);
if (AImageDecoder_decodeImage(image->src->decoder, image->buffer, image->src->stride,
image->bufferLen) == ANDROID_IMAGE_DECODER_FINISHED) {
AImageDecoder_rewind(image->decoder);
AImageDecoder_decodeImage(image->decoder, image->buffer, image->stride,
AImageDecoder_rewind(image->src->decoder);
AImageDecoder_decodeImage(image->src->decoder, image->buffer, image->src->stride,
image->bufferLen);
}
}
}
int get_delay(IMAGE *image, int format) {
if (format)
return AImageDecoderFrameInfo_getDuration(image->frameInfo) / 1000000;
int get_delay(IMAGE *image) {
if (image->isAnimated)
return (int) AImageDecoderFrameInfo_getDuration(image->src->frameInfo) / 1000000;
return 0;
}
bool is_opaque(IMAGE *image, int format) {
return image->alpha;
}
static void get_image_data(IMAGE *image, int format, void **pixel, int *width, int *height) {
*pixel = image->buffer;
*width = image->width;
*height = image->height;
}
bool is_gray(IMAGE *image, int format, int error) {
void *pixel = NULL;
int width = 0;
int height = 0;
get_image_data(image, format, &pixel, &width, &height);
if (pixel == NULL || width == 0 || height == 0) {
return false;
}
return IMAGE_is_gray(pixel, width, height, error);
}
void clahe(IMAGE *image, int format, bool to_gray) {
void *pixel = NULL;
int width = 0;
int height = 0;
get_image_data(image, format, &pixel, &width, &height);
if (pixel == NULL || width == 0 || height == 0) {
return;
}
IMAGE_clahe(pixel, width, height, to_gray);
}
void recycle(JNIEnv *env, IMAGE *image, int format) {
free(image->buffer);
image->buffer = NULL;
AImageDecoderFrameInfo_delete(image->frameInfo);
AImageDecoder_delete(image->decoder);
free(image->srcBuffer);
free(image);
}
+33 -27
View File
@@ -14,10 +14,6 @@
* limitations under the License.
*/
//
// Created by Hippo on 12/27/2015.
//
#ifndef IMAGE_IMAGE_H
#define IMAGE_IMAGE_H
@@ -25,45 +21,55 @@
#include <stdbool.h>
#include <jni.h>
#include "log.h"
typedef struct {
AImageDecoder *decoder;
void *srcBuffer;
size_t stride;
AImageDecoderFrameInfo *frameInfo;
int fd;
} SOURCE;
typedef struct {
int32_t width;
int32_t height;
void *buffer;
int bufferLen;
AImageDecoder *decoder;
void *srcBuffer;
size_t stride;
bool isAnimated;
AImageDecoderFrameInfo *frameInfo;
bool alpha;
SOURCE *src;
} IMAGE;
IMAGE *createFromFd(JNIEnv *env, int fd, bool partially, int *format);
static void recycleSource(SOURCE *src) {
if (!src)
return;
AImageDecoderFrameInfo_delete(src->frameInfo);
AImageDecoder_delete(src->decoder);
free(src->srcBuffer);
free(src);
}
IMAGE *createFromAddr(JNIEnv *env, void *addr, long size, bool partially, int *format);
static void recycle(IMAGE *image) {
if (!image)
return;
recycleSource(image->src);
free(image->buffer);
free(image);
}
void *create(int32_t width, int32_t height, const void *data);
IMAGE *createFromFd(JNIEnv *env, int fd);
int get_width(IMAGE *image, int format);
IMAGE *createFromAddr(JNIEnv *env, void *addr, long size);
int get_height(IMAGE *image, int format);
IMAGE *create(int32_t width, int32_t height, const void *data);
int get_byte_count(IMAGE *image, int format);
void render(IMAGE *image, int format, int src_x, int src_y,
void render(IMAGE *image, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color);
int width, int height);
void advance(IMAGE *image, int format);
void advance(IMAGE *image);
int get_delay(IMAGE *image, int format);
bool is_opaque(IMAGE *image, int format);
bool is_gray(IMAGE *image, int format, int error);
void clahe(IMAGE *image, int format, bool to_gray);
void recycle(JNIEnv *env, IMAGE *image, int format);
int get_delay(IMAGE *image);
#endif //IMAGE_IMAGE_H
+3 -79
View File
@@ -14,64 +14,14 @@
* limitations under the License.
*/
//
// Created by Hippo on 12/27/2015.
//
#include "image_utils.h"
#include <stdlib.h>
#include <string.h>
#define LITTLE_ENDIAN 0x00
#define BIG_ENDIAN 0x01
static unsigned int endian = ~0U;
static unsigned int get_endian() {
unsigned int x = 1;
if (endian == ~0U) {
if (1 == ((char *) &x)[0]) {
endian = LITTLE_ENDIAN;
} else {
endian = BIG_ENDIAN;
}
}
return endian;
}
static int convert_color(int origin) {
int result;
unsigned char *orPtr = (unsigned char *) &origin;
unsigned char *rePtr = (unsigned char *) &result;
if (get_endian() == BIG_ENDIAN) {
rePtr[0] = orPtr[1];
rePtr[1] = orPtr[2];
rePtr[2] = orPtr[3];
rePtr[3] = orPtr[0];
} else {
rePtr[0] = orPtr[2];
rePtr[1] = orPtr[1];
rePtr[2] = orPtr[0];
rePtr[3] = orPtr[3];
}
return result;
}
static void memset_int(int *dst, int val, size_t size) {
int *maxPtr = dst + size;
int *ptr = dst;
while (ptr < maxPtr)
*ptr++ = val;
}
bool copy_pixels_internal(const void *src, int src_w, int src_h, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int color) {
bool copy_pixels(const void *src, int src_w, int src_h, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height) {
int left;
int line;
size_t line_stride;
@@ -137,10 +87,6 @@ bool copy_pixels_internal(const void *src, int src_w, int src_h, int src_x, int
dst_pos = 0;
dst_blank_length = (size_t) (dst_y * dst_w + dst_x) * 4;
// Fill start blank if necessary
if (fill_blank) {
memset_int((int *) (dst + dst_pos), color, dst_blank_length / 4);
}
// First line
dst_pos += dst_blank_length;
@@ -151,33 +97,11 @@ bool copy_pixels_internal(const void *src, int src_w, int src_h, int src_x, int
// Other lines
dst_blank_length = (size_t) ((dst_w - width) * 4);
for (line = 1; line < height; line++) {
if (fill_blank) {
memset_int((int *) (dst + dst_pos), color, dst_blank_length / 4);
}
dst_pos += dst_blank_length;
memcpy(dst + dst_pos, src + src_pos, line_stride);
dst_pos += line_stride;
src_pos += src_stride;
}
// Fill left blank if necessary
if (fill_blank) {
memset_int((int *) (dst + dst_pos), color, (size_t) (dst_w * dst_h * 4 - dst_pos) / 4);
}
return true;
}
void copy_pixels(const void *src, int src_w, int src_h, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color) {
int color = 0;
if (fill_blank) {
color = convert_color(default_color);
}
if (!copy_pixels_internal(src, src_w, src_h, src_x, src_y, dst, dst_w, dst_h, dst_x,
dst_y, width, height, fill_blank, color) && fill_blank) {
memset_int(dst, color, (size_t) (dst_w * dst_h));
}
}
+8 -6
View File
@@ -17,17 +17,19 @@
* EhViewer. If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by Hippo on 12/27/2015.
//
#ifndef IMAGE_IMAGE_UTILS_H
#define IMAGE_IMAGE_UTILS_H
#include <stdbool.h>
void copy_pixels(const void *src, int src_w, int src_h, int src_x, int src_y,
bool copy_pixels(const void *src, int src_w, int src_h, int src_x, int src_y,
void *dst, int dst_w, int dst_h, int dst_x, int dst_y,
int width, int height, bool fill_blank, int default_color);
int width, int height);
#define STRINGIZE(L) #L
#define MAKESTRING(M, L) M(L)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif //IMAGE_IMAGE_UTILS_H
+33 -118
View File
@@ -20,6 +20,7 @@
#include "java_wrapper.h"
#include "image.h"
#include "image_utils.h"
#include "log.h"
static JavaVM *jvm;
@@ -80,42 +81,28 @@ jobject create_image_object(JNIEnv *env, void *ptr, int format, int width, int h
}
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeDecodeFdInt(JNIEnv *env,
jclass clazz, jint fd, jboolean partially) {
int format;
void *image;
jobject image_object;
Java_com_hippo_image_Image_nativeDecodeFdInt(JNIEnv *env, jclass clazz, jint fd) {
IMAGE *image;
image = createFromFd(env, fd, partially, &format);
image = createFromFd(env, fd);
if (image == NULL) {
return NULL;
}
image_object = create_image_object(env, image, format,
get_width(image, format), get_height(image, format));
if (image_object == NULL) {
recycle(env, image, format);
return NULL;
} else {
return image_object;
}
return create_image_object(env, image, image->isAnimated, image->width, image->height);
}
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeDecode(JNIEnv *env,
jclass clazz, jobject fd, jboolean partially) {
Java_com_hippo_image_Image_nativeDecode(JNIEnv *env, jclass clazz, jobject fd) {
return Java_com_hippo_image_Image_nativeDecodeFdInt(env, clazz,
jniGetFDFromFileDescriptor(env, fd),
partially);
jniGetFDFromFileDescriptor(env, fd));
}
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeCreate(JNIEnv *env,
jclass clazz, jobject bitmap) {
Java_com_hippo_image_Image_nativeCreate(JNIEnv *env, jclass clazz, jobject bitmap) {
AndroidBitmapInfo info;
void *pixels = NULL;
void *image = NULL;
jobject image_object;
AndroidBitmap_getInfo(env, bitmap, &info);
AndroidBitmap_lockPixels(env, bitmap, &pixels);
@@ -125,35 +112,14 @@ Java_com_hippo_image_Image_nativeCreate(JNIEnv *env,
}
image = create(info.width, info.height, pixels);
AndroidBitmap_unlockPixels(env, bitmap);
if (image == NULL) {
return NULL;
}
image_object = create_image_object(env, image, 0,
info.width, info.height);
if (image_object == NULL) {
recycle(env, image, 0);
return NULL;
} else {
return image_object;
}
}
JNIEXPORT jint JNICALL
Java_com_hippo_image_Image_nativeGetByteCount(JNIEnv *env,
jclass clazz, jlong ptr, jint format) {
return (jint) get_byte_count((void *) (intptr_t) ptr, format);
return create_image_object(env, image, 0, info.width, info.height);
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeRender(JNIEnv *env,
jclass clazz, jlong ptr, jint format,
jint src_x, jint src_y, jobject dst, jint dst_x, jint dst_y,
jint width, jint height, jboolean fill_blank,
jint default_color) {
Java_com_hippo_image_Image_nativeRender(JNIEnv *env, jclass clazz, jlong ptr, jint src_x,
jint src_y, jobject dst, jint dst_x, jint dst_y, jint width,
jint height) {
AndroidBitmapInfo info;
void *pixels = NULL;
@@ -164,82 +130,52 @@ Java_com_hippo_image_Image_nativeRender(JNIEnv *env,
return;
}
render((void *) (intptr_t) ptr, format, src_x, src_y,
pixels, info.width, info.height, dst_x, dst_y,
width, height, fill_blank, default_color);
render((IMAGE *) ptr, src_x, src_y, pixels, info.width, info.height, dst_x, dst_y, width,
height);
AndroidBitmap_unlockPixels(env, dst);
return;
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeTexImage(JNIEnv *env,
jclass clazz, jlong ptr, jint format, jboolean init,
Java_com_hippo_image_Image_nativeTexImage(JNIEnv *env, jclass clazz, jlong ptr, jboolean init,
jint src_x, jint src_y, jint width, jint height) {
// Check tile_buffer NULL
if (NULL == tile_buffer) {
if (width * height > IMAGE_TILE_MAX_SIZE)
return;
}
// Check render size
if (width * height > IMAGE_TILE_MAX_SIZE) {
return;
}
render((void *) (intptr_t) ptr, format, src_x, src_y,
tile_buffer, width, height, 0, 0,
width, height, false, 0);
render((IMAGE *) ptr, src_x, src_y, tile_buffer, width, height, 0, 0, width, height);
if (init) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, tile_buffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
tile_buffer);
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height,
GL_RGBA, GL_UNSIGNED_BYTE, tile_buffer);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
tile_buffer);
}
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeAdvance(JNIEnv *env,
jclass clazz, jlong ptr, jint format) {
advance((void *) (intptr_t) ptr, format);
Java_com_hippo_image_Image_nativeAdvance(JNIEnv *env, jclass clazz, jlong ptr) {
advance((IMAGE *) ptr);
}
JNIEXPORT jint JNICALL
Java_com_hippo_image_Image_nativeGetDelay(JNIEnv *env,
jclass clazz, jlong ptr, jint format) {
return (jint) get_delay((void *) (intptr_t) ptr, format);
Java_com_hippo_image_Image_nativeGetDelay(JNIEnv *env, jclass clazz, jlong ptr) {
return get_delay((IMAGE *) ptr);
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_image_Image_nativeIsOpaque(JNIEnv *env,
jclass clazz, jlong ptr, jint format) {
return (jboolean) is_opaque((void *) (intptr_t) ptr, format);
}
JNIEXPORT jboolean JNICALL
Java_com_hippo_image_Image_nativeIsGray(JNIEnv *env,
jclass clazz, jlong ptr, jint format, jint error) {
return (jboolean) is_gray((void *) (intptr_t) ptr, format, error);
Java_com_hippo_image_Image_nativeIsOpaque(JNIEnv *env, jclass clazz, jlong ptr) {
return ((IMAGE *) ptr)->alpha;
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeClahe(JNIEnv *env,
jclass clazz, jlong ptr, jint format, jboolean to_gray) {
clahe((void *) (intptr_t) ptr, format, to_gray);
}
JNIEXPORT void JNICALL
Java_com_hippo_image_Image_nativeRecycle(JNIEnv *env,
jclass clazz, jlong ptr, jint format) {
recycle(env, (void *) (intptr_t) ptr, format);
Java_com_hippo_image_Image_nativeRecycle(JNIEnv *env, jclass clazz, jlong ptr) {
recycle((IMAGE *) ptr);
}
bool image_onLoad(JavaVM *vm) {
jvm = vm;
tile_buffer = malloc(IMAGE_TILE_MAX_SIZE * 4);
return true;
}
@@ -249,31 +185,10 @@ JNI_OnUnload(JavaVM *vm, void *reserved) {
tile_buffer = NULL;
}
typedef struct Memarea {
void *buffer;
long size;
} Memarea;
JNIEXPORT jobject JNICALL
Java_com_hippo_image_Image_nativeDecodeAddr(JNIEnv *env, jclass clazz, jlong addr,
jboolean partially) {
int format;
void *image;
jobject image_object;
Java_com_hippo_image_Image_nativeDecodeAddr(JNIEnv *env, jclass clazz, jlong addr) {
Memarea *memarea = (Memarea *) addr;
image = createFromAddr(env, memarea->buffer, memarea->size, partially, &format);
IMAGE *image = createFromAddr(env, memarea->buffer, memarea->size);
free(memarea);
if (image == NULL) {
return NULL;
}
image_object = create_image_object(env, image, format,
get_width(image, format), get_height(image, format));
if (image_object == NULL) {
recycle(env, image, format);
return NULL;
} else {
return image_object;
}
}
return create_image_object(env, image, image->isAnimated, image->width, image->height);
}
+5 -4
View File
@@ -17,10 +17,6 @@
* EhViewer. If not, see <https://www.gnu.org/licenses/>.
*/
//
// Created by Hippo on 12/28/2015.
//
#ifndef IMAGE_JAVA_WRAPPER_H
#define IMAGE_JAVA_WRAPPER_H
@@ -29,6 +25,11 @@
#define IMAGE_TILE_MAX_SIZE (512 * 512)
typedef struct Memarea {
void *buffer;
long size;
} Memarea;
bool image_onLoad(JavaVM *vm);
JNIEnv *obtain_env(bool *attach);
+1 -7
View File
@@ -14,18 +14,12 @@
* limitations under the License.
*/
//
// Created by Hippo on 10/19/2015.
//
#ifndef LOG_H
#define LOG_H
#include <android/log.h>
#include "utils.h"
#define TAG "Image"
#define TAG "ImageDecoder_wrapper"
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG ,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG ,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG ,__VA_ARGS__)
-30
View File
@@ -1,30 +0,0 @@
/*
* Copyright 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by Hippo on 12/29/2015.
//
#ifndef UTILS_H
#define UTILS_H
#define STRINGIZE(L) #L
#define MAKESTRING(M, L) M(L)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif // UTILS_H