From 111d23ae542245c6a0682fdca60ada61649801a8 Mon Sep 17 00:00:00 2001 From: Jeff Gilbert Date: Fri, 10 Feb 2012 15:37:16 -0800 Subject: [PATCH] Bug 723221 - Premultiply JPG data correctly - r=joe --- image/encoders/jpeg/nsJPEGEncoder.cpp | 41 ++++++++++++++------------- image/encoders/jpeg/nsJPEGEncoder.h | 2 +- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/image/encoders/jpeg/nsJPEGEncoder.cpp b/image/encoders/jpeg/nsJPEGEncoder.cpp index e523606c676..ef4770fcf52 100644 --- a/image/encoders/jpeg/nsJPEGEncoder.cpp +++ b/image/encoders/jpeg/nsJPEGEncoder.cpp @@ -41,6 +41,7 @@ #include "prprf.h" #include "nsString.h" #include "nsStreamUtils.h" +#include "gfxColor.h" #include #include "jerror.h" @@ -186,7 +187,7 @@ NS_IMETHODIMP nsJPEGEncoder::InitFromData(const PRUint8* aData, } else if (aInputFormat == INPUT_FORMAT_RGBA) { PRUint8* row = new PRUint8[aWidth * 3]; while (cinfo.next_scanline < cinfo.image_height) { - StripAlpha(&aData[cinfo.next_scanline * aStride], row, aWidth); + ConvertRGBARow(&aData[cinfo.next_scanline * aStride], row, aWidth); jpeg_write_scanlines(&cinfo, &row, 1); } delete[] row; @@ -350,46 +351,48 @@ NS_IMETHODIMP nsJPEGEncoder::CloseWithStatus(nsresult aStatus) return Close(); } + + // nsJPEGEncoder::ConvertHostARGBRow // // Our colors are stored with premultiplied alphas, but we need // an output with no alpha in machine-independent byte order. // // See gfx/cairo/cairo/src/cairo-png.c - void nsJPEGEncoder::ConvertHostARGBRow(const PRUint8* aSrc, PRUint8* aDest, - PRUint32 aPixelWidth) + PRUint32 aPixelWidth) { - for (PRUint32 x = 0; x < aPixelWidth; x ++) { + for (PRUint32 x = 0; x < aPixelWidth; x++) { const PRUint32& pixelIn = ((const PRUint32*)(aSrc))[x]; PRUint8 *pixelOut = &aDest[x * 3]; - pixelOut[0] = (((pixelIn & 0xff0000) >> 16)); - pixelOut[1] = (((pixelIn & 0x00ff00) >> 8)); - pixelOut[2] = (((pixelIn & 0x0000ff) >> 0)); + pixelOut[0] = (pixelIn & 0xff0000) >> 16; + pixelOut[1] = (pixelIn & 0x00ff00) >> 8; + pixelOut[2] = (pixelIn & 0x0000ff) >> 0; } } - -// nsJPEGEncoder::StripAlpha -// -// Input is RGBA, output is RGB - +/** + * nsJPEGEncoder::ConvertRGBARow + * + * Input is RGBA, output is RGB, so we should alpha-premultiply. + */ void -nsJPEGEncoder::StripAlpha(const PRUint8* aSrc, PRUint8* aDest, - PRUint32 aPixelWidth) +nsJPEGEncoder::ConvertRGBARow(const PRUint8* aSrc, PRUint8* aDest, + PRUint32 aPixelWidth) { - for (PRUint32 x = 0; x < aPixelWidth; x ++) { + for (PRUint32 x = 0; x < aPixelWidth; x++) { const PRUint8* pixelIn = &aSrc[x * 4]; PRUint8* pixelOut = &aDest[x * 3]; - pixelOut[0] = pixelIn[0]; - pixelOut[1] = pixelIn[1]; - pixelOut[2] = pixelIn[2]; + + PRUint8 alpha = pixelIn[3]; + pixelOut[0] = GFX_PREMULTIPLY(pixelIn[0], alpha); + pixelOut[1] = GFX_PREMULTIPLY(pixelIn[1], alpha); + pixelOut[2] = GFX_PREMULTIPLY(pixelIn[2], alpha); } } - // nsJPEGEncoder::initDestination // // Initialize destination. This is called by jpeg_start_compress() before diff --git a/image/encoders/jpeg/nsJPEGEncoder.h b/image/encoders/jpeg/nsJPEGEncoder.h index a3a2a389d4b..02265479e4e 100644 --- a/image/encoders/jpeg/nsJPEGEncoder.h +++ b/image/encoders/jpeg/nsJPEGEncoder.h @@ -78,7 +78,7 @@ protected: void ConvertHostARGBRow(const PRUint8* aSrc, PRUint8* aDest, PRUint32 aPixelWidth); - void StripAlpha(const PRUint8* aSrc, PRUint8* aDest, PRUint32 aPixelWidth); + void ConvertRGBARow(const PRUint8* aSrc, PRUint8* aDest, PRUint32 aPixelWidth); static void initDestination(jpeg_compress_struct* cinfo); static boolean emptyOutputBuffer(jpeg_compress_struct* cinfo);