void PNG_recycle(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(get_env(), png->patch_head_input_stream); destroy_patch_head_input_stream(get_env(), &png->patch_head_input_stream); png->patch_head_input_stream = NULL; } }
bool PNG_complete(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(EMSG("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(get_env(), png->patch_head_input_stream); destroy_patch_head_input_stream(get_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; }
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(EMSG("Can't detect format %d"), *format); destroy_input_stream(get_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; destroy_input_stream(get_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(EMSG("Can't detect format %d"), *format); close_patch_head_input_stream(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_env(), &patch_head_input_stream); return NULL; } }
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(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_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(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_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(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_env(), &patch_head_input_stream); return NULL; } if (setjmp(png_jmpbuf(png_ptr))) { LOGE(EMSG("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(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_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(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_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(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_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; }
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(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_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(EMSG("%s"), emsg); free(jpeg); free(buffer); jpeg_destroy_decompress(&cinfo); close_patch_head_input_stream(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_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(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_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(get_env(), patch_head_input_stream); destroy_patch_head_input_stream(get_env(), &patch_head_input_stream); // Fill jpeg jpeg->width = cinfo.output_width; jpeg->height = cinfo.output_height; jpeg->buffer = buffer; return jpeg; }