38 const char icoSig[] = {
'\x00',
'\x00',
'\x01',
'\x00' };
39 const char curSig[] = {
'\x00',
'\x00',
'\x02',
'\x00' };
40 return bytesRead >=
sizeof(icoSig) &&
41 (!memcmp(
buffer, icoSig,
sizeof(icoSig)) ||
42 !memcmp(
buffer, curSig,
sizeof(curSig)));
69 constexpr uint32_t kIcoDirectoryBytes = 6;
70 constexpr uint32_t kIcoDirEntryBytes = 16;
73 if (data->size() < kIcoDirectoryBytes) {
74 SkCodecPrintf(
"Error: unable to read ico directory header.\n");
80 const uint16_t numImages =
get_short(data->bytes(), 4);
95 if (!dirEntryBuffer) {
96 SkCodecPrintf(
"Error: OOM allocating ICO directory for %i images.\n",
101 auto* directoryEntries =
reinterpret_cast<Entry*
>(dirEntryBuffer.get());
104 for (uint32_t i = 0; i < numImages; i++) {
105 const uint8_t* entryBuffer = data->bytes() + kIcoDirectoryBytes + i * kIcoDirEntryBytes;
106 if (data->size() < kIcoDirectoryBytes + (i+1) * kIcoDirEntryBytes) {
119 uint32_t size =
get_int(entryBuffer, 8);
127 directoryEntries[i].offset =
offset;
128 directoryEntries[i].size = size;
138 struct EntryLessThan {
139 bool operator() (Entry
a, Entry
b)
const {
140 return a.offset <
b.offset;
143 EntryLessThan lessThan;
144 SkTQSort(directoryEntries, directoryEntries + numImages, lessThan);
147 uint32_t bytesRead = kIcoDirectoryBytes + numImages * kIcoDirEntryBytes;
148 auto codecs = std::make_unique<TArray<std::unique_ptr<SkCodec>>>(numImages);
149 for (uint32_t i = 0; i < numImages; i++) {
150 uint32_t
offset = directoryEntries[i].offset;
151 uint32_t size = directoryEntries[i].size;
161 if (
offset >= data->size()) {
167 if (
offset + size > data->size()) {
168 SkCodecPrintf(
"Warning: could not create embedded stream.\n");
178 std::unique_ptr<SkCodec> codec;
186 if (
nullptr != codec) {
187 codecs->push_back(std::move(codec));
191 if (codecs->empty()) {
192 SkCodecPrintf(
"Error: could not find any valid embedded ico codecs.\n");
199 for (
int i = 0; i < codecs->size(); i++) {
201 size_t size =
info.computeMinByteSize();
203 if (size > maxSize) {
209 auto maxInfo = codecs->at(maxIndex)->getEncodedInfo().copy();
212 return std::unique_ptr<SkCodec>(
217 std::unique_ptr<SkStream> stream,
218 std::unique_ptr<
TArray<std::unique_ptr<SkCodec>>> codecs)
222 , fEmbeddedCodecs(
std::move(codecs))
223 , fCurrCodec(nullptr) {}
234 float desiredSize = desiredScale * origWidth * origHeight;
236 float minError = ((float) (origWidth * origHeight)) - desiredSize + 1.0f;
237 int32_t minIndex = -1;
238 for (int32_t i = 0; i < fEmbeddedCodecs->size(); i++) {
239 auto dimensions = fEmbeddedCodecs->at(i)->dimensions();
243 if (
error < minError) {
250 return fEmbeddedCodecs->at(minIndex)->dimensions();
253int SkIcoCodec::chooseCodec(
const SkISize& requestedSize,
int startIndex) {
257 for (
int i = startIndex; i < fEmbeddedCodecs->size(); i++) {
258 if (fEmbeddedCodecs->at(i)->dimensions() == requestedSize) {
267 return this->chooseCodec(dim, 0) >= 0;
274 void* dst,
size_t dstRowBytes,
290 SkCodec* embeddedCodec = fEmbeddedCodecs->at(index).get();
307 SkCodecPrintf(
"Error: No matching candidate image in ico.\n");
321 SkCodec* embeddedCodec = fEmbeddedCodecs->at(index).get();
324 fCurrCodec = embeddedCodec;
331 SkCodecPrintf(
"Error: No matching candidate image in ico.\n");
354 SkCodec* embeddedCodec = fEmbeddedCodecs->at(index).get();
358 fCurrCodec = embeddedCodec;
385 SkCodecPrintf(
"Error: No matching candidate image in ico.\n");
406 return fCurrCodec->
getSampler(createIfNecessary);
413bool IsIco(
const void* data,
size_t len) {
417std::unique_ptr<SkCodec>
Decode(std::unique_ptr<SkStream> stream,
419 SkCodecs::DecodeContext) {
422 outResult = &resultStorage;
429 SkCodecs::DecodeContext) {
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
static uint32_t get_int(const uint8_t *buffer, uint32_t i)
#define SkCodecPrintf(...)
static uint16_t get_short(const uint8_t *buffer, uint32_t i)
static void * sk_malloc_canfail(size_t size)
#define INHERITED(method,...)
sk_sp< SkData > SkCopyStreamToData(SkStream *stream)
void SkTQSort(T *begin, T *end, const C &lessThan)
static std::unique_ptr< SkCodec > MakeFromIco(std::unique_ptr< SkStream >, Result *)
int getScanlines(void *dst, int countLines, size_t rowBytes)
SkISize dimensions() const
const SkImageInfo & dstInfo() const
virtual SkScanlineOrder onGetScanlineOrder() const
Result startScanlineDecode(const SkImageInfo &dstInfo, const Options *options)
Result getPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, const Options *)
SkScanlineOrder getScanlineOrder() const
virtual SkSampler * getSampler(bool)
Result startIncrementalDecode(const SkImageInfo &dstInfo, void *dst, size_t rowBytes, const Options *)
Result incrementalDecode(int *rowsDecoded=nullptr)
bool skipScanlines(int countLines)
const Options & options() const
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
static sk_sp< SkData > MakeSubset(const SkData *src, size_t offset, size_t length)
Result onStartScanlineDecode(const SkImageInfo &dstInfo, const SkCodec::Options &options) override
SkISize onGetScaledDimensions(float desiredScale) const override
Result onGetPixels(const SkImageInfo &dstInfo, void *dst, size_t dstRowBytes, const Options &, int *) override
Result onIncrementalDecode(int *rowsDecoded) override
SkSampler * getSampler(bool createIfNecessary) override
static bool IsIco(const void *, size_t)
bool onSkipScanlines(int count) override
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, Result *)
Result onStartIncrementalDecode(const SkImageInfo &dstInfo, void *pixels, size_t rowBytes, const SkCodec::Options &) override
SkScanlineOrder onGetScanlineOrder() const override
bool onDimensionsSupported(const SkISize &) override
int onGetScanlines(void *dst, int count, size_t rowBytes) override
static std::unique_ptr< SkMemoryStream > Make(sk_sp< SkData > data)
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, Result *, SkPngChunkReader *=nullptr)
static bool IsPng(const void *, size_t)
virtual size_t getLength() const
virtual const void * getMemoryBase()
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
SK_API bool IsIco(const void *, size_t)
SK_API std::unique_ptr< SkCodec > Decode(std::unique_ptr< SkStream >, SkCodec::Result *, SkCodecs::DecodeContext=nullptr)
std::unique_ptr< void, SkOverloadedFunctionObject< void(void *), sk_free > > UniqueVoidPtr
constexpr int32_t width() const
constexpr int32_t height() const
SkISize dimensions() const