struct heif_error jpeg_decode_image()

in libheif/plugins/decoder_jpeg.cc [126:293]


struct heif_error jpeg_decode_image(void* decoder_raw, struct heif_image** out_img)
{
  struct jpeg_decoder* decoder = (struct jpeg_decoder*) decoder_raw;


  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;

  // to store embedded icc profile
//  uint32_t iccLen;
//  uint8_t* iccBuffer = NULL;

//  std::vector<uint8_t> xmpData;
//  std::vector<uint8_t> exifData;

  // initialize decompressor

  jpeg_create_decompress(&cinfo);

  cinfo.err = jpeg_std_error(&jerr);
  jpeg_mem_src(&cinfo, decoder->data.data(), static_cast<unsigned long>(decoder->data.size()));

  /* Adding this part to prepare for icc profile reading. */
//  jpeg_save_markers(&cinfo, JPEG_ICC_MARKER, 0xFFFF);
//  jpeg_save_markers(&cinfo, JPEG_XMP_MARKER, 0xFFFF);
//  jpeg_save_markers(&cinfo, JPEG_EXIF_MARKER, 0xFFFF);

  jpeg_read_header(&cinfo, TRUE);

//  bool embeddedIccFlag = ReadICCProfileFromJPEG(&cinfo, &iccBuffer, &iccLen);
//  bool embeddedXMPFlag = ReadXMPFromJPEG(&cinfo, xmpData);
//  if (embeddedXMPFlag) {
//    img.xmp = xmpData;
//  }

//  bool embeddedEXIFFlag = ReadEXIFFromJPEG(&cinfo, exifData);
//  if (embeddedEXIFFlag) {
//    img.exif = exifData;
//    img.orientation = (heif_orientation) read_exif_orientation_tag(exifData.data(), (int) exifData.size());
//  }

  if (cinfo.jpeg_color_space == JCS_GRAYSCALE) {
    cinfo.out_color_space = JCS_GRAYSCALE;

    jpeg_start_decompress(&cinfo);

    JSAMPARRAY buffer;
    buffer = (*cinfo.mem->alloc_sarray)
        ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);


    // create destination image

    struct heif_image* heif_img = nullptr;
    struct heif_error err = heif_image_create(cinfo.output_width, cinfo.output_height,
                                              heif_colorspace_monochrome,
                                              heif_chroma_monochrome,
                                              &heif_img);
    if (err.code != heif_error_Ok) {
      assert(heif_img==nullptr);
      return err;
    }

    heif_image_add_plane(heif_img, heif_channel_Y, cinfo.output_width, cinfo.output_height, 8);

    int y_stride;
    uint8_t* py = heif_image_get_plane(heif_img, heif_channel_Y, &y_stride);


    // read the image

    while (cinfo.output_scanline < cinfo.output_height) {
      (void) jpeg_read_scanlines(&cinfo, buffer, 1);

      memcpy(py + (cinfo.output_scanline - 1) * y_stride, *buffer, cinfo.output_width);
    }

    *out_img = heif_img;
  }
  else {
    cinfo.out_color_space = JCS_YCbCr;

    jpeg_start_decompress(&cinfo);

    JSAMPARRAY buffer;
    buffer = (*cinfo.mem->alloc_sarray)
        ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1);


    // create destination image

    struct heif_image* heif_img = nullptr;
    struct heif_error err = heif_image_create(cinfo.output_width, cinfo.output_height,
                                              heif_colorspace_YCbCr,
                                              heif_chroma_420,
                                              &heif_img);
    if (err.code != heif_error_Ok) {
      assert(heif_img==nullptr);
      return err;
    }

    heif_image_add_plane(heif_img, heif_channel_Y, cinfo.output_width, cinfo.output_height, 8);
    heif_image_add_plane(heif_img, heif_channel_Cb, (cinfo.output_width + 1) / 2, (cinfo.output_height + 1) / 2, 8);
    heif_image_add_plane(heif_img, heif_channel_Cr, (cinfo.output_width + 1) / 2, (cinfo.output_height + 1) / 2, 8);

    int y_stride;
    int cb_stride;
    int cr_stride;
    uint8_t* py = heif_image_get_plane(heif_img, heif_channel_Y, &y_stride);
    uint8_t* pcb = heif_image_get_plane(heif_img, heif_channel_Cb, &cb_stride);
    uint8_t* pcr = heif_image_get_plane(heif_img, heif_channel_Cr, &cr_stride);

    // read the image

    //printf("jpeg size: %d %d\n",cinfo.output_width, cinfo.output_height);

    while (cinfo.output_scanline < cinfo.output_height) {
      JOCTET* bufp;

      (void) jpeg_read_scanlines(&cinfo, buffer, 1);

      bufp = buffer[0];

      int y = cinfo.output_scanline - 1;

      for (unsigned int x = 0; x < cinfo.output_width; x += 2) {
        py[y * y_stride + x] = *bufp++;
        pcb[y / 2 * cb_stride + x / 2] = *bufp++;
        pcr[y / 2 * cr_stride + x / 2] = *bufp++;

        if (x + 1 < cinfo.output_width) {
          py[y * y_stride + x + 1] = *bufp++;
        }

        bufp += 2;
      }


      if (cinfo.output_scanline < cinfo.output_height) {
        (void) jpeg_read_scanlines(&cinfo, buffer, 1);

        bufp = buffer[0];

        y = cinfo.output_scanline - 1;

        for (unsigned int x = 0; x < cinfo.output_width; x++) {
          py[y * y_stride + x] = *bufp++;
          bufp += 2;
        }
      }
    }

    *out_img = heif_img;
  }

//  if (embeddedIccFlag && iccLen > 0) {
//    heif_image_set_raw_color_profile(image, "prof", iccBuffer, (size_t) iccLen);
//  }

  // cleanup
//  free(iccBuffer);
  jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);

  decoder->data.clear();

  return heif_error_ok;
}