static uint32_t get_argb8888_neighbor_avg_color(const SkBitmap& bitmap, int xOrig, int yOrig) { uint8_t count = 0; uint16_t r = 0; uint16_t g = 0; uint16_t b = 0; for (int y = yOrig - 1; y <= yOrig + 1; y++) { if (y < 0 || y >= bitmap.height()) { continue; } uint32_t* src = bitmap.getAddr32(0, y); for (int x = xOrig - 1; x <= xOrig + 1; x++) { if (x < 0 || x >= bitmap.width()) { continue; } if (SkGetPackedA32(src[x]) != SK_AlphaTRANSPARENT) { uint32_t color = remove_alpha_argb8888(src[x]); r += SkGetPackedR32(color); g += SkGetPackedG32(color); b += SkGetPackedB32(color); count++; } } } if (count == 0) { return SkPackARGB32NoCheck(SK_AlphaOPAQUE, 0, 0, 0); } else { return SkPackARGB32NoCheck(SK_AlphaOPAQUE, r / count, g / count, b / count); } }
/* * Set an RLE pixel from R, G, B values */ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue) { // Set the row int height = dstInfo.height(); int row; if (SkBmpCodec::kBottomUp_RowOrder == this->rowOrder()) { row = height - y - 1; } else { row = y; } // Set the pixel based on destination color type switch (dstInfo.colorType()) { case kN32_SkColorType: { SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst, row * (int) dstRowBytes); dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue); break; } case kRGB_565_SkColorType: { uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); dstRow[x] = SkPack888ToRGB16(red, green, blue); break; } default: // This case should not be reached. We should catch an invalid // color type when we check that the conversion is possible. SkASSERT(false); break; } }
/** * Removes the alpha component of an ARGB color (including unpremultiply) while * keeping the output in the same format as the input. */ static uint32_t remove_alpha_argb8888(uint32_t pmColor) { SkColor color = SkUnPreMultiply::PMColorToColor(pmColor); return SkPackARGB32NoCheck(SK_AlphaOPAQUE, SkColorGetR(color), SkColorGetG(color), SkColorGetB(color)); }
/* * Set an RLE pixel from R, G, B values */ void SkBmpRLECodec::setRGBPixel(void* dst, size_t dstRowBytes, const SkImageInfo& dstInfo, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue) { if (is_coord_necessary(x, fSampleX, dstInfo.width())) { // Set the row uint32_t row = this->getDstRow(y, dstInfo.height()); // Set the pixel based on destination color type const int dstX = get_dst_coord(x, fSampleX); switch (dstInfo.colorType()) { case kN32_SkColorType: { SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, row * (int) dstRowBytes); dstRow[dstX] = SkPackARGB32NoCheck(0xFF, red, green, blue); break; } case kRGB_565_SkColorType: { uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, row * (int) dstRowBytes); dstRow[dstX] = SkPack888ToRGB16(red, green, blue); break; } default: // This case should not be reached. We should catch an invalid // color type when we check that the conversion is possible. SkASSERT(false); break; } } }
// Returns an unpremultiplied version of color. It will have the same ordering and size as an // SkPMColor, but the alpha will not be premultiplied. static SkPMColor unpremultiply_pmcolor(SkPMColor color) { U8CPU a = SkGetPackedA32(color); const SkUnPreMultiply::Scale scale = SkUnPreMultiply::GetScale(a); return SkPackARGB32NoCheck(a, SkUnPreMultiply::ApplyScale(scale, SkGetPackedR32(color)), SkUnPreMultiply::ApplyScale(scale, SkGetPackedG32(color)), SkUnPreMultiply::ApplyScale(scale, SkGetPackedB32(color))); }
static SkPMColor unpremul_pm(SkPMColor c) { const U8CPU a = SkGetPackedA32(c); if (0 == a) { return 0; } else if (0xFF == a) { return c; } const unsigned scale = SkUnPreMultiply::GetScale(a); return SkPackARGB32NoCheck(a, SkUnPreMultiply::ApplyScale(scale, SkGetPackedR32(c)), SkUnPreMultiply::ApplyScale(scale, SkGetPackedG32(c)), SkUnPreMultiply::ApplyScale(scale, SkGetPackedB32(c))); }
static SkSwizzler::ResultAlpha swizzle_mask24_to_n32_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { // Use the masks to decode to the destination SkPMColor* dstPtr = (SkPMColor*) dstRow; for (int i = 0; i < 3*width; i += 3) { uint32_t p = srcRow[i] | (srcRow[i + 1] << 8) | srcRow[i + 2] << 16; uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); dstPtr[i/3] = SkPackARGB32NoCheck(0xFF, red, green, blue); } return SkSwizzler::kOpaque_ResultAlpha; }
static SkSwizzler::ResultAlpha swizzle_mask16_to_n32_opaque( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { // Use the masks to decode to the destination uint16_t* srcPtr = (uint16_t*) srcRow; SkPMColor* dstPtr = (SkPMColor*) dstRow; for (int i = 0; i < width; i++) { uint16_t p = srcPtr[i]; uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); dstPtr[i] = SkPackARGB32NoCheck(0xFF, red, green, blue); } return SkSwizzler::kOpaque_ResultAlpha; }
static void FromColor_D4444_Raw(void* dst, const SkColor src[], int width, int x, int y) { SkPMColor16* d = (SkPMColor16*)dst; DITHER_4444_SCAN(y); for (int stop = x + width; x < stop; x++) { SkColor c = *src++; // SkPMColor is used because the ordering is ARGB32, even though the target actually premultiplied SkPMColor pmc = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c)); *d++ = SkDitherARGB32To4444(pmc, DITHER_VALUE(x)); // *d++ = SkPixel32ToPixel4444(pmc); } }
static void FromColor_D32_Raw(void* dst, const SkColor src[], int width, int, int) { // SkColor's ordering may be different from SkPMColor if (SK_COLOR_MATCHES_PMCOLOR_BYTE_ORDER) { memcpy(dst, src, width * sizeof(SkColor)); return; } // order isn't same, repack each pixel manually SkPMColor* d = (SkPMColor*)dst; for (int i = 0; i < width; i++) { SkColor c = *src++; *d++ = SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c)); } }
static SkSwizzler::ResultAlpha swizzle_mask24_to_n32_unpremul( void* dstRow, const uint8_t* srcRow, int width, SkMasks* masks) { // Use the masks to decode to the destination SkPMColor* dstPtr = (SkPMColor*) dstRow; INIT_RESULT_ALPHA; for (int i = 0; i < 3*width; i += 3) { uint32_t p = srcRow[i] | (srcRow[i + 1] << 8) | srcRow[i + 2] << 16; uint8_t red = masks->getRed(p); uint8_t green = masks->getGreen(p); uint8_t blue = masks->getBlue(p); uint8_t alpha = masks->getAlpha(p); UPDATE_RESULT_ALPHA(alpha); dstPtr[i/3] = SkPackARGB32NoCheck(alpha, red, green, blue); } return COMPUTE_RESULT_ALPHA; }
inline uint32_t blendSrcOverDstNonPremultiplied(uint32_t src, uint32_t dst) { uint8_t srcA = SkGetPackedA32(src); if (srcA == 0) return dst; uint8_t dstA = SkGetPackedA32(dst); uint8_t dstFactorA = (dstA * SkAlpha255To256(255 - srcA)) >> 8; ASSERT(srcA + dstFactorA < (1U << 8)); uint8_t blendA = srcA + dstFactorA; unsigned scale = (1UL << 24) / blendA; uint8_t blendR = blendChannel(SkGetPackedR32(src), srcA, SkGetPackedR32(dst), dstFactorA, scale); uint8_t blendG = blendChannel(SkGetPackedG32(src), srcA, SkGetPackedG32(dst), dstFactorA, scale); uint8_t blendB = blendChannel(SkGetPackedB32(src), srcA, SkGetPackedB32(dst), dstFactorA, scale); return SkPackARGB32NoCheck(blendA, blendR, blendG, blendB); }
/* * Process the color table for the bmp input */ bool SkBmpRLECodec::createColorTable(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 (NULL != 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; } // Read the color table from the stream colorBytes = fNumColors * fBytesPerColor; SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(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 uint32_t i = 0; for (; i < fNumColors; 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] = SkPackARGB32NoCheck(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(SkNEW_ARGS(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; }
// This swizzles SkColor into the same component order as SkPMColor, but does not actually // "pre" multiply the color components. // // This allows us to map directly to Sk4f, and eventually scale down to bytes to output a // SkPMColor from the floats, without having to swizzle each time. // static uint32_t SkSwizzle_Color_to_PMColor(SkColor c) { return SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), SkColorGetB(c)); }
void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, SkDevice* dstDevice, const IntSize& size) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); int originX = sourceRect.x(); int destX = destPoint.x() + sourceRect.x(); ASSERT(destX >= 0); ASSERT(destX < size.width()); ASSERT(originX >= 0); ASSERT(originX < sourceRect.maxX()); int endX = destPoint.x() + sourceRect.maxX(); ASSERT(endX <= size.width()); int numColumns = endX - destX; int originY = sourceRect.y(); int destY = destPoint.y() + sourceRect.y(); ASSERT(destY >= 0); ASSERT(destY < size.height()); ASSERT(originY >= 0); ASSERT(originY < sourceRect.maxY()); int endY = destPoint.y() + sourceRect.maxY(); ASSERT(endY <= size.height()); int numRows = endY - destY; unsigned srcBytesPerRow = 4 * sourceSize.width(); SkBitmap deviceBitmap = dstDevice->accessBitmap(true); // If the device's bitmap doesn't have pixels we will make a temp and call writePixels on the device. bool temporaryBitmap = !!deviceBitmap.getTexture(); SkBitmap destBitmap; if (temporaryBitmap) { destBitmap.setConfig(SkBitmap::kARGB_8888_Config, numColumns, numRows, srcBytesPerRow); if (!destBitmap.allocPixels()) CRASH(); } else deviceBitmap.extractSubset(&destBitmap, SkIRect::MakeXYWH(destX, destY, numColumns, numRows)); // Whether we made a temporary or not destBitmap is always configured to be written at 0,0 SkAutoLockPixels destAutoLock(destBitmap); const unsigned char* srcRow = source->data() + originY * srcBytesPerRow + originX * 4; for (int y = 0; y < numRows; ++y) { SkPMColor* destRow = destBitmap.getAddr32(0, y); for (int x = 0; x < numColumns; ++x) { const unsigned char* srcPixel = &srcRow[x * 4]; if (multiplied == Unmultiplied) { unsigned char alpha = srcPixel[3]; unsigned char r = SkMulDiv255Ceiling(srcPixel[0], alpha); unsigned char g = SkMulDiv255Ceiling(srcPixel[1], alpha); unsigned char b = SkMulDiv255Ceiling(srcPixel[2], alpha); destRow[x] = SkPackARGB32(alpha, r, g, b); } else destRow[x] = SkPackARGB32NoCheck(srcPixel[3], srcPixel[0], srcPixel[1], srcPixel[2]); } srcRow += srcBytesPerRow; } // If we used a temporary then write it to the device if (temporaryBitmap) dstDevice->writePixels(destBitmap, destX, destY); }