struct heif_error opj_encode_image()

in libheif/plugins/encoder_openjpeg.cc [452:551]


struct heif_error opj_encode_image(void* encoder_raw, const struct heif_image* image, enum heif_image_input_class image_class)
{
  struct encoder_struct_opj* encoder = (struct encoder_struct_opj*) encoder_raw;
  struct heif_error err;

  heif_chroma chroma = heif_image_get_chroma_format(image);
  heif_colorspace colorspace = heif_image_get_colorspace(image);

  int width = heif_image_get_primary_width(image);
  int height = heif_image_get_primary_height(image);

  std::vector<heif_channel> channels;
  OPJ_COLOR_SPACE opj_colorspace;

  switch (colorspace) {
    case heif_colorspace_YCbCr:
      channels = {heif_channel_Y, heif_channel_Cb, heif_channel_Cr};
      opj_colorspace = OPJ_CLRSPC_SYCC;
      break;
    case heif_colorspace_RGB:
      channels = {heif_channel_R, heif_channel_G, heif_channel_B};
      opj_colorspace = OPJ_CLRSPC_SRGB;
      break;
    case heif_colorspace_monochrome:
      channels = {heif_channel_Y};
      opj_colorspace = OPJ_CLRSPC_GRAY;
      break;
    default:
      assert(false);
      return heif_error{heif_error_Encoding_error, heif_suberror_Unspecified, "OpenJPEG encoder plugin received image with invalid colorspace."};
  }

  int band_count = (int) channels.size();

  opj_image_cmptparm_t component_params[4];
  memset(&component_params, 0, band_count * sizeof(opj_image_cmptparm_t));

  for (int comp = 0; comp < band_count; comp++) {

    int bpp = heif_image_get_bits_per_pixel_range(image, channels[comp]);

    int sub_dx = 1, sub_dy = 1;
    switch (chroma) {
      case heif_chroma_420:
        sub_dx = 2;
        sub_dy = 2;
        break;
      case heif_chroma_422:
        sub_dx = 2;
        sub_dy = 1;
        break;
      default:
        break;
    }

    component_params[comp].prec = bpp;
    component_params[comp].sgnd = 0;
    component_params[comp].dx = comp == 0 ? 1 : sub_dx;
    component_params[comp].dy = comp == 0 ? 1 : sub_dy;
    component_params[comp].w = comp == 0 ? width : (width + sub_dx / 2) / sub_dx;
    component_params[comp].h = comp == 0 ? height : (height + sub_dy / 2) / sub_dy;
  }

  opj_image_t* opj_image = opj_image_create(band_count, &component_params[0], opj_colorspace);
  if (image == nullptr) {
    // Failed to create image
    err = {heif_error_Encoding_error, heif_suberror_Unspecified, "Failed create OpenJPEG image"};
    return err;
  }

  opj_image->x0 = 0;
  opj_image->y0 = 0;
  opj_image->x1 = width;
  opj_image->y1 = height;

  for (int comp = 0; comp < band_count; comp++) {
    int stride;
    const uint8_t* p = heif_image_get_plane_readonly(image, channels[comp], &stride);

    int cwidth = component_params[comp].w;
    int cheight = component_params[comp].h;

    // Note: obj_image data is 32bit integer
    for (int y = 0; y < cheight; y++) {
      for (int x = 0; x < cwidth; x++) {
        opj_image->comps[comp].data[y * cwidth + x] = p[y * stride + x];
      }
    }
  }

  encoder->data_read = false;
  encoder->codestream.clear(); //Fixes issue when encoding multiple images and old data persists.

  //Encodes the image into a 'codestream' which is stored in the 'encoder' variable
  err = generate_codestream(opj_image, encoder);

  opj_image_destroy(opj_image);

  return err;
}