SkPixmapDraw.cpp (3311B)
1 /* 2 * Copyright 2023 Google LLC 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 * This file contains implementations of SkPixmap methods which require the CPU backend. 8 */ 9 10 #include "include/core/SkAlphaType.h" 11 #include "include/core/SkBitmap.h" 12 #include "include/core/SkBlendMode.h" 13 #include "include/core/SkCanvas.h" 14 #include "include/core/SkImageInfo.h" 15 #include "include/core/SkMatrix.h" 16 #include "include/core/SkPaint.h" 17 #include "include/core/SkPixmap.h" 18 #include "include/core/SkRect.h" 19 #include "include/core/SkRefCnt.h" 20 #include "include/core/SkShader.h" 21 #include "include/core/SkSurface.h" 22 #include "include/core/SkTileMode.h" 23 #include "src/shaders/SkImageShader.h" 24 25 #include <utility> 26 27 struct SkSamplingOptions; 28 29 bool SkPixmap::scalePixels(const SkPixmap& actualDst, const SkSamplingOptions& sampling) const { 30 // We may need to tweak how we interpret these just a little below, so we make copies. 31 SkPixmap src = *this, 32 dst = actualDst; 33 34 // Can't do anthing with empty src or dst 35 if (src.width() <= 0 || src.height() <= 0 || 36 dst.width() <= 0 || dst.height() <= 0) { 37 return false; 38 } 39 40 // no scaling involved? 41 if (src.width() == dst.width() && src.height() == dst.height()) { 42 return src.readPixels(dst); 43 } 44 45 // If src and dst are both unpremul, we'll fake the source out to appear as if premul, 46 // and mark the destination as opaque. This odd combination allows us to scale unpremul 47 // pixels without ever premultiplying them (perhaps losing information in the color channels). 48 // This is an idiosyncratic feature of scalePixels(), and is tested by scalepixels_unpremul GM. 49 bool clampAsIfUnpremul = false; 50 if (src.alphaType() == kUnpremul_SkAlphaType && 51 dst.alphaType() == kUnpremul_SkAlphaType) { 52 src.reset(src.info().makeAlphaType(kPremul_SkAlphaType), src.addr(), src.rowBytes()); 53 dst.reset(dst.info().makeAlphaType(kOpaque_SkAlphaType), dst.addr(), dst.rowBytes()); 54 55 // We'll need to tell the image shader to clamp to [0,1] instead of the 56 // usual [0,a] when using a bicubic scaling (kHigh_SkFilterQuality). 57 clampAsIfUnpremul = true; 58 } 59 60 SkBitmap bitmap; 61 if (!bitmap.installPixels(src)) { 62 return false; 63 } 64 bitmap.setImmutable(); // Don't copy when we create an image. 65 66 SkMatrix scale = SkMatrix::RectToRectOrIdentity(SkRect::Make(src.bounds()), 67 SkRect::Make(dst.bounds())); 68 69 sk_sp<SkShader> shader = SkImageShader::Make(bitmap.asImage(), 70 SkTileMode::kClamp, 71 SkTileMode::kClamp, 72 sampling, 73 &scale, 74 clampAsIfUnpremul); 75 76 sk_sp<SkSurface> surface = 77 SkSurfaces::WrapPixels(dst.info(), dst.writable_addr(), dst.rowBytes()); 78 if (!shader || !surface) { 79 return false; 80 } 81 82 SkPaint paint; 83 paint.setBlendMode(SkBlendMode::kSrc); 84 paint.setShader(std::move(shader)); 85 surface->getCanvas()->drawPaint(paint); 86 return true; 87 }