Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8191f346 authored by Fyodor Kyslov's avatar Fyodor Kyslov Committed by Android (Google) Code Review
Browse files

Merge "jpegrecoverymap: Implement RGBA decoding"

parents 6ed93c89 ea9180ff
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -36,11 +36,11 @@ public:
    JpegDecoder();
    ~JpegDecoder();
    /*
     * Decompresses JPEG image to raw image (YUV420planer or grey-scale) format. After calling
     * this method, call getDecompressedImage() to get the image.
     * Decompresses JPEG image to raw image (YUV420planer, grey-scale or RGBA) format. After
     * calling this method, call getDecompressedImage() to get the image.
     * Returns false if decompressing the image fails.
     */
    bool decompressImage(const void* image, int length);
    bool decompressImage(const void* image, int length, bool decodeToRGBA = false);
    /*
     * Returns the decompressed raw image buffer pointer. This method must be called only after
     * calling decompressImage().
@@ -98,10 +98,11 @@ public:
    bool extractEXIF(const void* image, int length);

private:
    bool decode(const void* image, int length);
    bool decode(const void* image, int length, bool decodeToRGBA);
    // Returns false if errors occur.
    bool decompress(jpeg_decompress_struct* cinfo, const uint8_t* dest, bool isSingleChannel);
    bool decompressYUV(jpeg_decompress_struct* cinfo, const uint8_t* dest);
    bool decompressRGBA(jpeg_decompress_struct* cinfo, const uint8_t* dest);
    bool decompressSingleChannel(jpeg_decompress_struct* cinfo, const uint8_t* dest);
    // Process 16 lines of Y and 16 lines of U/V each time.
    // We must pass at least 16 scanlines according to libjpeg documentation.
+38 −10
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ JpegDecoder::JpegDecoder() {
JpegDecoder::~JpegDecoder() {
}

bool JpegDecoder::decompressImage(const void* image, int length) {
bool JpegDecoder::decompressImage(const void* image, int length, bool decodeToRGBA) {
    if (image == nullptr || length <= 0) {
        ALOGE("Image size can not be handled: %d", length);
        return false;
@@ -101,7 +101,7 @@ bool JpegDecoder::decompressImage(const void* image, int length) {

    mResultBuffer.clear();
    mXMPBuffer.clear();
    if (!decode(image, length)) {
    if (!decode(image, length, decodeToRGBA)) {
        return false;
    }

@@ -140,7 +140,7 @@ size_t JpegDecoder::getDecompressedImageHeight() {
    return mHeight;
}

bool JpegDecoder::decode(const void* image, int length) {
bool JpegDecoder::decode(const void* image, int length, bool decodeToRGBA) {
    jpeg_decompress_struct cinfo;
    jpegr_source_mgr mgr(static_cast<const uint8_t*>(image), length);
    jpegrerror_mgr myerr;
@@ -210,15 +210,26 @@ bool JpegDecoder::decode(const void* image, int length) {
    mWidth = cinfo.image_width;
    mHeight = cinfo.image_height;

    if (decodeToRGBA) {
        if (cinfo.jpeg_color_space == JCS_GRAYSCALE) {
            // We don't intend to support decoding grayscale to RGBA
            return false;
        }
        // 4 bytes per pixel
        mResultBuffer.resize(cinfo.image_width * cinfo.image_height * 4);
        cinfo.out_color_space = JCS_EXT_RGBA;
    } else {
        if (cinfo.jpeg_color_space == JCS_YCbCr) {
            // 1 byte per pixel for Y, 0.5 byte per pixel for U+V
            mResultBuffer.resize(cinfo.image_width * cinfo.image_height * 3 / 2, 0);
        } else if (cinfo.jpeg_color_space == JCS_GRAYSCALE) {
            mResultBuffer.resize(cinfo.image_width * cinfo.image_height, 0);
        }

        cinfo.out_color_space = cinfo.jpeg_color_space;
        cinfo.raw_data_out = TRUE;
    }

    cinfo.dct_method = JDCT_IFAST;
    cinfo.out_color_space = cinfo.jpeg_color_space;

    jpeg_start_decompress(&cinfo);

@@ -292,6 +303,9 @@ bool JpegDecoder::decompress(jpeg_decompress_struct* cinfo, const uint8_t* dest,
    if (isSingleChannel) {
        return decompressSingleChannel(cinfo, dest);
    }
    if (cinfo->out_color_space == JCS_EXT_RGBA)
        return decompressRGBA(cinfo, dest);
    else
        return decompressYUV(cinfo, dest);
}

@@ -331,6 +345,20 @@ bool JpegDecoder::getCompressedImageParameters(const void* image, int length,
    return true;
}

bool JpegDecoder::decompressRGBA(jpeg_decompress_struct* cinfo, const uint8_t* dest) {
    JSAMPLE* decodeDst = (JSAMPLE*) dest;
    uint32_t lines = 0;
    // TODO: use batches for more effectiveness
    while (lines < cinfo->image_height) {
        uint32_t ret = jpeg_read_scanlines(cinfo, &decodeDst, 1);
        if (ret == 0) {
            break;
        }
        decodeDst += cinfo->image_width * 4;
        lines++;
    }
    return lines == cinfo->image_height;
}

bool JpegDecoder::decompressYUV(jpeg_decompress_struct* cinfo, const uint8_t* dest) {

+20 −15
Original line number Diff line number Diff line
@@ -544,23 +544,37 @@ status_t RecoveryMap::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
  if (compressed_jpegr_image == nullptr || dest == nullptr) {
    return ERROR_JPEGR_INVALID_NULL_PTR;
  }

  // TODO: fill EXIF data
  (void) exif;

  if (request_sdr) {
    JpegDecoder jpeg_decoder;
    if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length,
                                      true)) {
        return ERROR_JPEGR_DECODE_ERROR;
    }
    jpegr_uncompressed_struct uncompressed_rgba_image;
    uncompressed_rgba_image.data = jpeg_decoder.getDecompressedImagePtr();
    uncompressed_rgba_image.width = jpeg_decoder.getDecompressedImageWidth();
    uncompressed_rgba_image.height = jpeg_decoder.getDecompressedImageHeight();
    memcpy(dest->data, uncompressed_rgba_image.data,
           uncompressed_rgba_image.width * uncompressed_rgba_image.height * 4);
    dest->width = uncompressed_rgba_image.width;
    dest->height = uncompressed_rgba_image.height;
    return NO_ERROR;
  }

  jpegr_compressed_struct compressed_map;
  jpegr_metadata metadata;
  JPEGR_CHECK(extractRecoveryMap(compressed_jpegr_image, &compressed_map));


  JpegDecoder jpeg_decoder;
  if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length)) {
    return ERROR_JPEGR_DECODE_ERROR;
  }

  JpegDecoder recovery_map_decoder;
  if (!recovery_map_decoder.decompressImage(compressed_map.data,
                                    compressed_map.length)) {
  if (!recovery_map_decoder.decompressImage(compressed_map.data, compressed_map.length)) {
    return ERROR_JPEGR_DECODE_ERROR;
  }

@@ -569,7 +583,6 @@ status_t RecoveryMap::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
  map.width = recovery_map_decoder.getDecompressedImageWidth();
  map.height = recovery_map_decoder.getDecompressedImageHeight();


  jpegr_uncompressed_struct uncompressed_yuv_420_image;
  uncompressed_yuv_420_image.data = jpeg_decoder.getDecompressedImagePtr();
  uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth();
@@ -580,15 +593,7 @@ status_t RecoveryMap::decodeJPEGR(jr_compressed_ptr compressed_jpegr_image,
    return ERROR_JPEGR_DECODE_ERROR;
  }

  if (request_sdr) {
    memcpy(dest->data, uncompressed_yuv_420_image.data,
            uncompressed_yuv_420_image.width*uncompressed_yuv_420_image.height *3 / 2);
    dest->width = uncompressed_yuv_420_image.width;
    dest->height = uncompressed_yuv_420_image.height;
  } else {
  JPEGR_CHECK(applyRecoveryMap(&uncompressed_yuv_420_image, &map, &metadata, dest));
  }

  return NO_ERROR;
}