Initial stupid migrate to ImageDecoder

This commit is contained in:
tarsin committed 2022-07-24 19:18:54 +08:00
1 parent 7ad67a3dbd
commit 76459c5dd2
14 files changed
+41 -2067

No files matched your search

@@ -44,7 +44,6 @@ class VersionPreference @JvmOverloads constructor(
val info = NativeLibInfo().addLib(Native.getlibarchiveVersion())
.addLib("lzma(xz-utils)", Native.getliblzmaVersion())
.addLib("zlib", Native.getzlibVersion())
.addLib("libjpeg-turbo", Native.getlibjpeg_turboVersion())
.addLib(Native.getnettleVersion())
builder.setMessage(info.getMessage())
}
@@ -28,8 +28,6 @@ public class Native {
public static native String getliblzmaVersion();
public static native String getlibjpeg_turboVersion();
public static native String getzlibVersion();
public static native String getnettleVersion();
-3
View File
@@ -16,6 +16,3 @@ cmake_minimum_required(VERSION 3.4.1)
add_subdirectory(image)
add_subdirectory(stream)
add_subdirectory(libjpeg-turbo)
add_subdirectory(libpng)
add_subdirectory(giflib)
@@ -19,9 +19,6 @@ set(IMAGE_SOURCES
image.c
image_utils.c
image_plain.c
image_jpeg.c
image_png.c
image_gif.c
filter/clahe.c
filter/gray.c
java_wrapper.c
@@ -34,9 +31,6 @@ set(IMAGE_LIBRARIES
jnigraphics
GLESv2
stream
jpeg
png
gif
)
add_library(image STATIC ${IMAGE_SOURCES})
+31 -396
View File
@@ -18,424 +18,97 @@
// Created by Hippo on 12/27/2015.
//
#include <android/imagedecoder.h>
#include <stdlib.h>
#include "image.h"
#include "image_plain.h"
#include "image_jpeg.h"
#include "image_png.h"
#include "image_gif.h"
#include "filter/clahe.h"
#include "filter/gray.h"
#include "../log.h"
static int get_format(JNIEnv* env, InputStream* stream)
{
unsigned char temp[2];
int read = read_input_stream(env, stream, temp, 0, 2);
if (read == 2) {
#ifdef IMAGE_SUPPORT_JPEG
if (temp[0] == IMAGE_JPEG_MAGIC_NUMBER_0 && temp[1] == IMAGE_JPEG_MAGIC_NUMBER_1) {
return IMAGE_FORMAT_JPEG;
}
#endif
#ifdef IMAGE_SUPPORT_PNG
if (temp[0] == IMAGE_PNG_MAGIC_NUMBER_0 && temp[1] == IMAGE_PNG_MAGIC_NUMBER_1) {
return IMAGE_FORMAT_PNG;
}
#endif
#ifdef IMAGE_SUPPORT_GIF
if (temp[0] == IMAGE_GIF_MAGIC_NUMBER_0 && temp[1] == IMAGE_GIF_MAGIC_NUMBER_1) {
return IMAGE_FORMAT_GIF;
}
#endif
LOGE(MSG("Can't recognize the two magic number: %d, %d"), temp[0], temp[1]);
} else {
LOGE(MSG("Can't read two magic number from stream"));
}
return IMAGE_FORMAT_UNKNOWN;
}
void* decode(JNIEnv* env, InputStream* stream, bool partially, int* format)
{
unsigned char magic_numbers[2];
PatchHeadInputStream* patch_head_input_stream;
*format = get_format(env, stream);
switch (*format) {
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
magic_numbers[0] = IMAGE_JPEG_MAGIC_NUMBER_0;
magic_numbers[1] = IMAGE_JPEG_MAGIC_NUMBER_1;
break;
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
magic_numbers[0] = IMAGE_PNG_MAGIC_NUMBER_0;
magic_numbers[1] = IMAGE_PNG_MAGIC_NUMBER_1;
break;
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
magic_numbers[0] = IMAGE_GIF_MAGIC_NUMBER_0;
magic_numbers[1] = IMAGE_GIF_MAGIC_NUMBER_1;
break;
#endif
default:
LOGE(MSG("Can't detect format %d"), *format);
destroy_input_stream(env, &stream);
return NULL;
}
patch_head_input_stream = create_patch_head_input_stream(stream, magic_numbers, 2);
if (patch_head_input_stream == NULL){
WTF_OM;
AImageDecoder *decoder;
size_t len = 1024 * 1024 * 4;
void* buffer = calloc(len, sizeof(char));
len = read_input_stream(env, stream, buffer, 0, len);
AImageDecoder_createFromBuffer(buffer, len, &decoder);
free(buffer);
AImageDecoderHeaderInfo *headerInfo = AImageDecoder_getHeaderInfo(decoder);
IMAGE *image = malloc(sizeof(IMAGE));
image->height = AImageDecoderHeaderInfo_getHeight(headerInfo);
image->width = AImageDecoderHeaderInfo_getWidth(headerInfo);
ssize_t bufferLen = 1024 * 1024 * 64;
image->buffer = malloc(bufferLen);
AImageDecoder_decodeImage(decoder, image->buffer, AImageDecoder_getMinimumStride(decoder), bufferLen);
AImageDecoder_delete(decoder);
destroy_input_stream(env, &stream);
return NULL;
}
switch (*format) {
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return JPEG_decode(env, patch_head_input_stream, partially);
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return PNG_decode(env, patch_head_input_stream, partially);
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return GIF_decode(env, patch_head_input_stream, partially);
#endif
default:
LOGE(MSG("Can't detect format %d"), *format);
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
*format = IMAGE_FORMAT_JPEG;
return image;
}
void* create(unsigned int width, unsigned int height, const void* data)
{
#ifdef IMAGE_SUPPORT_PLAIN
return PLAIN_create(width, height, data);
#else
return NULL;
#endif
return PLAIN_create(width, height, data);
}
bool complete(JNIEnv* env, void* image, int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
return PLAIN_complete((PLAIN*) image);
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return JPEG_complete((JPEG*) image);
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return PNG_complete(env, (PNG*) image);
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return GIF_complete(env, (GIF*) image);
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
return false;
}
return true;
}
bool is_completed(void* image, int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
return PLAIN_is_completed((PLAIN*) image);
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return JPEG_is_completed((JPEG*) image);
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return PNG_is_completed((PNG*) image);
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return GIF_is_completed((GIF*) image);
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
return false;
}
return true;
}
int get_width(void* image, int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
return PLAIN_get_width((PLAIN*) image);
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return JPEG_get_width((JPEG*) image);
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return PNG_get_width((PNG*) image);
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return GIF_get_width((GIF*) image);
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
return -1;
}
return ((IMAGE*)image)->width;
}
int get_height(void* image, int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
return PLAIN_get_height((PLAIN*) image);
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return JPEG_get_height((JPEG*) image);
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return PNG_get_height((PNG*) image);
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return GIF_get_height((GIF*) image);
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
return -1;
}
return ((IMAGE*)image)->height;
}
int get_byte_count(void* image, int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
return PLAIN_get_byte_count((PLAIN*) image);
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return JPEG_get_byte_count((JPEG*) image);
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return PNG_get_byte_count((PNG*) image);
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return GIF_get_byte_count((GIF*) image);
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
return -1;
}
return ((IMAGE*)image)->width * ((IMAGE*)image)->height * 4;
}
void render(void* image, int format, 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)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
PLAIN_render((PLAIN*) image, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
break;
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
JPEG_render((JPEG*) image, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
break;
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
PNG_render((PNG*) image, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
break;
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
GIF_render((GIF*) image, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
break;
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
break;
}
PLAIN_render((IMAGE *) image, src_x, src_y, dst, dst_w, dst_h, dst_x, dst_y, width, height, fill_blank, default_color);
}
void advance(void* image, int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
PLAIN_advance((PLAIN*) image);
break;
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
JPEG_advance((JPEG*) image);
break;
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
PNG_advance((PNG*) image);
break;
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
GIF_advance((GIF*) image);
break;
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
}
}
int get_delay(void* image, int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
return PLAIN_get_delay((PLAIN*) image);
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return JPEG_get_delay((JPEG*) image);
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return PNG_get_delay((PNG*) image);
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return GIF_get_delay((GIF*) image);
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
return false;
}
return 0;
}
int get_frame_count(void* image, int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
return PLAIN_get_frame_count((PLAIN*) image);
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return JPEG_get_frame_count((JPEG*) image);
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return PNG_get_frame_count((PNG*) image);
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return GIF_get_frame_count((GIF*) image);
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
return false;
}
return 1;
}
bool is_opaque(void* image, int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
return PLAIN_is_opaque((PLAIN*) image);
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return JPEG_is_opaque((JPEG*) image);
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return PNG_is_opaque((PNG*) image);
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return GIF_is_opaque((GIF*) image);
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
return false;
}
return false;
}
static void get_image_data(void* image, int format, void** pixel, int* width, int* height) {
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN: {
PLAIN* plain = (PLAIN*) image;
*pixel = PLAIN_get_pixels(plain);
*width = PLAIN_get_width(plain);
*height = PLAIN_get_height(plain);
break;
}
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG: {
JPEG* jpeg = (JPEG*) image;
*pixel = JPEG_get_pixels(jpeg);
*width = JPEG_get_width(jpeg);
*height = JPEG_get_height(jpeg);
break;
}
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG: {
PNG* png = (PNG*) image;
*pixel = PNG_get_pixels(png);
*width = PNG_get_width(png);
*height = PNG_get_height(png);
break;
}
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF: {
GIF* gif = (GIF*) image;
*pixel = GIF_get_pixels(gif);
*width = GIF_get_width(gif);
*height = GIF_get_height(gif);
break;
}
#endif
default:
*pixel = NULL;
*width = 0;
*height = 0;
break;
}
}
bool is_gray(void* image, int format, int error)
@@ -470,30 +143,7 @@ void clahe(void* image, int format, bool to_gray)
void recycle(JNIEnv *env, void* image, int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_PLAIN
case IMAGE_FORMAT_PLAIN:
PLAIN_recycle((PLAIN*) image);
break;
#endif
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
JPEG_recycle((JPEG*) image);
break;
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
PNG_recycle(env, (PNG*) image);
break;
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
GIF_recycle(env, (GIF*) image);
break;
#endif
default:
LOGE(MSG("Can't detect format %d"), format);
}
PLAIN_recycle((PLAIN*) image);
}
int get_supported_formats(int *formats)
@@ -513,20 +163,5 @@ int get_supported_formats(int *formats)
const char *get_decoder_description(int format)
{
switch (format) {
#ifdef IMAGE_SUPPORT_JPEG
case IMAGE_FORMAT_JPEG:
return IMAGE_JPEG_DECODER_DESCRIPTION;
#endif
#ifdef IMAGE_SUPPORT_PNG
case IMAGE_FORMAT_PNG:
return IMAGE_PNG_DECODER_DESCRIPTION;
#endif
#ifdef IMAGE_SUPPORT_GIF
case IMAGE_FORMAT_GIF:
return IMAGE_GIF_DECODER_DESCRIPTION;
#endif
default:
return NULL;
}
return NULL;
}
+7
View File
@@ -42,6 +42,13 @@
#define IMAGE_MAX_SUPPORTED_FORMAT_COUNT 3
typedef struct
{
unsigned int width;
unsigned int height;
void* buffer;
} IMAGE;
void* decode(JNIEnv* env, InputStream* stream, bool partially, int* format);
void* create(unsigned int width, unsigned int height, const void* data);
bool complete(JNIEnv* env, void* image, int format);
-558
View File
@@ -1,558 +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/27/2015.
//
#include "config.h"
#ifdef IMAGE_SUPPORT_GIF
#include <stdlib.h>
#include <string.h>
#include "image_gif.h"
#include "image_utils.h"
#include "java_wrapper.h"
#include "../log.h"
#include "../utils.h"
static int error_code = 0;
typedef struct {
unsigned char red;
unsigned char green;
unsigned char blue;
unsigned char alpha;
} RGBA;
static int custom_read_fun(GifFileType* gif, GifByteType* bytes, int size) {
bool attach;
int read;
PatchHeadInputStream* patch_head_input_stream = gif->UserData;
JNIEnv *env = obtain_env(&attach);
if (env == NULL) {
LOGE(MSG("Can't get JNIEnv"));
return 0;
}
read = read_patch_head_input_stream(env, patch_head_input_stream, bytes, 0, (size_t) size);
if (attach) {
release_env();
}
return read;
}
static void generate_prepare(GIF_FRAME_INFO* frame_info_array, int count)
{
int disposal = 0xff;
int i;
for (i = 0; i < count; i++){
GIF_FRAME_INFO* frame_info = frame_info_array + i;
switch (disposal) {
case DISPOSAL_UNSPECIFIED:
case DISPOSE_DO_NOT:
frame_info->prepare = IMAGE_GIF_PREPARE_NONE;
break;
case DISPOSE_BACKGROUND:
frame_info->prepare = IMAGE_GIF_PREPARE_BACKGROUND;
break;
case DISPOSE_PREVIOUS:
frame_info->prepare = IMAGE_GIF_PREPARE_USE_BACKUP;
break;
default:
frame_info->prepare = IMAGE_GIF_PREPARE_BACKGROUND;
break;
}
disposal = frame_info->disposal;
}
}
static void read_gcb(GifFileType* gif_file, int index, GIF_FRAME_INFO* frame_info)
{
GraphicsControlBlock gcb;
if (DGifSavedExtensionToGCB(gif_file, index, &gcb) == GIF_OK) {
frame_info->tran = gcb.TransparentColor;
frame_info->delay = gcb.DelayTime * 10;
frame_info->disposal = gcb.DisposalMode;
frame_info->prepare = IMAGE_GIF_PREPARE_UNKNOWN;
} else {
frame_info->tran = -1;
frame_info->delay = 0;
frame_info->disposal = DISPOSE_DO_NOT;
frame_info->prepare = IMAGE_GIF_PREPARE_UNKNOWN;
}
}
static void fix_gif_file(GifFileType* gif_file) {
if (gif_file->ImageCount == 0) {
return;
}
SavedImage last_image = gif_file->SavedImages[gif_file->ImageCount - 1];
// If RasterBits is NULL, discard this frame
if (last_image.RasterBits == NULL) {
gif_file->ImageCount--;
// Free last image
if (last_image.ImageDesc.ColorMap != NULL) {
GifFreeMapObject(last_image.ImageDesc.ColorMap);
last_image.ImageDesc.ColorMap = NULL;
}
GifFreeExtensions(&last_image.ExtensionBlockCount, &last_image.ExtensionBlocks);
}
}
void* GIF_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially)
{
GIF* gif = NULL;
GifFileType* gif_file = NULL;
void* buffer = NULL;
void*shown_buffer = NULL;
GIF_FRAME_INFO* frame_info_array = NULL;
int i;
gif = (GIF*) malloc(sizeof(GIF));
if (gif == NULL) {
WTF_OM;
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
// Open
gif_file = DGifOpen(patch_head_input_stream, &custom_read_fun, &error_code);
if (gif_file == NULL) {
WTF_OM;
free(gif);
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
// Buffer
buffer = malloc(gif_file->SWidth * gif_file->SHeight * sizeof(RGBA));
shown_buffer = malloc(gif_file->SWidth * gif_file->SHeight * sizeof(RGBA));
if (buffer == NULL || shown_buffer == NULL) {
WTF_OM;
free(buffer);
free(shown_buffer);
DGifCloseFile(gif_file, &error_code);
free(gif);
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
if (partially) {
// Glance
if (DGifGlance(gif_file) != GIF_OK) {
LOGE(MSG("GIF error code %d"), error_code);
DGifCloseFile(gif_file, &error_code);
free(buffer);
free(gif);
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
// Frame info
frame_info_array = (GIF_FRAME_INFO*) malloc(sizeof(GIF_FRAME_INFO));
if (frame_info_array == NULL) {
WTF_OM;
DGifCloseFile(gif_file, &error_code);
free(buffer);
free(gif);
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
// Read gcb
read_gcb(gif_file, 0, frame_info_array);
gif->partially = true;
gif->patch_head_input_stream = patch_head_input_stream;
} else {
// Slurp
if (DGifSlurp(gif_file) == GIF_ERROR) {
fix_gif_file(gif_file);
}
if (gif_file->ImageCount <= 0) {
LOGE(MSG("No frame"));
DGifCloseFile(gif_file, &error_code);
free(buffer);
free(gif);
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
// Frame info
frame_info_array = (GIF_FRAME_INFO*) malloc(gif_file->ImageCount * sizeof(GIF_FRAME_INFO));
if (frame_info_array == NULL) {
WTF_OM;
DGifCloseFile(gif_file, &error_code);
free(buffer);
free(gif);
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
// Read gcb
for (i = 0; i < gif_file->ImageCount; i++) {
read_gcb(gif_file, i, frame_info_array + i);
}
// Generate prepare
generate_prepare(frame_info_array, gif_file->ImageCount);
// Close input stream
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
gif->partially = false;
gif->patch_head_input_stream = NULL;
}
gif->gif_file = gif_file;
gif->frame_info_array = frame_info_array;
gif->buffer = buffer;
gif->buffer_index = -1;
gif->backup = NULL;
gif->shown_buffer = shown_buffer;
GIF_advance(gif);
return gif;
}
bool GIF_complete(JNIEnv* env, GIF* gif)
{
int i;
if (!gif->partially) {
return true;
}
if (gif->gif_file == NULL || gif->patch_head_input_stream == NULL) {
LOGE(MSG("Some stuff is NULL"));
return false;
}
if (DGifSlurp(gif->gif_file) == GIF_ERROR) {
fix_gif_file(gif->gif_file);
}
// Close input stream
close_patch_head_input_stream(env, gif->patch_head_input_stream);
destroy_patch_head_input_stream(env, &gif->patch_head_input_stream);
gif->patch_head_input_stream = NULL;
gif->partially = false;
gif->frame_info_array = (GIF_FRAME_INFO*) realloc(gif->frame_info_array,
gif->gif_file->ImageCount * sizeof(GIF_FRAME_INFO));
if (gif->frame_info_array == NULL) {
WTF_OM;
return false;
}
// Read gcb
for (i = 0; i < gif->gif_file->ImageCount; i++) {
read_gcb(gif->gif_file, i, gif->frame_info_array + i);
}
// Generate prepare
generate_prepare(gif->frame_info_array, gif->gif_file->ImageCount);
return true;
}
bool GIF_is_completed(GIF* gif)
{
return !gif->partially;
}
void* GIF_get_pixels(GIF* gif)
{
if (!gif->partially && GIF_get_frame_count(gif) == 1) {
return gif->buffer;
} else {
return NULL;
}
}
int GIF_get_width(GIF* gif)
{
return gif->gif_file->SWidth;
}
int GIF_get_height(GIF* gif)
{
return gif->gif_file->SHeight;
}
int GIF_get_byte_count(GIF* gif)
{
int i;
SavedImage saved_image;
int size = 0;
// Add buffer size
if (gif->buffer != NULL) {
size += gif->gif_file->SWidth * gif->gif_file->SHeight * 4;
}
// Add backup size
if (gif->backup != NULL) {
size += gif->gif_file->SWidth * gif->gif_file->SHeight * 4;
}
// Add shown buffer size
if (gif->shown_buffer != NULL) {
size += gif->gif_file->SWidth * gif->gif_file->SHeight * 4;
}
// Add frames size
if (gif->gif_file->SavedImages != NULL) {
for (i = 0; i < gif->gif_file->ImageCount; i++) {
saved_image = gif->gif_file->SavedImages[i];
if (saved_image.RasterBits != NULL) {
size += saved_image.ImageDesc.Width * saved_image.ImageDesc.Height * 1;
}
}
}
return size;
}
void GIF_render(GIF* gif, 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)
{
copy_pixels(gif->shown_buffer, gif->gif_file->SWidth, gif->gif_file->SHeight, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
}
static void backup(GIF* gif)
{
if (gif->backup == NULL) {
gif->backup = (unsigned char*) malloc((size_t) (gif->gif_file->SWidth * gif->gif_file->SHeight * 4));
if (gif->backup == NULL) {
WTF_OM;
return;
}
}
memcpy(gif->backup, gif->buffer, (size_t) (gif->gif_file->SWidth * gif->gif_file->SHeight * 4));
}
static void restore(GIF* gif)
{
if (gif->backup == NULL) {
LOGE(MSG("Backup is NULL"));
} else {
memcpy(gif->buffer, gif->backup, (size_t) (gif->gif_file->SWidth * gif->gif_file->SHeight * 4));
}
}
static void switch_buffer_backup(GIF* gif)
{
unsigned char* temp;
if (gif->backup == NULL) {
backup(gif);
} else {
temp = gif->buffer;
gif->buffer = gif->backup;
gif->backup = temp;
}
}
static void clear(RGBA* pixels, int num, RGBA color) {
RGBA* ptr = pixels;
int i;
for (i = 0; i < num; i++) {
*(ptr++) = color;
}
}
static bool get_color_from_table(const ColorMapObject* cmap, int index,
RGBA* color) {
if (cmap == NULL || index < 0 || index >= cmap->ColorCount) {
return false;
} else {
GifColorType gct = cmap->Colors[index];
color->red = gct.Red;
color->green = gct.Green;
color->blue = gct.Blue;
color->alpha = 0xff;
return true;
}
}
static void clear_bg(GifFileType* gif_file, void* pixels)
{
RGBA color;
if (!get_color_from_table(gif_file->SColorMap, gif_file->SBackGroundColor, &color)) {
color.red = 0x00;
color.green = 0x00;
color.blue = 0x00;
color.alpha = 0x00;
}
clear(pixels, gif_file->SWidth * gif_file->SHeight, color);
}
static void copy_line(GifByteType* src, RGBA* dst,
const ColorMapObject* cmap, int tran, int len)
{
for (; len > 0; len--, src++, dst++) {
int index = *src;
if (tran == -1 || index != tran) {
get_color_from_table(cmap, index, dst);
}
}
}
static void blend(GifFileType* gif_file, int index, void* pixels, int tran)
{
int width = gif_file->SWidth;
int height = gif_file->SHeight;
SavedImage cur = gif_file->SavedImages[index];
GifImageDesc desc = cur.ImageDesc;
int copy_width = MIN(width - desc.Left, desc.Width);
int copy_height = MIN(height - desc.Top, desc.Height);
ColorMapObject *cmap = desc.ColorMap;
GifByteType* src = cur.RasterBits;
RGBA* dst = pixels;
GifByteType* src_ptr;
RGBA* dst_ptr;
size_t len;
int i;
if (cmap == NULL) {
cmap = gif_file->SColorMap;
}
if (cmap != NULL) {
for (i = 0; i < copy_height; i++) {
src_ptr = src + (i * desc.Width);
dst_ptr = dst + ((desc.Top + i) * width + desc.Left);
len = (size_t) copy_width;
copy_line(src_ptr, dst_ptr, cmap, tran, len);
}
} else {
LOGW(MSG("Can't find color map"));
}
}
void GIF_advance(GIF* gif)
{
int index;
GIF_FRAME_INFO frame_info;
index = (gif->buffer_index + 1) % gif->gif_file->ImageCount;
if (index != 0 && gif->partially) {
LOGE(MSG("The png is only decoded partially. Only the first frame can be shown."));
return;
}
if (gif->frame_info_array == NULL) {
frame_info.tran = -1;
frame_info.disposal = DISPOSE_DO_NOT;
frame_info.delay = 0;
frame_info.prepare = IMAGE_GIF_PREPARE_BACKGROUND;
} else {
memcpy(&frame_info, gif->frame_info_array + index, sizeof(GIF_FRAME_INFO));
}
if (frame_info.disposal == DISPOSE_PREVIOUS && frame_info.prepare == IMAGE_GIF_PREPARE_USE_BACKUP) {
switch_buffer_backup(gif);
} else {
// Backup
if (frame_info.disposal == DISPOSE_PREVIOUS) {
backup(gif);
}
// Prepare
switch (frame_info.prepare) {
case IMAGE_GIF_PREPARE_NONE:
// Do nothing
break;
default:
case IMAGE_GIF_PREPARE_BACKGROUND:
// Set bg
clear_bg(gif->gif_file, gif->buffer);
break;
case IMAGE_GIF_PREPARE_USE_BACKUP:
restore(gif);
break;
}
}
blend(gif->gif_file, index, gif->buffer, frame_info.tran);
// Copy to shown buffer
memcpy(gif->shown_buffer, gif->buffer, (size_t) (gif->gif_file->SWidth * gif->gif_file->SHeight * 4));
gif->buffer_index = index;
}
int GIF_get_delay(GIF* gif)
{
if (gif->frame_info_array == NULL) {
return 0;
} else {
return gif->frame_info_array[gif->buffer_index].delay;
}
}
int GIF_get_frame_count(GIF* gif)
{
return gif->gif_file->ImageCount;
}
bool GIF_is_opaque(GIF* gif)
{
return gif->frame_info_array->tran < 0;
}
void GIF_recycle(JNIEnv* env, GIF* gif)
{
DGifCloseFile(gif->gif_file, &error_code);
gif->gif_file = NULL;
free(gif->frame_info_array);
gif->frame_info_array = NULL;
free(gif->buffer);
gif->buffer = NULL;
free(gif->backup);
gif->backup = NULL;
free(gif->shown_buffer);
gif->shown_buffer = NULL;
if (gif->patch_head_input_stream != NULL) {
close_patch_head_input_stream(env, gif->patch_head_input_stream);
destroy_patch_head_input_stream(env, &gif->patch_head_input_stream);
gif->patch_head_input_stream = NULL;
}
}
#endif // IMAGE_SUPPORT_GIF
@@ -1,84 +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/27/2015.
//
#ifndef IMAGE_IMAGE_GIF_H
#define IMAGE_IMAGE_GIF_H
#include "config.h"
#ifdef IMAGE_SUPPORT_GIF
#include <stdbool.h>
#include "patch_head_input_stream.h"
#include "gif_lib.h"
#include "../utils.h"
#define IMAGE_GIF_DECODER_DESCRIPTION ("giflib " MAKESTRING(STRINGIZE, GIFLIB_MAJOR) "." \
MAKESTRING(STRINGIZE, GIFLIB_MINOR) "." \
MAKESTRING(STRINGIZE, GIFLIB_RELEASE))
#define IMAGE_GIF_MAGIC_NUMBER_0 0x47
#define IMAGE_GIF_MAGIC_NUMBER_1 0x49
#define IMAGE_GIF_PREPARE_UNKNOWN 0x00
#define IMAGE_GIF_PREPARE_NONE 0x01
#define IMAGE_GIF_PREPARE_BACKGROUND 0x02
#define IMAGE_GIF_PREPARE_USE_BACKUP 0x03
typedef struct
{
int tran;
int disposal;
int delay;
int prepare;
} GIF_FRAME_INFO;
typedef struct
{
GifFileType* gif_file;
GIF_FRAME_INFO* frame_info_array;
void* buffer;
int buffer_index;
void* backup;
bool partially;
// Use extra buffer to avoid blink
void* shown_buffer;
PatchHeadInputStream* patch_head_input_stream;
} GIF;
void* GIF_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially);
bool GIF_complete(JNIEnv* env, GIF* gif);
bool GIF_is_completed(GIF* gif);
void* GIF_get_pixels(GIF* gif);
int GIF_get_width(GIF* gif);
int GIF_get_height(GIF* gif);
int GIF_get_byte_count(GIF* gif);
void GIF_render(GIF* gif, 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);
void GIF_advance(GIF* gif);
int GIF_get_delay(GIF* gif);
int GIF_get_frame_count(GIF* gif);
bool GIF_is_opaque(GIF* gif);
void GIF_recycle(JNIEnv* env, GIF* gif);
#endif // IMAGE_SUPPORT_GIF
#endif // IMAGE_IMAGE_GIF_H
@@ -1,210 +0,0 @@
/*
* Copyright 2016 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 1/3/2016.
//
#include "config.h"
#ifdef IMAGE_SUPPORT_JPEG
#include <setjmp.h>
#include <stdlib.h>
#include "image_jpeg.h"
#include "image_utils.h"
#include "java_wrapper.h"
#include "../log.h"
struct my_error_mgr {
struct jpeg_error_mgr pub;
jmp_buf setjmp_buffer;
};
typedef struct my_error_mgr * my_error_ptr;
static char emsg[JMSG_LENGTH_MAX];
static void my_error_exit(j_common_ptr cinfo)
{
my_error_ptr myerr = (my_error_ptr) cinfo->err;
(*cinfo->err->format_message)(cinfo, emsg);
longjmp(myerr->setjmp_buffer, 1);
}
static size_t custom_read(void * custom_stuff, unsigned char * buffer, size_t size)
{
bool attach;
size_t read;
PatchHeadInputStream* patch_head_input_stream = custom_stuff;
JNIEnv *env = obtain_env(&attach);
if (env == NULL) {
LOGE(MSG("Can't get JNIEnv"));
return 0;
}
read = read_patch_head_input_stream(env, patch_head_input_stream, buffer, 0, size);
if (attach) {
release_env();
}
return read;
}
void* JPEG_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially)
{
JPEG* jpeg = NULL;
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
unsigned char* buffer = NULL;
size_t stride;
unsigned char* line_buffer_array[3];
int read_lines;
jpeg = (JPEG*) malloc(sizeof(JPEG));
if (jpeg == NULL) {
WTF_OM;
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
// Init
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
LOGE(MSG("%s"), emsg);
free(jpeg);
free(buffer);
jpeg_destroy_decompress(&cinfo);
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
jpeg_create_decompress(&cinfo);
jpeg_custom_src(&cinfo, &custom_read, patch_head_input_stream);
jpeg_read_header(&cinfo, TRUE);
// Start decompress
cinfo.out_color_space = JCS_EXT_RGBA;
jpeg_start_decompress(&cinfo);
stride = cinfo.output_components * cinfo.output_width;
buffer = malloc(stride * cinfo.output_height);
if (buffer == NULL) {
free(jpeg);
jpeg_destroy_decompress(&cinfo);
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
// Copy buffer
line_buffer_array[0] = buffer;
line_buffer_array[1] = line_buffer_array[0] + stride;
line_buffer_array[2] = line_buffer_array[1] + stride;
while (cinfo.output_scanline < cinfo.output_height) {
read_lines = jpeg_read_scanlines(&cinfo, line_buffer_array, 3);
line_buffer_array[0] += stride * read_lines;
line_buffer_array[1] = line_buffer_array[0] + stride;
line_buffer_array[2] = line_buffer_array[1] + stride;
}
// Finish decompress
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
// Close stream
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
// Fill jpeg
jpeg->width = cinfo.output_width;
jpeg->height = cinfo.output_height;
jpeg->buffer = buffer;
return jpeg;
}
bool JPEG_complete(JPEG* jpeg)
{
return true;
}
bool JPEG_is_completed(JPEG* jpeg)
{
return true;
}
void* JPEG_get_pixels(JPEG* jpeg)
{
return jpeg->buffer;
}
int JPEG_get_width(JPEG* jpeg)
{
return jpeg->width;
}
int JPEG_get_height(JPEG* jpeg)
{
return jpeg->height;
}
int JPEG_get_byte_count(JPEG* jpeg)
{
return jpeg->width * jpeg->height * 4;
}
void JPEG_render(JPEG* jpeg, 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)
{
copy_pixels(jpeg->buffer, jpeg->width, jpeg->height, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
}
void JPEG_advance(JPEG* jpeg)
{
}
int JPEG_get_delay(JPEG* jpeg)
{
return 0;
}
int JPEG_get_frame_count(JPEG* jpeg)
{
return 1;
}
bool JPEG_is_opaque(JPEG* jpeg)
{
return true;
}
void JPEG_recycle(JPEG* jpeg)
{
free(jpeg->buffer);
jpeg->buffer = NULL;
free(jpeg);
}
#endif // IMAGE_SUPPORT_JPEG
@@ -1,64 +0,0 @@
/*
* Copyright 2016 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 1/3/2016.
//
#ifndef IMAGE_IMAGE_JPEG_H
#define IMAGE_IMAGE_JPEG_H
#include "config.h"
#ifdef IMAGE_SUPPORT_JPEG
#include <stdio.h>
#include <stdbool.h>
#include "jpeglib.h"
#include "patch_head_input_stream.h"
#include "../utils.h"
#define IMAGE_JPEG_DECODER_DESCRIPTION ("libjpeg-turbo " MAKESTRING(STRINGIZE, LIBJPEG_TURBO_VERSION))
#define IMAGE_JPEG_MAGIC_NUMBER_0 0xFF
#define IMAGE_JPEG_MAGIC_NUMBER_1 0xD8
typedef struct
{
unsigned int width;
unsigned int height;
void* buffer;
} JPEG;
void* JPEG_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially);
bool JPEG_complete(JPEG* jpeg);
bool JPEG_is_completed(JPEG* jpeg);
void* JPEG_get_pixels(JPEG* jpeg);
int JPEG_get_width(JPEG* jpeg);
int JPEG_get_height(JPEG* jpeg);
int JPEG_get_byte_count(JPEG* jpeg);
void JPEG_render(JPEG* jpeg, 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);
void JPEG_advance(JPEG* jpeg);
int JPEG_get_delay(JPEG* jpeg);
int JPEG_get_frame_count(JPEG* jpeg);
bool JPEG_is_opaque(JPEG* jpeg);
void JPEG_recycle(JPEG* jpeg);
#endif // IMAGE_SUPPORT_JPEG
#endif // IMAGE_IMAGE_JPEG_H
@@ -28,12 +28,9 @@
#include "patch_head_input_stream.h"
typedef struct
{
unsigned int width;
unsigned int height;
void* buffer;
} PLAIN;
#include "image.h"
typedef IMAGE PLAIN;
void* PLAIN_create(unsigned int width, unsigned int height, const void* data);
bool PLAIN_complete(PLAIN* plain);
-642
View File
@@ -1,642 +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/27/2015.
//
#include "config.h"
#ifdef IMAGE_SUPPORT_PNG
#include <stdlib.h>
#include <string.h>
#include "../log.h"
#include "../utils.h"
#include "image_png.h"
#include "image_utils.h"
#include "java_wrapper.h"
static void user_read_fn(png_structp png_ptr,
png_bytep data, png_size_t length)
{
bool attach;
PatchHeadInputStream* patch_head_input_stream = png_get_io_ptr(png_ptr);
JNIEnv *env = obtain_env(&attach);
if (env == NULL) {
LOGE(MSG("Can't get JNIEnv"));
}
read_patch_head_input_stream(env, patch_head_input_stream, data, 0, length);
if (attach) {
release_env();
}
}
static void user_error_fn(png_structp png_ptr,
png_const_charp error_msg)
{
LOGE(MSG("%s"), error_msg);
}
static void user_warn_fn(png_structp png_ptr,
png_const_charp error_msg)
{
LOGW(MSG("%s"), error_msg);
}
static void free_frame_info_array(PNG_FRAME_INFO* frame_info_array, unsigned int count)
{
int i;
if (frame_info_array == NULL) {
return;
}
for (i = 0; i < count; i++) {
PNG_FRAME_INFO* frame_info = frame_info_array + i;
free(frame_info->buffer);
frame_info->buffer = NULL;
}
free(frame_info_array);
}
static bool read_image(png_structp png_ptr, unsigned char* buffer, unsigned int width, unsigned int height)
{
int i;
unsigned char** line_buffer_ptr_array = (unsigned char**) malloc(height * sizeof(unsigned char*));
if (line_buffer_ptr_array == NULL) {
WTF_OM;
return false;
}
for (i = 0; i < height; i++) {
line_buffer_ptr_array[i] = buffer + (width * i * 4);
}
png_read_image(png_ptr, line_buffer_ptr_array);
free(line_buffer_ptr_array);
return true;
}
static void read_frame(png_structp png_ptr, png_infop info_ptr, PNG_FRAME_INFO* frame_info)
{
unsigned int width;
unsigned int height;
unsigned int offset_x;
unsigned int offset_y;
unsigned short delay_num;
unsigned short delay_den;
unsigned char dop;
unsigned char bop;
unsigned int delay;
unsigned char* buffer = NULL;
png_read_frame_head(png_ptr, info_ptr);
png_get_next_frame_fcTL(png_ptr, info_ptr, &width, &height, &offset_x, &offset_y, &delay_num, &delay_den, &dop, &bop);
delay = 1000u * delay_num / delay_den;
frame_info->width = width;
frame_info->height = height;
frame_info->offset_x = offset_x;
frame_info->offset_y = offset_y;
frame_info->delay = delay;
frame_info->dop = dop;
frame_info->bop = bop;
frame_info->pop = IMAGE_PNG_PREPARE_UNKNOWN;
buffer = (unsigned char*) malloc(width * height * 4);
if (buffer == NULL) {
frame_info->buffer = NULL;
return;
}
read_image(png_ptr, buffer, width, height);
frame_info->buffer = buffer;
}
static void generate_pop(PNG_FRAME_INFO* frame_info_array, int count)
{
unsigned char dop = 0xff;
int i;
for (i = 0; i < count; i++){
PNG_FRAME_INFO* frame_info = frame_info_array + i;
switch (dop) {
case PNG_DISPOSE_OP_NONE:
frame_info->pop = IMAGE_PNG_PREPARE_NONE;
break;
case PNG_DISPOSE_OP_BACKGROUND:
frame_info->pop = IMAGE_PNG_PREPARE_BACKGROUND;
break;
case PNG_DISPOSE_OP_PREVIOUS:
frame_info->pop = IMAGE_PNG_PREPARE_USE_BACKUP;
break;
default:
frame_info->pop = IMAGE_PNG_PREPARE_BACKGROUND;
break;
}
dop = frame_info->dop;
}
}
void* PNG_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially)
{
PNG *png = NULL;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
bool apng;
unsigned int width;
unsigned int height;
int color_type;
int bit_depth;
bool is_opaque;
unsigned char* buffer = NULL;
unsigned int frame_count = 0;
bool hide_first_frame = false;
PNG_FRAME_INFO* frame_info_array = NULL;
int i;
png = (PNG *) malloc(sizeof(PNG));
if (png == NULL) {
WTF_OM;
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, &user_error_fn, &user_warn_fn);
if (png_ptr == NULL) {
free(png);
png = NULL;
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
free(png);
png = NULL;
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
if (setjmp(png_jmpbuf(png_ptr))) {
LOGE(MSG("Error in png decode"));
free_frame_info_array(frame_info_array, frame_count);
frame_info_array = NULL;
free(buffer);
buffer = NULL;
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
free(png);
png = NULL;
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
// Set custom read function
png_set_read_fn(png_ptr, patch_head_input_stream, &user_read_fn);
// Get png info
png_read_info(png_ptr, info_ptr);
// Check apng
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL)) {
apng = true;
} else {
apng = false;
}
// PNG info
width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr, info_ptr);
color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
// Create buffer
buffer = (unsigned char*) malloc(width * height * 4);
if (buffer == NULL) {
WTF_OM;
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
free(png);
png = NULL;
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
if (apng) {
// Get frame count
frame_count = png_get_num_frames(png_ptr, info_ptr);
hide_first_frame = png_get_first_frame_is_hidden(png_ptr, info_ptr);
if (hide_first_frame) {
frame_count--;
}
// Create frame info array
frame_info_array = (PNG_FRAME_INFO*) calloc(frame_count, sizeof(PNG_FRAME_INFO));
if (frame_info_array == NULL) {
WTF_OM;
free(buffer);
buffer = NULL;
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
free(png);
png = NULL;
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
return NULL;
}
}
// Configure to ARGB
png_set_expand(png_ptr);
if (bit_depth == 16) {
png_set_scale_16(png_ptr);
}
if (color_type == PNG_COLOR_TYPE_GRAY ||
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
png_set_gray_to_rgb(png_ptr);
}
if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
is_opaque = true;
png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
} else {
is_opaque = false;
}
if (apng) {
if (hide_first_frame) {
// Skip first frame
read_image(png_ptr, buffer, width, height);
}
// Read first frame
read_frame(png_ptr, info_ptr, frame_info_array);
// Fix dop
if (frame_info_array->dop == PNG_DISPOSE_OP_PREVIOUS) {
frame_info_array->dop = PNG_DISPOSE_OP_BACKGROUND;
}
if (!partially || frame_count == 1) {
// Read all frame
for (i = 1; i < frame_count; read_frame(png_ptr, info_ptr, frame_info_array + i++));
// Generate pop
generate_pop(frame_info_array, frame_count);
// End read
png_read_end(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
// Close input stream
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
png->partially = false;
png->png_ptr = NULL;
png->info_ptr = NULL;
png->patch_head_input_stream = NULL;
} else {
png->partially = true;
png->png_ptr = png_ptr;
png->info_ptr = info_ptr;
png->patch_head_input_stream = patch_head_input_stream;
}
// Fill PNG
png->width = width;
png->height = height;
png->is_opaque = is_opaque;
png->buffer = buffer;
png->apng = true;
png->buffer_index = -1;
png->frame_info_array = frame_info_array;
png->frame_count = frame_count;
png->backup = NULL;
// Render first frame
PNG_advance(png);
} else {
read_image(png_ptr, buffer, width, height);
// End read
png_read_end(png_ptr, info_ptr);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
// Close input stream
close_patch_head_input_stream(env, patch_head_input_stream);
destroy_patch_head_input_stream(env, &patch_head_input_stream);
// Fill PNG
png->width = width;
png->height = height;
png->buffer = buffer;
png->apng = false;
png->buffer_index = 0;
png->frame_info_array = NULL;
png->frame_count = 0;
png->backup = NULL;
png->partially = false;
png->png_ptr = NULL;
png->info_ptr = NULL;
png->patch_head_input_stream = NULL;
}
return png;
}
bool PNG_complete(JNIEnv *env, PNG* png)
{
int i;
if (!png->partially) {
return true;
}
if (png->png_ptr == NULL || png->info_ptr == NULL || png->patch_head_input_stream == NULL) {
LOGE(MSG("Some stuff is NULL"));
return false;
}
// Read left frames
for (i = 1; i < png->frame_count; read_frame(png->png_ptr, png->info_ptr, png->frame_info_array + i++));
// Generate pop
generate_pop(png->frame_info_array, png->frame_count);
// End read
png_read_end(png->png_ptr, png->info_ptr);
png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
// Close input stream
close_patch_head_input_stream(env, png->patch_head_input_stream);
destroy_patch_head_input_stream(env, &png->patch_head_input_stream);
// Clean up
png->partially = false;
png->png_ptr = NULL;
png->info_ptr = NULL;
png->patch_head_input_stream = NULL;
return true;
}
bool PNG_is_completed(PNG* png)
{
return !png->partially;
}
void* PNG_get_pixels(PNG* png)
{
if (!png->partially && PNG_get_frame_count(png) == 1) {
return png->buffer;
} else {
return NULL;
}
}
int PNG_get_width(PNG* png)
{
return png->width;
}
int PNG_get_height(PNG* png)
{
return png->height;
}
int PNG_get_byte_count(PNG* png)
{
int i;
PNG_FRAME_INFO* frame_info;
int size = 0;
// Add buffer size
if (png->buffer != NULL) {
size += png->width * png->height * 4;
}
// Add backup size
if (png->backup != NULL) {
size += png->width * png->height * 4;
}
// Add frames size
if (png->frame_info_array != NULL) {
for (i = 0; i < png->frame_count; i++) {
frame_info = png->frame_info_array + i;
// Add frame buffer size
if (frame_info->buffer != NULL) {
size += frame_info->width * frame_info->height * 4;
}
}
}
return size;
}
void PNG_render(PNG* png, 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)
{
copy_pixels(png->buffer, png->width, png->height, src_x, src_y,
dst, dst_w, dst_h, dst_x, dst_y,
width, height, fill_blank, default_color);
}
static void backup(PNG* png)
{
if (png->backup == NULL) {
png->backup = (unsigned char*) malloc(png->width * png->height * 4);
if (png->backup == NULL) {
WTF_OM;
return;
}
}
memcpy(png->backup, png->buffer, png->width * png->height * 4);
}
static void restore(PNG* png)
{
if (png->backup == NULL) {
LOGE(MSG("Backup is NULL"));
} else {
memcpy(png->buffer, png->backup, png->width * png->height * 4);
}
}
static void switch_buffer_backup(PNG* png)
{
unsigned char* temp;
if (png->backup == NULL) {
backup(png);
} else {
temp = png->buffer;
png->buffer = png->backup;
png->backup = temp;
}
}
static void blend_over(unsigned char* dp, const unsigned char* sp, size_t len)
{
unsigned int i;
int u, v, al;
for (i = 0; i < len; i += 4, sp += 4, dp += 4) {
if (sp[3] == 255) {
memcpy(dp, sp, 4);
} else if (sp[3] != 0) {
if (dp[3] != 0) {
u = sp[3] * 255;
v = (255 - sp[3]) * dp[3];
al = u + v;
dp[0] = (unsigned char) ((sp[0] * u + dp[0] * v) / al);
dp[1] = (unsigned char) ((sp[1] * u + dp[1] * v) / al);
dp[2] = (unsigned char) ((sp[2] * u + dp[2] * v) / al);
dp[3] = (unsigned char) (al / 255);
} else {
memcpy(dp, sp, 4);
}
}
}
}
static void blend(unsigned char* src, int src_width, int src_height, int offset_x, int offset_y,
unsigned char* dst, int dst_width, int dst_height, bool blend_op_over)
{
int i;
unsigned char* src_ptr;
unsigned char* dst_ptr;
size_t len;
int copy_width = MIN(dst_width - offset_x, src_width);
int copy_height = MIN(dst_height - offset_y, src_height);
for (i = 0; i < copy_height; i++) {
src_ptr = src + (i * src_width * 4);
dst_ptr = dst + (((offset_y + i) * dst_width + offset_x) * 4);
len = (size_t) (copy_width * 4);
if (blend_op_over) {
blend_over(dst_ptr, src_ptr, len);
} else {
memcpy(dst_ptr, src_ptr, len);
}
}
}
void PNG_advance(PNG* png)
{
int index;
if (!png->apng) {
LOGW(MSG("It is not apng, no need to advance"));
return;
}
index = (png->buffer_index + 1) % png->frame_count;
if (index != 0 && png->partially) {
LOGE(MSG("The png is only decoded partially. Only the first frame can be shown."));
return;
}
PNG_FRAME_INFO* frame_info = png->frame_info_array + index;
if (frame_info->dop == PNG_DISPOSE_OP_PREVIOUS && frame_info->pop == IMAGE_PNG_PREPARE_USE_BACKUP) {
switch_buffer_backup(png);
} else {
// Backup
if (frame_info->dop == PNG_DISPOSE_OP_PREVIOUS) {
backup(png);
}
// Prepare
switch (frame_info->pop) {
case IMAGE_PNG_PREPARE_NONE:
// Do nothing
break;
default:
case IMAGE_PNG_PREPARE_BACKGROUND:
// Set transparent
memset(png->buffer, '\0', png->width * png->height * 4);
break;
case IMAGE_PNG_PREPARE_USE_BACKUP:
restore(png);
break;
}
}
blend(frame_info->buffer, frame_info->width, frame_info->height, frame_info->offset_x, frame_info->offset_y,
png->buffer, png->width, png->height, frame_info->bop == PNG_BLEND_OP_OVER);
png->buffer_index = index;
}
int PNG_get_delay(PNG* png)
{
if (png->apng) {
return png->frame_info_array[png->buffer_index].delay;
} else {
return 0;
}
}
int PNG_get_frame_count(PNG* png)
{
if (png->apng) {
return png->frame_count;
} else {
return 1;
}
}
bool PNG_is_opaque(PNG* png)
{
return png->is_opaque;
}
void PNG_recycle(JNIEnv *env, PNG* png)
{
if (png == NULL) {
return;
}
free(png->buffer);
png->buffer = NULL;
free_frame_info_array(png->frame_info_array, png->frame_count);
png->frame_info_array = NULL;
free(png->backup);
png->backup = NULL;
if (png->png_ptr != NULL && png->info_ptr != NULL) {
png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
}
png->png_ptr = NULL;
png->info_ptr = NULL;
if (png->patch_head_input_stream != NULL) {
close_patch_head_input_stream(env, png->patch_head_input_stream);
destroy_patch_head_input_stream(env, &png->patch_head_input_stream);
png->patch_head_input_stream = NULL;
}
}
#endif // IMAGE_SUPPORT_PNG
@@ -1,89 +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/27/2015.
//
#ifndef IMAGE_IMAGE_PNG_H
#define IMAGE_IMAGE_PNG_H
#include "config.h"
#ifdef IMAGE_SUPPORT_PNG
#include <stdbool.h>
#include "png.h"
#include "patch_head_input_stream.h"
#define IMAGE_PNG_DECODER_DESCRIPTION ("libpng " PNG_LIBPNG_VER_STRING)
#define IMAGE_PNG_MAGIC_NUMBER_0 0x89
#define IMAGE_PNG_MAGIC_NUMBER_1 0x50
#define IMAGE_PNG_PREPARE_UNKNOWN 0x00
#define IMAGE_PNG_PREPARE_NONE 0x01
#define IMAGE_PNG_PREPARE_BACKGROUND 0x02
#define IMAGE_PNG_PREPARE_USE_BACKUP 0x03
typedef struct {
unsigned char* buffer;
unsigned int width;
unsigned int height;
unsigned int offset_x;
unsigned int offset_y;
unsigned int delay; // ms
unsigned char dop;
unsigned char bop;
unsigned char pop;
} PNG_FRAME_INFO;
typedef struct
{
unsigned int width;
unsigned int height;
bool is_opaque;
unsigned char* buffer;
bool apng;
int buffer_index;
PNG_FRAME_INFO* frame_info_array;
unsigned int frame_count;
unsigned char* backup;
bool partially;
png_structp png_ptr;
png_infop info_ptr;
PatchHeadInputStream* patch_head_input_stream;
} PNG;
void* PNG_decode(JNIEnv* env, PatchHeadInputStream* patch_head_input_stream, bool partially);
bool PNG_complete(JNIEnv* env, PNG* png);
bool PNG_is_completed(PNG* png);
void* PNG_get_pixels(PNG* png);
int PNG_get_width(PNG* png);
int PNG_get_height(PNG* png);
int PNG_get_byte_count(PNG* png);
void PNG_render(PNG* png, 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);
void PNG_advance(PNG* png);
int PNG_get_delay(PNG* png);
int PNG_get_frame_count(PNG* png);
bool PNG_is_opaque(PNG* png);
void PNG_recycle(JNIEnv* env, PNG* png);
#endif // IMAGE_SUPPORT_PNG
#endif // IMAGE_IMAGE_PNG_H
-6
View File
@@ -21,7 +21,6 @@
#include <archive.h>
#include <lzma.h>
#include <zlib.h>
#include "image/libjpeg-turbo/jconfigint.h"
#include <nettle/config.h>
#include "java_wrapper.h"
@@ -50,11 +49,6 @@ Java_com_hippo_Native_getliblzmaVersion(JNIEnv *env, jclass clazz) {
return (*env)->NewStringUTF(env, lzma_version_string());
}
JNIEXPORT jstring JNICALL
Java_com_hippo_Native_getlibjpeg_1turboVersion(JNIEnv *env, jclass clazz) {
return (*env)->NewStringUTF(env, VERSION);
}
JNIEXPORT jstring JNICALL
Java_com_hippo_Native_getzlibVersion(JNIEnv *env, jclass clazz) {
return (*env)->NewStringUTF(env, ZLIB_VERSION);