sk_sp<SkColorTable> SkGIFColorMap::buildTable(SkStreamBuffer* streamBuffer, SkColorType colorType, int transparentPixel) const { if (!m_isDefined) return nullptr; const PackColorProc proc = choose_pack_color_proc(false, colorType); if (m_table && proc == m_packColorProc && m_transPixel == transparentPixel) { SkASSERT(transparentPixel == kNotFound || transparentPixel > m_table->count() || m_table->operator[](transparentPixel) == SK_ColorTRANSPARENT); // This SkColorTable has already been built with the same transparent color and // packing proc. Reuse it. return m_table; } m_packColorProc = proc; m_transPixel = transparentPixel; const size_t bytes = m_colors * SK_BYTES_PER_COLORMAP_ENTRY; sk_sp<SkData> rawData(streamBuffer->getDataAtPosition(m_position, bytes)); if (!rawData) { return nullptr; } SkASSERT(m_colors <= SK_MAX_COLORS); const uint8_t* srcColormap = rawData->bytes(); SkPMColor colorStorage[SK_MAX_COLORS]; for (int i = 0; i < m_colors; i++) { if (i == transparentPixel) { colorStorage[i] = SK_ColorTRANSPARENT; } else { colorStorage[i] = proc(255, srcColormap[0], srcColormap[1], srcColormap[2]); } srcColormap += SK_BYTES_PER_COLORMAP_ENTRY; } for (int i = m_colors; i < SK_MAX_COLORS; i++) { colorStorage[i] = SK_ColorTRANSPARENT; } m_table = sk_sp<SkColorTable>(new SkColorTable(colorStorage, SK_MAX_COLORS)); return m_table; }
/* * Process the color table for the bmp input */ bool SkBmpRLECodec::createColorTable(SkColorType dstColorType, int* numColors) { // Allocate memory for color table uint32_t colorBytes = 0; SkPMColor colorTable[256]; if (this->bitsPerPixel() <= 8) { // Inform the caller of the number of colors uint32_t maxColors = 1 << this->bitsPerPixel(); if (nullptr != numColors) { // We set the number of colors to maxColors in order to ensure // safe memory accesses. Otherwise, an invalid pixel could // access memory outside of our color table array. *numColors = maxColors; } // Don't bother reading more than maxColors. const uint32_t numColorsToRead = fNumColors == 0 ? maxColors : SkTMin(fNumColors, maxColors); // Read the color table from the stream colorBytes = numColorsToRead * fBytesPerColor; SkAutoTDeleteArray<uint8_t> cBuffer(new uint8_t[colorBytes]); if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) { SkCodecPrintf("Error: unable to read color table.\n"); return false; } // Fill in the color table PackColorProc packARGB = choose_pack_color_proc(false, dstColorType); uint32_t i = 0; for (; i < numColorsToRead; i++) { uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor); uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1); uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2); colorTable[i] = packARGB(0xFF, red, green, blue); } // To avoid segmentation faults on bad pixel data, fill the end of the // color table with black. This is the same the behavior as the // chromium decoder. for (; i < maxColors; i++) { colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); } // Set the color table fColorTable.reset(new SkColorTable(colorTable, maxColors)); } // Check that we have not read past the pixel array offset if(fOffset < colorBytes) { // This may occur on OS 2.1 and other old versions where the color // table defaults to max size, and the bmp tries to use a smaller // color table. This is invalid, and our decision is to indicate // an error, rather than try to guess the intended size of the // color table. SkCodecPrintf("Error: pixel data offset less than color table size.\n"); return false; } // After reading the color table, skip to the start of the pixel array if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) { SkCodecPrintf("Error: unable to skip to image data.\n"); return false; } // Return true on success return true; }
void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, SkPMColor* inputColorPtr, int* inputColorCount) { // Set up our own color table const uint32_t maxColors = 256; SkPMColor colorPtr[256]; if (NULL != inputColorCount) { // We set the number of colors to maxColors in order to ensure // safe memory accesses. Otherwise, an invalid pixel could // access memory outside of our color table array. *inputColorCount = maxColors; } // Get local color table ColorMapObject* colorMap = fGif->Image.ColorMap; // If there is no local color table, use the global color table if (NULL == colorMap) { colorMap = fGif->SColorMap; } uint32_t colorCount = 0; if (NULL != colorMap) { colorCount = colorMap->ColorCount; // giflib guarantees these properties SkASSERT(colorCount == (unsigned) (1 << (colorMap->BitsPerPixel))); SkASSERT(colorCount <= 256); PackColorProc proc = choose_pack_color_proc(false, dstInfo.colorType()); for (uint32_t i = 0; i < colorCount; i++) { colorPtr[i] = proc(0xFF, colorMap->Colors[i].Red, colorMap->Colors[i].Green, colorMap->Colors[i].Blue); } } // Fill in the color table for indices greater than color count. // This allows for predictable, safe behavior. if (colorCount > 0) { // Gifs have the option to specify the color at a single index of the color // table as transparent. If the transparent index is greater than the // colorCount, we know that there is no valid transparent color in the color // table. If there is not valid transparent index, we will try to use the // backgroundIndex as the fill index. If the backgroundIndex is also not // valid, we will let fFillIndex default to 0 (it is set to zero in the // constructor). This behavior is not specified but matches // SkImageDecoder_libgif. uint32_t backgroundIndex = fGif->SBackGroundColor; if (fTransIndex < colorCount) { colorPtr[fTransIndex] = SK_ColorTRANSPARENT; fFillIndex = fTransIndex; } else if (backgroundIndex < colorCount) { fFillIndex = backgroundIndex; } for (uint32_t i = colorCount; i < maxColors; i++) { colorPtr[i] = colorPtr[fFillIndex]; } } else { sk_memset32(colorPtr, 0xFF000000, maxColors); } fColorTable.reset(new SkColorTable(colorPtr, maxColors)); copy_color_table(dstInfo, this->fColorTable, inputColorPtr, inputColorCount); }
// Note: SkColorTable claims to store SkPMColors, which is not necessarily // the case here. bool SkPngCodec::createColorTable(SkColorType dstColorType, bool premultiply, int* ctableCount) { int numColors; png_color* palette; if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { return false; } // Note: These are not necessarily SkPMColors. SkPMColor colorPtr[256]; png_bytep alphas; int numColorsWithAlpha = 0; if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) { // Choose which function to use to create the color table. If the final destination's // colortype is unpremultiplied, the color table will store unpremultiplied colors. PackColorProc proc = choose_pack_color_proc(premultiply, dstColorType); for (int i = 0; i < numColorsWithAlpha; i++) { // We don't have a function in SkOpts that combines a set of alphas with a set // of RGBs. We could write one, but it's hardly worth it, given that this // is such a small fraction of the total decode time. colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette->blue); palette++; } } if (numColorsWithAlpha < numColors) { // The optimized code depends on a 3-byte png_color struct with the colors // in RGB order. These checks make sure it is safe to use. static_assert(3 == sizeof(png_color), "png_color struct has changed. Opts are broken."); #ifdef SK_DEBUG SkASSERT(&palette->red < &palette->green); SkASSERT(&palette->green < &palette->blue); #endif if (is_rgba(dstColorType)) { SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha); } else { SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha); } } // Pad the color table with the last color in the table (or black) in the case that // invalid pixel indices exceed the number of colors in the table. const int maxColors = 1 << fBitDepth; if (numColors < maxColors) { SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_ColorBLACK; sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors); } // Set the new color count. if (ctableCount != nullptr) { *ctableCount = maxColors; } fColorTable.reset(new SkColorTable(colorPtr, maxColors)); return true; }
// Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here. bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo, int* ctableCount) { int numColors; png_color* palette; if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { return false; } // Contents depend on tableColorType and our choice of if/when to premultiply: // { kPremul, kUnpremul, kOpaque } x { RGBA, BGRA } SkPMColor colorTable[256]; SkColorType tableColorType = fColorXform ? kRGBA_8888_SkColorType : dstInfo.colorType(); png_bytep alphas; int numColorsWithAlpha = 0; if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) { // If we are performing a color xform, it will handle the premultiply. Otherwise, // we'll do it here. bool premultiply = !fColorXform && needs_premul(dstInfo, this->getInfo()); // Choose which function to use to create the color table. If the final destination's // colortype is unpremultiplied, the color table will store unpremultiplied colors. PackColorProc proc = choose_pack_color_proc(premultiply, tableColorType); for (int i = 0; i < numColorsWithAlpha; i++) { // We don't have a function in SkOpts that combines a set of alphas with a set // of RGBs. We could write one, but it's hardly worth it, given that this // is such a small fraction of the total decode time. colorTable[i] = proc(alphas[i], palette->red, palette->green, palette->blue); palette++; } } if (numColorsWithAlpha < numColors) { // The optimized code depends on a 3-byte png_color struct with the colors // in RGB order. These checks make sure it is safe to use. static_assert(3 == sizeof(png_color), "png_color struct has changed. Opts are broken."); #ifdef SK_DEBUG SkASSERT(&palette->red < &palette->green); SkASSERT(&palette->green < &palette->blue); #endif if (is_rgba(tableColorType)) { SkOpts::RGB_to_RGB1(colorTable + numColorsWithAlpha, palette, numColors - numColorsWithAlpha); } else { SkOpts::RGB_to_BGR1(colorTable + numColorsWithAlpha, palette, numColors - numColorsWithAlpha); } } // If we are not decoding to F16, we can color xform now and store the results // in the color table. if (fColorXform && kRGBA_F16_SkColorType != dstInfo.colorType()) { SkColorType xformColorType = is_rgba(dstInfo.colorType()) ? kRGBA_8888_SkColorType : kBGRA_8888_SkColorType; SkAlphaType xformAlphaType = xform_alpha_type(dstInfo.alphaType(), this->getInfo().alphaType()); fColorXform->apply(colorTable, colorTable, numColors, xformColorType, xformAlphaType); } // Pad the color table with the last color in the table (or black) in the case that // invalid pixel indices exceed the number of colors in the table. const int maxColors = 1 << fBitDepth; if (numColors < maxColors) { SkPMColor lastColor = numColors > 0 ? colorTable[numColors - 1] : SK_ColorBLACK; sk_memset32(colorTable + numColors, lastColor, maxColors - numColors); } // Set the new color count. if (ctableCount != nullptr) { *ctableCount = maxColors; } fColorTable.reset(new SkColorTable(colorTable, maxColors)); return true; }