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 "SkBitmap.h" 9 #include "SkCanvas.h" 10 #include "SkColorData.h" 11 #include "SkConvertPixels.h" 12 #include "SkData.h" 13 #include "SkImageInfoPriv.h" 14 #include "SkImageShader.h" 15 #include "SkHalf.h" 16 #include "SkMask.h" 17 #include "SkNx.h" 18 #include "SkPM4f.h" 19 #include "SkPixmapPriv.h" 20 #include "SkReadPixelsRec.h" 21 #include "SkSurface.h" 22 #include "SkTemplates.h" 23 #include "SkUnPreMultiply.h" 24 #include "SkUtils.h" 25 26 ///////////////////////////////////////////////////////////////////////////////////////////////// 27 28 void SkPixmap::reset() { 29 fPixels = nullptr; 30 fRowBytes = 0; 31 fInfo = SkImageInfo::MakeUnknown(); 32 } 33 34 void SkPixmap::reset(const SkImageInfo& info, const void* addr, size_t rowBytes) { 35 if (addr) { 36 SkASSERT(info.validRowBytes(rowBytes)); 37 } 38 fPixels = addr; 39 fRowBytes = rowBytes; 40 fInfo = info; 41 } 42 43 bool SkPixmap::reset(const SkMask& src) { 44 if (SkMask::kA8_Format == src.fFormat) { 45 this->reset(SkImageInfo::MakeA8(src.fBounds.width(), src.fBounds.height()), 46 src.fImage, src.fRowBytes); 47 return true; 48 } 49 this->reset(); 50 return false; 51 } 52 53 void SkPixmap::setColorSpace(sk_sp<SkColorSpace> cs) { 54 fInfo = fInfo.makeColorSpace(std::move(cs)); 55 } 56 57 bool SkPixmap::extractSubset(SkPixmap* result, const SkIRect& subset) const { 58 SkIRect srcRect, r; 59 srcRect.set(0, 0, this->width(), this->height()); 60 if (!r.intersect(srcRect, subset)) { 61 return false; // r is empty (i.e. no intersection) 62 } 63 64 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have 65 // exited above. 66 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width())); 67 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height())); 68 69 const void* pixels = nullptr; 70 if (fPixels) { 71 const size_t bpp = fInfo.bytesPerPixel(); 72 pixels = (const uint8_t*)fPixels + r.fTop * fRowBytes + r.fLeft * bpp; 73 } 74 result->reset(fInfo.makeWH(r.width(), r.height()), pixels, fRowBytes); 75 return true; 76 } 77 78 bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int x, int y, 79 SkTransferFunctionBehavior behavior) const { 80 if (!SkImageInfoValidConversion(dstInfo, fInfo)) { 81 return false; 82 } 83 84 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, x, y); 85 if (!rec.trim(fInfo.width(), fInfo.height())) { 86 return false; 87 } 88 89 const void* srcPixels = this->addr(rec.fX, rec.fY); 90 const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height()); 91 SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(), 92 nullptr, behavior); 93 return true; 94 } 95 96 static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) { 97 unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) | 98 (SkR32To4444(r) << SK_R4444_SHIFT) | 99 (SkG32To4444(g) << SK_G4444_SHIFT) | 100 (SkB32To4444(b) << SK_B4444_SHIFT); 101 return SkToU16(pixel); 102 } 103 104 bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const { 105 if (nullptr == fPixels) { 106 return false; 107 } 108 SkIRect area; 109 if (!area.intersect(this->bounds(), inArea)) { 110 return false; 111 } 112 113 U8CPU a = SkColorGetA(color); 114 U8CPU r = SkColorGetR(color); 115 U8CPU g = SkColorGetG(color); 116 U8CPU b = SkColorGetB(color); 117 118 int height = area.height(); 119 const int width = area.width(); 120 const int rowBytes = this->rowBytes(); 121 122 if (color == 0 123 && width == this->rowBytesAsPixels() 124 && inArea == this->bounds()) { 125 // All formats represent SkColor(0) as byte 0. 126 memset(this->writable_addr(), 0, (int64_t)height * rowBytes); 127 return true; 128 } 129 130 switch (this->colorType()) { 131 case kGray_8_SkColorType: { 132 if (255 != a) { 133 r = SkMulDiv255Round(r, a); 134 g = SkMulDiv255Round(g, a); 135 b = SkMulDiv255Round(b, a); 136 } 137 int gray = SkComputeLuminance(r, g, b); 138 uint8_t* p = this->writable_addr8(area.fLeft, area.fTop); 139 while (--height >= 0) { 140 memset(p, gray, width); 141 p += rowBytes; 142 } 143 break; 144 } 145 case kAlpha_8_SkColorType: { 146 uint8_t* p = this->writable_addr8(area.fLeft, area.fTop); 147 while (--height >= 0) { 148 memset(p, a, width); 149 p += rowBytes; 150 } 151 break; 152 } 153 case kARGB_4444_SkColorType: 154 case kRGB_565_SkColorType: { 155 uint16_t* p = this->writable_addr16(area.fLeft, area.fTop); 156 uint16_t v; 157 158 // make rgb premultiplied 159 if (255 != a) { 160 r = SkMulDiv255Round(r, a); 161 g = SkMulDiv255Round(g, a); 162 b = SkMulDiv255Round(b, a); 163 } 164 165 if (kARGB_4444_SkColorType == this->colorType()) { 166 v = pack_8888_to_4444(a, r, g, b); 167 } else { 168 v = SkPackRGB16(r >> (8 - SK_R16_BITS), 169 g >> (8 - SK_G16_BITS), 170 b >> (8 - SK_B16_BITS)); 171 } 172 while (--height >= 0) { 173 sk_memset16(p, v, width); 174 p = (uint16_t*)((char*)p + rowBytes); 175 } 176 break; 177 } 178 case kBGRA_8888_SkColorType: 179 case kRGBA_8888_SkColorType: { 180 uint32_t* p = this->writable_addr32(area.fLeft, area.fTop); 181 182 if (255 != a && kPremul_SkAlphaType == this->alphaType()) { 183 r = SkMulDiv255Round(r, a); 184 g = SkMulDiv255Round(g, a); 185 b = SkMulDiv255Round(b, a); 186 } 187 uint32_t v = kRGBA_8888_SkColorType == this->colorType() 188 ? SkPackARGB_as_RGBA(a, r, g, b) 189 : SkPackARGB_as_BGRA(a, r, g, b); 190 191 while (--height >= 0) { 192 sk_memset32(p, v, width); 193 p = (uint32_t*)((char*)p + rowBytes); 194 } 195 break; 196 } 197 case kRGBA_F16_SkColorType: 198 // The colorspace is unspecified, so assume linear just like getColor(). 199 this->erase(SkColor4f{(1 / 255.0f) * r, 200 (1 / 255.0f) * g, 201 (1 / 255.0f) * b, 202 (1 / 255.0f) * a}, &area); 203 break; 204 default: 205 return false; // no change, so don't call notifyPixelsChanged() 206 } 207 return true; 208 } 209 210 bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const { 211 SkPixmap pm; 212 if (subset) { 213 if (!this->extractSubset(&pm, *subset)) { 214 return false; 215 } 216 } else { 217 pm = *this; 218 } 219 220 const SkColor4f color = origColor.pin(); 221 222 if (kRGBA_F16_SkColorType != pm.colorType()) { 223 return pm.erase(color.toSkColor()); 224 } 225 226 const uint64_t half4 = color.premul().toF16(); 227 for (int y = 0; y < pm.height(); ++y) { 228 sk_memset64(pm.writable_addr64(0, y), half4, pm.width()); 229 } 230 return true; 231 } 232 233 bool SkPixmap::scalePixels(const SkPixmap& actualDst, SkFilterQuality quality) const { 234 // We may need to tweak how we interpret these just a little below, so we make copies. 235 SkPixmap src = *this, 236 dst = actualDst; 237 238 // Can't do anthing with empty src or dst 239 if (src.width() <= 0 || src.height() <= 0 || 240 dst.width() <= 0 || dst.height() <= 0) { 241 return false; 242 } 243 244 // no scaling involved? 245 if (src.width() == dst.width() && src.height() == dst.height()) { 246 return src.readPixels(dst); 247 } 248 249 // If src and dst are both unpremul, we'll fake them out to appear as if premul. 250 bool clampAsIfUnpremul = false; 251 if (src.alphaType() == kUnpremul_SkAlphaType && 252 dst.alphaType() == kUnpremul_SkAlphaType) { 253 src.reset(src.info().makeAlphaType(kPremul_SkAlphaType), src.addr(), src.rowBytes()); 254 dst.reset(dst.info().makeAlphaType(kPremul_SkAlphaType), dst.addr(), dst.rowBytes()); 255 256 // In turn, we'll need to tell the image shader to clamp to [0,1] instead 257 // of the usual [0,a] when using a bicubic scaling (kHigh_SkFilterQuality) 258 // or a gamut transformation. 259 clampAsIfUnpremul = true; 260 } 261 262 SkBitmap bitmap; 263 if (!bitmap.installPixels(src)) { 264 return false; 265 } 266 bitmap.setImmutable(); // Don't copy when we create an image. 267 bitmap.setIsVolatile(true); // Disable any caching. 268 269 SkMatrix scale = SkMatrix::MakeRectToRect(SkRect::Make(src.bounds()), 270 SkRect::Make(dst.bounds()), 271 SkMatrix::kFill_ScaleToFit); 272 273 // We'll create a shader to do this draw so we have control over the bicubic clamp. 274 sk_sp<SkShader> shader = SkImageShader::Make(SkImage::MakeFromBitmap(bitmap), 275 SkShader::kClamp_TileMode, 276 SkShader::kClamp_TileMode, 277 &scale, 278 clampAsIfUnpremul); 279 280 sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(dst.info(), 281 dst.writable_addr(), 282 dst.rowBytes()); 283 if (!shader || !surface) { 284 return false; 285 } 286 287 SkPaint paint; 288 paint.setBlendMode(SkBlendMode::kSrc); 289 paint.setFilterQuality(quality); 290 paint.setShader(std::move(shader)); 291 surface->getCanvas()->drawPaint(paint); 292 return true; 293 } 294 295 ////////////////////////////////////////////////////////////////////////////////////////////////// 296 297 SkColor SkPixmap::getColor(int x, int y) const { 298 SkASSERT(this->addr()); 299 SkASSERT((unsigned)x < (unsigned)this->width()); 300 SkASSERT((unsigned)y < (unsigned)this->height()); 301 302 const bool needsUnpremul = (kPremul_SkAlphaType == fInfo.alphaType()); 303 auto toColor = [needsUnpremul](uint32_t maybePremulColor) { 304 return needsUnpremul ? SkUnPreMultiply::PMColorToColor(maybePremulColor) 305 : SkSwizzle_BGRA_to_PMColor(maybePremulColor); 306 }; 307 308 switch (this->colorType()) { 309 case kGray_8_SkColorType: { 310 uint8_t value = *this->addr8(x, y); 311 return SkColorSetRGB(value, value, value); 312 } 313 case kAlpha_8_SkColorType: { 314 return SkColorSetA(0, *this->addr8(x, y)); 315 } 316 case kRGB_565_SkColorType: { 317 return SkPixel16ToColor(*this->addr16(x, y)); 318 } 319 case kARGB_4444_SkColorType: { 320 uint16_t value = *this->addr16(x, y); 321 SkPMColor c = SkPixel4444ToPixel32(value); 322 return toColor(c); 323 } 324 case kBGRA_8888_SkColorType: { 325 uint32_t value = *this->addr32(x, y); 326 SkPMColor c = SkSwizzle_BGRA_to_PMColor(value); 327 return toColor(c); 328 } 329 case kRGBA_8888_SkColorType: { 330 uint32_t value = *this->addr32(x, y); 331 SkPMColor c = SkSwizzle_RGBA_to_PMColor(value); 332 return toColor(c); 333 } 334 case kRGBA_F16_SkColorType: { 335 const uint64_t* addr = 336 (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x; 337 Sk4f p4 = SkHalfToFloat_finite_ftz(*addr); 338 if (p4[3] && needsUnpremul) { 339 float inva = 1 / p4[3]; 340 p4 = p4 * Sk4f(inva, inva, inva, 1); 341 } 342 SkColor c; 343 SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c); 344 // p4 is RGBA, but we want BGRA, so we need to swap next 345 return SkSwizzle_RB(c); 346 } 347 default: 348 SkDEBUGFAIL(""); 349 return SkColorSetARGB(0, 0, 0, 0); 350 } 351 } 352 353 bool SkPixmap::computeIsOpaque() const { 354 const int height = this->height(); 355 const int width = this->width(); 356 357 switch (this->colorType()) { 358 case kAlpha_8_SkColorType: { 359 unsigned a = 0xFF; 360 for (int y = 0; y < height; ++y) { 361 const uint8_t* row = this->addr8(0, y); 362 for (int x = 0; x < width; ++x) { 363 a &= row[x]; 364 } 365 if (0xFF != a) { 366 return false; 367 } 368 } 369 return true; 370 } break; 371 case kRGB_565_SkColorType: 372 case kGray_8_SkColorType: 373 return true; 374 break; 375 case kARGB_4444_SkColorType: { 376 unsigned c = 0xFFFF; 377 for (int y = 0; y < height; ++y) { 378 const SkPMColor16* row = this->addr16(0, y); 379 for (int x = 0; x < width; ++x) { 380 c &= row[x]; 381 } 382 if (0xF != SkGetPackedA4444(c)) { 383 return false; 384 } 385 } 386 return true; 387 } break; 388 case kBGRA_8888_SkColorType: 389 case kRGBA_8888_SkColorType: { 390 SkPMColor c = (SkPMColor)~0; 391 for (int y = 0; y < height; ++y) { 392 const SkPMColor* row = this->addr32(0, y); 393 for (int x = 0; x < width; ++x) { 394 c &= row[x]; 395 } 396 if (0xFF != SkGetPackedA32(c)) { 397 return false; 398 } 399 } 400 return true; 401 } 402 case kRGBA_F16_SkColorType: { 403 const SkHalf* row = (const SkHalf*)this->addr(); 404 for (int y = 0; y < height; ++y) { 405 for (int x = 0; x < width; ++x) { 406 if (row[4 * x + 3] < SK_Half1) { 407 return false; 408 } 409 } 410 row += this->rowBytes() >> 1; 411 } 412 return true; 413 } 414 default: 415 break; 416 } 417 return false; 418 } 419 420 ////////////////////////////////////////////////////////////////////////////////////////////////// 421 422 static bool draw_orientation(const SkPixmap& dst, const SkPixmap& src, unsigned flags) { 423 auto surf = SkSurface::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes()); 424 if (!surf) { 425 return false; 426 } 427 428 SkBitmap bm; 429 bm.installPixels(src); 430 431 SkMatrix m; 432 m.setIdentity(); 433 434 SkScalar W = SkIntToScalar(src.width()); 435 SkScalar H = SkIntToScalar(src.height()); 436 if (flags & SkPixmapPriv::kSwapXY) { 437 SkMatrix s; 438 s.setAll(0, 1, 0, 1, 0, 0, 0, 0, 1); 439 m.postConcat(s); 440 SkTSwap(W, H); 441 } 442 if (flags & SkPixmapPriv::kMirrorX) { 443 m.postScale(-1, 1); 444 m.postTranslate(W, 0); 445 } 446 if (flags & SkPixmapPriv::kMirrorY) { 447 m.postScale(1, -1); 448 m.postTranslate(0, H); 449 } 450 SkPaint p; 451 p.setBlendMode(SkBlendMode::kSrc); 452 surf->getCanvas()->concat(m); 453 surf->getCanvas()->drawBitmap(bm, 0, 0, &p); 454 return true; 455 } 456 457 bool SkPixmapPriv::Orient(const SkPixmap& dst, const SkPixmap& src, OrientFlags flags) { 458 SkASSERT((flags & ~(kMirrorX | kMirrorY | kSwapXY)) == 0); 459 if (src.colorType() != dst.colorType()) { 460 return false; 461 } 462 // note: we just ignore alphaType and colorSpace for this transformation 463 464 int w = src.width(); 465 int h = src.height(); 466 if (flags & kSwapXY) { 467 SkTSwap(w, h); 468 } 469 if (dst.width() != w || dst.height() != h) { 470 return false; 471 } 472 if (w == 0 || h == 0) { 473 return true; 474 } 475 476 // check for aliasing to self 477 if (src.addr() == dst.addr()) { 478 return flags == 0; 479 } 480 return draw_orientation(dst, src, flags); 481 } 482 483 #define kMirrorX SkPixmapPriv::kMirrorX 484 #define kMirrorY SkPixmapPriv::kMirrorY 485 #define kSwapXY SkPixmapPriv::kSwapXY 486 487 static constexpr uint8_t gOrientationFlags[] = { 488 0, // kTopLeft_SkEncodedOrigin 489 kMirrorX, // kTopRight_SkEncodedOrigin 490 kMirrorX | kMirrorY, // kBottomRight_SkEncodedOrigin 491 kMirrorY, // kBottomLeft_SkEncodedOrigin 492 kSwapXY, // kLeftTop_SkEncodedOrigin 493 kMirrorX | kSwapXY, // kRightTop_SkEncodedOrigin 494 kMirrorX | kMirrorY | kSwapXY, // kRightBottom_SkEncodedOrigin 495 kMirrorY | kSwapXY, // kLeftBottom_SkEncodedOrigin 496 }; 497 498 SkPixmapPriv::OrientFlags SkPixmapPriv::OriginToOrient(SkEncodedOrigin o) { 499 unsigned io = static_cast<int>(o) - 1; 500 SkASSERT(io < SK_ARRAY_COUNT(gOrientationFlags)); 501 return static_cast<SkPixmapPriv::OrientFlags>(gOrientationFlags[io]); 502 } 503 504 bool SkPixmapPriv::ShouldSwapWidthHeight(SkEncodedOrigin o) { 505 return SkToBool(OriginToOrient(o) & kSwapXY); 506 } 507 508 SkImageInfo SkPixmapPriv::SwapWidthHeight(const SkImageInfo& info) { 509 return info.makeWH(info.height(), info.width()); 510 } 511 512