// render 1 ass image into a 32bit QImage with alpha channel. //use dstX, dstY instead of img->dst_x/y because image size is small then ass renderer size void RenderASS(QImage *image, const SubImage& img, int dstX, int dstY) { const quint8 a = 255 - _a(img.color); if (a == 0) return; const quint8 r = _r(img.color); const quint8 g = _g(img.color); const quint8 b = _b(img.color); const quint8 *src = (const quint8*)img.data.constData(); // use QRgb to avoid endian issue QRgb *dst = (QRgb*)image->constBits() + dstY * image->width() + dstX; // k*src+(1-k)*dst for (int y = 0; y < img.height(); ++y) { for (int x = 0; x < img.width(); ++x) { const unsigned k = ((unsigned) src[x])*a/255; #if USE_QRGBA const unsigned A = qAlpha(dst[x]); #else quint8 *c = (quint8*)(&dst[x]); const unsigned A = ARGB32_A(c); #endif if (A == 0) { // dst color can be ignored #if USE_QRGBA dst[x] = qRgba(r, g, b, k); #else ARGB32_SET(c, r, g, b, k); #endif //USE_QRGBA } else if (k == 0) { //no change //dst[x] = qRgba(qRed(dst[x])), qGreen(dst[x]), qBlue(dst[x]), qAlpha(dst[x])) == dst[x]; } else if (k == 255) { #if USE_QRGBA dst[x] = qRgba(r, g, b, k); #else ARGB32_SET(c, r, g, b, k); #endif //USE_QRGBA } else { // c=k*dc/255=k*dc/256 * (1-1/256), -1<err(c) = k*dc/256^2<1, -1 is bad! #if USE_QRGBA // no need to &0xff because always be 0~255 dst[x] += qRgba2(k*(r-qRed(dst[x]))/255, k*(g-qGreen(dst[x]))/255, k*(b-qBlue(dst[x]))/255, k*(a-A)/255); #else const unsigned R = ARGB32_R(c); const unsigned G = ARGB32_G(c); const unsigned B = ARGB32_B(c); ARGB32_ADD(c, r == R ? 0 : k*(r-R)/255, g == G ? 0 : k*(g-G)/255, b == B ? 0 : k*(b-B)/255, a == A ? 0 : k*(a-A)/255); #endif } } src += img.stride(); dst += image->width(); } }
// C[i] = C'[i] = (k*c[i]+(255-k)*C[i])/255 = C[i] + k*(c[i]-C[i])/255, min(c[i],C[i]) <= C'[i] <= max(c[i],C[i]) void SubtitleProcessorLibASS::renderASS32(QImage *image, ASS_Image *img, int dstX, int dstY) { const quint8 a = 255 - _a(img->color); if (a == 0) return; const quint8 r = _r(img->color); const quint8 g = _g(img->color); const quint8 b = _b(img->color); quint8 *src = img->bitmap; // use QRgb to avoid endian issue QRgb *dst = (QRgb*)image->bits() + dstY * image->width() + dstX; for (int y = 0; y < img->h; ++y) { for (int x = 0; x < img->w; ++x) { const unsigned k = ((unsigned) src[x])*a/255; #if USE_QRGBA const unsigned A = qAlpha(dst[x]); #else quint8 *c = (quint8*)(&dst[x]); const unsigned A = ARGB32_A(c); #endif if (A == 0) { // dst color can be ignored #if USE_QRGBA dst[x] = qRgba(r, g, b, k); #else ARGB32_SET(c, r, g, b, k); #endif //USE_QRGBA } else if (k == 0) { //no change //dst[x] = qRgba(qRed(dst[x])), qGreen(dst[x]), qBlue(dst[x]), qAlpha(dst[x])) == dst[x]; } else if (k == 255) { #if USE_QRGBA dst[x] = qRgba(r, g, b, k); #else ARGB32_SET(c, r, g, b, k); #endif //USE_QRGBA } else { #if USE_QRGBA // no need to &0xff because always be 0~255 dst[x] += qRgba2(k*(r-qRed(dst[x]))/255, k*(g-qGreen(dst[x]))/255, k*(b-qBlue(dst[x]))/255, k*(a-A)/255); #else const unsigned R = ARGB32_R(c); const unsigned G = ARGB32_G(c); const unsigned B = ARGB32_B(c); ARGB32_ADD(c, r == R ? 0 : k*(r-R)/255, g == G ? 0 : k*(g-G)/255, b == B ? 0 : k*(b-B)/255, a == A ? 0 : k*(a-A)/255); #endif } } src += img->stride; dst += image->width(); } }