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 void check_fill(skiatest::Reporter* r, const SkImageInfo& imageInfo, uint32_t startRow, uint32_t endRow, size_t rowBytes, uint32_t offset, uint32_t colorOrIndex) { // Calculate the total size of the image in bytes. Use the smallest possible size. // The offset value tells us to adjust the pointer from the memory we allocate in order // to test on different memory alignments. If offset is nonzero, we need to increase the // size of the memory we allocate in order to make sure that we have enough. We are // still allocating the smallest possible size. const size_t totalBytes = imageInfo.computeByteSize(rowBytes) + offset; // Create fake image data where every byte has a value of 0 std::unique_ptr<uint8_t[]> storage(new uint8_t[totalBytes]); memset(storage.get(), 0, totalBytes); // Adjust the pointer in order to test on different memory alignments uint8_t* imageData = storage.get() + offset; uint8_t* imageStart = imageData + rowBytes * startRow; const SkImageInfo fillInfo = imageInfo.makeWH(imageInfo.width(), endRow - startRow + 1); SkSampler::Fill(fillInfo, imageStart, rowBytes, colorOrIndex, SkCodec::kNo_ZeroInitialized); // Ensure that the pixels are filled properly // The bots should catch any memory corruption uint8_t* indexPtr = imageData + startRow * rowBytes; uint8_t* grayPtr = indexPtr; uint32_t* colorPtr = (uint32_t*) indexPtr; uint16_t* color565Ptr = (uint16_t*) indexPtr; for (uint32_t y = startRow; y <= endRow; y++) { for (int32_t x = 0; x < imageInfo.width(); x++) { switch (imageInfo.colorType()) { case kN32_SkColorType: REPORTER_ASSERT(r, kFillColor == colorPtr[x]); break; case kGray_8_SkColorType: REPORTER_ASSERT(r, kFillGray == grayPtr[x]); break; case kRGB_565_SkColorType: REPORTER_ASSERT(r, kFill565 == color565Ptr[x]); break; default: REPORTER_ASSERT(r, false); break; } } indexPtr += rowBytes; colorPtr = (uint32_t*) indexPtr; } }
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); }
static void test_newraster(skiatest::Reporter* reporter) { SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); const size_t minRowBytes = info.minRowBytes(); const size_t size = info.computeByteSize(minRowBytes); SkAutoTMalloc<SkPMColor> storage(size); SkPMColor* baseAddr = storage.get(); sk_bzero(baseAddr, size); std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes); REPORTER_ASSERT(reporter, canvas); SkPixmap pmap; const SkPMColor* addr = canvas->peekPixels(&pmap) ? pmap.addr32() : nullptr; REPORTER_ASSERT(reporter, addr); REPORTER_ASSERT(reporter, info == pmap.info()); REPORTER_ASSERT(reporter, minRowBytes == pmap.rowBytes()); for (int y = 0; y < info.height(); ++y) { for (int x = 0; x < info.width(); ++x) { REPORTER_ASSERT(reporter, 0 == addr[x]); } addr = (const SkPMColor*)((const char*)addr + pmap.rowBytes()); } // now try a deliberately bad info info = info.makeWH(-1, info.height()); REPORTER_ASSERT(reporter, nullptr == SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes)); // too big info = info.makeWH(1 << 30, 1 << 30); REPORTER_ASSERT(reporter, nullptr == SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes)); // not a valid pixel type info = SkImageInfo::Make(10, 10, kUnknown_SkColorType, info.alphaType()); REPORTER_ASSERT(reporter, nullptr == SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes)); // We should succeed with a zero-sized valid info info = SkImageInfo::MakeN32Premul(0, 0); canvas = SkCanvas::MakeRasterDirect(info, baseAddr, minRowBytes); REPORTER_ASSERT(reporter, canvas); }
void SkSampler::Fill(const SkImageInfo& info, void* dst, size_t rowBytes, uint64_t colorOrIndex, SkCodec::ZeroInitialized zeroInit) { SkASSERT(dst != nullptr); // Calculate bytes to fill. const size_t bytesToFill = info.computeByteSize(rowBytes); const int width = info.width(); const int numRows = info.height(); // Use the proper memset routine to fill the remaining bytes switch (info.colorType()) { case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: { // If memory is zero initialized, we may not need to fill uint32_t color = (uint32_t) colorOrIndex; if (SkCodec::kYes_ZeroInitialized == zeroInit && 0 == color) { return; } uint32_t* dstRow = (uint32_t*) dst; for (int row = 0; row < numRows; row++) { sk_memset32((uint32_t*) dstRow, color, width); dstRow = SkTAddOffset<uint32_t>(dstRow, rowBytes); } break; } case kRGB_565_SkColorType: { // If the destination is k565, the caller passes in a 16-bit color. // We will not assert that the high bits of colorOrIndex must be zeroed. // This allows us to take advantage of the fact that the low 16 bits of an // SKPMColor may be a valid a 565 color. For example, the low 16 // bits of SK_ColorBLACK are identical to the 565 representation // for black. // If memory is zero initialized, we may not need to fill uint16_t color = (uint16_t) colorOrIndex; if (SkCodec::kYes_ZeroInitialized == zeroInit && 0 == color) { return; } uint16_t* dstRow = (uint16_t*) dst; for (int row = 0; row < numRows; row++) { sk_memset16((uint16_t*) dstRow, color, width); dstRow = SkTAddOffset<uint16_t>(dstRow, rowBytes); } break; } case kGray_8_SkColorType: // If the destination is kGray, the caller passes in an 8-bit color. // We will not assert that the high bits of colorOrIndex must be zeroed. // This allows us to take advantage of the fact that the low 8 bits of an // SKPMColor may be a valid a grayscale color. For example, the low 8 // bits of SK_ColorBLACK are identical to the grayscale representation // for black. // If memory is zero initialized, we may not need to fill if (SkCodec::kYes_ZeroInitialized == zeroInit && 0 == (uint8_t) colorOrIndex) { return; } memset(dst, (uint8_t) colorOrIndex, bytesToFill); break; case kRGBA_F16_SkColorType: { uint64_t color = colorOrIndex; if (SkCodec::kYes_ZeroInitialized == zeroInit && 0 == color) { return; } uint64_t* dstRow = (uint64_t*) dst; for (int row = 0; row < numRows; row++) { sk_memset64((uint64_t*) dstRow, color, width); dstRow = SkTAddOffset<uint64_t>(dstRow, rowBytes); } break; } default: SkCodecPrintf("Error: Unsupported dst color type for fill(). Doing nothing.\n"); SkASSERT(false); break; } }