Beispiel #1
0
void advance(void* image, int format)
{
  switch (format) {
#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(EMSG("Can't detect format %d"), format);
  }
}
Beispiel #2
0
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;
}