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