// Test Fill() with different combinations of dimensions, alignment, and padding DEF_TEST(SwizzlerFill, r) { // Test on an invalid width and representative widths const uint32_t widths[] = { 0, 10, 50 }; // In order to call Fill(), there must be at least one row to fill // Test on the smallest possible height and representative heights const uint32_t heights[] = { 1, 5, 10 }; // Test on interesting possibilities for row padding const uint32_t paddings[] = { 0, 4 }; // Iterate over test dimensions for (uint32_t width : widths) { for (uint32_t height : heights) { // Create image info objects const SkImageInfo colorInfo = SkImageInfo::MakeN32(width, height, kUnknown_SkAlphaType); const SkImageInfo grayInfo = colorInfo.makeColorType(kGray_8_SkColorType); const SkImageInfo indexInfo = colorInfo.makeColorType(kIndex_8_SkColorType); const SkImageInfo color565Info = colorInfo.makeColorType(kRGB_565_SkColorType); for (uint32_t padding : paddings) { // Calculate row bytes const size_t colorRowBytes = SkColorTypeBytesPerPixel(kN32_SkColorType) * width + padding; const size_t indexRowBytes = width + padding; const size_t grayRowBytes = indexRowBytes; const size_t color565RowBytes = SkColorTypeBytesPerPixel(kRGB_565_SkColorType) * width + padding; // If there is padding, we can invent an offset to change the memory alignment for (uint32_t offset = 0; offset <= padding; offset += 4) { // Test all possible start rows with all possible end rows for (uint32_t startRow = 0; startRow < height; startRow++) { for (uint32_t endRow = startRow; endRow < height; endRow++) { // Test fill with each color type check_fill(r, colorInfo, startRow, endRow, colorRowBytes, offset, kFillColor); check_fill(r, indexInfo, startRow, endRow, indexRowBytes, offset, kFillIndex); check_fill(r, grayInfo, startRow, endRow, grayRowBytes, offset, kFillGray); check_fill(r, color565Info, startRow, endRow, color565RowBytes, offset, kFill565); } } } } } } }
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); }
// Test Fill() with different combinations of dimensions, alignment, and padding DEF_TEST(SwizzlerFill, r) { // Set up a color table SkPMColor colorTable[kFillIndex + 1]; colorTable[kFillIndex] = kFillColor; // Apart from the fill index, we will leave the other colors in the color table uninitialized. // If we incorrectly try to fill with this uninitialized memory, the bots will catch it. // Test on an invalid width and representative widths const uint32_t widths[] = { 0, 10, 50 }; // In order to call Fill(), there must be at least one row to fill // Test on the smallest possible height and representative heights const uint32_t heights[] = { 1, 5, 10 }; // Test on interesting possibilities for row padding const uint32_t paddings[] = { 0, 1, 2, 3, 4 }; // Iterate over test dimensions for (uint32_t width : widths) { for (uint32_t height : heights) { // Create image info objects const SkImageInfo colorInfo = SkImageInfo::MakeN32(width, height, kUnknown_SkAlphaType); const SkImageInfo indexInfo = colorInfo.makeColorType(kIndex_8_SkColorType); for (uint32_t padding : paddings) { // Calculate row bytes size_t colorRowBytes = SkColorTypeBytesPerPixel(kN32_SkColorType) * width + padding; size_t indexRowBytes = width + padding; // If there is padding, we can invent an offset to change the memory alignment for (uint32_t offset = 0; offset <= padding; offset++) { // Test all possible start rows with all possible end rows for (uint32_t startRow = 0; startRow < height; startRow++) { for (uint32_t endRow = startRow; endRow < height; endRow++) { // Fill with an index that we use to look up a color check_fill(r, colorInfo, startRow, endRow, colorRowBytes, offset, kFillIndex, colorTable); // Fill with a color check_fill(r, colorInfo, startRow, endRow, colorRowBytes, offset, kFillColor, NULL); // Fill with an index check_fill(r, indexInfo, startRow, endRow, indexRowBytes, offset, kFillIndex, NULL); } } } } } } }
/* * Initiates the gif decode */ SkCodec::Result SkGifCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts, SkPMColor* inputColorPtr, int* inputColorCount, int* rowsDecoded) { Result result = this->prepareToDecode(dstInfo, inputColorPtr, inputColorCount, opts); if (kSuccess != result) { return result; } if (dstInfo.dimensions() != this->getInfo().dimensions()) { return gif_error("Scaling not supported.\n", kInvalidScale); } // Initialize the swizzler if (fFrameIsSubset) { const SkImageInfo subsetDstInfo = dstInfo.makeWH(fFrameRect.width(), fFrameRect.height()); if (kSuccess != this->initializeSwizzler(subsetDstInfo, opts)) { return gif_error("Could not initialize swizzler.\n", kUnimplemented); } // Fill the background SkSampler::Fill(dstInfo, dst, dstRowBytes, this->getFillValue(dstInfo.colorType(), dstInfo.alphaType()), opts.fZeroInitialized); // Modify the dst pointer const int32_t dstBytesPerPixel = SkColorTypeBytesPerPixel(dstInfo.colorType()); dst = SkTAddOffset<void*>(dst, dstRowBytes * fFrameRect.top() + dstBytesPerPixel * fFrameRect.left()); } else { if (kSuccess != this->initializeSwizzler(dstInfo, opts)) { return gif_error("Could not initialize swizzler.\n", kUnimplemented); } } // Iterate over rows of the input uint32_t height = fFrameRect.height(); for (uint32_t y = 0; y < height; y++) { if (!this->readRow()) { *rowsDecoded = y; return gif_error("Could not decode line.\n", kIncompleteInput); } void* dstRow = SkTAddOffset<void>(dst, dstRowBytes * this->outputScanline(y)); fSwizzler->swizzle(dstRow, fSrcBuffer.get()); } return kSuccess; }
static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle, jint width, jint height, jint configHandle, jint allocSize, jboolean requestPremul) { SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapHandle); SkColorType colorType = GraphicsJNI::legacyBitmapConfigToColorType(configHandle); // ARGB_4444 is a deprecated format, convert automatically to 8888 if (colorType == kARGB_4444_SkColorType) { colorType = kN32_SkColorType; } if (width * height * SkColorTypeBytesPerPixel(colorType) > allocSize) { // done in native as there's no way to get BytesPerPixel in Java doThrowIAE(env, "Bitmap not large enough to support new configuration"); return; } SkPixelRef* ref = bitmap->pixelRef(); ref->ref(); SkAlphaType alphaType; if (bitmap->colorType() != kRGB_565_SkColorType && bitmap->alphaType() == kOpaque_SkAlphaType) { // If the original bitmap was set to opaque, keep that setting, unless it // was 565, which is required to be opaque. alphaType = kOpaque_SkAlphaType; } else { // Otherwise respect the premultiplied request. alphaType = requestPremul ? kPremul_SkAlphaType : kUnpremul_SkAlphaType; } bitmap->setInfo(SkImageInfo::Make(width, height, colorType, alphaType)); // FIXME: Skia thinks of an SkPixelRef as having a constant SkImageInfo (except for // its alphatype), so it would make more sense from Skia's perspective to create a // new SkPixelRef. That said, libhwui uses the pointer to the SkPixelRef as a key // for its cache, so it won't realize this is the same Java Bitmap. SkImageInfo& info = const_cast<SkImageInfo&>(ref->info()); // Use the updated from the SkBitmap, which may have corrected an invalid alphatype. // (e.g. 565 non-opaque) info = bitmap->info(); bitmap->setPixelRef(ref); // notifyPixelsChanged will increment the generation ID even though the actual pixel data // hasn't been touched. This signals the renderer that the bitmap (including width, height, // colortype and alphatype) has changed. ref->notifyPixelsChanged(); ref->unref(); }
void draw(SkCanvas* canvas) { const char* colors[] = { "Unknown", "Alpha_8", "RGB_565", "ARGB_4444", "RGBA_8888", "RGB_888x", "BGRA_8888", "RGBA_1010102", "RGB_101010x", "Gray_8", "RGBA_F16Norm", "RGBA_F16" }; SkPaint paint; SkFont font(SkTypeface::MakeFromName("monospace", SkFontStyle()), 10); int y = 15; canvas->drawString(" colorType bytes", 10, y, font, paint); for (SkColorType colorType : { kUnknown_SkColorType, kAlpha_8_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kRGB_888x_SkColorType, kBGRA_8888_SkColorType, kRGBA_1010102_SkColorType, kRGB_101010x_SkColorType, kGray_8_SkColorType, kRGBA_F16_SkColorType } ) { int result = SkColorTypeBytesPerPixel(colorType); SkString string; string.printf("%13s %4d", colors[(int) colorType], result); canvas->drawString(string, 10, y += 14, font, paint); } }
bool SkPngEncoder::onEncodeRows(int numRows) { if (setjmp(png_jmpbuf(fEncoderMgr->pngPtr()))) { return false; } const void* srcRow = fSrc.addr(0, fCurrRow); for (int y = 0; y < numRows; y++) { fEncoderMgr->proc()((char*) fStorage.get(), (const char*) srcRow, fSrc.width(), SkColorTypeBytesPerPixel(fSrc.colorType()), nullptr); png_bytep rowPtr = (png_bytep) fStorage.get(); png_write_rows(fEncoderMgr->pngPtr(), &rowPtr, 1); srcRow = SkTAddOffset<const void>(srcRow, fSrc.rowBytes()); } fCurrRow += numRows; if (fCurrRow == fSrc.height()) { png_write_end(fEncoderMgr->pngPtr(), fEncoderMgr->infoPtr()); } return true; }
int SkGifCodec::onGetScanlines(void* dst, int count, size_t rowBytes) { int rowsBeforeFrame = 0; int rowsAfterFrame = 0; int rowsInFrame = count; if (fFrameIsSubset) { // Fill the requested rows SkImageInfo fillInfo = this->dstInfo().makeWH(this->dstInfo().width(), count); uint32_t fillValue = this->onGetFillValue(this->dstInfo().colorType(), this->dstInfo().alphaType()); SkSampler::Fill(fillInfo, dst, rowBytes, fillValue, this->options().fZeroInitialized); // Do nothing for rows before the image frame rowsBeforeFrame = SkTMax(0, fFrameRect.top() - this->INHERITED::nextScanline()); rowsInFrame = SkTMax(0, rowsInFrame - rowsBeforeFrame); dst = SkTAddOffset<void>(dst, rowBytes * rowsBeforeFrame); // Do nothing for rows after the image frame rowsAfterFrame = SkTMax(0, this->INHERITED::nextScanline() + rowsInFrame - fFrameRect.bottom()); rowsInFrame = SkTMax(0, rowsInFrame - rowsAfterFrame); // Adjust dst pointer for left offset int offset = SkColorTypeBytesPerPixel(this->dstInfo().colorType()) * fFrameRect.left(); dst = SkTAddOffset<void>(dst, offset); } for (int i = 0; i < rowsInFrame; i++) { if (!this->readRow()) { return i + rowsBeforeFrame; } fSwizzler->swizzle(dst, fSrcBuffer.get()); dst = SkTAddOffset<void>(dst, rowBytes); } return count; }
int SkImageInfo::bytesPerPixel() const { return SkColorTypeBytesPerPixel(fColorType); }