1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkImage_Base.h" 9 #include "SkCanvas.h" 10 #include "SkColorSpaceXformCanvas.h" 11 #include "SkMakeUnique.h" 12 #include "SkMatrix.h" 13 #include "SkPaint.h" 14 #include "SkPicture.h" 15 #include "SkPictureImageGenerator.h" 16 #include "SkSurface.h" 17 18 std::unique_ptr<SkImageGenerator> 19 SkPictureImageGenerator::Make(const SkISize& size, sk_sp<SkPicture> picture, const SkMatrix* matrix, 20 const SkPaint* paint, SkImage::BitDepth bitDepth, 21 sk_sp<SkColorSpace> colorSpace) { 22 if (!picture || size.isEmpty()) { 23 return nullptr; 24 } 25 26 if (SkImage::BitDepth::kF16 == bitDepth && (!colorSpace || !colorSpace->gammaIsLinear())) { 27 return nullptr; 28 } 29 30 if (colorSpace && (!colorSpace->gammaCloseToSRGB() && !colorSpace->gammaIsLinear())) { 31 return nullptr; 32 } 33 34 SkColorType colorType = kN32_SkColorType; 35 if (SkImage::BitDepth::kF16 == bitDepth) { 36 colorType = kRGBA_F16_SkColorType; 37 } 38 39 SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType, 40 kPremul_SkAlphaType, std::move(colorSpace)); 41 return std::unique_ptr<SkImageGenerator>( 42 new SkPictureImageGenerator(info, std::move(picture), matrix, paint)); 43 } 44 45 SkPictureImageGenerator::SkPictureImageGenerator(const SkImageInfo& info, sk_sp<SkPicture> picture, 46 const SkMatrix* matrix, const SkPaint* paint) 47 : INHERITED(info) 48 , fPicture(std::move(picture)) { 49 50 if (matrix) { 51 fMatrix = *matrix; 52 } else { 53 fMatrix.reset(); 54 } 55 56 if (paint) { 57 fPaint.set(*paint); 58 } 59 } 60 61 bool SkPictureImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, 62 const Options& opts) { 63 bool useXformCanvas = 64 SkTransferFunctionBehavior::kIgnore == opts.fBehavior && info.colorSpace(); 65 66 SkImageInfo canvasInfo = useXformCanvas ? info.makeColorSpace(nullptr) : info; 67 std::unique_ptr<SkCanvas> canvas = SkCanvas::MakeRasterDirect(canvasInfo, pixels, rowBytes); 68 if (!canvas) { 69 return false; 70 } 71 canvas->clear(0); 72 73 SkCanvas* canvasPtr = canvas.get(); 74 std::unique_ptr<SkCanvas> xformCanvas; 75 if (useXformCanvas) { 76 xformCanvas = SkCreateColorSpaceXformCanvas(canvas.get(), info.refColorSpace()); 77 canvasPtr = xformCanvas.get(); 78 } 79 80 canvasPtr->drawPicture(fPicture, &fMatrix, fPaint.getMaybeNull()); 81 return true; 82 } 83 84 /////////////////////////////////////////////////////////////////////////////////////////////////// 85 86 std::unique_ptr<SkImageGenerator> 87 SkImageGenerator::MakeFromPicture(const SkISize& size, sk_sp<SkPicture> picture, 88 const SkMatrix* matrix, const SkPaint* paint, 89 SkImage::BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace) { 90 // Check this here (rather than in SkPictureImageGenerator::Create) so SkPictureShader 91 // has a private entry point to create legacy picture backed images. 92 if (!colorSpace) { 93 return nullptr; 94 } 95 96 return SkPictureImageGenerator::Make(size, std::move(picture), matrix, paint, bitDepth, 97 std::move(colorSpace)); 98 } 99 100 /////////////////////////////////////////////////////////////////////////////////////////////////// 101 102 #if SK_SUPPORT_GPU 103 sk_sp<GrTextureProxy> SkPictureImageGenerator::onGenerateTexture( 104 GrContext* ctx, const SkImageInfo& info, const SkIPoint& origin, 105 SkTransferFunctionBehavior behavior) { 106 SkASSERT(ctx); 107 bool useXformCanvas = SkTransferFunctionBehavior::kIgnore == behavior && info.colorSpace(); 108 109 // 110 // TODO: respect the usage, by possibly creating a different (pow2) surface 111 // 112 SkImageInfo surfaceInfo = useXformCanvas ? info.makeColorSpace(nullptr) : info; 113 sk_sp<SkSurface> surface(SkSurface::MakeRenderTarget(ctx, SkBudgeted::kYes, surfaceInfo)); 114 if (!surface) { 115 return nullptr; 116 } 117 118 SkCanvas* canvas = surface->getCanvas(); 119 std::unique_ptr<SkCanvas> xformCanvas; 120 if (useXformCanvas) { 121 xformCanvas = SkCreateColorSpaceXformCanvas(canvas, info.refColorSpace()); 122 canvas = xformCanvas.get(); 123 } 124 125 SkMatrix matrix = fMatrix; 126 matrix.postTranslate(-origin.x(), -origin.y()); 127 canvas->clear(0); // does NewRenderTarget promise to do this for us? 128 canvas->drawPicture(fPicture.get(), &matrix, fPaint.getMaybeNull()); 129 sk_sp<SkImage> image(surface->makeImageSnapshot()); 130 if (!image) { 131 return nullptr; 132 } 133 return as_IB(image)->asTextureProxyRef(); 134 } 135 #endif 136