static float png_inverted_fixed_point_to_float(png_fixed_point x) { // This is necessary because the gAMA chunk actually stores 1/gamma. return 1.0f / png_fixed_point_to_float(x); }
// Returns a colorSpace object that represents any color space information in // the encoded data. If the encoded data contains no color space, this will // return NULL. sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) { #if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6) // First check for an ICC profile png_bytep profile; png_uint_32 length; // The below variables are unused, however, we need to pass them in anyway or // png_get_iCCP() will return nothing. // Could knowing the |name| of the profile ever be interesting? Maybe for debugging? png_charp name; // The |compression| is uninteresting since: // (1) libpng has already decompressed the profile for us. // (2) "deflate" is the only mode of decompression that libpng supports. int compression; if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile, &length)) { return SkColorSpace::NewICC(profile, length); } // Second, check for sRGB. if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { // sRGB chunks also store a rendering intent: Absolute, Relative, // Perceptual, and Saturation. // FIXME (msarett): Extract this information from the sRGB chunk once // we are able to handle this information in // SkColorSpace. return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); } // Next, check for chromaticities. png_fixed_point XYZ[9]; float toXYZD50[9]; png_fixed_point gamma; float gammas[3]; if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &XYZ[0], &XYZ[1], &XYZ[2], &XYZ[3], &XYZ[4], &XYZ[5], &XYZ[6], &XYZ[7], &XYZ[8])) { // FIXME (msarett): Here we are treating XYZ values as D50 even though the color // temperature is unspecified. I suspect that this assumption // is most often ok, but we could also calculate the color // temperature (D value) and then convert the XYZ to D50. Maybe // we should add a new constructor to SkColorSpace that accepts // XYZ with D-Unkown? for (int i = 0; i < 9; i++) { toXYZD50[i] = png_fixed_point_to_float(XYZ[i]); } if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { float value = png_inverted_fixed_point_to_float(gamma); gammas[0] = value; gammas[1] = value; gammas[2] = value; } else { // Default to sRGB (gamma = 2.2f) if the image has color space information, // but does not specify gamma. gammas[0] = 2.2f; gammas[1] = 2.2f; gammas[2] = 2.2f; } SkMatrix44 mat(SkMatrix44::kUninitialized_Constructor); mat.set3x3ColMajorf(toXYZD50); return SkColorSpace::NewRGB(gammas, mat); } // Last, check for gamma. if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { // Guess a default value for cHRM? Or should we just give up? // Here we use the identity matrix as a default. // Set the gammas. float value = png_inverted_fixed_point_to_float(gamma); gammas[0] = value; gammas[1] = value; gammas[2] = value; return SkColorSpace::NewRGB(gammas, SkMatrix44::I()); } #endif // LIBPNG >= 1.6 // Finally, what should we do if there is no color space information in the PNG? // The specification says that this indicates "gamma is unknown" and that the // "color is device dependent". I'm assuming we can represent this with NULL. // But should we guess sRGB? Most images are sRGB, even if they don't specify. return nullptr; }
// Returns a colorSpace object that represents any color space information in // the encoded data. If the encoded data contains no color space, this will // return NULL. sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) { #if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6) // First check for an ICC profile png_bytep profile; png_uint_32 length; // The below variables are unused, however, we need to pass them in anyway or // png_get_iCCP() will return nothing. // Could knowing the |name| of the profile ever be interesting? Maybe for debugging? png_charp name; // The |compression| is uninteresting since: // (1) libpng has already decompressed the profile for us. // (2) "deflate" is the only mode of decompression that libpng supports. int compression; if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile, &length)) { return SkColorSpace::NewICC(profile, length); } // Second, check for sRGB. if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { // sRGB chunks also store a rendering intent: Absolute, Relative, // Perceptual, and Saturation. // FIXME (msarett): Extract this information from the sRGB chunk once // we are able to handle this information in // SkColorSpace. return SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); } // Next, check for chromaticities. png_fixed_point toXYZFixed[9]; float toXYZ[9]; png_fixed_point whitePointFixed[2]; float whitePoint[2]; png_fixed_point gamma; float gammas[3]; if (png_get_cHRM_XYZ_fixed(png_ptr, info_ptr, &toXYZFixed[0], &toXYZFixed[1], &toXYZFixed[2], &toXYZFixed[3], &toXYZFixed[4], &toXYZFixed[5], &toXYZFixed[6], &toXYZFixed[7], &toXYZFixed[8]) && png_get_cHRM_fixed(png_ptr, info_ptr, &whitePointFixed[0], &whitePointFixed[1], nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)) { for (int i = 0; i < 9; i++) { toXYZ[i] = png_fixed_point_to_float(toXYZFixed[i]); } whitePoint[0] = png_fixed_point_to_float(whitePointFixed[0]); whitePoint[1] = png_fixed_point_to_float(whitePointFixed[1]); SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); if (!convert_to_D50(&toXYZD50, toXYZ, whitePoint)) { toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50); } if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { float value = png_inverted_fixed_point_to_float(gamma); gammas[0] = value; gammas[1] = value; gammas[2] = value; return SkColorSpace_Base::NewRGB(gammas, toXYZD50); } // Default to sRGB gamma if the image has color space information, // but does not specify gamma. return SkColorSpace::NewRGB(SkColorSpace::kSRGB_GammaNamed, toXYZD50); } // Last, check for gamma. if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) { // Set the gammas. float value = png_inverted_fixed_point_to_float(gamma); gammas[0] = value; gammas[1] = value; gammas[2] = value; // Since there is no cHRM, we will guess sRGB gamut. SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor); toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50); return SkColorSpace_Base::NewRGB(gammas, toXYZD50); } #endif // LIBPNG >= 1.6 // Report that there is no color space information in the PNG. SkPngCodec is currently // implemented to guess sRGB in this case. return nullptr; }