/* * Copyright 2023 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkAlphaType.h" #include "include/core/SkBitmap.h" #include "include/core/SkColorType.h" #include "include/core/SkData.h" #include "include/core/SkImage.h" #include "include/core/SkImageInfo.h" #include "include/core/SkPixmap.h" #include "include/core/SkRefCnt.h" #include "include/private/base/SkMath.h" #include "src/core/SkCompressedDataUtils.h" #include "src/core/SkImageFilterTypes.h" #include "src/core/SkImageFilter_Base.h" #include "src/core/SkImagePriv.h" #include "src/image/SkImage_Base.h" #include "src/image/SkImage_Raster.h" #include #include #include class SkImageFilter; struct SkIPoint; struct SkIRect; enum class SkTextureCompressionType; static bool valid_args(const SkImageInfo& info, size_t rowBytes, size_t* minSize) { const int maxDimension = SK_MaxS32 >> 2; // TODO(mtklein): eliminate anything here that setInfo() has already checked. SkBitmap b; if (!b.setInfo(info, rowBytes)) { return false; } if (info.width() <= 0 || info.height() <= 0) { return false; } if (info.width() > maxDimension || info.height() > maxDimension) { return false; } if ((unsigned)info.colorType() > (unsigned)kLastEnum_SkColorType) { return false; } if ((unsigned)info.alphaType() > (unsigned)kLastEnum_SkAlphaType) { return false; } if (kUnknown_SkColorType == info.colorType()) { return false; } if (!info.validRowBytes(rowBytes)) { return false; } size_t size = info.computeByteSize(rowBytes); if (SkImageInfo::ByteSizeOverflowed(size)) { return false; } if (minSize) { *minSize = size; } return true; } namespace SkImages { sk_sp RasterFromBitmap(const SkBitmap& bm) { if (!bm.pixelRef()) { return nullptr; } return SkMakeImageFromRasterBitmap(bm, kIfMutable_SkCopyPixelsMode); } sk_sp RasterFromPixmapCopy(const SkPixmap& pmap) { return MakeRasterCopyPriv(pmap, kNeedNewImageUniqueID); } sk_sp RasterFromData(const SkImageInfo& info, sk_sp data, size_t rowBytes) { size_t size; if (!valid_args(info, rowBytes, &size) || !data) { return nullptr; } // did they give us enough data? if (data->size() < size) { return nullptr; } return sk_make_sp(info, std::move(data), rowBytes); } sk_sp MakeWithFilter(sk_sp src, const SkImageFilter* filter, const SkIRect& subset, const SkIRect& clipBounds, SkIRect* outSubset, SkIPoint* offset) { if (!src || !filter) { return nullptr; } sk_sp backend = skif::MakeRasterBackend({}, src->colorType()); return as_IFB(filter)->makeImageWithFilter(std::move(backend), std::move(src), subset, clipBounds, outSubset, offset); } // TODO: this could be improved to decode and make use of the mipmap // levels potentially present in the compressed data. For now, any // mipmap levels are discarded. sk_sp RasterFromCompressedTextureData(sk_sp data, int width, int height, SkTextureCompressionType type) { size_t expectedSize = SkCompressedFormatDataSize(type, {width, height}, false); if (!data || data->size() < expectedSize) { return nullptr; } SkAlphaType at = SkTextureCompressionTypeIsOpaque(type) ? kOpaque_SkAlphaType : kPremul_SkAlphaType; SkImageInfo ii = SkImageInfo::MakeN32(width, height, at); if (!valid_args(ii, ii.minRowBytes(), nullptr)) { return nullptr; } SkBitmap bitmap; if (!bitmap.tryAllocPixels(ii)) { return nullptr; } if (!SkDecompress(std::move(data), {width, height}, type, &bitmap)) { return nullptr; } bitmap.setImmutable(); return RasterFromBitmap(bitmap); } sk_sp RasterFromPixmap(const SkPixmap& pmap, RasterReleaseProc proc, ReleaseContext ctx) { size_t size; if (!valid_args(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) { return nullptr; } sk_sp data(SkData::MakeWithProc(pmap.addr(), size, proc, ctx)); return sk_make_sp(pmap.info(), std::move(data), pmap.rowBytes()); } } // namespace SkImages sk_sp MakeRasterCopyPriv(const SkPixmap& pmap, uint32_t id) { size_t size; if (!valid_args(pmap.info(), pmap.rowBytes(), &size) || !pmap.addr()) { return nullptr; } // Here we actually make a copy of the caller's pixel data sk_sp data(SkData::MakeWithCopy(pmap.addr(), size)); return sk_make_sp(pmap.info(), std::move(data), pmap.rowBytes(), id); }