void draw(SkCanvas* canvas) { SkImageInfo info = SkImageInfo::MakeN32Premul(2, 2); const size_t size = info.computeMinByteSize(); SkAutoTMalloc<SkPMColor> storage(size); SkPMColor* pixels = storage.get(); SkBitmap bitmap; bitmap.setInfo(info); bitmap.setPixels(pixels); bitmap.eraseColor(SK_ColorRED); canvas->scale(50, 50); canvas->rotate(8); canvas->drawBitmap(bitmap, 2, 0); }
void draw(SkCanvas* ) { SkImageInfo info = SkImageInfo::MakeN32Premul(3, 3); const size_t size = info.computeMinByteSize(); SkAutoTMalloc<SkPMColor> storage(size); SkPMColor* pixels = storage.get(); sk_sp<SkSurface> surface(SkSurface::MakeRasterDirect(info, pixels, info.minRowBytes())); SkCanvas* canvas = surface->getCanvas(); canvas->clear(SK_ColorWHITE); SkPMColor pmWhite = pixels[0]; SkPaint paint; canvas->drawPoint(1, 1, paint); canvas->flush(); // ensure that point was drawn for (int y = 0; y < info.height(); ++y) { for (int x = 0; x < info.width(); ++x) { SkDebugf("%c", *pixels++ == pmWhite ? '-' : 'x'); } SkDebugf("\n"); } }
std::unique_ptr<SkCodec> SkIcoCodec::MakeFromStream(std::unique_ptr<SkStream> stream, Result* result) { // Header size constants constexpr uint32_t kIcoDirectoryBytes = 6; constexpr uint32_t kIcoDirEntryBytes = 16; // Read the directory header std::unique_ptr<uint8_t[]> dirBuffer(new uint8_t[kIcoDirectoryBytes]); if (stream->read(dirBuffer.get(), kIcoDirectoryBytes) != kIcoDirectoryBytes) { SkCodecPrintf("Error: unable to read ico directory header.\n"); *result = kIncompleteInput; return nullptr; } // Process the directory header const uint16_t numImages = get_short(dirBuffer.get(), 4); if (0 == numImages) { SkCodecPrintf("Error: No images embedded in ico.\n"); *result = kInvalidInput; return nullptr; } // This structure is used to represent the vital information about entries // in the directory header. We will obtain this information for each // directory entry. struct Entry { uint32_t offset; uint32_t size; }; SkAutoFree dirEntryBuffer(sk_malloc_canfail(sizeof(Entry) * numImages)); if (!dirEntryBuffer) { SkCodecPrintf("Error: OOM allocating ICO directory for %i images.\n", numImages); *result = kInternalError; return nullptr; } auto* directoryEntries = reinterpret_cast<Entry*>(dirEntryBuffer.get()); // Iterate over directory entries for (uint32_t i = 0; i < numImages; i++) { uint8_t entryBuffer[kIcoDirEntryBytes]; if (stream->read(entryBuffer, kIcoDirEntryBytes) != kIcoDirEntryBytes) { SkCodecPrintf("Error: Dir entries truncated in ico.\n"); *result = kIncompleteInput; return nullptr; } // The directory entry contains information such as width, height, // bits per pixel, and number of colors in the color palette. We will // ignore these fields since they are repeated in the header of the // embedded image. In the event of an inconsistency, we would always // defer to the value in the embedded header anyway. // Specifies the size of the embedded image, including the header uint32_t size = get_int(entryBuffer, 8); // Specifies the offset of the embedded image from the start of file. // It does not indicate the start of the pixel data, but rather the // start of the embedded image header. uint32_t offset = get_int(entryBuffer, 12); // Save the vital fields directoryEntries[i].offset = offset; directoryEntries[i].size = size; } // Default Result, if no valid embedded codecs are found. *result = kInvalidInput; // It is "customary" that the embedded images will be stored in order of // increasing offset. However, the specification does not indicate that // they must be stored in this order, so we will not trust that this is the // case. Here we sort the embedded images by increasing offset. struct EntryLessThan { bool operator() (Entry a, Entry b) const { return a.offset < b.offset; } }; EntryLessThan lessThan; SkTQSort(directoryEntries, &directoryEntries[numImages - 1], lessThan); // Now will construct a candidate codec for each of the embedded images uint32_t bytesRead = kIcoDirectoryBytes + numImages * kIcoDirEntryBytes; std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> codecs( new SkTArray<std::unique_ptr<SkCodec>, true>(numImages)); for (uint32_t i = 0; i < numImages; i++) { uint32_t offset = directoryEntries[i].offset; uint32_t size = directoryEntries[i].size; // Ensure that the offset is valid if (offset < bytesRead) { SkCodecPrintf("Warning: invalid ico offset.\n"); continue; } // If we cannot skip, assume we have reached the end of the stream and // stop trying to make codecs if (stream->skip(offset - bytesRead) != offset - bytesRead) { SkCodecPrintf("Warning: could not skip to ico offset.\n"); break; } bytesRead = offset; // Create a new stream for the embedded codec SkAutoFree buffer(sk_malloc_canfail(size)); if (!buffer) { SkCodecPrintf("Warning: OOM trying to create embedded stream.\n"); break; } if (stream->read(buffer.get(), size) != size) { SkCodecPrintf("Warning: could not create embedded stream.\n"); *result = kIncompleteInput; break; } sk_sp<SkData> data(SkData::MakeFromMalloc(buffer.release(), size)); auto embeddedStream = SkMemoryStream::Make(data); bytesRead += size; // Check if the embedded codec is bmp or png and create the codec std::unique_ptr<SkCodec> codec; Result dummyResult; if (SkPngCodec::IsPng((const char*) data->bytes(), data->size())) { codec = SkPngCodec::MakeFromStream(std::move(embeddedStream), &dummyResult); } else { codec = SkBmpCodec::MakeFromIco(std::move(embeddedStream), &dummyResult); } // Save a valid codec if (nullptr != codec) { codecs->push_back().reset(codec.release()); } } // Recognize if there are no valid codecs if (0 == codecs->count()) { SkCodecPrintf("Error: could not find any valid embedded ico codecs.\n"); return nullptr; } // Use the largest codec as a "suggestion" for image info size_t maxSize = 0; int maxIndex = 0; for (int i = 0; i < codecs->count(); i++) { SkImageInfo info = codecs->operator[](i)->getInfo(); size_t size = info.computeMinByteSize(); if (size > maxSize) { maxSize = size; maxIndex = i; } } auto maxInfo = codecs->operator[](maxIndex)->getEncodedInfo().copy(); *result = kSuccess; // The original stream is no longer needed, because the embedded codecs own their // own streams. return std::unique_ptr<SkCodec>(new SkIcoCodec(std::move(maxInfo), codecs.release())); }