// pre-conditions: // - bottom and top image have the same size // - bottom image format is ARGB32_Premultiplied void IndependentChannelBlending::blend( QImage * const bottom, TextureTile const * const top ) const { QImage const * const topImage = top->image(); Q_ASSERT( topImage ); Q_ASSERT( bottom->size() == topImage->size() ); Q_ASSERT( bottom->format() == QImage::Format_ARGB32_Premultiplied ); int const width = bottom->width(); int const height = bottom->height(); QImage const topImagePremult = topImage->convertToFormat( QImage::Format_ARGB32_Premultiplied ); for ( int y = 0; y < height; ++y ) { for ( int x = 0; x < width; ++x ) { QRgb const bottomPixel = bottom->pixel( x, y ); QRgb const topPixel = topImagePremult.pixel( x, y ); qreal const resultRed = blendChannel( qRed( bottomPixel ) / 255.0, qRed( topPixel ) / 255.0 ); qreal const resultGreen = blendChannel( qGreen( bottomPixel ) / 255.0, qGreen( topPixel ) / 255.0 ); qreal const resultBlue = blendChannel( qBlue( bottomPixel ) / 255.0, qBlue( topPixel ) / 255.0 ); bottom->setPixel( x, y, qRgb( resultRed * 255.0, resultGreen * 255.0, resultBlue * 255.0 )); } } }
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); }