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

Commit 5ad0df9b authored by Nick Deakin's avatar Nick Deakin Committed by Automerger Merge Worker
Browse files

libultrahdr: correct srgb, p3 calculations and jpeg yuv handling am: 0db53ee3

parents fc0c4ac0 0db53ee3
Loading
Loading
Loading
Loading
+132 −17
Original line number Diff line number Diff line
@@ -119,34 +119,39 @@ static float clampPixelFloat(float value) {
    return (value < 0.0f) ? 0.0f : (value > kMaxPixelFloat) ? kMaxPixelFloat : value;
}

// See IEC 61966-2-1, Equation F.7.
// See IEC 61966-2-1/Amd 1:2003, Equation F.7.
static const float kSrgbR = 0.2126f, kSrgbG = 0.7152f, kSrgbB = 0.0722f;

float srgbLuminance(Color e) {
  return kSrgbR * e.r + kSrgbG * e.g + kSrgbB * e.b;
}

// See ECMA TR/98, Section 7.
static const float kSrgbRCr = 1.402f, kSrgbGCb = 0.34414f, kSrgbGCr = 0.71414f, kSrgbBCb = 1.772f;
// See ITU-R BT.709-6, Section 3.
// Uses the same coefficients for deriving luma signal as
// IEC 61966-2-1/Amd 1:2003 states for luminance, so we reuse the luminance
// function above.
static const float kSrgbCb = 1.8556f, kSrgbCr = 1.5748f;

