/* * High quality is implemented by performing up-right scale-only filtering and then * using bilerp for any remaining transformations. */ bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmap& origBitmap) { if (fQuality != kHigh_SkFilterQuality) { return false; } // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap // to a valid bitmap. If we succeed, we will set this to Low instead. fQuality = kMedium_SkFilterQuality; if (kN32_SkColorType != origBitmap.colorType() || !cache_size_okay(origBitmap, fInvMatrix) || fInvMatrix.hasPerspective()) { return false; // can't handle the reqeust } SkScalar invScaleX = fInvMatrix.getScaleX(); SkScalar invScaleY = fInvMatrix.getScaleY(); if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) { SkSize scale; if (!fInvMatrix.decomposeScale(&scale)) { return false; } invScaleX = scale.width(); invScaleY = scale.height(); } if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) { return false; // no need for HQ } SkScalar trueDestWidth = origBitmap.width() / invScaleX; SkScalar trueDestHeight = origBitmap.height() / invScaleY; SkScalar roundedDestWidth = SkScalarRoundToScalar(trueDestWidth); SkScalar roundedDestHeight = SkScalarRoundToScalar(trueDestHeight); if (!SkBitmapCache::Find(origBitmap, roundedDestWidth, roundedDestHeight, &fResultBitmap)) { SkAutoPixmapUnlock src; if (!origBitmap.requestLock(&src)) { return false; } if (!SkBitmapScaler::Resize(&fResultBitmap, src.pixmap(), SkBitmapScaler::RESIZE_BEST, roundedDestWidth, roundedDestHeight, SkResourceCache::GetAllocator())) { return false; // we failed to create fScaledBitmap } SkASSERT(fResultBitmap.getPixels()); fResultBitmap.setImmutable(); SkBitmapCache::Add(origBitmap, roundedDestWidth, roundedDestHeight, fResultBitmap); } SkASSERT(fResultBitmap.getPixels()); fInvMatrix.postScale(roundedDestWidth / origBitmap.width(), roundedDestHeight / origBitmap.height()); fQuality = kLow_SkFilterQuality; return true; }
void SkBinaryWriteBuffer::writeBitmap(const SkBitmap& bitmap) { // Record the width and height. This way if readBitmap fails a dummy bitmap can be drawn at the // right size. this->writeInt(bitmap.width()); this->writeInt(bitmap.height()); // Record information about the bitmap in one of two ways, in order of priority: // 1. If there is a function for encoding bitmaps, use it to write an encoded version of the // bitmap. After writing a boolean value of false, signifying that a heap was not used, write // the size of the encoded data. A non-zero size signifies that encoded data was written. // 2. Call SkBitmap::flatten. After writing a boolean value of false, signifying that a heap was // not used, write a zero to signify that the data was not encoded. // Write a bool to indicate that we did not use an SkBitmapHeap. That feature is deprecated. this->writeBool(false); SkPixelRef* pixelRef = bitmap.pixelRef(); if (pixelRef) { // see if the pixelref already has an encoded version SkAutoDataUnref existingData(pixelRef->refEncodedData()); if (existingData.get() != nullptr) { // Assumes that if the client did not set a serializer, they are // happy to get the encoded data. if (!fPixelSerializer || fPixelSerializer->useEncodedData(existingData->data(), existingData->size())) { write_encoded_bitmap(this, existingData, bitmap.pixelRefOrigin()); return; } } // see if the caller wants to manually encode SkAutoPixmapUnlock result; if (fPixelSerializer && bitmap.requestLock(&result)) { SkAutoDataUnref data(fPixelSerializer->encode(result.pixmap())); if (data.get() != nullptr) { // if we have to "encode" the bitmap, then we assume there is no // offset to share, since we are effectively creating a new pixelref write_encoded_bitmap(this, data, SkIPoint::Make(0, 0)); return; } } } this->writeUInt(0); // signal raw pixels SkBitmap::WriteRawPixels(this, bitmap); }
SkData* SkImage::encode(SkPixelSerializer* serializer) const { DefaultSerializer defaultSerializer; SkPixelSerializer* effectiveSerializer = serializer ? serializer : &defaultSerializer; SkAutoTUnref<SkData> encoded(this->refEncoded()); if (encoded && effectiveSerializer->useEncodedData(encoded->data(), encoded->size())) { return encoded.detach(); } SkBitmap bm; SkAutoPixmapUnlock apu; if (as_IB(this)->getROPixels(&bm) && bm.requestLock(&apu)) { const SkPixmap& pmap = apu.pixmap(); return effectiveSerializer->encodePixels(pmap.info(), pmap.addr(), pmap.rowBytes()); } return nullptr; }
sk_sp<SkPDFObject> SkPDFCreateBitmapObject(sk_sp<SkImage> image, SkPixelSerializer* pixelSerializer) { SkASSERT(image); sk_sp<SkData> data(image->refEncoded()); SkJFIFInfo info; if (data && SkIsJFIF(data.get(), &info) && (!pixelSerializer || pixelSerializer->useEncodedData(data->data(), data->size()))) { // If there is a SkPixelSerializer, give it a chance to // re-encode the JPEG with more compression by returning false // from useEncodedData. bool yuv = info.fType == SkJFIFInfo::kYCbCr; if (info.fSize == image->dimensions()) { // Sanity check. // hold on to data, not image. #ifdef SK_PDF_IMAGE_STATS gJpegImageObjects.fetch_add(1); #endif return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv); } } if (pixelSerializer) { SkBitmap bm; SkAutoPixmapUnlock apu; if (as_IB(image.get())->getROPixels(&bm) && bm.requestLock(&apu)) { data.reset(pixelSerializer->encode(apu.pixmap())); if (data && SkIsJFIF(data.get(), &info)) { bool yuv = info.fType == SkJFIFInfo::kYCbCr; if (info.fSize == image->dimensions()) { // Sanity check. return sk_make_sp<PDFJpegBitmap>(info.fSize, data.get(), yuv); } } } } sk_sp<SkPDFObject> smask; if (!image_compute_is_opaque(image.get())) { smask = sk_make_sp<PDFAlphaBitmap>(image); } #ifdef SK_PDF_IMAGE_STATS gRegularImageObjects.fetch_add(1); #endif return sk_make_sp<PDFDefaultBitmap>(std::move(image), std::move(smask)); }
SkData* SkImage::encode(SkPixelSerializer* serializer) const { SkAutoTUnref<SkPixelSerializer> defaultSerializer; SkPixelSerializer* effectiveSerializer = serializer; if (!effectiveSerializer) { defaultSerializer.reset(SkImageEncoder::CreatePixelSerializer()); SkASSERT(defaultSerializer.get()); effectiveSerializer = defaultSerializer.get(); } SkAutoTUnref<SkData> encoded(this->refEncoded()); if (encoded && effectiveSerializer->useEncodedData(encoded->data(), encoded->size())) { return encoded.detach(); } SkBitmap bm; SkAutoPixmapUnlock apu; if (as_IB(this)->getROPixels(&bm) && bm.requestLock(&apu)) { return effectiveSerializer->encode(apu.pixmap()); } return nullptr; }
/* * High quality is implemented by performing up-right scale-only filtering and then * using bilerp for any remaining transformations. */ bool SkDefaultBitmapControllerState::processHQRequest(const SkBitmapProvider& provider) { if (fQuality != kHigh_SkFilterQuality) { return false; } // Our default return state is to downgrade the request to Medium, w/ or w/o setting fBitmap // to a valid bitmap. If we succeed, we will set this to Low instead. fQuality = kMedium_SkFilterQuality; if (kN32_SkColorType != provider.info().colorType() || !cache_size_okay(provider, fInvMatrix) || fInvMatrix.hasPerspective()) { return false; // can't handle the reqeust } SkScalar invScaleX = fInvMatrix.getScaleX(); SkScalar invScaleY = fInvMatrix.getScaleY(); if (fInvMatrix.getType() & SkMatrix::kAffine_Mask) { SkSize scale; if (!fInvMatrix.decomposeScale(&scale)) { return false; } invScaleX = scale.width(); invScaleY = scale.height(); } if (SkScalarNearlyEqual(invScaleX, 1) && SkScalarNearlyEqual(invScaleY, 1)) { return false; // no need for HQ } #ifndef SK_SUPPORT_LEGACY_HQ_DOWNSAMPLING if (invScaleX > 1 || invScaleY > 1) { return false; // only use HQ when upsampling } #endif const int dstW = SkScalarRoundToScalar(provider.width() / invScaleX); const int dstH = SkScalarRoundToScalar(provider.height() / invScaleY); const SkBitmapCacheDesc desc = provider.makeCacheDesc(dstW, dstH); if (!SkBitmapCache::FindWH(desc, &fResultBitmap)) { SkBitmap orig; if (!provider.asBitmap(&orig)) { return false; } SkAutoPixmapUnlock src; if (!orig.requestLock(&src)) { return false; } if (!SkBitmapScaler::Resize(&fResultBitmap, src.pixmap(), kHQ_RESIZE_METHOD, dstW, dstH, SkResourceCache::GetAllocator())) { return false; // we failed to create fScaledBitmap } SkASSERT(fResultBitmap.getPixels()); fResultBitmap.setImmutable(); if (!provider.isVolatile()) { if (SkBitmapCache::AddWH(desc, fResultBitmap)) { provider.notifyAddedToCache(); } } } SkASSERT(fResultBitmap.getPixels()); fInvMatrix.postScale(SkIntToScalar(dstW) / provider.width(), SkIntToScalar(dstH) / provider.height()); fQuality = kLow_SkFilterQuality; return true; }
void SkWriteBuffer::writeBitmap(const SkBitmap& bitmap) { // Record the width and height. This way if readBitmap fails a dummy bitmap can be drawn at the // right size. this->writeInt(bitmap.width()); this->writeInt(bitmap.height()); // Record information about the bitmap in one of three ways, in order of priority: // 1. If there is an SkBitmapHeap, store it in the heap. The client can avoid serializing the // bitmap entirely or serialize it later as desired. A boolean value of true will be written // to the stream to signify that a heap was used. // 2. If there is a function for encoding bitmaps, use it to write an encoded version of the // bitmap. After writing a boolean value of false, signifying that a heap was not used, write // the size of the encoded data. A non-zero size signifies that encoded data was written. // 3. Call SkBitmap::flatten. After writing a boolean value of false, signifying that a heap was // not used, write a zero to signify that the data was not encoded. bool useBitmapHeap = fBitmapHeap != NULL; // Write a bool: true if the SkBitmapHeap is to be used, in which case the reader must use an // SkBitmapHeapReader to read the SkBitmap. False if the bitmap was serialized another way. this->writeBool(useBitmapHeap); if (useBitmapHeap) { SkASSERT(NULL == fPixelSerializer); int32_t slot = fBitmapHeap->insert(bitmap); fWriter.write32(slot); // crbug.com/155875 // The generation ID is not required information. We write it to prevent collisions // in SkFlatDictionary. It is possible to get a collision when a previously // unflattened (i.e. stale) instance of a similar flattenable is in the dictionary // and the instance currently being written is re-using the same slot from the // bitmap heap. fWriter.write32(bitmap.getGenerationID()); return; } SkPixelRef* pixelRef = bitmap.pixelRef(); if (pixelRef) { // see if the pixelref already has an encoded version SkAutoDataUnref existingData(pixelRef->refEncodedData()); if (existingData.get() != NULL) { // Assumes that if the client did not set a serializer, they are // happy to get the encoded data. if (!fPixelSerializer || fPixelSerializer->useEncodedData(existingData->data(), existingData->size())) { write_encoded_bitmap(this, existingData, bitmap.pixelRefOrigin()); return; } } // see if the caller wants to manually encode SkAutoPixmapUnlock result; if (fPixelSerializer && bitmap.requestLock(&result)) { const SkPixmap& pmap = result.pixmap(); SkASSERT(NULL == fBitmapHeap); SkAutoDataUnref data(fPixelSerializer->encodePixels(pmap.info(), pmap.addr(), pmap.rowBytes())); if (data.get() != NULL) { // if we have to "encode" the bitmap, then we assume there is no // offset to share, since we are effectively creating a new pixelref write_encoded_bitmap(this, data, SkIPoint::Make(0, 0)); return; } } } this->writeUInt(0); // signal raw pixels SkBitmap::WriteRawPixels(this, bitmap); }