diff options
-rw-r--r-- | vcl/source/filter/jpeg/JpegReader.cxx | 214 | ||||
-rw-r--r-- | vcl/source/filter/jpeg/JpegReader.hxx | 23 | ||||
-rw-r--r-- | vcl/source/filter/jpeg/jpegc.cxx | 149 |
3 files changed, 139 insertions, 247 deletions
diff --git a/vcl/source/filter/jpeg/JpegReader.cxx b/vcl/source/filter/jpeg/JpegReader.cxx index 8959e4e8bd99..cd00518dcf44 100644 --- a/vcl/source/filter/jpeg/JpegReader.cxx +++ b/vcl/source/filter/jpeg/JpegReader.cxx @@ -178,9 +178,6 @@ void jpeg_svstream_src (j_decompress_ptr cinfo, void* input) JPEGReader::JPEGReader( SvStream& rStream, void* /*pCallData*/, bool bSetLogSize ) : mrStream ( rStream ), - mpAcc ( nullptr ), - mpAcc1 ( nullptr ), - mpBuffer ( nullptr ), mnLastPos ( rStream.Tell() ), mnLastLines ( 0 ), mbSetLogSize ( bSetLogSize ) @@ -191,46 +188,32 @@ JPEGReader::JPEGReader( SvStream& rStream, void* /*pCallData*/, bool bSetLogSize JPEGReader::~JPEGReader() { - delete[] mpBuffer; - - if( mpAcc ) - Bitmap::ReleaseAccess( mpAcc ); - - if( mpAcc1 ) - Bitmap::ReleaseAccess( mpAcc1 ); } -unsigned char * JPEGReader::CreateBitmap(JPEGCreateBitmapParam& rParam) +bool JPEGReader::CreateBitmap(JPEGCreateBitmapParam& rParam) { if (rParam.nWidth > SAL_MAX_INT32 / 8 || rParam.nHeight > SAL_MAX_INT32 / 8) - return nullptr; // avoid overflows later + return false; // avoid overflows later if (rParam.nWidth == 0 || rParam.nHeight == 0) - return nullptr; + return false; - Size aSize(rParam.nWidth, rParam.nHeight ); - bool bGray = rParam.bGray != 0; + Size aSize(rParam.nWidth, rParam.nHeight); + bool bGray = rParam.bGray; - unsigned char * pBmpBuf = nullptr; + maBitmap = Bitmap(); - if( mpAcc ) - { - Bitmap::ReleaseAccess( mpAcc ); - maBmp = Bitmap(); - mpAcc = nullptr; - } + sal_uInt64 nSize = aSize.Width() * aSize.Height(); - sal_uInt64 nSize = aSize.Width(); - nSize *= aSize.Height(); if (nSize > SAL_MAX_INT32 / (bGray?1:3)) - return nullptr; + return false; // Check if the bitmap is atypically large. if (nSize*(bGray?1:3) > MAX_BITMAP_BYTE_SIZE) { // Do not try to acquire resources for the large bitmap or to // read the bitmap into memory. - return nullptr; + return false; } if( bGray ) @@ -243,18 +226,18 @@ unsigned char * JPEGReader::CreateBitmap(JPEGCreateBitmapParam& rParam) aGrayPal[ n ] = BitmapColor( cGray, cGray, cGray ); } - maBmp = Bitmap( aSize, 8, &aGrayPal ); + maBitmap = Bitmap(aSize, 8, &aGrayPal); } else { - maBmp = Bitmap( aSize, 24 ); + maBitmap = Bitmap(aSize, 24); } - if ( mbSetLogSize ) + if (mbSetLogSize) { unsigned long nUnit = rParam.density_unit; - if( ( ( 1 == nUnit ) || ( 2 == nUnit ) ) && rParam.X_density && rParam.Y_density ) + if (((1 == nUnit) || (2 == nUnit)) && rParam.X_density && rParam.Y_density ) { Point aEmptyPoint; Fraction aFractX( 1, rParam.X_density ); @@ -262,161 +245,48 @@ unsigned char * JPEGReader::CreateBitmap(JPEGCreateBitmapParam& rParam) MapMode aMapMode( nUnit == 1 ? MAP_INCH : MAP_CM, aEmptyPoint, aFractX, aFractY ); Size aPrefSize = OutputDevice::LogicToLogic( aSize, aMapMode, MAP_100TH_MM ); - maBmp.SetPrefSize( aPrefSize ); - maBmp.SetPrefMapMode( MapMode( MAP_100TH_MM ) ); + maBitmap.SetPrefSize(aPrefSize); + maBitmap.SetPrefMapMode(MapMode(MAP_100TH_MM)); } } - mpAcc = maBmp.AcquireWriteAccess(); - - if( mpAcc ) - { - const ScanlineFormat nFormat = mpAcc->GetScanlineFormat(); - - if( - ( bGray && ( ScanlineFormat::N8BitPal == nFormat ) ) || - ( !bGray && ( ScanlineFormat::N24BitTcRgb == nFormat ) ) - ) - { - pBmpBuf = mpAcc->GetBuffer(); - rParam.nAlignedWidth = mpAcc->GetScanlineSize(); - rParam.bTopDown = mpAcc->IsTopDown(); - } - else - { - rParam.nAlignedWidth = AlignedWidth4Bytes( aSize.Width() * ( bGray ? 8 : 24 ) ); - rParam.bTopDown = true; - pBmpBuf = mpBuffer = new unsigned char[rParam.nAlignedWidth * aSize.Height()]; - } - } - - // clean up, if no Bitmap buffer can be provided. - if ( !pBmpBuf ) - { - Bitmap::ReleaseAccess( mpAcc ); - maBmp = Bitmap(); - mpAcc = nullptr; - } - - return pBmpBuf; -} - -void JPEGReader::FillBitmap() -{ - if( mpBuffer && mpAcc ) - { - unsigned char * pTmp; - BitmapColor aColor; - long nAlignedWidth; - long nWidth = mpAcc->Width(); - long nHeight = mpAcc->Height(); - - if( mpAcc->GetBitCount() == 8 ) - { - std::unique_ptr<BitmapColor[]> pCols(new BitmapColor[ 256 ]); - - for( sal_uInt16 n = 0; n < 256; n++ ) - { - const sal_uInt8 cGray = (sal_uInt8) n; - pCols[ n ] = mpAcc->GetBestMatchingColor( BitmapColor( cGray, cGray, cGray ) ); - } - - nAlignedWidth = AlignedWidth4Bytes( mpAcc->Width() * 8L ); - - for( long nY = 0L; nY < nHeight; nY++ ) - { - pTmp = mpBuffer + nY * nAlignedWidth; - - for( long nX = 0L; nX < nWidth; nX++ ) - { - mpAcc->SetPixel( nY, nX, pCols[ *pTmp++ ] ); - } - } - } - else - { - nAlignedWidth = AlignedWidth4Bytes( mpAcc->Width() * 24L ); - - for( long nY = 0L; nY < nHeight; nY++ ) - { - // #i122985# Added fast-lane implementations using CopyScanline with direct supported mem formats - static bool bCheckOwnReader(true); - - if(bCheckOwnReader) - { - // #i122985# Trying to copy the RGB data from jpeg import to make things faster. Unfortunately - // it has no GBR format, so RGB three-byte groups need to be 'flipped' to GBR first, - // then CopyScanline can use a memcpy to do the data transport. CopyScanline can also - // do the needed conversion from ScanlineFormat::N24BitTcRgb (and it works well), but this - // is not faster that the old loop below using SetPixel. - sal_uInt8* aSource(mpBuffer + nY * nAlignedWidth); - sal_uInt8* aEnd(aSource + (nWidth * 3)); - - for(sal_uInt8* aTmp(aSource); aTmp < aEnd; aTmp += 3) - { - ::std::swap(*aTmp, *(aTmp + 2)); - } - - mpAcc->CopyScanline(nY, aSource, ScanlineFormat::N24BitTcBgr, nWidth * 3); - } - else - { - // old version: WritePixel - pTmp = mpBuffer + nY * nAlignedWidth; - - for( long nX = 0L; nX < nWidth; nX++ ) - { - aColor.SetRed( *pTmp++ ); - aColor.SetGreen( *pTmp++ ); - aColor.SetBlue( *pTmp++ ); - mpAcc->SetPixel( nY, nX, aColor ); - } - } - } - } - } + return true; } -Graphic JPEGReader::CreateIntermediateGraphic( const Bitmap& rBitmap, long nLines ) +Graphic JPEGReader::CreateIntermediateGraphic(long nLines) { - Graphic aGraphic; - const Size aSizePixel( rBitmap.GetSizePixel() ); + Graphic aGraphic; + const Size aSizePixel(maBitmap.GetSizePixel()); - if( !mnLastLines ) + if (!mnLastLines) { - if( mpAcc1 ) - { - Bitmap::ReleaseAccess( mpAcc1 ); - } - - maBmp1 = Bitmap( rBitmap.GetSizePixel(), 1 ); - maBmp1.Erase( Color( COL_WHITE ) ); - mpAcc1 = maBmp1.AcquireWriteAccess(); + maIncompleteAlpha = Bitmap(aSizePixel, 1); + maIncompleteAlpha.Erase(Color(COL_WHITE)); } - if( nLines && ( nLines < aSizePixel.Height() ) ) + if (nLines && (nLines < aSizePixel.Height())) { - if( mpAcc1 ) - { - const long nNewLines = nLines - mnLastLines; + const long nNewLines = nLines - mnLastLines; - if( nNewLines ) + if (nNewLines > 0) + { { - mpAcc1->SetFillColor( Color( COL_BLACK ) ); - mpAcc1->FillRect( Rectangle( Point( 0, mnLastLines ), Size( mpAcc1->Width(), nNewLines ) ) ); + Bitmap::ScopedWriteAccess pAccess(maIncompleteAlpha); + pAccess->SetFillColor(Color(COL_BLACK)); + pAccess->FillRect(Rectangle(Point(0, mnLastLines), Size(pAccess->Width(), nNewLines))); } - Bitmap::ReleaseAccess( mpAcc1 ); - aGraphic = BitmapEx( rBitmap, maBmp1 ); - mpAcc1 = maBmp1.AcquireWriteAccess(); + aGraphic = BitmapEx(maBitmap, maIncompleteAlpha); } else { - aGraphic = rBitmap; + aGraphic = maBitmap; } } else - aGraphic = rBitmap; + { + aGraphic = maBitmap; + } mnLastLines = nLines; @@ -454,25 +324,15 @@ ReadState JPEGReader::Read( Graphic& rGraphic ) // read the (partial) image ReadJPEG( this, &mrStream, &nLines, GetPreviewSize() ); - if( mpAcc ) + if (!maBitmap.IsEmpty()) { - if( mpBuffer ) - { - FillBitmap(); - delete[] mpBuffer; - mpBuffer = nullptr; - } - - Bitmap::ReleaseAccess( mpAcc ); - mpAcc = nullptr; - if( mrStream.GetError() == ERRCODE_IO_PENDING ) { - rGraphic = CreateIntermediateGraphic( maBmp, nLines ); + rGraphic = CreateIntermediateGraphic(nLines); } else { - rGraphic = maBmp; + rGraphic = maBitmap; } bRet = true; diff --git a/vcl/source/filter/jpeg/JpegReader.hxx b/vcl/source/filter/jpeg/JpegReader.hxx index 71f8b9ae37e2..c3b52fd2abf9 100644 --- a/vcl/source/filter/jpeg/JpegReader.hxx +++ b/vcl/source/filter/jpeg/JpegReader.hxx @@ -39,34 +39,33 @@ struct JPEGCreateBitmapParam unsigned long density_unit; unsigned long X_density; unsigned long Y_density; - long bGray; - long nAlignedWidth; // these members will be filled by the - bool bTopDown; // CreateBitmap method in svtools + bool bGray; + bool bTopDown; // CreateBitmap method in svtools }; class JPEGReader : public GraphicReader { SvStream& mrStream; - Bitmap maBmp; - Bitmap maBmp1; - BitmapWriteAccess* mpAcc; - BitmapWriteAccess* mpAcc1; - unsigned char * mpBuffer; + Bitmap maBitmap; + Bitmap maIncompleteAlpha; + long mnLastPos; long mnFormerPos; long mnLastLines; bool mbSetLogSize; - Graphic CreateIntermediateGraphic( const Bitmap& rBitmap, long nLines ); - void FillBitmap(); + Graphic CreateIntermediateGraphic(long nLines); public: JPEGReader( SvStream& rStream, void* pCallData, bool bSetLogSize ); virtual ~JPEGReader() override; - ReadState Read( Graphic& rGraphic ); - unsigned char * CreateBitmap( JPEGCreateBitmapParam& param ); + ReadState Read(Graphic& rGraphic); + + bool CreateBitmap(JPEGCreateBitmapParam& param); + + Bitmap& GetBitmap() { return maBitmap; } }; #endif // INCLUDED_VCL_SOURCE_FILTER_JPEG_JPEGREADER_HXX diff --git a/vcl/source/filter/jpeg/jpegc.cxx b/vcl/source/filter/jpeg/jpegc.cxx index 74be061644c1..28af8c915d4b 100644 --- a/vcl/source/filter/jpeg/jpegc.cxx +++ b/vcl/source/filter/jpeg/jpegc.cxx @@ -36,6 +36,7 @@ extern "C" { #include <JpegReader.hxx> #include <JpegWriter.hxx> #include <memory> +#include <vcl/bitmapaccess.hxx> #ifdef _MSC_VER #pragma warning(push, 1) /* disable to __declspec(align()) aligned warning */ @@ -68,16 +69,8 @@ extern "C" void outputMessage (j_common_ptr cinfo) void ReadJPEG( JPEGReader* pJPEGReader, void* pInputStream, long* pLines, Size const & previewSize ) { - jpeg_decompress_struct cinfo; - ErrorManagerStruct jerr; - JPEGCreateBitmapParam aCreateBitmapParam; - unsigned char * pDIB; - unsigned char * pTmp; - long nWidth; - long nHeight; - long nAlignedWidth; - JSAMPLE* aRangeLimit; - std::unique_ptr<unsigned char[]> pScanLineBuffer; + jpeg_decompress_struct cinfo; + ErrorManagerStruct jerr; if ( setjmp( jerr.setjmp_buffer ) ) { @@ -151,72 +144,114 @@ void ReadJPEG( JPEGReader* pJPEGReader, void* pInputStream, long* pLines, jpeg_start_decompress( &cinfo ); - nWidth = cinfo.output_width; - nHeight = cinfo.output_height; + long nWidth = cinfo.output_width; + long nHeight = cinfo.output_height; + + bool bGray = (cinfo.output_components == 1); + + JPEGCreateBitmapParam aCreateBitmapParam; + aCreateBitmapParam.nWidth = nWidth; aCreateBitmapParam.nHeight = nHeight; aCreateBitmapParam.density_unit = cinfo.density_unit; aCreateBitmapParam.X_density = cinfo.X_density; aCreateBitmapParam.Y_density = cinfo.Y_density; - aCreateBitmapParam.bGray = long(cinfo.output_components == 1); - pDIB = pJPEGReader->CreateBitmap(aCreateBitmapParam); - nAlignedWidth = aCreateBitmapParam.nAlignedWidth; - aRangeLimit = cinfo.sample_range_limit; + aCreateBitmapParam.bGray = bGray; - long nScanLineBufferComponents = 0; - if ( cinfo.out_color_space == JCS_CMYK ) - { - nScanLineBufferComponents = cinfo.output_width * 4; - pScanLineBuffer.reset(new unsigned char[nScanLineBufferComponents]); - } + bool bBitmapCreated = pJPEGReader->CreateBitmap(aCreateBitmapParam); - if( pDIB ) + if (bBitmapCreated) { - if( aCreateBitmapParam.bTopDown ) - { - pTmp = pDIB; - } - else - { - pTmp = pDIB + ( nHeight - 1 ) * nAlignedWidth; - nAlignedWidth = -nAlignedWidth; - } + Bitmap::ScopedWriteAccess pAccess(pJPEGReader->GetBitmap()); - for ( *pLines = 0; *pLines < nHeight; (*pLines)++ ) + if (pAccess) { - if (pScanLineBuffer) - { // in other words cinfo.out_color_space == JCS_CMYK - int i; - int j; - unsigned char *pSLB = pScanLineBuffer.get(); - jpeg_read_scanlines( &cinfo, reinterpret_cast<JSAMPARRAY>(&pSLB), 1 ); - // convert CMYK to RGB - for( i=0, j=0; i < nScanLineBufferComponents; i+=4, j+=3 ) + JSAMPLE* aRangeLimit = cinfo.sample_range_limit; + + std::vector<sal_uInt8> pScanLineBuffer(nWidth * (bGray ? 1 : 3)); + std::vector<sal_uInt8> pCYMKBuffer; + + if (cinfo.out_color_space == JCS_CMYK) + { + pCYMKBuffer.resize(nWidth * 4); + } + + const ScanlineFormat nFormat = pAccess->GetScanlineFormat(); + + bool bTopDown = true; + + if (( bGray && nFormat == ScanlineFormat::N8BitPal) || + (!bGray && nFormat == ScanlineFormat::N24BitTcRgb)) + { + bTopDown = pAccess->IsTopDown(); + } + + std::unique_ptr<BitmapColor[]> pCols; + + if (bGray) + { + pCols.reset(new BitmapColor[256]); + + for (sal_uInt16 n = 0; n < 256; n++) { - int color_C = 255 - pScanLineBuffer[i+0]; - int color_M = 255 - pScanLineBuffer[i+1]; - int color_Y = 255 - pScanLineBuffer[i+2]; - int color_K = 255 - pScanLineBuffer[i+3]; - pTmp[j+0] = aRangeLimit[ 255L - ( color_C + color_K ) ]; - pTmp[j+1] = aRangeLimit[ 255L - ( color_M + color_K ) ]; - pTmp[j+2] = aRangeLimit[ 255L - ( color_Y + color_K ) ]; + const sal_uInt8 cGray = n; + pCols[n] = pAccess->GetBestMatchingColor(BitmapColor(cGray, cGray, cGray)); } } - else + + for (*pLines = 0; *pLines < nHeight; (*pLines)++) { - jpeg_read_scanlines( &cinfo, reinterpret_cast<JSAMPARRAY>(&pTmp), 1 ); - } + size_t yIndex = *pLines; - /* PENDING ??? */ - if ( cinfo.err->msg_code == 113 ) - break; + if (cinfo.out_color_space == JCS_CMYK) + { + sal_uInt8* p = pCYMKBuffer.data(); + jpeg_read_scanlines(&cinfo, reinterpret_cast<JSAMPARRAY>(&p), 1); + + // convert CMYK to RGB + for (int cmyk = 0, rgb = 0; cmyk < nWidth * 4; cmyk += 4, rgb += 3) + { + int color_C = 255 - pCYMKBuffer[cmyk + 0]; + int color_M = 255 - pCYMKBuffer[cmyk + 1]; + int color_Y = 255 - pCYMKBuffer[cmyk + 2]; + int color_K = 255 - pCYMKBuffer[cmyk + 3]; + + pScanLineBuffer[rgb + 0] = aRangeLimit[255L - (color_C + color_K)]; + pScanLineBuffer[rgb + 1] = aRangeLimit[255L - (color_M + color_K)]; + pScanLineBuffer[rgb + 2] = aRangeLimit[255L - (color_Y + color_K)]; + } + } + else + { + sal_uInt8* p = pScanLineBuffer.data(); + jpeg_read_scanlines(&cinfo, reinterpret_cast<JSAMPARRAY>(&p), 1); + } + + if (!bTopDown) + yIndex = nHeight - 1 - yIndex; - pTmp += nAlignedWidth; + if (bGray) + { + for (long x = 0; x < nWidth; ++x) + { + sal_uInt8 nColorGray = pScanLineBuffer[x]; + pAccess->SetPixel(yIndex, x, pCols[nColorGray]); + } + } + else + { + pAccess->CopyScanline(yIndex, pScanLineBuffer.data(), ScanlineFormat::N24BitTcRgb, nWidth * 3); + } + + /* PENDING ??? */ + if (cinfo.err->msg_code == 113) + break; + } } } - if ( pDIB ) + if (bBitmapCreated) { jpeg_finish_decompress( &cinfo ); } @@ -225,8 +260,6 @@ void ReadJPEG( JPEGReader* pJPEGReader, void* pInputStream, long* pLines, jpeg_abort_decompress( &cinfo ); } - pScanLineBuffer.reset(); - jpeg_destroy_decompress( &cinfo ); } |