Color srgbYuvToRgb(Color e_gamma) {
  return {{{ clampPixelFloat(e_gamma.y + kSrgbRCr * e_gamma.v),
             clampPixelFloat(e_gamma.y - kSrgbGCb * e_gamma.u - kSrgbGCr * e_gamma.v),
             clampPixelFloat(e_gamma.y + kSrgbBCb * e_gamma.u) }}};
Color srgbRgbToYuv(Color e_gamma) {
  float y_gamma = srgbLuminance(e_gamma);
  return {{{ y_gamma,
             (e_gamma.b - y_gamma) / kSrgbCb,
             (e_gamma.r - y_gamma) / kSrgbCr }}};
}

// See ECMA TR/98, Section 7.
static const float kSrgbYR = 0.299f, kSrgbYG = 0.587f, kSrgbYB = 0.114f;
static const float kSrgbUR = -0.1687f, kSrgbUG = -0.3313f, kSrgbUB = 0.5f;
static const float kSrgbVR = 0.5f, kSrgbVG = -0.4187f, kSrgbVB = -0.0813f;
// See ITU-R BT.709-6, Section 3.
// Same derivation to BT.2100's YUV->RGB, below. Similar to srgbRgbToYuv, we
// can reuse the luminance coefficients since they are the same.
static const float kSrgbGCb = kSrgbB * kSrgbCb / kSrgbG;
static const float kSrgbGCr = kSrgbR * kSrgbCr / kSrgbG;

Color srgbRgbToYuv(Color e_gamma) {
  return {{{ kSrgbYR * e_gamma.r + kSrgbYG * e_gamma.g + kSrgbYB * e_gamma.b,
             kSrgbUR * e_gamma.r + kSrgbUG * e_gamma.g + kSrgbUB * e_gamma.b,
             kSrgbVR * e_gamma.r + kSrgbVG * e_gamma.g + kSrgbVB * e_gamma.b }}};
Color srgbYuvToRgb(Color e_gamma) {
  return {{{ clampPixelFloat(e_gamma.y + kSrgbCr * e_gamma.v),
             clampPixelFloat(e_gamma.y - kSrgbGCb * e_gamma.u - kSrgbGCr * e_gamma.v),
             clampPixelFloat(e_gamma.y + kSrgbCb * e_gamma.u) }}};
}

// See IEC 61966-2-1, Equations F.5 and F.6.
// See IEC 61966-2-1/Amd 1:2003, Equations F.5 and F.6.
float srgbInvOetf(float e_gamma) {
  if (e_gamma <= 0.04045f) {
    return e_gamma / 12.92f;
@@ -178,13 +183,38 @@ Color srgbInvOetfLUT(Color e_gamma) {
////////////////////////////////////////////////////////////////////////////////
// Display-P3 transformations

// See SMPTE EG 432-1, Table 7-2.
// See SMPTE EG 432-1, Equation 7-8.
static const float kP3R = 0.20949f, kP3G = 0.72160f, kP3B = 0.06891f;

float p3Luminance(Color e) {
  return kP3R * e.r + kP3G * e.g + kP3B * e.b;
}

// See ITU-R BT.601-7, Sections 2.5.1 and 2.5.2.
// Unfortunately, calculation of luma signal differs from calculation of
// luminance for Display-P3, so we can't reuse p3Luminance here.
static const float kP3YR = 0.299f, kP3YG = 0.587f, kP3YB = 0.114f;
static const float kP3Cb = 1.772f, kP3Cr = 1.402f;

Color p3RgbToYuv(Color e_gamma) {
  float y_gamma = kP3YR * e_gamma.r + kP3YG * e_gamma.g + kP3YB * e_gamma.b;
  return {{{ y_gamma,
             (e_gamma.b - y_gamma) / kP3Cb,
             (e_gamma.r - y_gamma) / kP3Cr }}};
}

// See ITU-R BT.601-7, Sections 2.5.1 and 2.5.2.
// Same derivation to BT.2100's YUV->RGB, below. Similar to p3RgbToYuv, we must
// use luma signal coefficients rather than the luminance coefficients.
static const float kP3GCb = kP3YB * kP3Cb / kP3YG;
static const float kP3GCr = kP3YR * kP3Cr / kP3YG;

Color p3YuvToRgb(Color e_gamma) {
  return {{{ clampPixelFloat(e_gamma.y + kP3Cr * e_gamma.v),
             clampPixelFloat(e_gamma.y - kP3GCb * e_gamma.u - kP3GCr * e_gamma.v),
             clampPixelFloat(e_gamma.y + kP3Cb * e_gamma.u) }}};
}


////////////////////////////////////////////////////////////////////////////////
// BT.2100 transformations - according to ITU-R BT.2100-2
@@ -197,6 +227,8 @@ float bt2100Luminance(Color e) {
}

// See ITU-R BT.2100-2, Table 6, Derivation of colour difference signals.
// BT.2100 uses the same coefficients for calculating luma signal and luminance,
// so we reuse the luminance function here.
static const float kBt2100Cb = 1.8814f, kBt2100Cr = 1.4746f;

Color bt2100RgbToYuv(Color e_gamma) {
@@ -206,6 +238,10 @@ Color bt2100RgbToYuv(Color e_gamma) {
             (e_gamma.r - y_gamma) / kBt2100Cr }}};
}

// See ITU-R BT.2100-2, Table 6, Derivation of colour difference signals.
//
// Similar to bt2100RgbToYuv above, we can reuse the luminance coefficients.
//
// Derived by inversing bt2100RgbToYuv. The derivation for R and B are  pretty
// straight forward; we just invert the formulas for U and V above. But deriving
// the formula for G is a bit more complicated:
@@ -440,6 +476,85 @@ ColorTransformFn getHdrConversionFn(ultrahdr_color_gamut sdr_gamut,
  }
}

// All of these conversions are derived from the respective input YUV->RGB conversion followed by
// the RGB->YUV for the receiving encoding. They are consistent with the RGB<->YUV functions in this
// file, given that we uses BT.709 encoding for sRGB and BT.601 encoding for Display-P3, to match
// DataSpace.

Color yuv709To601(Color e_gamma) {
  return {{{ 1.0f * e_gamma.y +  0.101579f * e_gamma.u +  0.196076f * e_gamma.v,
             0.0f * e_gamma.y +  0.989854f * e_gamma.u + -0.110653f * e_gamma.v,
             0.0f * e_gamma.y + -0.072453f * e_gamma.u +  0.983398f * e_gamma.v }}};
}

Color yuv709To2100(Color e_gamma) {
  return {{{ 1.0f * e_gamma.y + -0.016969f * e_gamma.u +  0.096312f * e_gamma.v,
             0.0f * e_gamma.y +  0.995306f * e_gamma.u + -0.051192f * e_gamma.v,
             0.0f * e_gamma.y +  0.011507f * e_gamma.u +  1.002637f * e_gamma.v }}};
}

Color yuv601To709(Color e_gamma) {
  return {{{ 1.0f * e_gamma.y + -0.118188f * e_gamma.u + -0.212685f * e_gamma.v,
             0.0f * e_gamma.y +  1.018640f * e_gamma.u +  0.114618f * e_gamma.v,
             0.0f * e_gamma.y +  0.075049f * e_gamma.u +  1.025327f * e_gamma.v }}};
}

Color yuv601To2100(Color e_gamma) {
  return {{{ 1.0f * e_gamma.y + -0.128245f * e_gamma.u + -0.115879f * e_gamma.v,
             0.0f * e_gamma.y +  1.010016f * e_gamma.u +  0.061592f * e_gamma.v,
             0.0f * e_gamma.y +  0.086969f * e_gamma.u +  1.029350f * e_gamma.v }}};
}

Color yuv2100To709(Color e_gamma) {
  return {{{ 1.0f * e_gamma.y +  0.018149f * e_gamma.u + -0.095132f * e_gamma.v,
             0.0f * e_gamma.y +  1.004123f * e_gamma.u +  0.051267f * e_gamma.v,
             0.0f * e_gamma.y + -0.011524f * e_gamma.u +  0.996782f * e_gamma.v }}};
}

Color yuv2100To601(Color e_gamma) {
  return {{{ 1.0f * e_gamma.y +  0.117887f * e_gamma.u +  0.105521f * e_gamma.v,
             0.0f * e_gamma.y +  0.995211f * e_gamma.u + -0.059549f * e_gamma.v,
             0.0f * e_gamma.y + -0.084085f * e_gamma.u +  0.976518f * e_gamma.v }}};
}

void transformYuv420(jr_uncompressed_ptr image, size_t x_chroma, size_t y_chroma,
                     ColorTransformFn fn) {
  Color yuv1 = getYuv420Pixel(image, x_chroma * 2,     y_chroma * 2    );
  Color yuv2 = getYuv420Pixel(image, x_chroma * 2 + 1, y_chroma * 2    );
  Color yuv3 = getYuv420Pixel(image, x_chroma * 2,     y_chroma * 2 + 1);
  Color yuv4 = getYuv420Pixel(image, x_chroma * 2 + 1, y_chroma * 2 + 1);

  yuv1 = fn(yuv1);
  yuv2 = fn(yuv2);
  yuv3 = fn(yuv3);
  yuv4 = fn(yuv4);

  Color new_uv = (yuv1 + yuv2 + yuv3 + yuv4) / 4.0f;

  size_t pixel_y1_idx =  x_chroma * 2      +  y_chroma * 2      * image->width;
  size_t pixel_y2_idx = (x_chroma * 2 + 1) +  y_chroma * 2      * image->width;
  size_t pixel_y3_idx =  x_chroma * 2      + (y_chroma * 2 + 1) * image->width;
  size_t pixel_y4_idx = (x_chroma * 2 + 1) + (y_chroma * 2 + 1) * image->width;

  uint8_t& y1_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_y1_idx];
  uint8_t& y2_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_y2_idx];
  uint8_t& y3_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_y3_idx];
  uint8_t& y4_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_y4_idx];

  size_t pixel_count = image->width * image->height;
  size_t pixel_uv_idx = x_chroma + y_chroma * (image->width / 2);

  uint8_t& u_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_count + pixel_uv_idx];
  uint8_t& v_uint = reinterpret_cast<uint8_t*>(image->data)[pixel_count * 5 / 4 + pixel_uv_idx];

  y1_uint = static_cast<uint8_t>(floor(yuv1.y * 255.0f + 0.5f));
  y2_uint = static_cast<uint8_t>(floor(yuv2.y * 255.0f + 0.5f));
  y3_uint = static_cast<uint8_t>(floor(yuv3.y * 255.0f + 0.5f));
  y4_uint = static_cast<uint8_t>(floor(yuv4.y * 255.0f + 0.5f));

  u_uint = static_cast<uint8_t>(floor(new_uv.u * 255.0f + 128.0f + 0.5f));
  v_uint = static_cast<uint8_t>(floor(new_uv.v * 255.0f + 128.0f + 0.5f));
}

