/** * Test that for Jpeg files that use the JFIF colorspace, they are * directly embedded into the PDF (without re-encoding) when that * makes sense. */ DEF_TEST(PDFJpegEmbedTest, r) { const char test[] = "PDFJpegEmbedTest"; SkAutoTUnref<SkData> mandrillData( load_resource(r, test, "mandrill_512_q075.jpg")); SkAutoTUnref<SkData> cmykData(load_resource(r, test, "CMYK.jpg")); if (!mandrillData || !cmykData) { return; } //////////////////////////////////////////////////////////////////////////// SkDynamicMemoryWStream pdf; SkAutoTUnref<SkDocument> document(SkDocument::CreatePDF(&pdf)); SkCanvas* canvas = document->beginPage(642, 1028); canvas->clear(SK_ColorLTGRAY); SkBitmap bm1(bitmap_from_data(mandrillData)); canvas->drawBitmap(bm1, 65.0, 0.0, nullptr); SkBitmap bm2(bitmap_from_data(cmykData)); canvas->drawBitmap(bm2, 0.0, 512.0, nullptr); canvas->flush(); document->endPage(); document->close(); SkAutoTUnref<SkData> pdfData(pdf.copyToData()); SkASSERT(pdfData); pdf.reset(); REPORTER_ASSERT(r, is_subset_of(mandrillData, pdfData)); // This JPEG uses a nonstandard colorspace - it can not be // embedded into the PDF directly. REPORTER_ASSERT(r, !is_subset_of(cmykData, pdfData)); //////////////////////////////////////////////////////////////////////////// pdf.reset(); document.reset(SkDocument::CreatePDF(&pdf)); canvas = document->beginPage(642, 1028); canvas->clear(SK_ColorLTGRAY); SkAutoTUnref<SkImage> im1(SkImage::NewFromEncoded(mandrillData)); canvas->drawImage(im1, 65.0, 0.0, nullptr); SkAutoTUnref<SkImage> im2(SkImage::NewFromEncoded(cmykData)); canvas->drawImage(im2, 0.0, 512.0, nullptr); canvas->flush(); document->endPage(); document->close(); pdfData.reset(pdf.copyToData()); SkASSERT(pdfData); pdf.reset(); REPORTER_ASSERT(r, is_subset_of(mandrillData, pdfData)); // This JPEG uses a nonstandard colorspace - it can not be // embedded into the PDF directly. REPORTER_ASSERT(r, !is_subset_of(cmykData, pdfData)); }
static SkImage* create_picture_image() { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(10, 10); canvas->clear(SK_ColorCYAN); SkAutoTUnref<SkPicture> picture(recorder.endRecording()); return SkImage::NewFromPicture(picture, SkISize::Make(10, 10), nullptr, nullptr); };
static void render_picture(GrContext* grContext, int width, int height, const SkPicture* picture, const SkMatrix& matrix) { SkASSERT(grContext); if (!picture) { SkDebugf(TAG "!picture\n"); return; } // Render to the default framebuffer render target. GrBackendRenderTargetDesc desc; desc.fWidth = width; desc.fHeight = height; desc.fConfig = kSkia8888_GrPixelConfig; desc.fOrigin = kBottomLeft_GrSurfaceOrigin; SkSurfaceProps surfaceProps(SkSurfaceProps::kUseDeviceIndependentFonts_Flag, kUnknown_SkPixelGeometry); // TODO: Check to see if we can keep the surface between draw calls. SkAutoTUnref<SkSurface> surface( SkSurface::NewFromBackendRenderTarget( grContext, desc, &surfaceProps)); if (surface) { SkCanvas* canvas = surface->getCanvas(); SkASSERT(canvas); canvas->clear(SK_ColorGRAY); canvas->concat(matrix); SkRect cullRect = picture->cullRect(); canvas->clipRect(cullRect); picture->playback(canvas); canvas->flush(); } }
void onDraw(SkCanvas* canvas) override { SkPaint blurPaint; SkAutoTUnref<SkImageFilter> blur(SkBlurImageFilter::Create(5.0f, 5.0f)); blurPaint.setImageFilter(blur); const SkScalar tile_size = SkIntToScalar(128); SkRect bounds; if (!canvas->getClipBounds(&bounds)) { bounds.setEmpty(); } int ts = SkScalarCeilToInt(tile_size); SkImageInfo info = SkImageInfo::MakeN32Premul(ts, ts); SkAutoTUnref<SkSurface> tileSurface(canvas->newSurface(info)); if (!tileSurface.get()) { tileSurface.reset(SkSurface::NewRaster(info)); } SkCanvas* tileCanvas = tileSurface->getCanvas(); for (SkScalar y = bounds.top(); y < bounds.bottom(); y += tile_size) { for (SkScalar x = bounds.left(); x < bounds.right(); x += tile_size) { tileCanvas->save(); tileCanvas->clear(0); tileCanvas->translate(-x, -y); SkRect rect = SkRect::MakeWH(WIDTH, HEIGHT); tileCanvas->saveLayer(&rect, &blurPaint); SkRRect rrect = SkRRect::MakeRectXY(rect.makeInset(20, 20), 25, 25); tileCanvas->clipRRect(rrect, SkRegion::kDifference_Op, true); SkPaint paint; tileCanvas->drawRect(rect, paint); tileCanvas->restore(); tileCanvas->restore(); canvas->drawImage(tileSurface->makeImageSnapshot().get(), x, y); } } }
// Verify that associated bitmap cache entries are purged on SkImage destruction. DEF_TEST(BitmapCache_discarded_image, reporter) { // Cache entries associated with SkImages fall into two categories: // // 1) generated image bitmaps (managed by the image cacherator) // 2) scaled/resampled bitmaps (cached when HQ filters are used) // // To exercise the first cache type, we use generated/picture-backed SkImages. // To exercise the latter, we draw scaled bitmap images using HQ filters. const SkMatrix xforms[] = { SkMatrix::MakeScale(1, 1), SkMatrix::MakeScale(1.7f, 0.5f), }; for (size_t i = 0; i < SK_ARRAY_COUNT(xforms); ++i) { test_discarded_image(reporter, xforms[i], []() { auto surface(SkSurface::MakeRasterN32Premul(10, 10)); surface->getCanvas()->clear(SK_ColorCYAN); return surface->makeImageSnapshot(); }); test_discarded_image(reporter, xforms[i], []() { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(10, 10); canvas->clear(SK_ColorCYAN); return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(), SkISize::Make(10, 10), nullptr, nullptr, SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB()); }); } }
int main(int, char**) { bool gl_ok = setup_gl_context(); srand(time(nullptr)); std::shared_ptr<SkSurface> surface = (gl_ok && rand() % 2) ? create_opengl_surface(320, 240) : create_raster_surface(320, 240); // Create a left-to-right green-to-purple gradient shader. SkPoint pts[] = { {0,0}, {320,240} }; SkColor colors[] = { 0xFF00FF00, 0xFFFF00FF }; // Our text will draw with this paint: size 24, antialiased, with the shader. SkPaint paint; paint.setTextSize(24); paint.setAntiAlias(true); paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkShader::kRepeat_TileMode)); // Draw to the surface via its SkCanvas. SkCanvas* canvas = surface->getCanvas(); // We don't manage this pointer's lifetime. static const char* msg = "Hello world!"; canvas->clear(SK_ColorWHITE); canvas->drawText(msg, strlen(msg), 90,120, paint); // Grab a snapshot of the surface as an immutable SkImage. std::shared_ptr<SkImage> image = adopt(surface->newImageSnapshot()); // Encode that image as a .png into a blob in memory. std::shared_ptr<SkData> png = adopt(image->encode(SkImageEncoder::kPNG_Type, 100)); // This code is no longer Skia-specific. We just dump the .png to disk. Any way works. static const char* path = "example.png"; std::ofstream(path, std::ios::out | std::ios::binary) .write((const char*)png->data(), png->size()); std::cout << "Wrote " << path << std::endl; return 0; }
static sk_sp<SkImage> create_gpu_image(GrContext* grContext) { const SkImageInfo info = SkImageInfo::MakeN32(20, 20, kOpaque_SkAlphaType); auto surface(SkSurface::MakeRenderTarget(grContext, SkBudgeted::kNo, info)); SkCanvas* canvas = surface->getCanvas(); canvas->clear(SK_ColorWHITE); SkPaint paint; paint.setColor(SK_ColorBLACK); canvas->drawRect(SkRect::MakeXYWH(5, 5, 10, 10), paint); return surface->makeImageSnapshot(); }
// Creates a bitmap and a matching image. static sk_sp<SkImage> makebm(SkCanvas* origCanvas, SkBitmap* resultBM, int w, int h) { SkImageInfo info = SkImageInfo::MakeN32Premul(w, h); auto surface(sk_tool_utils::makeSurface(origCanvas, info)); SkCanvas* canvas = surface->getCanvas(); canvas->clear(SK_ColorTRANSPARENT); SkScalar wScalar = SkIntToScalar(w); SkScalar hScalar = SkIntToScalar(h); SkPoint pt = { wScalar / 2, hScalar / 2 }; SkScalar radius = 4 * SkMaxScalar(wScalar, hScalar); SkColor colors[] = { SK_ColorRED, SK_ColorYELLOW, SK_ColorGREEN, SK_ColorMAGENTA, SK_ColorBLUE, SK_ColorCYAN, SK_ColorRED}; SkScalar pos[] = {0, SK_Scalar1 / 6, 2 * SK_Scalar1 / 6, 3 * SK_Scalar1 / 6, 4 * SK_Scalar1 / 6, 5 * SK_Scalar1 / 6, SK_Scalar1}; SkPaint paint; SkRect rect = SkRect::MakeWH(wScalar, hScalar); SkMatrix mat = SkMatrix::I(); for (int i = 0; i < 4; ++i) { paint.setShader(SkGradientShader::MakeRadial( pt, radius, colors, pos, SK_ARRAY_COUNT(colors), SkShader::kRepeat_TileMode, 0, &mat)); canvas->drawRect(rect, paint); rect.inset(wScalar / 8, hScalar / 8); mat.postScale(SK_Scalar1 / 4, SK_Scalar1 / 4); } auto image = surface->makeImageSnapshot(); SkBitmap tempBM; image->asLegacyBitmap(&tempBM); // Let backends know we won't change this, so they don't have to deep copy it defensively. tempBM.setImmutable(); *resultBM = tempBM; return image; }
// Test out the layer replacement functionality with and w/o a BBH void test_replacements(skiatest::Reporter* r, GrContext* context, bool doReplace) { sk_sp<SkPicture> pic; { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight)); SkPaint paint; canvas->saveLayer(nullptr, &paint); canvas->clear(SK_ColorRED); canvas->restore(); canvas->drawRect(SkRect::MakeWH(SkIntToScalar(kWidth / 2), SkIntToScalar(kHeight / 2)), SkPaint()); pic = recorder.finishRecordingAsPicture(); } SkAutoTUnref<GrTexture> texture; SkPaint paint; GrLayerCache* layerCache = context->getLayerCache(); if (doReplace) { int key[1] = { 0 }; GrCachedLayer* layer = layerCache->findLayerOrCreate(pic->uniqueID(), 0, 2, SkIRect::MakeWH(kWidth, kHeight), SkIRect::MakeWH(kWidth, kHeight), SkMatrix::I(), key, 1, &paint); GrSurfaceDesc desc; desc.fConfig = kSkia8888_GrPixelConfig; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = kWidth; desc.fHeight = kHeight; desc.fSampleCnt = 0; // Giving the texture some initial data so the Gpu (specifically vulkan) does not complain // when reading from an uninitialized texture. SkAutoTMalloc<uint32_t> srcBuffer(kWidth*kHeight); memset(srcBuffer.get(), 0, kWidth*kHeight*sizeof(uint32_t)); texture.reset(context->textureProvider()->createTexture( desc, SkBudgeted::kNo, srcBuffer.get(), 0)); layer->setTexture(texture, SkIRect::MakeWH(kWidth, kHeight), false); } SkRecord rerecord; SkRecorder canvas(&rerecord, kWidth, kHeight); GrRecordReplaceDraw(pic.get(), &canvas, layerCache, SkMatrix::I(), nullptr/*callback*/); int numLayers = count_instances_of_type<SkRecords::SaveLayer>(rerecord); if (doReplace) { REPORTER_ASSERT(r, 0 == numLayers); } else { REPORTER_ASSERT(r, 1 == numLayers); } }
SkCanvas* PictureRenderer::setupCanvas(int width, int height) { SkCanvas* canvas; switch(fDeviceType) { case kBitmap_DeviceType: { SkBitmap bitmap; sk_tools::setup_bitmap(&bitmap, width, height); canvas = SkNEW_ARGS(SkCanvas, (bitmap)); } break; #if SK_SUPPORT_GPU #if SK_ANGLE case kAngle_DeviceType: // fall through #endif #if SK_MESA case kMesa_DeviceType: // fall through #endif case kGPU_DeviceType: case kNVPR_DeviceType: { SkAutoTUnref<GrSurface> target; if (fGrContext) { // create a render target to back the device GrTextureDesc desc; desc.fConfig = kSkia8888_GrPixelConfig; desc.fFlags = kRenderTarget_GrTextureFlagBit; desc.fWidth = width; desc.fHeight = height; desc.fSampleCnt = fSampleCount; target.reset(fGrContext->createUncachedTexture(desc, NULL, 0)); } if (NULL == target.get()) { SkASSERT(0); return NULL; } SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(target)); canvas = SkNEW_ARGS(SkCanvas, (device.get())); break; } #endif default: SkASSERT(0); return NULL; } setUpFilter(canvas, fDrawFilters); this->scaleToScaleFactor(canvas); // Pictures often lie about their extent (i.e., claim to be 100x100 but // only ever draw to 90x100). Clear here so the undrawn portion will have // a consistent color canvas->clear(SK_ColorTRANSPARENT); return canvas; }
void makePicture() { SkCanvas* canvas = fPicture.beginRecording(100, 100); canvas->clear(0x00000000); SkPaint paint; paint.setAntiAlias(true); paint.setColor(0xFFFFFFFF); paint.setTextSize(SkIntToScalar(96)); const char* str = "e"; canvas->drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint); fPicture.endRecording(); }
sk_sp<SkSpecialImage> SkDropShadowImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint inputOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); if (!input) { return nullptr; } const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.x(), inputOffset.y(), input->width(), input->height()); SkIRect bounds; if (!this->applyCropRect(ctx, inputBounds, &bounds)) { return nullptr; } const SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(), kPremul_SkAlphaType); sk_sp<SkSpecialSurface> surf(source->makeSurface(info)); if (!surf) { return nullptr; } SkCanvas* canvas = surf->getCanvas(); SkASSERT(canvas); canvas->clear(0x0); SkVector sigma = SkVector::Make(fSigmaX, fSigmaY); ctx.ctm().mapVectors(&sigma, 1); sigma.fX = SkMaxScalar(0, sigma.fX); sigma.fY = SkMaxScalar(0, sigma.fY); SkAutoTUnref<SkImageFilter> blurFilter(SkBlurImageFilter::Create(sigma.fX, sigma.fY)); SkPaint paint; paint.setImageFilter(blurFilter.get()); paint.setColorFilter(SkColorFilter::MakeModeFilter(fColor, SkXfermode::kSrcIn_Mode)); paint.setXfermodeMode(SkXfermode::kSrcOver_Mode); SkVector offsetVec = SkVector::Make(fDx, fDy); ctx.ctm().mapVectors(&offsetVec, 1); canvas->translate(SkIntToScalar(inputOffset.fX - bounds.fLeft), SkIntToScalar(inputOffset.fY - bounds.fTop)); input->draw(canvas, offsetVec.fX, offsetVec.fY, &paint); if (fShadowMode == kDrawShadowAndForeground_ShadowMode) { input->draw(canvas, 0, 0, nullptr); } offset->fX = bounds.fLeft; offset->fY = bounds.fTop; return surf->makeImageSnapshot(); }
sk_sp<SkSpecialImage> SkImageSource::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkRect dstRect; ctx.ctm().mapRect(&dstRect, fDstRect); SkRect bounds = SkRect::MakeIWH(fImage->width(), fImage->height()); if (fSrcRect == bounds) { int iLeft = dstRect.fLeft; int iTop = dstRect.fTop; // TODO: this seems to be a very noise-prone way to determine this (esp. the floating-point // widths & heights). if (dstRect.width() == bounds.width() && dstRect.height() == bounds.height() && iLeft == dstRect.fLeft && iTop == dstRect.fTop) { // The dest is just an un-scaled integer translation of the entire image; return it offset->fX = iLeft; offset->fY = iTop; return SkSpecialImage::MakeFromImage(SkIRect::MakeWH(fImage->width(), fImage->height()), fImage, ctx.outputProperties().colorSpace(), &source->props()); } } const SkIRect dstIRect = dstRect.roundOut(); sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), dstIRect.size())); if (!surf) { return nullptr; } SkCanvas* canvas = surf->getCanvas(); SkASSERT(canvas); // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075) canvas->clear(0x0); SkPaint paint; // Subtract off the integer component of the translation (will be applied in offset, below). dstRect.offset(-SkIntToScalar(dstIRect.fLeft), -SkIntToScalar(dstIRect.fTop)); paint.setBlendMode(SkBlendMode::kSrc); // FIXME: this probably shouldn't be necessary, but drawImageRect asserts // None filtering when it's translate-only paint.setFilterQuality( fSrcRect.width() == dstRect.width() && fSrcRect.height() == dstRect.height() ? kNone_SkFilterQuality : fFilterQuality); canvas->drawImageRect(fImage.get(), fSrcRect, dstRect, &paint, SkCanvas::kStrict_SrcRectConstraint); offset->fX = dstIRect.fLeft; offset->fY = dstIRect.fTop; return surf->makeImageSnapshot(); }
static SkImage* make_image(GrContext* ctx, int w, int h, const SkIRect& ir) { const SkImageInfo info = SkImageInfo::MakeN32(w, h, kOpaque_SkAlphaType); SkAutoTUnref<SkSurface> surface(ctx ? SkSurface::NewRenderTarget(ctx, SkSurface::kNo_Budgeted, info) : SkSurface::NewRaster(info)); SkCanvas* canvas = surface->getCanvas(); canvas->clear(SK_ColorWHITE); SkPaint paint; paint.setColor(SK_ColorBLACK); canvas->drawRect(SkRect::Make(ir), paint); return surface->newImageSnapshot(); }
static sk_sp<SkPicture> make_picture() { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(100, 100, nullptr, 0); canvas->clear(SK_ColorBLACK); SkPaint paint; paint.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&paint); paint.setColor(0xFFFFFFFF); paint.setTextSize(SkIntToScalar(96)); const char* str = "e"; canvas->drawText(str, strlen(str), SkIntToScalar(20), SkIntToScalar(70), paint); return recorder.finishRecordingAsPicture(); }
static SkImage* create_circle_texture(int size, SkColor color) { SkAutoTUnref<SkSurface> surface(SkSurface::NewRasterN32Premul(size, size)); SkCanvas* canvas = surface->getCanvas(); canvas->clear(0xFF000000); SkPaint paint; paint.setColor(color); paint.setStrokeWidth(3); paint.setStyle(SkPaint::kStroke_Style); canvas->drawCircle(SkScalarHalf(size), SkScalarHalf(size), SkScalarHalf(size), paint); return surface->newImageSnapshot(); }
// Test out the layer replacement functionality with and w/o a BBH void test_replacements(skiatest::Reporter* r, GrContext* context, bool doReplace) { SkAutoTUnref<const SkPicture> pic; { SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kWidth), SkIntToScalar(kHeight)); SkPaint paint; canvas->saveLayer(nullptr, &paint); canvas->clear(SK_ColorRED); canvas->restore(); canvas->drawRect(SkRect::MakeWH(SkIntToScalar(kWidth / 2), SkIntToScalar(kHeight / 2)), SkPaint()); pic.reset(recorder.endRecording()); } SkAutoTUnref<GrTexture> texture; SkPaint paint; GrLayerCache* layerCache = context->getLayerCache(); if (doReplace) { int key[1] = { 0 }; GrCachedLayer* layer = layerCache->findLayerOrCreate(pic->uniqueID(), 0, 2, SkIRect::MakeWH(kWidth, kHeight), SkIRect::MakeWH(kWidth, kHeight), SkMatrix::I(), key, 1, &paint); GrSurfaceDesc desc; desc.fConfig = kSkia8888_GrPixelConfig; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = kWidth; desc.fHeight = kHeight; desc.fSampleCnt = 0; texture.reset(context->textureProvider()->createTexture( desc, SkBudgeted::kNo, nullptr, 0)); layer->setTexture(texture, SkIRect::MakeWH(kWidth, kHeight), false); } SkRecord rerecord; SkRecorder canvas(&rerecord, kWidth, kHeight); GrRecordReplaceDraw(pic, &canvas, layerCache, SkMatrix::I(), nullptr/*callback*/); int numLayers = count_instances_of_type<SkRecords::SaveLayer>(rerecord); if (doReplace) { REPORTER_ASSERT(r, 0 == numLayers); } else { REPORTER_ASSERT(r, 1 == numLayers); } }
SkSpecialImage* SkOffsetImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint srcOffset = SkIPoint::Make(0, 0); SkAutoTUnref<SkSpecialImage> input(this->filterInput(0, source, ctx, &srcOffset)); if (!input) { return nullptr; } SkVector vec; ctx.ctm().mapVectors(&vec, &fOffset, 1); if (!this->cropRectIsSet()) { offset->fX = srcOffset.fX + SkScalarRoundToInt(vec.fX); offset->fY = srcOffset.fY + SkScalarRoundToInt(vec.fY); return input.release(); } else { SkIRect bounds; SkIRect srcBounds = SkIRect::MakeWH(input->width(), input->height()); srcBounds.offset(srcOffset); if (!this->applyCropRect(ctx, srcBounds, &bounds)) { return nullptr; } SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(), kPremul_SkAlphaType); sk_sp<SkSpecialSurface> surf(source->makeSurface(info)); if (!surf) { return nullptr; } SkCanvas* canvas = surf->getCanvas(); SkASSERT(canvas); // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075) canvas->clear(0x0); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); canvas->translate(SkIntToScalar(srcOffset.fX - bounds.fLeft), SkIntToScalar(srcOffset.fY - bounds.fTop)); input->draw(canvas, vec.x(), vec.y(), &paint); offset->fX = bounds.fLeft; offset->fY = bounds.fTop; return surf->makeImageSnapshot().release(); } }
void GrLayerHoister::DrawLayersToAtlas(GrContext* context, const SkTDArray<GrHoistedLayer>& atlased) { if (atlased.count() > 0) { // All the atlased layers are rendered into the same GrTexture SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( atlased[0].fLayer->texture()->asRenderTarget(), &props)); SkCanvas* atlasCanvas = surface->getCanvas(); for (int i = 0; i < atlased.count(); ++i) { const GrCachedLayer* layer = atlased[i].fLayer; const SkBigPicture* pict = atlased[i].fPicture->asSkBigPicture(); if (!pict) { // TODO: can we assume / assert this? continue; } const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop); SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();) SkASSERT(!layerPaint || !layerPaint->getImageFilter()); SkASSERT(!layer->filter()); atlasCanvas->save(); // Add a rect clip to make sure the rendering doesn't // extend beyond the boundaries of the atlased sub-rect const SkRect bound = SkRect::Make(layer->rect()); atlasCanvas->clipRect(bound); atlasCanvas->clear(0); // '-offset' maps the layer's top/left to the origin. // Since this layer is atlased, the top/left corner needs // to be offset to the correct location in the backing texture. SkMatrix initialCTM; initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); initialCTM.preTranslate(bound.fLeft, bound.fTop); initialCTM.preConcat(atlased[i].fPreMat); atlasCanvas->setMatrix(initialCTM); atlasCanvas->concat(atlased[i].fLocalMat); pict->partialPlayback(atlasCanvas, layer->start() + 1, layer->stop(), initialCTM); atlasCanvas->restore(); } atlasCanvas->flush(); }
static sk_sp<SkImage> make_gradient_circle(int width, int height) { SkScalar x = SkIntToScalar(width / 2); SkScalar y = SkIntToScalar(height / 2); SkScalar radius = SkMinScalar(x, y) * 0.8f; auto surface(SkSurface::MakeRasterN32Premul(width, height)); SkCanvas* canvas = surface->getCanvas(); canvas->clear(0x00000000); SkColor colors[2]; colors[0] = SK_ColorWHITE; colors[1] = SK_ColorBLACK; SkPaint paint; paint.setShader(SkGradientShader::MakeRadial(SkPoint::Make(x, y), radius, colors, nullptr, 2, SkTileMode::kClamp)); canvas->drawCircle(x, y, radius, paint); return surface->makeImageSnapshot(); }
sk_sp<SkSpecialImage> SkOffsetImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint srcOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &srcOffset)); if (!input) { return nullptr; } SkIPoint vec = map_offset_vector(ctx.ctm(), fOffset); if (!this->cropRectIsSet()) { offset->fX = Sk32_sat_add(srcOffset.fX, vec.fX); offset->fY = Sk32_sat_add(srcOffset.fY, vec.fY); return input; } else { SkIRect bounds; SkIRect srcBounds = SkIRect::MakeWH(input->width(), input->height()); srcBounds.offset(srcOffset); if (!this->applyCropRect(ctx, srcBounds, &bounds)) { return nullptr; } sk_sp<SkSpecialSurface> surf(source->makeSurface(ctx.outputProperties(), bounds.size())); if (!surf) { return nullptr; } SkCanvas* canvas = surf->getCanvas(); SkASSERT(canvas); // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075) canvas->clear(0x0); SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); canvas->translate(SkIntToScalar(srcOffset.fX - bounds.fLeft), SkIntToScalar(srcOffset.fY - bounds.fTop)); input->draw(canvas, vec.fX, vec.fY, &paint); offset->fX = bounds.fLeft; offset->fY = bounds.fTop; return surf->makeImageSnapshot(); } }
// Return a larger (newWidth x newHeight) copy of 'src' with black padding // around it. static sk_sp<SkSpecialImage> pad_image(SkSpecialImage* src, int newWidth, int newHeight, int offX, int offY) { SkImageInfo info = SkImageInfo::MakeN32Premul(newWidth, newHeight); sk_sp<SkSpecialSurface> surf(src->makeSurface(info)); if (!surf) { return nullptr; } SkCanvas* canvas = surf->getCanvas(); SkASSERT(canvas); canvas->clear(0x0); src->draw(canvas, offX, offY, nullptr); return surf->makeImageSnapshot(); }
void draw_child(skiatest::Reporter* reporter, const sk_gpu_test::ContextInfo& childInfo, const GrBackendTexture& backendTexture, const GrBackendSemaphore& semaphore) { childInfo.testContext()->makeCurrent(); const SkImageInfo childII = SkImageInfo::Make(CHILD_W, CHILD_H, kRGBA_8888_SkColorType, kPremul_SkAlphaType); GrContext* childCtx = childInfo.grContext(); sk_sp<SkSurface> childSurface(SkSurface::MakeRenderTarget(childCtx, SkBudgeted::kNo, childII, 0, kTopLeft_GrSurfaceOrigin, nullptr)); sk_sp<SkImage> childImage = SkImage::MakeFromTexture(childCtx, backendTexture, kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr, nullptr, nullptr); SkCanvas* childCanvas = childSurface->getCanvas(); childCanvas->clear(SK_ColorRED); childSurface->wait(1, &semaphore); childCanvas->drawImage(childImage, CHILD_W/2, 0); SkPaint paint; paint.setColor(SK_ColorGREEN); SkIRect rect = SkIRect::MakeLTRB(0, CHILD_H/2, CHILD_W, CHILD_H); childCanvas->drawIRect(rect, paint); // read pixels SkBitmap bitmap; bitmap.allocPixels(childII); childSurface->readPixels(bitmap, 0, 0); check_pixels(reporter, bitmap); }
void draw(SkCanvas* ) { SkImageInfo info = SkImageInfo::MakeN32Premul(3, 3); const size_t size = info.computeMinByteSize(); SkAutoTMalloc<SkPMColor> storage(size); SkPMColor* pixels = storage.get(); sk_sp<SkSurface> surface(SkSurface::MakeRasterDirect(info, pixels, info.minRowBytes())); SkCanvas* canvas = surface->getCanvas(); canvas->clear(SK_ColorWHITE); SkPMColor pmWhite = pixels[0]; SkPaint paint; canvas->drawPoint(1, 1, paint); canvas->flush(); // ensure that point was drawn for (int y = 0; y < info.height(); ++y) { for (int x = 0; x < info.width(); ++x) { SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x'); } SkDebugf("\n"); } }
/** * Test that for Jpeg files that use the JFIF colorspace, they are * directly embedded into the PDF (without re-encoding) when that * makes sense. */ DEF_TEST(PDFJpegEmbedTest, r) { const char test[] = "PDFJpegEmbedTest"; SkAutoTUnref<SkData> mandrillData( load_resource(r, test, "mandrill_512_q075.jpg")); SkAutoTUnref<SkData> cmykData(load_resource(r, test, "CMYK.jpg")); if (!mandrillData || !cmykData) { return; } SkDynamicMemoryWStream pdf; SkAutoTUnref<SkDocument> document(SkDocument::CreatePDF(&pdf)); SkCanvas* canvas = document->beginPage(642, 1028); canvas->clear(SK_ColorLTGRAY); SkBitmap bm1(bitmap_from_data(mandrillData)); canvas->drawBitmap(bm1, 65.0, 0.0, NULL); SkBitmap bm2(bitmap_from_data(cmykData)); canvas->drawBitmap(bm2, 0.0, 512.0, NULL); canvas->flush(); document->endPage(); document->close(); SkAutoTUnref<SkData> pdfData(pdf.copyToData()); SkASSERT(pdfData); pdf.reset(); // Test disabled, waiting on resolution to http://skbug.com/3180 // REPORTER_ASSERT(r, is_subset_of(mandrillData, pdfData)); // This JPEG uses a nonstandard colorspace - it can not be // embedded into the PDF directly. REPORTER_ASSERT(r, !is_subset_of(cmykData, pdfData)); // The following is for debugging purposes only. const char* outputPath = getenv("SKIA_TESTS_PDF_JPEG_EMBED_OUTPUT_PATH"); if (outputPath) { SkFILEWStream output(outputPath); if (output.isValid()) { output.write(pdfData->data(), pdfData->size()); } } }
DEF_TEST(Picture_preserveCullRect, r) { SkPictureRecorder recorder; SkCanvas* c = recorder.beginRecording(SkRect::MakeLTRB(1, 2, 3, 4)); c->clear(SK_ColorCYAN); sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture()); SkDynamicMemoryWStream wstream; picture->serialize(&wstream); SkAutoTDelete<SkStream> rstream(wstream.detachAsStream()); sk_sp<SkPicture> deserializedPicture(SkPicture::MakeFromStream(rstream)); REPORTER_ASSERT(r, deserializedPicture != nullptr); REPORTER_ASSERT(r, deserializedPicture->cullRect().left() == 1); REPORTER_ASSERT(r, deserializedPicture->cullRect().top() == 2); REPORTER_ASSERT(r, deserializedPicture->cullRect().right() == 3); REPORTER_ASSERT(r, deserializedPicture->cullRect().bottom() == 4); }
static sk_sp<SkImage> make_img() { const SkImageInfo info = SkImageInfo::MakeN32Premul(WIDTH_HEIGHT, WIDTH_HEIGHT); sk_sp<SkSurface> surf(SkSurface::MakeRaster(info)); SkCanvas* canvas = surf->getCanvas(); canvas->clear(0x0); SkPaint paint; paint.setColor(SK_ColorBLUE); for (float pos = 0; pos < WIDTH_HEIGHT; pos += 16) { canvas->drawLine(0, pos, SkIntToScalar(WIDTH_HEIGHT), pos, paint); canvas->drawLine(pos, 0, pos, SkIntToScalar(WIDTH_HEIGHT), paint); } return surf->makeImageSnapshot(); }
sk_sp<SkSpecialImage> SkColorFilterImageFilter::onFilterImage(SkSpecialImage* source, const Context& ctx, SkIPoint* offset) const { SkIPoint inputOffset = SkIPoint::Make(0, 0); sk_sp<SkSpecialImage> input(this->filterInput(0, source, ctx, &inputOffset)); if (!input) { return nullptr; } SkIRect bounds; const SkIRect inputBounds = SkIRect::MakeXYWH(inputOffset.fX, inputOffset.fY, input->width(), input->height()); if (!this->applyCropRect(ctx, inputBounds, &bounds)) { return nullptr; } SkImageInfo info = SkImageInfo::MakeN32(bounds.width(), bounds.height(), kPremul_SkAlphaType); sk_sp<SkSpecialSurface> surf(source->makeSurface(info)); if (!surf) { return nullptr; } SkCanvas* canvas = surf->getCanvas(); SkASSERT(canvas); // TODO: it seems like this clear shouldn't be necessary (see skbug.com/5075) canvas->clear(0x0); SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); paint.setColorFilter(fColorFilter); input->draw(canvas, SkIntToScalar(inputOffset.fX - bounds.fLeft), SkIntToScalar(inputOffset.fY - bounds.fTop), &paint); offset->fX = bounds.fLeft; offset->fY = bounds.fTop; return surf->makeImageSnapshot(); }
static sk_sp<SkImage> MakeAtlas(SkCanvas* caller, const SkRect& target) { SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100); auto surface(sk_tool_utils::makeSurface(caller, info)); SkCanvas* canvas = surface->getCanvas(); // draw red everywhere, but we don't expect to see it in the draw, testing the notion // that drawAtlas draws a subset-region of the atlas. canvas->clear(SK_ColorRED); SkPaint paint; paint.setBlendMode(SkBlendMode::kClear); SkRect r(target); r.inset(-1, -1); // zero out a place (with a 1-pixel border) to land our drawing. canvas->drawRect(r, paint); paint.setBlendMode(SkBlendMode::kSrcOver); paint.setColor(SK_ColorBLUE); paint.setAntiAlias(true); canvas->drawOval(target, paint); return surface->makeImageSnapshot(); }
static void make_bitmap(SkBitmap* bitmap, GrContext* ctx, SkIRect* center) { SkDevice* dev; SkCanvas canvas; const int kFixed = 28; const int kStretchy = 8; const int kSize = 2*kFixed + kStretchy; #if SK_SUPPORT_GPU if (ctx) { dev = new SkGpuDevice(ctx, SkBitmap::kARGB_8888_Config, kSize, kSize); *bitmap = dev->accessBitmap(false); } else #endif { bitmap->setConfig(SkBitmap::kARGB_8888_Config, kSize, kSize); bitmap->allocPixels(); dev = new SkDevice(*bitmap); } canvas.setDevice(dev)->unref(); canvas.clear(0); SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize)); const SkScalar strokeWidth = SkIntToScalar(6); const SkScalar radius = SkIntToScalar(kFixed) - strokeWidth/2; center->setXYWH(kFixed, kFixed, kStretchy, kStretchy); SkPaint paint; paint.setAntiAlias(true); paint.setColor(0xFFFF0000); canvas.drawRoundRect(r, radius, radius, paint); r.setXYWH(SkIntToScalar(kFixed), 0, SkIntToScalar(kStretchy), SkIntToScalar(kSize)); paint.setColor(0x8800FF00); canvas.drawRect(r, paint); r.setXYWH(0, SkIntToScalar(kFixed), SkIntToScalar(kSize), SkIntToScalar(kStretchy)); paint.setColor(0x880000FF); canvas.drawRect(r, paint); }