/* * Copyright 2010 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkImageInfo.h" #include "SkReadBuffer.h" #include "SkWriteBuffer.h" static bool color_type_supports_sRGB(SkColorType colorType) { switch (colorType) { case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: return true; default: return false; } } static bool color_type_supports_gamma(SkColorType colorType) { switch (colorType) { case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: // case kLuminance ... return true; default: return false; } } static float pin_gamma_to_legal(float gamma) { if (!SkScalarIsFinite(gamma)) { return 1; } // these limits are just made up -- feel free to change them within reason const float min_gamma = 0.01f; const float max_gamma = 4.0; return SkScalarPin(gamma, min_gamma, max_gamma); } SkImageInfo SkImageInfo::MakeSRGB(int width, int height, SkColorType ct, SkAlphaType at) { Profile p = color_type_supports_sRGB(ct) ? kSRGB_Profile : kUnknown_Profile; return SkImageInfo(width, height, ct, at, p, 0); } SkImageInfo SkImageInfo::MakeWithGamma(int width, int height, SkColorType ct, SkAlphaType at, float gamma) { Profile p; if (color_type_supports_gamma(ct)) { gamma = pin_gamma_to_legal(gamma); p = kExponential_Profile; } else { p = kUnknown_Profile; gamma = 0; } return SkImageInfo(width, height, ct, at, p, gamma); } bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType, SkAlphaType* canonical) { switch (colorType) { case kUnknown_SkColorType: alphaType = kIgnore_SkAlphaType; break; case kAlpha_8_SkColorType: if (kUnpremul_SkAlphaType == alphaType) { alphaType = kPremul_SkAlphaType; } // fall-through case kIndex_8_SkColorType: case kARGB_4444_SkColorType: case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: if (kIgnore_SkAlphaType == alphaType) { return false; } break; case kRGB_565_SkColorType: alphaType = kOpaque_SkAlphaType; break; default: return false; } if (canonical) { *canonical = alphaType; } return true; } void SkImageInfo::unflatten(SkReadBuffer& buffer) { *this = Unflatten(buffer); } //////////////////////////////////////////////////////////////////////////////////////////// static bool alpha_type_is_valid(SkAlphaType alphaType) { return (alphaType >= 0) && (alphaType <= kLastEnum_SkAlphaType); } static bool color_type_is_valid(SkColorType colorType) { return (colorType >= 0) && (colorType <= kLastEnum_SkColorType); } static float igamma_to_gamma(int gamma3dot9) { return gamma3dot9 / 512.0f; } static unsigned gamma_to_igamma(float gamma) { SkASSERT(gamma >= 0 && gamma < 8); int igamma = SkScalarRoundToInt(gamma * 512); SkASSERT(igamma >= 0 && igamma <= 0xFFF); return igamma; } SkImageInfo SkImageInfo::Unflatten(SkReadBuffer& buffer) { int width = buffer.read32(); int height = buffer.read32(); uint32_t packed = buffer.read32(); SkColorType ct = (SkColorType)((packed >> 0) & 0xFF); // 8 bits for colortype SkAlphaType at = (SkAlphaType)((packed >> 8) & 0xFF); // 8 bits for alphatype if (!alpha_type_is_valid(at) || !color_type_is_valid(ct)) { return MakeUnknown(); } // Earlier formats always stored 0 in the upper 16 bits. That corresponds to // days before we had gamma/profile. That happens to correspond to kUnknown_Profile, // which means we can just ignore the gamma value anyways. // int iprofile = ((packed >> 16) & 0xF); // 4 bits for profile switch (iprofile) { case kUnknown_Profile: return Make(width, height, ct, at); case kSRGB_Profile: return MakeSRGB(width, height, ct, at); case kExponential_Profile: { int igamma = packed >> 20; // 12 bits for gamma 3.9 float gamma = igamma_to_gamma(igamma); return MakeWithGamma(width, height, ct, at, gamma); } default: (void)buffer.validate(false); return MakeUnknown(); } } void SkImageInfo::flatten(SkWriteBuffer& buffer) const { buffer.write32(fWidth); buffer.write32(fHeight); SkASSERT(0 == (fColorType & ~0xFF)); // 8 bits for colortype SkASSERT(0 == (fAlphaType & ~0xFF)); // 8 bits for alphatype SkASSERT(0 == (fProfile & ~0xF)); // 4 bits for profile int igamma = gamma_to_igamma(fGamma); // 12 bits for gamma (if needed) uint32_t packed = (igamma << 20) | (fProfile << 16) | (fAlphaType << 8) | fColorType; buffer.write32(packed); }