Bug 155942: use libjpeg to handle grayscale, support YCbCr, use

less memory on non-mac platforms.  r=biesi, sr=blizzard


git-svn-id: svn://10.0.0.236/trunk@141238 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
tor%cs.brown.edu
2003-04-16 10:47:27 +00:00
parent dd8edb2662
commit d30d0effaa
2 changed files with 71 additions and 111 deletions

View File

@@ -78,9 +78,7 @@ nsJPEGDecoder::nsJPEGDecoder()
mFillState = READING_BACK;
mSamples = nsnull;
mSamples3 = nsnull;
mRGBPadRow = nsnull;
mRGBPadRowLength = 0;
mRGBRow = nsnull;
mBytesToSkip = 0;
@@ -102,8 +100,8 @@ nsJPEGDecoder::~nsJPEGDecoder()
PR_Free(mBuffer);
if (mBackBuffer)
PR_Free(mBackBuffer);
if (mRGBPadRow)
PR_Free(mRGBPadRow);
if (mRGBRow)
PR_Free(mRGBRow);
}
@@ -238,6 +236,20 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
if (jpeg_read_header(&mInfo, TRUE) == JPEG_SUSPENDED)
return NS_OK; /* I/O suspension */
/* let libjpeg take care of gray->RGB and YCbCr->RGB conversions */
switch (mInfo.jpeg_color_space) {
case JCS_GRAYSCALE:
case JCS_RGB:
case JCS_YCbCr:
mInfo.out_color_space = JCS_RGB;
break;
case JCS_CMYK:
case JCS_YCCK:
default:
mState = JPEG_ERROR;
return NS_ERROR_UNEXPECTED;
}
/*
* Don't allocate a giant and superfluous memory buffer
* when the image is a sequential JPEG.
@@ -249,13 +261,6 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
mObserver->OnStartDecode(nsnull);
/* we only support jpegs with 1 or 3 components currently. */
if (mInfo.output_components != 1 &&
mInfo.output_components != 3) {
mState = JPEG_ERROR;
return NS_ERROR_UNEXPECTED;
}
/* Check if the request already has an image container.
this is the case when multipart/x-mixed-replace is being downloaded
if we already have one and it has the same width and height, reuse it.
@@ -331,34 +336,21 @@ NS_IMETHODIMP nsJPEGDecoder::WriteFrom(nsIInputStream *inStr, PRUint32 count, PR
*/
int row_stride;
if (mInfo.output_components == 1)
row_stride = mInfo.output_width;
else
row_stride = mInfo.output_width * 4; // use 4 instead of mInfo.output_components
// so we don't have to fuss with byte alignment.
// Mac wants 4 anyways.
#if defined(XP_MAC) || defined(XP_MACOSX)
row_stride = mInfo.output_width * 4;
#else
row_stride = mInfo.output_width * 3;
#endif
mSamples = (*mInfo.mem->alloc_sarray)((j_common_ptr) &mInfo,
JPOOL_IMAGE,
row_stride, 1);
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(XP_MAC) || defined(XP_MACOSX) || defined(MOZ_WIDGET_PHOTON)
// allocate buffer to do byte flipping if needed
if (mInfo.output_components == 3) {
mRGBPadRow = (PRUint8*) PR_MALLOC(row_stride);
mRGBPadRowLength = row_stride;
memset(mRGBPadRow, 0, mRGBPadRowLength);
}
// allocate buffer to do byte flipping / padding
mRGBRow = (PRUint8*) PR_MALLOC(row_stride);
#endif
/* Allocate RGB buffer for conversion from greyscale. */
if (mInfo.output_components != 3) {
row_stride = mInfo.output_width * 4;
mSamples3 = (*mInfo.mem->alloc_sarray)((j_common_ptr) &mInfo,
JPOOL_IMAGE,
row_stride, 1);
}
mState = JPEG_START_DECOMPRESS;
}
@@ -508,65 +500,35 @@ nsJPEGDecoder::OutputScanlines()
break;
}
/* If grayscale image ... */
if (mInfo.output_components == 1) {
JSAMPLE j;
JSAMPLE *j1 = mSamples[0];
const JSAMPLE *j1end = j1 + mInfo.output_width;
JSAMPLE *j3 = mSamples3[0];
/* Convert from grayscale to RGB. */
while (j1 < j1end) {
#if defined(XP_MAC) || defined(XP_MACOSX)
j = *j1++;
j3[0] = 0;
j3[1] = j;
j3[2] = j;
j3[3] = j;
j3 += 4;
#else
j = *j1++;
j3[0] = j;
j3[1] = j;
j3[2] = j;
j3 += 3;
#endif
}
samples = mSamples3[0];
} else {
/* 24-bit color image */
#if defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS) || defined(MOZ_WIDGET_PHOTON)
memset(mRGBPadRow, 0, mInfo.output_width * 4);
PRUint8 *ptrOutputBuf = mRGBPadRow;
PRUint8 *ptrOutputBuf = mRGBRow;
JSAMPLE *j1 = mSamples[0];
for (PRUint32 i=0;i<mInfo.output_width;++i) {
ptrOutputBuf[2] = *j1++;
ptrOutputBuf[1] = *j1++;
ptrOutputBuf[0] = *j1++;
ptrOutputBuf += 3;
}
samples = mRGBPadRow;
#elif defined(XP_MAC) || defined(XP_MACOSX)
memset(mRGBPadRow, 0, mInfo.output_width * 4);
PRUint8 *ptrOutputBuf = mRGBPadRow;
JSAMPLE *j1 = mSamples[0];
for (PRUint32 i=0;i<mInfo.output_width;++i) {
ptrOutputBuf[0] = 0;
ptrOutputBuf[1] = *j1++;
ptrOutputBuf[2] = *j1++;
ptrOutputBuf[3] = *j1++;
ptrOutputBuf += 4;
}
samples = mRGBPadRow;
#else
samples = mSamples[0];
#endif
JSAMPLE *j1 = mSamples[0];
for (PRUint32 i=0;i<mInfo.output_width;++i) {
ptrOutputBuf[2] = *j1++;
ptrOutputBuf[1] = *j1++;
ptrOutputBuf[0] = *j1++;
ptrOutputBuf += 3;
}
samples = mRGBRow;
#elif defined(XP_MAC) || defined(XP_MACOSX)
PRUint8 *ptrOutputBuf = mRGBRow;
JSAMPLE *j1 = mSamples[0];
for (PRUint32 i=0;i<mInfo.output_width;++i) {
ptrOutputBuf[0] = 0;
ptrOutputBuf[1] = *j1++;
ptrOutputBuf[2] = *j1++;
ptrOutputBuf[3] = *j1++;
ptrOutputBuf += 4;
}
samples = mRGBRow;
#else
samples = mSamples[0];
#endif
PRUint32 bpr;
mFrame->GetImageBytesPerRow(&bpr);
mFrame->SetImageData(
@@ -649,10 +611,10 @@ my_error_exit (j_common_ptr cinfo)
/******************************************************************************/
/* data source manager method
Initialize source. This is called by jpeg_read_header() before any
data is actually read. May leave
bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
will occur immediately).
Initialize source. This is called by jpeg_read_header() before any
data is actually read. May leave
bytes_in_buffer set to 0 (in which case a fill_input_buffer() call
will occur immediately).
*/
void PR_CALLBACK
init_source (j_decompress_ptr jd)
@@ -661,14 +623,14 @@ init_source (j_decompress_ptr jd)
/******************************************************************************/
/* data source manager method
Skip num_bytes worth of data. The buffer pointer and count should
be advanced over num_bytes input bytes, refilling the buffer as
needed. This is used to skip over a potentially large amount of
uninteresting data (such as an APPn marker). In some applications
it may be possible to optimize away the reading of the skipped data,
but it's not clear that being smart is worth much trouble; large
skips are uncommon. bytes_in_buffer may be zero on return.
A zero or negative skip count should be treated as a no-op.
Skip num_bytes worth of data. The buffer pointer and count should
be advanced over num_bytes input bytes, refilling the buffer as
needed. This is used to skip over a potentially large amount of
uninteresting data (such as an APPn marker). In some applications
it may be possible to optimize away the reading of the skipped data,
but it's not clear that being smart is worth much trouble; large
skips are uncommon. bytes_in_buffer may be zero on return.
A zero or negative skip count should be treated as a no-op.
*/
void PR_CALLBACK
skip_input_data (j_decompress_ptr jd, long num_bytes)
@@ -696,15 +658,15 @@ skip_input_data (j_decompress_ptr jd, long num_bytes)
/******************************************************************************/
/* data source manager method
This is called whenever bytes_in_buffer has reached zero and more
data is wanted. In typical applications, it should read fresh data
into the buffer (ignoring the current state of next_input_byte and
bytes_in_buffer), reset the pointer & count to the start of the
buffer, and return TRUE indicating that the buffer has been reloaded.
It is not necessary to fill the buffer entirely, only to obtain at
least one more byte. bytes_in_buffer MUST be set to a positive value
if TRUE is returned. A FALSE return should only be used when I/O
suspension is desired.
This is called whenever bytes_in_buffer has reached zero and more
data is wanted. In typical applications, it should read fresh data
into the buffer (ignoring the current state of next_input_byte and
bytes_in_buffer), reset the pointer & count to the start of the
buffer, and return TRUE indicating that the buffer has been reloaded.
It is not necessary to fill the buffer entirely, only to obtain at
least one more byte. bytes_in_buffer MUST be set to a positive value
if TRUE is returned. A FALSE return should only be used when I/O
suspension is desired.
*/
boolean PR_CALLBACK
fill_input_buffer (j_decompress_ptr jd)

View File

@@ -94,9 +94,7 @@ public:
jstate mState;
JSAMPARRAY mSamples;
JSAMPARRAY mSamples3;
PRUint8* mRGBPadRow;
PRUint32 mRGBPadRowLength;
PRUint8* mRGBRow;
PRInt32 mCompletedPasses;
PRInt32 mPasses;