////////////////////////////////////////////////////////////////////////////////
// Gain map calculations
+94 −2
Original line number Diff line number Diff line
@@ -14,6 +14,10 @@
 * limitations under the License.
 */

#ifndef USE_BIG_ENDIAN
#define USE_BIG_ENDIAN true
#endif

#include <ultrahdr/icc.h>
#include <ultrahdr/gainmapmath.h>
#include <vector>
@@ -540,13 +544,21 @@ sp<DataStruct> IccHelper::writeIccProfile(ultrahdr_transfer_function tf,
    size_t tag_table_size = kICCTagTableEntrySize * tags.size();
    size_t profile_size = kICCHeaderSize + tag_table_size + tag_data_size;

    sp<DataStruct> dataStruct = sp<DataStruct>::make(profile_size + kICCIdentifierSize);

    // Write identifier, chunk count, and chunk ID
    if (!dataStruct->write(kICCIdentifier, sizeof(kICCIdentifier)) ||
        !dataStruct->write8(1) || !dataStruct->write8(1)) {
        ALOGE("writeIccProfile(): error in identifier");
        return dataStruct;
    }

    // Write the header.
    header.data_color_space = Endian_SwapBE32(Signature_RGB);
    header.pcs = Endian_SwapBE32(tf == ULTRAHDR_TF_PQ ? Signature_Lab : Signature_XYZ);
    header.size = Endian_SwapBE32(profile_size);
    header.tag_count = Endian_SwapBE32(tags.size());

    sp<DataStruct> dataStruct = sp<DataStruct>::make(profile_size);
    if (!dataStruct->write(&header, sizeof(header))) {
        ALOGE("writeIccProfile(): error in header");
        return dataStruct;
@@ -582,4 +594,84 @@ sp<DataStruct> IccHelper::writeIccProfile(ultrahdr_transfer_function tf,
    return dataStruct;
}

bool IccHelper::tagsEqualToMatrix(const Matrix3x3& matrix,
                                  const uint8_t* red_tag,
                                  const uint8_t* green_tag,
                                  const uint8_t* blue_tag) {
    sp<DataStruct> red_tag_test = write_xyz_tag(matrix.vals[0][0], matrix.vals[1][0],
                                                matrix.vals[2][0]);
    sp<DataStruct> green_tag_test = write_xyz_tag(matrix.vals[0][1], matrix.vals[1][1],
                                                  matrix.vals[2][1]);
    sp<DataStruct> blue_tag_test = write_xyz_tag(matrix.vals[0][2], matrix.vals[1][2],
                                                 matrix.vals[2][2]);
    return memcmp(red_tag, red_tag_test->getData(), kColorantTagSize) == 0 &&
           memcmp(green_tag, green_tag_test->getData(), kColorantTagSize) == 0 &&
           memcmp(blue_tag, blue_tag_test->getData(), kColorantTagSize) == 0;
}

ultrahdr_color_gamut IccHelper::readIccColorGamut(void* icc_data, size_t icc_size) {
    // Each tag table entry consists of 3 fields of 4 bytes each.
    static const size_t kTagTableEntrySize = 12;

    if (icc_data == nullptr || icc_size < sizeof(ICCHeader) + kICCIdentifierSize) {
        return ULTRAHDR_COLORGAMUT_UNSPECIFIED;
    }

    if (memcmp(icc_data, kICCIdentifier, sizeof(kICCIdentifier)) != 0) {
        return ULTRAHDR_COLORGAMUT_UNSPECIFIED;
    }

    uint8_t* icc_bytes = reinterpret_cast<uint8_t*>(icc_data) + kICCIdentifierSize;

    ICCHeader* header = reinterpret_cast<ICCHeader*>(icc_bytes);

    // Use 0 to indicate not found, since offsets are always relative to start
    // of ICC data and therefore a tag offset of zero would never be valid.
    size_t red_primary_offset = 0, green_primary_offset = 0, blue_primary_offset = 0;
    size_t red_primary_size = 0, green_primary_size = 0, blue_primary_size = 0;
    for (size_t tag_idx = 0; tag_idx < Endian_SwapBE32(header->tag_count); ++tag_idx) {
        uint32_t* tag_entry_start = reinterpret_cast<uint32_t*>(
            icc_bytes + sizeof(ICCHeader) + tag_idx * kTagTableEntrySize);
        // first 4 bytes are the tag signature, next 4 bytes are the tag offset,
        // last 4 bytes are the tag length in bytes.
        if (red_primary_offset == 0 && *tag_entry_start == Endian_SwapBE32(kTAG_rXYZ)) {
            red_primary_offset = Endian_SwapBE32(*(tag_entry_start+1));
            red_primary_size = Endian_SwapBE32(*(tag_entry_start+2));
        } else if (green_primary_offset == 0 && *tag_entry_start == Endian_SwapBE32(kTAG_gXYZ)) {
            green_primary_offset = Endian_SwapBE32(*(tag_entry_start+1));
            green_primary_size = Endian_SwapBE32(*(tag_entry_start+2));
        } else if (blue_primary_offset == 0 && *tag_entry_start == Endian_SwapBE32(kTAG_bXYZ)) {
            blue_primary_offset = Endian_SwapBE32(*(tag_entry_start+1));
            blue_primary_size = Endian_SwapBE32(*(tag_entry_start+2));
        }
    }

    if (red_primary_offset == 0 || red_primary_size != kColorantTagSize ||
        kICCIdentifierSize + red_primary_offset + red_primary_size > icc_size ||
        green_primary_offset == 0 || green_primary_size != kColorantTagSize ||
        kICCIdentifierSize + green_primary_offset + green_primary_size > icc_size ||
        blue_primary_offset == 0 || blue_primary_size != kColorantTagSize ||
        kICCIdentifierSize + blue_primary_offset + blue_primary_size > icc_size) {
        return ULTRAHDR_COLORGAMUT_UNSPECIFIED;
    }

    uint8_t* red_tag = icc_bytes + red_primary_offset;
    uint8_t* green_tag = icc_bytes + green_primary_offset;
    uint8_t* blue_tag = icc_bytes + blue_primary_offset;

    // Serialize tags as we do on encode and compare what we find to that to
    // determine the gamut (since we don't have a need yet for full deserialize).
    if (tagsEqualToMatrix(kSRGB, red_tag, green_tag, blue_tag)) {
        return ULTRAHDR_COLORGAMUT_BT709;
    } else if (tagsEqualToMatrix(kDisplayP3, red_tag, green_tag, blue_tag)) {
        return ULTRAHDR_COLORGAMUT_P3;
    } else if (tagsEqualToMatrix(kRec2020, red_tag, green_tag, blue_tag)) {
        return ULTRAHDR_COLORGAMUT_BT2100;
    }

    // Didn't find a match to one of the profiles we write; indicate the gamut
    // is unspecified since we don't understand it.
    return ULTRAHDR_COLORGAMUT_UNSPECIFIED;
}

} // namespace android::ultrahdr
+57 −8
Original line number Diff line number Diff line
@@ -218,24 +218,30 @@ struct ShepardsIDW {
// except for those concerning transfer functions.

/*
 * Calculate the luminance of a linear RGB sRGB pixel, according to IEC 61966-2-1.
 * Calculate the luminance of a linear RGB sRGB pixel, according to
 * IEC 61966-2-1/Amd 1:2003.
 *
 * [0.0, 1.0] range in and out.
 */
float srgbLuminance(Color e);

/*
 * Convert from OETF'd srgb YUV to RGB, according to ECMA TR/98.
 * Convert from OETF'd srgb RGB to YUV, according to ITU-R BT.709-6.
 *
 * BT.709 YUV<->RGB matrix is used to match expectations for DataSpace.
 */
Color srgbYuvToRgb(Color e_gamma);
Color srgbRgbToYuv(Color e_gamma);


/*
 * Convert from OETF'd srgb RGB to YUV, according to ECMA TR/98.
 * Convert from OETF'd srgb YUV to RGB, according to ITU-R BT.709-6.
 *
 * BT.709 YUV<->RGB matrix is used to match expectations for DataSpace.
 */
Color srgbRgbToYuv(Color e_gamma);
Color srgbYuvToRgb(Color e_gamma);

/*
 * Convert from srgb to linear, according to IEC 61966-2-1.
 * Convert from srgb to linear, according to IEC 61966-2-1/Amd 1:2003.
 *
 * [0.0, 1.0] range in and out.
 */
@@ -257,6 +263,20 @@ constexpr size_t kSrgbInvOETFNumEntries = 1 << kSrgbInvOETFPrecision;
 */
float p3Luminance(Color e);

/*
 * Convert from OETF'd P3 RGB to YUV, according to ITU-R BT.601-7.
 *
 * BT.601 YUV<->RGB matrix is used to match expectations for DataSpace.
 */
Color p3RgbToYuv(Color e_gamma);

/*
 * Convert from OETF'd P3 YUV to RGB, according to ITU-R BT.601-7.
 *
 * BT.601 YUV<->RGB matrix is used to match expectations for DataSpace.
 */
Color p3YuvToRgb(Color e_gamma);


////////////////////////////////////////////////////////////////////////////////
// BT.2100 transformations - according to ITU-R BT.2100-2
@@ -269,12 +289,16 @@ float p3Luminance(Color e);
float bt2100Luminance(Color e);

/*
 * Convert from OETF'd BT.2100 RGB to YUV.
 * Convert from OETF'd BT.2100 RGB to YUV, according to ITU-R BT.2100-2.
 *
 * BT.2100 YUV<->RGB matrix is used to match expectations for DataSpace.
 */
Color bt2100RgbToYuv(Color e_gamma);

/*
 * Convert from OETF'd BT.2100 YUV to RGB.
 * Convert from OETF'd BT.2100 YUV to RGB, according to ITU-R BT.2100-2.
 *
 * BT.2100 YUV<->RGB matrix is used to match expectations for DataSpace.
 */
Color bt2100YuvToRgb(Color e_gamma);

@@ -358,6 +382,31 @@ inline Color identityConversion(Color e) { return e; }
 */
ColorTransformFn getHdrConversionFn(ultrahdr_color_gamut sdr_gamut, ultrahdr_color_gamut hdr_gamut);

/*
 * Convert between YUV encodings, according to ITU-R BT.709-6, ITU-R BT.601-7, and ITU-R BT.2100-2.
 *
 * Bt.709 and Bt.2100 have well-defined YUV encodings; Display-P3's is less well defined, but is
 * treated as Bt.601 by DataSpace, hence we do the same.
 */
Color yuv709To601(Color e_gamma);
Color yuv709To2100(Color e_gamma);
Color yuv601To709(Color e_gamma);
Color yuv601To2100(Color e_gamma);
Color yuv2100To709(Color e_gamma);
Color yuv2100To601(Color e_gamma);

/*
 * Performs a transformation at the chroma x and y coordinates provided on a YUV420 image.
 *
 * Apply the transformation by determining transformed YUV for each of the 4 Y + 1 UV; each Y gets
 * this result, and UV gets the averaged result.
 *
 * x_chroma and y_chroma should be less than or equal to half the image's width and height
 * respecitively, since input is 4:2:0 subsampled.
 */
void transformYuv420(jr_uncompressed_ptr image, size_t x_chroma, size_t y_chroma,
                     ColorTransformFn fn);


////////////////////////////////////////////////////////////////////////////////
// Gain map calculations
+23 −2
Original line number Diff line number Diff line
@@ -56,12 +56,16 @@ enum {
    Signature_XYZ  = 0x58595A20,
};


typedef uint32_t FourByteTag;
static inline constexpr FourByteTag SetFourByteTag(char a, char b, char c, char d) {
    return (((uint32_t)a << 24) | ((uint32_t)b << 16) | ((uint32_t)c << 8) | (uint32_t)d);
}

static constexpr char kICCIdentifier[] = "ICC_PROFILE";
// 12 for the actual identifier, +2 for the chunk count and chunk index which
// will always follow.
static constexpr size_t kICCIdentifierSize = 14;

// This is equal to the header size according to the ICC specification (128)
// plus the size of the tag count (4).  We include the tag count since we
// always require it to be present anyway.
@@ -70,6 +74,10 @@ static constexpr size_t kICCHeaderSize = 132;
// Contains a signature (4), offset (4), and size (4).
static constexpr size_t kICCTagTableEntrySize = 12;

// size should be 20; 4 bytes for type descriptor, 4 bytes reserved, 12
// bytes for a single XYZ number type (4 bytes per coordinate).
static constexpr size_t kColorantTagSize = 20;

static constexpr uint32_t kDisplay_Profile    = SetFourByteTag('m', 'n', 't', 'r');
static constexpr uint32_t kRGB_ColorSpace     = SetFourByteTag('R', 'G', 'B', ' ');
static constexpr uint32_t kXYZ_PCSSpace       = SetFourByteTag('X', 'Y', 'Z', ' ');
@@ -225,9 +233,22 @@ private:
    static void compute_lut_entry(const Matrix3x3& src_to_XYZD50, float rgb[3]);
    static sp<DataStruct> write_clut(const uint8_t* grid_points, const uint8_t* grid_16);

    // Checks if a set of xyz tags is equivalent to a 3x3 Matrix. Each input
    // tag buffer assumed to be at least kColorantTagSize in size.
    static bool tagsEqualToMatrix(const Matrix3x3& matrix,
                                  const uint8_t* red_tag,
                                  const uint8_t* green_tag,
                                  const uint8_t* blue_tag);

public:
    // Output includes JPEG embedding identifier and chunk information, but not
    // APPx information.
    static sp<DataStruct> writeIccProfile(const ultrahdr_transfer_function tf,
                                          const ultrahdr_color_gamut gamut);
    // NOTE: this function is not robust; it can infer gamuts that IccHelper
    // writes out but should not be considered a reference implementation for
    // robust parsing of ICC profiles or their gamuts.
    static ultrahdr_color_gamut readIccColorGamut(void* icc_data, size_t icc_size);
};
}  // namespace android::ultrahdr

+9 −6
Original line number Diff line number Diff line
@@ -83,11 +83,14 @@ public:
     */
    size_t getEXIFSize();
    /*
     * Returns the position offset of EXIF package
     * (4 bypes offset to FF sign, the byte after FF E1 XX XX <this byte>),
     * or -1  if no EXIF exists.
     * Returns the ICC data from the image.
     */
    int getEXIFPos() { return mExifPos; }
    void* getICCPtr();
    /*
     * Returns the decompressed ICC buffer size. This method must be called only after
     * calling decompressImage() or getCompressedImageParameters().
     */
    size_t getICCSize();
    /*
     * Decompresses metadata of the image. All vectors are owned by the caller.
     */
@@ -112,12 +115,12 @@ private:
    std::vector<JOCTET> mXMPBuffer;
    // The buffer that holds EXIF Data.
    std::vector<JOCTET> mEXIFBuffer;
    // The buffer that holds ICC Data.
    std::vector<JOCTET> mICCBuffer;

    // Resolution of the decompressed image.
    size_t mWidth;
    size_t mHeight;
    // Position of EXIF package, default value is -1 which means no EXIF package appears.
    size_t mExifPos;
};
} /* namespace android::ultrahdr  */

Loading