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 "SkColorPriv.h" 11#include "SkConvertPixels.h" 12#include "SkData.h" 13#include "SkImageInfoPriv.h" 14#include "SkHalf.h" 15#include "SkMask.h" 16#include "SkNx.h" 17#include "SkPM4f.h" 18#include "SkPixmap.h" 19#include "SkReadPixelsRec.h" 20#include "SkSurface.h" 21#include "SkUtils.h" 22 23///////////////////////////////////////////////////////////////////////////////////////////////// 24 25void SkPixmap::reset() { 26 fPixels = nullptr; 27 fRowBytes = 0; 28 fInfo = SkImageInfo::MakeUnknown(); 29} 30 31void SkPixmap::reset(const SkImageInfo& info, const void* addr, size_t rowBytes) { 32 if (addr) { 33 SkASSERT(info.validRowBytes(rowBytes)); 34 } 35 fPixels = addr; 36 fRowBytes = rowBytes; 37 fInfo = info; 38} 39 40bool SkPixmap::reset(const SkMask& src) { 41 if (SkMask::kA8_Format == src.fFormat) { 42 this->reset(SkImageInfo::MakeA8(src.fBounds.width(), src.fBounds.height()), 43 src.fImage, src.fRowBytes); 44 return true; 45 } 46 this->reset(); 47 return false; 48} 49 50void SkPixmap::setColorSpace(sk_sp<SkColorSpace> cs) { 51 fInfo = fInfo.makeColorSpace(std::move(cs)); 52} 53 54bool SkPixmap::extractSubset(SkPixmap* result, const SkIRect& subset) const { 55 SkIRect srcRect, r; 56 srcRect.set(0, 0, this->width(), this->height()); 57 if (!r.intersect(srcRect, subset)) { 58 return false; // r is empty (i.e. no intersection) 59 } 60 61 // If the upper left of the rectangle was outside the bounds of this SkBitmap, we should have 62 // exited above. 63 SkASSERT(static_cast<unsigned>(r.fLeft) < static_cast<unsigned>(this->width())); 64 SkASSERT(static_cast<unsigned>(r.fTop) < static_cast<unsigned>(this->height())); 65 66 const void* pixels = nullptr; 67 if (fPixels) { 68 const size_t bpp = fInfo.bytesPerPixel(); 69 pixels = (const uint8_t*)fPixels + r.fTop * fRowBytes + r.fLeft * bpp; 70 } 71 result->reset(fInfo.makeWH(r.width(), r.height()), pixels, fRowBytes); 72 return true; 73} 74 75bool SkPixmap::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB, int x, int y, 76 SkTransferFunctionBehavior behavior) const { 77 if (!SkImageInfoValidConversion(dstInfo, fInfo)) { 78 return false; 79 } 80 81 SkReadPixelsRec rec(dstInfo, dstPixels, dstRB, x, y); 82 if (!rec.trim(fInfo.width(), fInfo.height())) { 83 return false; 84 } 85 86 const void* srcPixels = this->addr(rec.fX, rec.fY); 87 const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height()); 88 SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(), 89 nullptr, behavior); 90 return true; 91} 92 93static uint16_t pack_8888_to_4444(unsigned a, unsigned r, unsigned g, unsigned b) { 94 unsigned pixel = (SkA32To4444(a) << SK_A4444_SHIFT) | 95 (SkR32To4444(r) << SK_R4444_SHIFT) | 96 (SkG32To4444(g) << SK_G4444_SHIFT) | 97 (SkB32To4444(b) << SK_B4444_SHIFT); 98 return SkToU16(pixel); 99} 100 101bool SkPixmap::erase(SkColor color, const SkIRect& inArea) const { 102 if (nullptr == fPixels) { 103 return false; 104 } 105 SkIRect area; 106 if (!area.intersect(this->bounds(), inArea)) { 107 return false; 108 } 109 110 U8CPU a = SkColorGetA(color); 111 U8CPU r = SkColorGetR(color); 112 U8CPU g = SkColorGetG(color); 113 U8CPU b = SkColorGetB(color); 114 115 int height = area.height(); 116 const int width = area.width(); 117 const int rowBytes = this->rowBytes(); 118 119 switch (this->colorType()) { 120 case kGray_8_SkColorType: { 121 if (255 != a) { 122 r = SkMulDiv255Round(r, a); 123 g = SkMulDiv255Round(g, a); 124 b = SkMulDiv255Round(b, a); 125 } 126 int gray = SkComputeLuminance(r, g, b); 127 uint8_t* p = this->writable_addr8(area.fLeft, area.fTop); 128 while (--height >= 0) { 129 memset(p, gray, width); 130 p += rowBytes; 131 } 132 break; 133 } 134 case kAlpha_8_SkColorType: { 135 uint8_t* p = this->writable_addr8(area.fLeft, area.fTop); 136 while (--height >= 0) { 137 memset(p, a, width); 138 p += rowBytes; 139 } 140 break; 141 } 142 case kARGB_4444_SkColorType: 143 case kRGB_565_SkColorType: { 144 uint16_t* p = this->writable_addr16(area.fLeft, area.fTop); 145 uint16_t v; 146 147 // make rgb premultiplied 148 if (255 != a) { 149 r = SkMulDiv255Round(r, a); 150 g = SkMulDiv255Round(g, a); 151 b = SkMulDiv255Round(b, a); 152 } 153 154 if (kARGB_4444_SkColorType == this->colorType()) { 155 v = pack_8888_to_4444(a, r, g, b); 156 } else { 157 v = SkPackRGB16(r >> (8 - SK_R16_BITS), 158 g >> (8 - SK_G16_BITS), 159 b >> (8 - SK_B16_BITS)); 160 } 161 while (--height >= 0) { 162 sk_memset16(p, v, width); 163 p = (uint16_t*)((char*)p + rowBytes); 164 } 165 break; 166 } 167 case kBGRA_8888_SkColorType: 168 case kRGBA_8888_SkColorType: { 169 uint32_t* p = this->writable_addr32(area.fLeft, area.fTop); 170 171 if (255 != a && kPremul_SkAlphaType == this->alphaType()) { 172 r = SkMulDiv255Round(r, a); 173 g = SkMulDiv255Round(g, a); 174 b = SkMulDiv255Round(b, a); 175 } 176 uint32_t v = kRGBA_8888_SkColorType == this->colorType() 177 ? SkPackARGB_as_RGBA(a, r, g, b) 178 : SkPackARGB_as_BGRA(a, r, g, b); 179 180 while (--height >= 0) { 181 sk_memset32(p, v, width); 182 p = (uint32_t*)((char*)p + rowBytes); 183 } 184 break; 185 } 186 case kRGBA_F16_SkColorType: 187 // The colorspace is unspecified, so assume linear just like getColor(). 188 this->erase(SkColor4f{(1 / 255.0f) * r, 189 (1 / 255.0f) * g, 190 (1 / 255.0f) * b, 191 (1 / 255.0f) * a}, &area); 192 break; 193 default: 194 return false; // no change, so don't call notifyPixelsChanged() 195 } 196 return true; 197} 198 199bool SkPixmap::erase(const SkColor4f& origColor, const SkIRect* subset) const { 200 SkPixmap pm; 201 if (subset) { 202 if (!this->extractSubset(&pm, *subset)) { 203 return false; 204 } 205 } else { 206 pm = *this; 207 } 208 209 const SkColor4f color = origColor.pin(); 210 211 if (kRGBA_F16_SkColorType != pm.colorType()) { 212 return pm.erase(color.toSkColor()); 213 } 214 215 const uint64_t half4 = color.premul().toF16(); 216 for (int y = 0; y < pm.height(); ++y) { 217 sk_memset64(pm.writable_addr64(0, y), half4, pm.width()); 218 } 219 return true; 220} 221 222bool SkPixmap::scalePixels(const SkPixmap& dst, SkFilterQuality quality) const { 223 // Can't do anthing with empty src or dst 224 if (this->width() <= 0 || this->height() <= 0 || dst.width() <= 0 || dst.height() <= 0) { 225 return false; 226 } 227 228 // no scaling involved? 229 if (dst.width() == this->width() && dst.height() == this->height()) { 230 return this->readPixels(dst); 231 } 232 233 SkBitmap bitmap; 234 if (!bitmap.installPixels(*this)) { 235 return false; 236 } 237 bitmap.setIsVolatile(true); // so we don't try to cache it 238 239 auto surface(SkSurface::MakeRasterDirect(dst.info(), dst.writable_addr(), dst.rowBytes())); 240 if (!surface) { 241 return false; 242 } 243 244 SkPaint paint; 245 paint.setFilterQuality(quality); 246 paint.setBlendMode(SkBlendMode::kSrc); 247 surface->getCanvas()->drawBitmapRect(bitmap, SkRect::MakeIWH(dst.width(), dst.height()), 248 &paint); 249 return true; 250} 251 252////////////////////////////////////////////////////////////////////////////////////////////////// 253 254SkColor SkPixmap::getColor(int x, int y) const { 255 SkASSERT(this->addr()); 256 SkASSERT((unsigned)x < (unsigned)this->width()); 257 SkASSERT((unsigned)y < (unsigned)this->height()); 258 259 const bool needsUnpremul = (kPremul_SkAlphaType == fInfo.alphaType()); 260 auto toColor = [needsUnpremul](uint32_t maybePremulColor) { 261 return needsUnpremul ? SkUnPreMultiply::PMColorToColor(maybePremulColor) 262 : SkSwizzle_BGRA_to_PMColor(maybePremulColor); 263 }; 264 265 switch (this->colorType()) { 266 case kGray_8_SkColorType: { 267 uint8_t value = *this->addr8(x, y); 268 return SkColorSetRGB(value, value, value); 269 } 270 case kAlpha_8_SkColorType: { 271 return SkColorSetA(0, *this->addr8(x, y)); 272 } 273 case kRGB_565_SkColorType: { 274 return SkPixel16ToColor(*this->addr16(x, y)); 275 } 276 case kARGB_4444_SkColorType: { 277 uint16_t value = *this->addr16(x, y); 278 SkPMColor c = SkPixel4444ToPixel32(value); 279 return toColor(c); 280 } 281 case kBGRA_8888_SkColorType: { 282 uint32_t value = *this->addr32(x, y); 283 SkPMColor c = SkSwizzle_BGRA_to_PMColor(value); 284 return toColor(c); 285 } 286 case kRGBA_8888_SkColorType: { 287 uint32_t value = *this->addr32(x, y); 288 SkPMColor c = SkSwizzle_RGBA_to_PMColor(value); 289 return toColor(c); 290 } 291 case kRGBA_F16_SkColorType: { 292 const uint64_t* addr = 293 (const uint64_t*)fPixels + y * (fRowBytes >> 3) + x; 294 Sk4f p4 = SkHalfToFloat_finite_ftz(*addr); 295 if (p4[3] && needsUnpremul) { 296 float inva = 1 / p4[3]; 297 p4 = p4 * Sk4f(inva, inva, inva, 1); 298 } 299 SkColor c; 300 SkNx_cast<uint8_t>(p4 * Sk4f(255) + Sk4f(0.5f)).store(&c); 301 // p4 is RGBA, but we want BGRA, so we need to swap next 302 return SkSwizzle_RB(c); 303 } 304 default: 305 SkDEBUGFAIL(""); 306 return SkColorSetARGB(0, 0, 0, 0); 307 } 308} 309 310bool SkPixmap::computeIsOpaque() const { 311 const int height = this->height(); 312 const int width = this->width(); 313 314 switch (this->colorType()) { 315 case kAlpha_8_SkColorType: { 316 unsigned a = 0xFF; 317 for (int y = 0; y < height; ++y) { 318 const uint8_t* row = this->addr8(0, y); 319 for (int x = 0; x < width; ++x) { 320 a &= row[x]; 321 } 322 if (0xFF != a) { 323 return false; 324 } 325 } 326 return true; 327 } break; 328 case kRGB_565_SkColorType: 329 case kGray_8_SkColorType: 330 return true; 331 break; 332 case kARGB_4444_SkColorType: { 333 unsigned c = 0xFFFF; 334 for (int y = 0; y < height; ++y) { 335 const SkPMColor16* row = this->addr16(0, y); 336 for (int x = 0; x < width; ++x) { 337 c &= row[x]; 338 } 339 if (0xF != SkGetPackedA4444(c)) { 340 return false; 341 } 342 } 343 return true; 344 } break; 345 case kBGRA_8888_SkColorType: 346 case kRGBA_8888_SkColorType: { 347 SkPMColor c = (SkPMColor)~0; 348 for (int y = 0; y < height; ++y) { 349 const SkPMColor* row = this->addr32(0, y); 350 for (int x = 0; x < width; ++x) { 351 c &= row[x]; 352 } 353 if (0xFF != SkGetPackedA32(c)) { 354 return false; 355 } 356 } 357 return true; 358 } 359 case kRGBA_F16_SkColorType: { 360 const SkHalf* row = (const SkHalf*)this->addr(); 361 for (int y = 0; y < height; ++y) { 362 for (int x = 0; x < width; ++x) { 363 if (row[4 * x + 3] < SK_Half1) { 364 return false; 365 } 366 } 367 row += this->rowBytes() >> 1; 368 } 369 return true; 370 } 371 default: 372 break; 373 } 374 return false; 375} 376