bool SkPixmap::readPixels(const SkImageInfo& requestedDstInfo, void* dstPixels, size_t dstRB, int x, int y) const { if (kUnknown_SkColorType == requestedDstInfo.colorType()) { return false; } if (nullptr == dstPixels || dstRB < requestedDstInfo.minRowBytes()) { return false; } if (0 == requestedDstInfo.width() || 0 == requestedDstInfo.height()) { return false; } SkIRect srcR = SkIRect::MakeXYWH(x, y, requestedDstInfo.width(), requestedDstInfo.height()); if (!srcR.intersect(0, 0, this->width(), this->height())) { return false; } // the intersect may have shrunk info's logical size const SkImageInfo dstInfo = requestedDstInfo.makeWH(srcR.width(), srcR.height()); // if x or y are negative, then we have to adjust pixels if (x > 0) { x = 0; } if (y > 0) { y = 0; } // here x,y are either 0 or negative dstPixels = ((char*)dstPixels - y * dstRB - x * dstInfo.bytesPerPixel()); const SkImageInfo srcInfo = this->info().makeWH(dstInfo.width(), dstInfo.height()); const void* srcPixels = this->addr(srcR.x(), srcR.y()); return SkPixelInfo::CopyPixels(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, this->rowBytes(), this->ctable()); }
bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options& options) override { REPORTER_ASSERT(fReporter, pixels != nullptr); REPORTER_ASSERT(fReporter, rowBytes >= info.minRowBytes()); if (fType != kSucceedGetPixels_TestType) { return false; } if (info.colorType() != kN32_SkColorType && info.colorType() != getInfo().colorType()) { return false; } char* bytePtr = static_cast<char*>(pixels); switch (info.colorType()) { case kN32_SkColorType: for (int y = 0; y < info.height(); ++y) { sk_memset32((uint32_t*)bytePtr, TestImageGenerator::PMColor(), info.width()); bytePtr += rowBytes; } break; case kRGB_565_SkColorType: for (int y = 0; y < info.height(); ++y) { sk_memset16((uint16_t*)bytePtr, SkPixel32ToPixel16(TestImageGenerator::PMColor()), info.width()); bytePtr += rowBytes; } break; default: return false; } return true; }
/* * Performs the heif decode */ SkCodec::Result SkHeifCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& options, int* rowsDecoded) { if (options.fSubset) { // Not supporting subsets on this path for now. // TODO: if the heif has tiles, we can support subset here, but // need to retrieve tile config from metadata retriever first. return kUnimplemented; } if (!fHeifDecoder->decode(&fFrameInfo)) { return kInvalidInput; } fSwizzler.reset(nullptr); this->allocateStorage(dstInfo); int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height(), options); if (rows < dstInfo.height()) { *rowsDecoded = rows; return kIncompleteInput; } return kSuccess; }
/* * Performs the heif decode */ SkCodec::Result SkHeifCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& options, int* rowsDecoded) { if (options.fSubset) { // Not supporting subsets on this path for now. // TODO: if the heif has tiles, we can support subset here, but // need to retrieve tile config from metadata retriever first. return kUnimplemented; } if (!this->initializeColorXform(dstInfo, options.fPremulBehavior)) { return kInvalidConversion; } // Check if we can decode to the requested destination and set the output color space if (!this->setOutputColorFormat(dstInfo)) { return kInvalidConversion; } if (!fHeifDecoder->decode(&fFrameInfo)) { return kInvalidInput; } fSwizzler.reset(nullptr); this->allocateStorage(dstInfo); int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height(), options); if (rows < dstInfo.height()) { *rowsDecoded = rows; return kIncompleteInput; } return kSuccess; }
/* * Performs the decoding */ SkCodec::Result SkBmpMaskCodec::decode(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts) { // Set constant values const int width = dstInfo.width(); const int height = dstInfo.height(); const size_t rowBytes = SkAlign4(compute_row_bytes(width, this->bitsPerPixel())); // Iterate over rows of the image uint8_t* srcRow = fSrcBuffer.get(); for (int y = 0; y < height; y++) { // Read a row of the input if (this->stream()->read(srcRow, rowBytes) != rowBytes) { SkCodecPrintf("Warning: incomplete input stream.\n"); // Fill the destination image on failure SkPMColor fillColor = dstInfo.alphaType() == kOpaque_SkAlphaType ? SK_ColorBLACK : SK_ColorTRANSPARENT; if (kNo_ZeroInitialized == opts.fZeroInitialized || 0 != fillColor) { void* dstStart = this->getDstStartRow(dst, dstRowBytes, y); SkSwizzler::Fill(dstStart, dstInfo, dstRowBytes, dstInfo.height() - y, fillColor, nullptr); } return kIncompleteInput; } // Decode the row in destination format int row = SkBmpCodec::kBottomUp_RowOrder == this->rowOrder() ? height - 1 - y : y; void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); fMaskSwizzler->swizzle(dstRow, srcRow); } // Finished decoding the entire image return kSuccess; }
bool ImageFrameGenerator::decodeAndScale(size_t index, const SkImageInfo& info, void* pixels, size_t rowBytes) { // Prevent concurrent decode or scale operations on the same image data. MutexLocker lock(m_decodeMutex); if (m_decodeFailed) return false; TRACE_EVENT1("blink", "ImageFrameGenerator::decodeAndScale", "frame index", static_cast<int>(index)); m_externalAllocator = adoptPtr(new ExternalMemoryAllocator(info, pixels, rowBytes)); // This implementation does not support scaling so check the requested size. SkISize scaledSize = SkISize::Make(info.width(), info.height()); ASSERT(m_fullSize == scaledSize); SkBitmap bitmap = tryToResumeDecode(index, scaledSize); if (bitmap.isNull()) return false; // Don't keep the allocator because it contains a pointer to memory // that we do not own. m_externalAllocator.clear(); // Check to see if the decoder has written directly to the pixel memory // provided. If not, make a copy. ASSERT(bitmap.width() == scaledSize.width()); ASSERT(bitmap.height() == scaledSize.height()); SkAutoLockPixels bitmapLock(bitmap); if (bitmap.getPixels() != pixels) return bitmap.copyPixelsTo(pixels, rowBytes * info.height(), rowBytes); return true; }
/* * Performs the decoding */ int SkBmpMaskCodec::decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts) { // Iterate over rows of the image uint8_t* srcRow = fSrcBuffer.get(); const int height = dstInfo.height(); for (int y = 0; y < height; y++) { // Read a row of the input if (this->stream()->read(srcRow, this->srcRowBytes()) != this->srcRowBytes()) { SkCodecPrintf("Warning: incomplete input stream.\n"); return y; } // Decode the row in destination format uint32_t row = this->getDstRow(y, height); void* dstRow = SkTAddOffset<void>(dst, row * dstRowBytes); if (this->colorXform()) { SkImageInfo xformInfo = dstInfo.makeWH(fMaskSwizzler->swizzleWidth(), dstInfo.height()); fMaskSwizzler->swizzle(this->xformBuffer(), srcRow); this->applyColorXform(xformInfo, dstRow, this->xformBuffer()); } else { fMaskSwizzler->swizzle(dstRow, srcRow); } } // Finished decoding the entire image return height; }
// check if scaling to dstInfo size from srcInfo size using sampleSize is possible static bool scaling_supported(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo, int* sampleX, int* sampleY) { SkScaledCodec::ComputeSampleSize(dstInfo, srcInfo, sampleX, sampleY); const int dstWidth = dstInfo.width(); const int dstHeight = dstInfo.height(); const int srcWidth = srcInfo.width(); const int srcHeight = srcInfo.height(); // only support down sampling, not up sampling if (dstWidth > srcWidth || dstHeight > srcHeight) { return false; } // check that srcWidth is scaled down by an integer value if (get_scaled_dimension(srcWidth, *sampleX) != dstWidth) { return false; } // check that src height is scaled down by an integer value if (get_scaled_dimension(srcHeight, *sampleY) != dstHeight) { return false; } // sampleX and sampleY should be equal unless the original sampleSize requested was larger // than srcWidth or srcHeight. If so, the result of this is dstWidth or dstHeight = 1. // This functionality allows for tall thin images to still be scaled down by scaling factors. if (*sampleX != *sampleY){ if (1 != dstWidth && 1 != dstHeight) { return false; } } return true; }
SK_API bool SkCopyPixelsFromCGImage(const SkImageInfo& info, size_t rowBytes, void* pixels, CGImageRef image) { CGBitmapInfo cg_bitmap_info = 0; size_t bitsPerComponent = 0; switch (info.colorType()) { case kRGBA_8888_SkColorType: bitsPerComponent = 8; cg_bitmap_info = ComputeCGAlphaInfo_RGBA(info.alphaType()); break; case kBGRA_8888_SkColorType: bitsPerComponent = 8; cg_bitmap_info = ComputeCGAlphaInfo_BGRA(info.alphaType()); break; default: return false; // no other colortypes are supported (for now) } CGColorSpaceRef cs = CGColorSpaceCreateDeviceRGB(); CGContextRef cg = CGBitmapContextCreate(pixels, info.width(), info.height(), bitsPerComponent, rowBytes, cs, cg_bitmap_info); CFRelease(cs); if (NULL == cg) { return false; } // use this blend mode, to avoid having to erase the pixels first, and to avoid CG performing // any blending (which could introduce errors and be slower). CGContextSetBlendMode(cg, kCGBlendModeCopy); CGContextDrawImage(cg, CGRectMake(0, 0, info.width(), info.height()), image); CGContextRelease(cg); return true; }
void SkDrawCommandGeometryWidget::paintEvent(QPaintEvent* event) { this->QFrame::paintEvent(event); if (!fSurface) { return; } QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); SkImageInfo info; size_t rowBytes; if (const void* pixels = fSurface->peekPixels(&info, &rowBytes)) { SkASSERT(info.width() > 0); SkASSERT(info.height() > 0); QRectF resultRect; if (this->width() < this->height()) { float ratio = this->width() / info.width(); resultRect = QRectF(0, 0, this->width(), ratio * info.height()); } else { float ratio = this->height() / info.height(); resultRect = QRectF(0, 0, ratio * info.width(), this->height()); } resultRect.moveCenter(this->contentsRect().center()); QImage image(reinterpret_cast<const uchar*>(pixels), info.width(), info.height(), rowBytes, QImage::Format_ARGB32_Premultiplied); painter.drawImage(resultRect, image); } }
/* * Initiates the bitmap decode */ SkCodec::Result SkBmpRLECodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts, SkPMColor* inputColorPtr, int* inputColorCount, int* rowsDecoded) { if (opts.fSubset) { // Subsets are not supported. return kUnimplemented; } if (!conversion_possible_ignore_color_space(dstInfo, this->getInfo())) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { return result; } // Perform the decode int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); if (rows != dstInfo.height()) { // We set rowsDecoded equal to the height because the background has already // been filled. RLE encodings sometimes skip pixels, so we always start by // filling the background. *rowsDecoded = dstInfo.height(); return kIncompleteInput; } return kSuccess; }
bool allocPixelRef(SkBitmap* bm, SkColorTable* ctable) override { const SkImageInfo bmi = bm->info(); if (bmi.width() != fInfo.width() || bmi.height() != fInfo.height() || bmi.colorType() != fInfo.colorType()) { return false; } return bm->installPixels(bmi, fMemory, fRowBytes, ctable, NULL, NULL); }
bool SkBaseDevice::readPixels(const SkImageInfo& info, void* dstP, size_t rowBytes, int x, int y) { #ifdef SK_DEBUG SkASSERT(info.width() > 0 && info.height() > 0); SkASSERT(dstP); SkASSERT(rowBytes >= info.minRowBytes()); SkASSERT(x >= 0 && y >= 0); const SkImageInfo& srcInfo = this->imageInfo(); SkASSERT(x + info.width() <= srcInfo.width()); SkASSERT(y + info.height() <= srcInfo.height()); #endif return this->onReadPixels(info, dstP, rowBytes, x, y); }
bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) { TRACE_EVENT1("blink", "DecodingImageGenerator::getPixels", "index", static_cast<int>(m_frameIndex)); // Implementation doesn't support scaling yet so make sure we're not given a different size. if (info.width() != info.width() || info.height() != info.height() || info.colorType() != info.colorType()) { // ImageFrame may have changed the owning SkBitmap to kOpaque_SkAlphaType after sniffing the encoded data, so if we see a request // for opaque, that is ok even if our initial alphatype was not opaque. return false; } return m_frameGenerator->decodeAndScale(info, m_frameIndex, pixels, rowBytes); }
/* * Performs the jpeg decode */ SkCodec::Result SkJpegCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& options, SkPMColor*, int*, int* rowsDecoded) { if (options.fSubset) { // Subsets are not supported. return kUnimplemented; } // Get a pointer to the decompress info since we will use it quite frequently jpeg_decompress_struct* dinfo = fDecoderMgr->dinfo(); // Set the jump location for libjpeg errors if (setjmp(fDecoderMgr->getJmpBuf())) { return fDecoderMgr->returnFailure("setjmp", kInvalidInput); } // Check if we can decode to the requested destination and set the output color space bool needsColorXform = needs_color_xform(dstInfo, this->getInfo()); if (!this->setOutputColorSpace(dstInfo, needsColorXform)) { return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion); } if (!this->initializeColorXform(dstInfo, needsColorXform)) { return fDecoderMgr->returnFailure("initializeColorXform", kInvalidParameters); } if (!jpeg_start_decompress(dinfo)) { return fDecoderMgr->returnFailure("startDecompress", kInvalidInput); } // The recommended output buffer height should always be 1 in high quality modes. // If it's not, we want to know because it means our strategy is not optimal. SkASSERT(1 == dinfo->rec_outbuf_height); J_COLOR_SPACE colorSpace = dinfo->out_color_space; if (JCS_CMYK == colorSpace || JCS_RGB == colorSpace) { this->initializeSwizzler(dstInfo, options); } this->allocateStorage(dstInfo); int rows = this->readRows(dstInfo, dst, dstRowBytes, dstInfo.height()); if (rows < dstInfo.height()) { *rowsDecoded = rows; return fDecoderMgr->returnFailure("Incomplete image data", kIncompleteInput); } return kSuccess; }
bool SkBaseDevice::writePixels(const SkImageInfo& info, const void* pixels, size_t rowBytes, int x, int y) { #ifdef SK_DEBUG SkASSERT(info.width() > 0 && info.height() > 0); SkASSERT(pixels); SkASSERT(rowBytes >= info.minRowBytes()); SkASSERT(x >= 0 && y >= 0); const SkImageInfo& dstInfo = this->imageInfo(); SkASSERT(x + info.width() <= dstInfo.width()); SkASSERT(y + info.height() <= dstInfo.height()); #endif return this->onWritePixels(info, pixels, rowBytes, x, y); }
void draw(SkCanvas* canvas) { SkPaint paint; SkFont font(nullptr, 100); canvas->drawString("ABC", 20, 160, font, paint); SkRect layerBounds = SkRect::MakeXYWH(32, 32, 192, 192); canvas->saveLayerAlpha(&layerBounds, 128); canvas->clear(SK_ColorWHITE); canvas->drawString("DEF", 20, 160, font, paint); SkImageInfo imageInfo; size_t rowBytes; SkIPoint origin; uint32_t* access = (uint32_t*) canvas->accessTopLayerPixels(&imageInfo, &rowBytes, &origin); if (access) { int h = imageInfo.height(); int v = imageInfo.width(); int rowWords = rowBytes / sizeof(uint32_t); for (int y = 0; y < h; ++y) { int newY = (y - h / 2) * 2 + h / 2; if (newY < 0 || newY >= h) { continue; } for (int x = 0; x < v; ++x) { int newX = (x - v / 2) * 2 + v / 2; if (newX < 0 || newX >= v) { continue; } if (access[y * rowWords + x] == SK_ColorBLACK) { access[newY * rowWords + newX] = SK_ColorGRAY; } } } } canvas->restore(); }
bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor table[], int* tableCount) { TRACE_EVENT1("blink", "DecodingImageGenerator::getPixels", "frame index", static_cast<int>(m_frameIndex)); // Implementation doesn't support scaling yet, so make sure we're not given a // different size. if (info.width() != getInfo().width() || info.height() != getInfo().height()) return false; if (info.colorType() != getInfo().colorType()) { // blink::ImageFrame may have changed the owning SkBitmap to // kOpaque_SkAlphaType after fully decoding the image frame, so if we see a // request for opaque, that is ok even if our initial alpha type was not // opaque. return false; } PlatformInstrumentation::willDecodeLazyPixelRef(uniqueID()); bool decoded = m_frameGenerator->decodeAndScale( m_data.get(), m_allDataReceived, m_frameIndex, getInfo(), pixels, rowBytes); PlatformInstrumentation::didDecodeLazyPixelRef(); return decoded; }
static void copy_32_to_g8(void* dst, size_t dstRB, const void* src, size_t srcRB, const SkImageInfo& srcInfo) { uint8_t* dst8 = (uint8_t*)dst; const uint32_t* src32 = (const uint32_t*)src; const int w = srcInfo.width(); const int h = srcInfo.height(); const bool isBGRA = (kBGRA_8888_SkColorType == srcInfo.colorType()); for (int y = 0; y < h; ++y) { if (isBGRA) { // BGRA for (int x = 0; x < w; ++x) { uint32_t s = src32[x]; dst8[x] = SkComputeLuminance((s >> 16) & 0xFF, (s >> 8) & 0xFF, s & 0xFF); } } else { // RGBA for (int x = 0; x < w; ++x) { uint32_t s = src32[x]; dst8[x] = SkComputeLuminance(s & 0xFF, (s >> 8) & 0xFF, (s >> 16) & 0xFF); } } src32 = (const uint32_t*)((const char*)src32 + srcRB); dst8 += dstRB; }
/* * Initiates the bitmap decode */ SkCodec::Result SkBmpMaskCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes, const Options& opts, SkPMColor* inputColorPtr, int* inputColorCount, int* rowsDecoded) { if (opts.fSubset) { // Subsets are not supported. return kUnimplemented; } if (dstInfo.dimensions() != this->getInfo().dimensions()) { SkCodecPrintf("Error: scaling not supported.\n"); return kInvalidScale; } if (!conversion_possible(dstInfo, this->getInfo())) { SkCodecPrintf("Error: cannot convert input type to output type.\n"); return kInvalidConversion; } Result result = this->prepareToDecode(dstInfo, opts, inputColorPtr, inputColorCount); if (kSuccess != result) { return result; } int rows = this->decodeRows(dstInfo, dst, dstRowBytes, opts); if (rows != dstInfo.height()) { *rowsDecoded = rows; return kIncompleteInput; } return kSuccess; }
/* * Set an RLE pixel from R, G, B values */ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue) { // Set the row int height = dstInfo.height(); int row; if (SkBmpCodec::kBottomUp_RowOrder == this->rowOrder()) { row = height - y - 1; } else { row = y; } // Set the pixel based on destination color type switch (dstInfo.colorType()) { case kN32_SkColorType: { SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst, row * (int) dstRowBytes); dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue); break; } case kRGB_565_SkColorType: { uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); dstRow[x] = SkPack888ToRGB16(red, green, blue); break; } default: // This case should not be reached. We should catch an invalid // color type when we check that the conversion is possible. SkASSERT(false); break; } }
static void make_texture_desc(const SkImageInfo& info, GrSurfaceDesc* desc) { desc->fFlags = kNone_GrSurfaceFlags; desc->fWidth = info.width(); desc->fHeight = info.height(); desc->fConfig = SkImageInfo2GrPixelConfig(info); desc->fSampleCnt = 0; }
/* * Set an RLE pixel using the color table */ void SkBmpRLECodec::setPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t index) { if (is_coord_necessary(x, fSampleX, dstInfo.width())) { // Set the row uint32_t row = this->getDstRow(y, dstInfo.height()); // Set the pixel based on destination color type const int dstX = get_dst_coord(x, fSampleX); switch (dstInfo.colorType()) { case kN32_SkColorType: { SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes); dstRow[dstX] = fColorTable->operator[](index); break; } case kRGB_565_SkColorType: { uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); dstRow[dstX] = SkPixel32ToPixel16(fColorTable->operator[](index)); break; } default: // This case should not be reached. We should catch an invalid // color type when we check that the conversion is possible. SkASSERT(false); break; } } }
SkImage* SkImage::NewFromBitmap(const SkBitmap& bm) { SkPixelRef* pr = bm.pixelRef(); if (nullptr == pr) { return nullptr; } #if SK_SUPPORT_GPU if (GrTexture* tex = pr->getTexture()) { SkAutoTUnref<GrTexture> unrefCopy; if (!bm.isImmutable()) { const bool notBudgeted = false; tex = GrDeepCopyTexture(tex, notBudgeted); if (nullptr == tex) { return nullptr; } unrefCopy.reset(tex); } const SkImageInfo info = bm.info(); return new SkImage_Gpu(info.width(), info.height(), bm.getGenerationID(), info.alphaType(), tex, 0, SkSurface::kNo_Budgeted); } #endif // This will check for immutable (share or copy) return SkNewImageFromRasterBitmap(bm, nullptr); }
SkSurface::SkSurface(const SkImageInfo& info, const SkSurfaceProps* props) : fProps(SkSurfacePropsCopyOrDefault(props)), fWidth(info.width()), fHeight(info.height()) { SkASSERT(fWidth > 0); SkASSERT(fHeight > 0); fGenerationID = 0; }
static void draw_content(SkCanvas* canvas) { SkImageInfo info = canvas->imageInfo(); SkPaint paint; paint.setAntiAlias(true); canvas->drawCircle(SkScalarHalf(info.width()), SkScalarHalf(info.height()), SkScalarHalf(info.width()), paint); }
void drawHere(SkCanvas* canvas, SkFilterQuality filter, SkScalar dx, SkScalar dy) { SkCanvas* origCanvas = canvas; SkAutoCanvasRestore acr(canvas, true); SkISize size = SkISize::Make(fImage->width(), fImage->height()); SkAutoTUnref<SkSurface> surface; if (fShowFatBits) { // scale up so we don't clip rotations SkImageInfo info = SkImageInfo::MakeN32(fImage->width() * 2, fImage->height() * 2, kOpaque_SkAlphaType); surface.reset(make_surface(canvas, info)); canvas = surface->getCanvas(); canvas->drawColor(SK_ColorWHITE); size.set(info.width(), info.height()); } else { canvas->translate(SkScalarHalf(fCell.width() - fImage->width()), SkScalarHalf(fCell.height() - fImage->height())); } this->drawTheImage(canvas, size, filter, dx, dy); if (surface) { SkAutoTUnref<SkImage> orig(surface->newImageSnapshot()); SkAutoTUnref<SkImage> zoomed(zoom_up(orig)); origCanvas->drawImage(zoomed, SkScalarHalf(fCell.width() - zoomed->width()), SkScalarHalf(fCell.height() - zoomed->height())); } }
bool SkImage_Gpu::onReadPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, int srcX, int srcY, CachingHint) const { GrPixelConfig config = SkImageInfo2GrPixelConfig(info, *fTexture->getContext()->caps()); uint32_t flags = 0; if (kUnpremul_SkAlphaType == info.alphaType() && kPremul_SkAlphaType == fAlphaType) { // let the GPU perform this transformation for us flags = GrContext::kUnpremul_PixelOpsFlag; } if (!fTexture->readPixels(srcX, srcY, info.width(), info.height(), config, pixels, rowBytes, flags)) { return false; } // do we have to manually fix-up the alpha channel? // src dst // unpremul premul fix manually // premul unpremul done by kUnpremul_PixelOpsFlag // all other combos need to change. // // Should this be handled by Ganesh? todo:? // if (kPremul_SkAlphaType == info.alphaType() && kUnpremul_SkAlphaType == fAlphaType) { apply_premul(info, pixels, rowBytes); } return true; }
sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot(SkBudgeted budgeted, ForceCopyMode forceCopyMode) { GrRenderTarget* rt = fDevice->accessDrawContext()->accessRenderTarget(); SkASSERT(rt); GrTexture* tex = rt->asTexture(); SkAutoTUnref<GrTexture> copy; // If the original render target is a buffer originally created by the client, then we don't // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid // copy-on-write. if (kYes_ForceCopyMode == forceCopyMode || !tex || rt->resourcePriv().refsWrappedObjects()) { GrSurfaceDesc desc = fDevice->accessDrawContext()->desc(); GrContext* ctx = fDevice->context(); desc.fFlags = desc.fFlags & ~kRenderTarget_GrSurfaceFlag; copy.reset(ctx->textureProvider()->createTexture(desc, budgeted)); if (!copy) { return nullptr; } if (!ctx->copySurface(copy, rt)) { return nullptr; } tex = copy; } const SkImageInfo info = fDevice->imageInfo(); sk_sp<SkImage> image; if (tex) { image = sk_make_sp<SkImage_Gpu>(info.width(), info.height(), kNeedNewImageUniqueID, info.alphaType(), tex, sk_ref_sp(info.colorSpace()), budgeted); } return image; }
/* * Set an RLE pixel from R, G, B values */ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue) { if (dst && is_coord_necessary(x, fSampleX, dstInfo.width())) { // Set the row uint32_t row = this->getDstRow(y, dstInfo.height()); // Set the pixel based on destination color type const int dstX = get_dst_coord(x, fSampleX); switch (dstInfo.colorType()) { case kRGBA_8888_SkColorType: { SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes); dstRow[dstX] = SkPackARGB_as_RGBA(0xFF, red, green, blue); break; } case kBGRA_8888_SkColorType: { SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes); dstRow[dstX] = SkPackARGB_as_BGRA(0xFF, red, green, blue); break; } case kRGB_565_SkColorType: { uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); dstRow[dstX] = SkPack888ToRGB16(red, green, blue); break; } default: // This case should not be reached. We should catch an invalid // color type when we check that the conversion is possible. SkASSERT(false); break; } } }