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