SkImageInfo SkImage_Lazy::buildCacheInfo(CachedFormat format) const { switch (format) { case kLegacy_CachedFormat: return fInfo.makeColorSpace(nullptr); case kLinearF16_CachedFormat: return fInfo.makeColorType(kRGBA_F16_SkColorType) .makeColorSpace(fInfo.colorSpace()->makeLinearGamma()); case kSRGB8888_CachedFormat: // If the transfer function is nearly (but not exactly) sRGB, we don't want the codec // to bother trans-coding. It would be slow, and do more harm than good visually, // so we make sure to leave the colorspace as-is. if (fInfo.colorSpace()->gammaCloseToSRGB()) { return fInfo.makeColorType(kRGBA_8888_SkColorType); } else { return fInfo.makeColorType(kRGBA_8888_SkColorType) .makeColorSpace(fInfo.colorSpace()->makeSRGBGamma()); } case kSBGR8888_CachedFormat: // See note above about not-quite-sRGB transfer functions. if (fInfo.colorSpace()->gammaCloseToSRGB()) { return fInfo.makeColorType(kBGRA_8888_SkColorType); } else { return fInfo.makeColorType(kBGRA_8888_SkColorType) .makeColorSpace(fInfo.colorSpace()->makeSRGBGamma()); } default: SkDEBUGFAIL("Invalid cached format"); return fInfo; } }
static void draw_image(SkCanvas* canvas, SkImage* image, SkColorType dstColorType, SkAlphaType dstAlphaType, sk_sp<SkColorSpace> dstColorSpace, SkImage::CachingHint hint) { size_t rowBytes = image->width() * SkColorTypeBytesPerPixel(dstColorType); sk_sp<SkData> data = SkData::MakeUninitialized(rowBytes * image->height()); dstColorSpace = fix_for_colortype(dstColorSpace.get(), dstColorType); SkImageInfo dstInfo = SkImageInfo::Make(image->width(), image->height(), dstColorType, dstAlphaType, dstColorSpace); if (!image->readPixels(dstInfo, data->writable_data(), rowBytes, 0, 0, hint)) { memset(data->writable_data(), 0, rowBytes * image->height()); } // SkImage must be premul, so manually premul the data if we unpremul'd during readPixels if (kUnpremul_SkAlphaType == dstAlphaType) { auto xform = SkColorSpaceXform::New(dstColorSpace.get(), dstColorSpace.get()); if (!xform->apply(select_xform_format(dstColorType), data->writable_data(), select_xform_format(dstColorType), data->data(), image->width() * image->height(), kPremul_SkAlphaType)) { memset(data->writable_data(), 0, rowBytes * image->height()); } dstInfo = dstInfo.makeAlphaType(kPremul_SkAlphaType); } // readPixels() does not always clamp F16. The drawing code expects pixels in the 0-1 range. clamp_if_necessary(dstInfo, data->writable_data()); // Now that we have called readPixels(), dump the raw pixels into an srgb image. sk_sp<SkColorSpace> srgb = fix_for_colortype( SkColorSpace::MakeSRGB().get(), dstColorType); sk_sp<SkImage> raw = SkImage::MakeRasterData(dstInfo.makeColorSpace(srgb), data, rowBytes); canvas->drawImage(raw.get(), 0.0f, 0.0f, nullptr); }
sk_sp<SkImage> SkImageMakeRasterCopyAndAssignColorSpace(const SkImage* src, SkColorSpace* colorSpace) { // Read the pixels out of the source image, with no conversion SkImageInfo info = as_IB(src)->onImageInfo(); if (kUnknown_SkColorType == info.colorType()) { SkDEBUGFAIL("Unexpected color type"); return nullptr; } size_t rowBytes = info.minRowBytes(); size_t size = info.computeByteSize(rowBytes); if (SkImageInfo::ByteSizeOverflowed(size)) { return nullptr; } auto data = SkData::MakeUninitialized(size); if (!data) { return nullptr; } SkPixmap pm(info, data->writable_data(), rowBytes); if (!src->readPixels(pm, 0, 0, SkImage::kDisallow_CachingHint)) { return nullptr; } // Wrap them in a new image with a different color space return SkImage::MakeRasterData(info.makeColorSpace(sk_ref_sp(colorSpace)), data, rowBytes); }
static std::unique_ptr<Dst> Create(Options options) { SkImageInfo info = SkImageInfo::MakeN32Premul(0,0); if (options("ct") == "565") { info = info.makeColorType(kRGB_565_SkColorType); } if (options("ct") == "f16") { info = info.makeColorType(kRGBA_F16_SkColorType); } if (options("cs") == "srgb") { auto cs = info.colorType() == kRGBA_F16_SkColorType ? SkColorSpace::MakeSRGBLinear() : SkColorSpace::MakeSRGB(); info = info.makeColorSpace(std::move(cs)); } SWDst dst; dst.info = info; return move_unique(dst); }
static void test_flatten(skiatest::Reporter* reporter, const SkImageInfo& info) { // just need a safe amount of storage, but ensure that it is 4-byte aligned. int32_t storage[(sizeof(SkImageInfo)*2) / sizeof(int32_t)]; SkBinaryWriteBuffer wb(storage, sizeof(storage)); info.flatten(wb); SkASSERT(wb.bytesWritten() < sizeof(storage)); SkReadBuffer rb(storage, wb.bytesWritten()); // pick a noisy byte pattern, so we ensure that unflatten sets all of our fields SkImageInfo info2 = SkImageInfo::Make(0xB8, 0xB8, (SkColorType) 0xB8, (SkAlphaType) 0xB8, (SkColorProfileType) 0xB8); info2.unflatten(rb); REPORTER_ASSERT(reporter, rb.offset() == wb.bytesWritten()); // FIXME (msarett): // Support flatten/unflatten of SkColorSpace objects. REPORTER_ASSERT(reporter, info.makeColorSpace(nullptr) == info2.makeColorSpace(nullptr)); }
sk_sp<SkImage> SkImage::makeRasterImage() const { SkPixmap pm; if (this->peekPixels(&pm)) { return sk_ref_sp(const_cast<SkImage*>(this)); } const SkImageInfo info = as_IB(this)->onImageInfo(); const size_t rowBytes = info.minRowBytes(); size_t size = info.computeByteSize(rowBytes); if (SkImageInfo::ByteSizeOverflowed(size)) { return nullptr; } sk_sp<SkData> data = SkData::MakeUninitialized(size); pm = { info.makeColorSpace(nullptr), data->writable_data(), info.minRowBytes() }; if (!this->readPixels(pm, 0, 0)) { return nullptr; } return SkImage::MakeRasterData(info, std::move(data), rowBytes); }