1 /* 2 * Copyright 2012 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 "SkBitmapCache.h" 10 #include "SkCanvas.h" 11 #include "SkData.h" 12 #include "SkImageEncoder.h" 13 #include "SkImageFilter.h" 14 #include "SkImageFilterCache.h" 15 #include "SkImageGenerator.h" 16 #include "SkImagePriv.h" 17 #include "SkImageShader.h" 18 #include "SkImage_Base.h" 19 #include "SkNextID.h" 20 #include "SkPicture.h" 21 #include "SkPixelRef.h" 22 #include "SkReadPixelsRec.h" 23 #include "SkSpecialImage.h" 24 #include "SkString.h" 25 #include "SkSurface.h" 26 27 #if SK_SUPPORT_GPU 28 #include "GrTexture.h" 29 #include "GrContext.h" 30 #include "SkImage_Gpu.h" 31 #endif 32 33 SkImage::SkImage(int width, int height, uint32_t uniqueID) 34 : fWidth(width) 35 , fHeight(height) 36 , fUniqueID(kNeedNewImageUniqueID == uniqueID ? SkNextID::ImageID() : uniqueID) 37 { 38 SkASSERT(width > 0); 39 SkASSERT(height > 0); 40 } 41 42 bool SkImage::peekPixels(SkPixmap* pm) const { 43 SkPixmap tmp; 44 if (!pm) { 45 pm = &tmp; 46 } 47 return as_IB(this)->onPeekPixels(pm); 48 } 49 50 bool SkImage::readPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes, 51 int srcX, int srcY, CachingHint chint) const { 52 return as_IB(this)->onReadPixels(dstInfo, dstPixels, dstRowBytes, srcX, srcY, chint); 53 } 54 55 bool SkImage::scalePixels(const SkPixmap& dst, SkFilterQuality quality, CachingHint chint) const { 56 if (this->width() == dst.width() && this->height() == dst.height()) { 57 return this->readPixels(dst, 0, 0, chint); 58 } 59 60 // Idea: If/when SkImageGenerator supports a native-scaling API (where the generator itself 61 // can scale more efficiently) we should take advantage of it here. 62 // 63 SkBitmap bm; 64 if (as_IB(this)->getROPixels(&bm, dst.info().colorSpace(), chint)) { 65 SkPixmap pmap; 66 // Note: By calling the pixmap scaler, we never cache the final result, so the chint 67 // is (currently) only being applied to the getROPixels. If we get a request to 68 // also attempt to cache the final (scaled) result, we would add that logic here. 69 // 70 return bm.peekPixels(&pmap) && pmap.scalePixels(dst, quality); 71 } 72 return false; 73 } 74 75 /////////////////////////////////////////////////////////////////////////////////////////////////// 76 77 SkAlphaType SkImage::alphaType() const { 78 return as_IB(this)->onAlphaType(); 79 } 80 81 SkColorSpace* SkImage::colorSpace() const { 82 return as_IB(this)->onImageInfo().colorSpace(); 83 } 84 85 sk_sp<SkColorSpace> SkImage::refColorSpace() const { 86 return as_IB(this)->onImageInfo().refColorSpace(); 87 } 88 89 sk_sp<SkShader> SkImage::makeShader(SkShader::TileMode tileX, SkShader::TileMode tileY, 90 const SkMatrix* localMatrix) const { 91 return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tileX, tileY, localMatrix); 92 } 93 94 sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const { 95 SkBitmap bm; 96 SkColorSpace* legacyColorSpace = nullptr; 97 if (as_IB(this)->getROPixels(&bm, legacyColorSpace)) { 98 return SkEncodeBitmap(bm, type, quality); 99 } 100 return nullptr; 101 } 102 103 sk_sp<SkData> SkImage::encodeToData() const { 104 if (auto encoded = this->refEncodedData()) { 105 return encoded; 106 } 107 108 SkBitmap bm; 109 SkPixmap pmap; 110 SkColorSpace* legacyColorSpace = nullptr; 111 if (as_IB(this)->getROPixels(&bm, legacyColorSpace) && bm.peekPixels(&pmap)) { 112 return SkEncodePixmap(pmap, SkEncodedImageFormat::kPNG, 100); 113 } 114 return nullptr; 115 } 116 117 sk_sp<SkData> SkImage::refEncodedData() const { 118 return sk_sp<SkData>(as_IB(this)->onRefEncoded()); 119 } 120 121 sk_sp<SkImage> SkImage::MakeFromEncoded(sk_sp<SkData> encoded, const SkIRect* subset) { 122 if (nullptr == encoded || 0 == encoded->size()) { 123 return nullptr; 124 } 125 return SkImage::MakeFromGenerator(SkImageGenerator::MakeFromEncoded(encoded), subset); 126 } 127 128 /////////////////////////////////////////////////////////////////////////////////////////////////// 129 130 const char* SkImage::toString(SkString* str) const { 131 str->appendf("image: (id:%d (%d, %d) %s)", this->uniqueID(), this->width(), this->height(), 132 this->isOpaque() ? "opaque" : ""); 133 return str->c_str(); 134 } 135 136 sk_sp<SkImage> SkImage::makeSubset(const SkIRect& subset) const { 137 if (subset.isEmpty()) { 138 return nullptr; 139 } 140 141 const SkIRect bounds = SkIRect::MakeWH(this->width(), this->height()); 142 if (!bounds.contains(subset)) { 143 return nullptr; 144 } 145 146 // optimization : return self if the subset == our bounds 147 if (bounds == subset) { 148 return sk_ref_sp(const_cast<SkImage*>(this)); 149 } 150 return as_IB(this)->onMakeSubset(subset); 151 } 152 153 #if SK_SUPPORT_GPU 154 155 GrTexture* SkImage::getTexture() const { 156 return as_IB(this)->onGetTexture(); 157 } 158 159 bool SkImage::isTextureBacked() const { return SkToBool(as_IB(this)->peekProxy()); } 160 161 GrBackendObject SkImage::getTextureHandle(bool flushPendingGrContextIO, 162 GrSurfaceOrigin* origin) const { 163 return as_IB(this)->onGetTextureHandle(flushPendingGrContextIO, origin); 164 } 165 166 bool SkImage::isValid(GrContext* context) const { 167 if (context && context->abandoned()) { 168 return false; 169 } 170 return as_IB(this)->onIsValid(context); 171 } 172 173 #else 174 175 GrTexture* SkImage::getTexture() const { return nullptr; } 176 177 bool SkImage::isTextureBacked() const { return false; } 178 179 GrBackendObject SkImage::getTextureHandle(bool, GrSurfaceOrigin*) const { return 0; } 180 181 bool SkImage::isValid(GrContext* context) const { 182 if (context) { 183 return false; 184 } 185 return as_IB(this)->onIsValid(context); 186 } 187 188 #endif 189 190 /////////////////////////////////////////////////////////////////////////////// 191 192 SkImage_Base::SkImage_Base(int width, int height, uint32_t uniqueID) 193 : INHERITED(width, height, uniqueID) 194 , fAddedToCache(false) 195 {} 196 197 SkImage_Base::~SkImage_Base() { 198 if (fAddedToCache.load()) { 199 SkNotifyBitmapGenIDIsStale(this->uniqueID()); 200 } 201 } 202 203 bool SkImage::readPixels(const SkPixmap& pmap, int srcX, int srcY, CachingHint chint) const { 204 return this->readPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes(), srcX, srcY, chint); 205 } 206 207 /////////////////////////////////////////////////////////////////////////////////////////////////// 208 209 sk_sp<SkImage> SkImage::MakeFromBitmap(const SkBitmap& bm) { 210 SkPixelRef* pr = bm.pixelRef(); 211 if (nullptr == pr) { 212 return nullptr; 213 } 214 215 return SkMakeImageFromRasterBitmap(bm, kIfMutable_SkCopyPixelsMode); 216 } 217 218 bool SkImage::asLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { 219 return as_IB(this)->onAsLegacyBitmap(bitmap, mode); 220 } 221 222 bool SkImage_Base::onAsLegacyBitmap(SkBitmap* bitmap, LegacyBitmapMode mode) const { 223 // As the base-class, all we can do is make a copy (regardless of mode). 224 // Subclasses that want to be more optimal should override. 225 SkImageInfo info = this->onImageInfo().makeColorType(kN32_SkColorType).makeColorSpace(nullptr); 226 if (!bitmap->tryAllocPixels(info)) { 227 return false; 228 } 229 if (!this->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0)) { 230 bitmap->reset(); 231 return false; 232 } 233 234 if (kRO_LegacyBitmapMode == mode) { 235 bitmap->setImmutable(); 236 } 237 return true; 238 } 239 240 sk_sp<SkImage> SkImage::MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions, 241 const SkMatrix* matrix, const SkPaint* paint, 242 BitDepth bitDepth, sk_sp<SkColorSpace> colorSpace) { 243 return MakeFromGenerator(SkImageGenerator::MakeFromPicture(dimensions, std::move(picture), 244 matrix, paint, bitDepth, 245 std::move(colorSpace))); 246 } 247 248 sk_sp<SkImage> SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRect& subset, 249 const SkIRect& clipBounds, SkIRect* outSubset, 250 SkIPoint* offset) const { 251 if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) { 252 return nullptr; 253 } 254 SkColorSpace* colorSpace = as_IB(this)->onImageInfo().colorSpace(); 255 sk_sp<SkSpecialImage> srcSpecialImage = SkSpecialImage::MakeFromImage( 256 subset, sk_ref_sp(const_cast<SkImage*>(this)), colorSpace); 257 if (!srcSpecialImage) { 258 return nullptr; 259 } 260 261 sk_sp<SkImageFilterCache> cache( 262 SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize)); 263 SkImageFilter::OutputProperties outputProperties(colorSpace); 264 SkImageFilter::Context context(SkMatrix::I(), clipBounds, cache.get(), outputProperties); 265 266 sk_sp<SkSpecialImage> result = filter->filterImage(srcSpecialImage.get(), context, offset); 267 if (!result) { 268 return nullptr; 269 } 270 271 *outSubset = SkIRect::MakeWH(result->width(), result->height()); 272 if (!outSubset->intersect(clipBounds.makeOffset(-offset->x(), -offset->y()))) { 273 return nullptr; 274 } 275 offset->fX += outSubset->x(); 276 offset->fY += outSubset->y(); 277 278 // Note that here we're returning the special image's entire backing store, loose padding 279 // and all! 280 return result->asImage(); 281 } 282 283 bool SkImage::isLazyGenerated() const { 284 return as_IB(this)->onIsLazyGenerated(); 285 } 286 287 bool SkImage::isAlphaOnly() const { 288 return as_IB(this)->onImageInfo().colorType() == kAlpha_8_SkColorType; 289 } 290 291 sk_sp<SkImage> SkImage::makeColorSpace(sk_sp<SkColorSpace> target, 292 SkTransferFunctionBehavior premulBehavior) const { 293 SkColorSpaceTransferFn fn; 294 if (!target || !target->isNumericalTransferFn(&fn)) { 295 return nullptr; 296 } 297 298 // No need to create a new image if: 299 // (1) The color spaces are equal. 300 // (2) The color type is kAlpha8. 301 if (SkColorSpace::Equals(this->colorSpace(), target.get()) || 302 kAlpha_8_SkColorType == as_IB(this)->onImageInfo().colorType()) { 303 return sk_ref_sp(const_cast<SkImage*>(this)); 304 } 305 306 SkColorType targetColorType = kN32_SkColorType; 307 if (SkTransferFunctionBehavior::kRespect == premulBehavior && target->gammaIsLinear()) { 308 targetColorType = kRGBA_F16_SkColorType; 309 } 310 311 // TODO: We might consider making this a deferred conversion? 312 return as_IB(this)->onMakeColorSpace(std::move(target), targetColorType, premulBehavior); 313 } 314 315 sk_sp<SkImage> SkImage::makeNonTextureImage() const { 316 if (!this->isTextureBacked()) { 317 return sk_ref_sp(const_cast<SkImage*>(this)); 318 } 319 return this->makeRasterImage(); 320 } 321 322 sk_sp<SkImage> SkImage::makeRasterImage() const { 323 SkPixmap pm; 324 if (this->peekPixels(&pm)) { 325 return sk_ref_sp(const_cast<SkImage*>(this)); 326 } 327 328 const SkImageInfo info = as_IB(this)->onImageInfo(); 329 const size_t rowBytes = info.minRowBytes(); 330 size_t size = info.computeByteSize(rowBytes); 331 if (SkImageInfo::ByteSizeOverflowed(size)) { 332 return nullptr; 333 } 334 335 sk_sp<SkData> data = SkData::MakeUninitialized(size); 336 pm = { info.makeColorSpace(nullptr), data->writable_data(), info.minRowBytes() }; 337 if (!this->readPixels(pm, 0, 0)) { 338 return nullptr; 339 } 340 341 return SkImage::MakeRasterData(info, std::move(data), rowBytes); 342 } 343 344 ////////////////////////////////////////////////////////////////////////////////////// 345 346 #if !SK_SUPPORT_GPU 347 348 sk_sp<SkImage> MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMipLevel texels[], 349 int mipLevelCount, SkBudgeted, SkDestinationSurfaceColorMode) { 350 return nullptr; 351 } 352 353 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, 354 const GrBackendTexture& tex, GrSurfaceOrigin origin, 355 SkAlphaType at, sk_sp<SkColorSpace> cs, 356 TextureReleaseProc releaseP, ReleaseContext releaseC) { 357 return nullptr; 358 } 359 360 size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy&, 361 const DeferredTextureImageUsageParams[], 362 int paramCnt, void* buffer, 363 SkColorSpace* dstColorSpace, 364 SkColorType dstColorType) const { 365 return 0; 366 } 367 368 sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void*, 369 SkBudgeted) { 370 return nullptr; 371 } 372 373 sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, 374 const GrBackendTexture& tex, GrSurfaceOrigin origin, 375 SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs, 376 TextureReleaseProc releaseP, ReleaseContext releaseC) { 377 return nullptr; 378 } 379 380 bool SkImage::MakeBackendTextureFromSkImage(GrContext*, 381 sk_sp<SkImage>, 382 GrBackendTexture*, 383 BackendTextureReleaseProc*) { 384 return false; 385 } 386 387 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, 388 const GrBackendTexture& tex, GrSurfaceOrigin origin, 389 SkAlphaType at, sk_sp<SkColorSpace> cs) { 390 return nullptr; 391 } 392 393 sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, 394 const GrBackendTexture& tex, GrSurfaceOrigin origin, 395 SkColorType ct, SkAlphaType at, 396 sk_sp<SkColorSpace> cs) { 397 return nullptr; 398 } 399 400 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace space, 401 const GrBackendObject yuvTextureHandles[3], 402 const SkISize yuvSizes[3], 403 GrSurfaceOrigin origin, 404 sk_sp<SkColorSpace> imageColorSpace) { 405 return nullptr; 406 } 407 408 sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace space, 409 const GrBackendTexture yuvTextureHandles[3], 410 const SkISize yuvSizes[3], 411 GrSurfaceOrigin origin, 412 sk_sp<SkColorSpace> imageColorSpace) { 413 return nullptr; 414 } 415 416 sk_sp<SkImage> SkImage::makeTextureImage(GrContext*, SkColorSpace* dstColorSpace) const { 417 return nullptr; 418 } 419 420 #endif 421 422 /////////////////////////////////////////////////////////////////////////////////////////////////// 423 424 sk_sp<SkImage> MakeTextureFromMipMap(GrContext*, const SkImageInfo&, const GrMipLevel texels[], 425 int mipLevelCount, SkBudgeted) { 426 return nullptr; 427 } 428 429 /////////////////////////////////////////////////////////////////////////////////////////////////// 430 431 bool SkImage_pinAsTexture(const SkImage* image, GrContext* ctx) { 432 SkASSERT(image); 433 SkASSERT(ctx); 434 return as_IB(image)->onPinAsTexture(ctx); 435 } 436 437 void SkImage_unpinAsTexture(const SkImage* image, GrContext* ctx) { 438 SkASSERT(image); 439 SkASSERT(ctx); 440 as_IB(image)->onUnpinAsTexture(ctx); 441 } 442 443 /////////////////////////////////////////////////////////////////////////////////////////////////// 444 445 sk_sp<SkImage> SkImageMakeRasterCopyAndAssignColorSpace(const SkImage* src, 446 SkColorSpace* colorSpace) { 447 // Read the pixels out of the source image, with no conversion 448 SkImageInfo info = as_IB(src)->onImageInfo(); 449 if (kUnknown_SkColorType == info.colorType()) { 450 SkDEBUGFAIL("Unexpected color type"); 451 return nullptr; 452 } 453 454 size_t rowBytes = info.minRowBytes(); 455 size_t size = info.computeByteSize(rowBytes); 456 if (SkImageInfo::ByteSizeOverflowed(size)) { 457 return nullptr; 458 } 459 auto data = SkData::MakeUninitialized(size); 460 if (!data) { 461 return nullptr; 462 } 463 464 SkPixmap pm(info, data->writable_data(), rowBytes); 465 if (!src->readPixels(pm, 0, 0, SkImage::kDisallow_CachingHint)) { 466 return nullptr; 467 } 468 469 // Wrap them in a new image with a different color space 470 return SkImage::MakeRasterData(info.makeColorSpace(sk_ref_sp(colorSpace)), data, rowBytes); 471 } 472