diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2014-04-18 20:46:34 +0200 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.co.uk> | 2014-04-19 13:07:16 +0000 |
commit | 85e088c70aa3cfdd638276a2555b35ed1275c352 (patch) | |
tree | 00c8f31f9176d4af34910adb4e79cc614ec4414b | |
parent | bd10baa8565ac4ea8697a4e9ed8c5a489ae7a4fb (diff) |
handle strange brightness+contrast adjustment from msoffice (fdo#38410)
LO uses basically the formula "newpixel=(oldpixel-128)*contrast+128+brightness",
i.e. contrast is applied first. It looks like there's no "oficial" formula for this,
so a formula that applies brightness first would be ok too. MSO for some weird reason
apparently uses a formula that applies half of brightness before contrast and
half afterwards (insert funny political correctness or compromise joke here).
While the result is the same like with the LO formula if only either brightness
or contrast is adjusted, the result is different if both are involved. Just modify
the image using the MSO algorithm if this is the case.
Conflicts:
filter/source/msfilter/msdffimp.cxx
include/vcl/bitmap.hxx
include/vcl/bitmapex.hxx
include/vcl/gdimtf.hxx
vcl/source/gdi/bitmap3.cxx
vcl/source/gdi/bitmapex.cxx
vcl/source/gdi/gdimtf.cxx
Change-Id: I55fe8f395832685b90f024cf2f58b0797c1ba588
Reviewed-on: https://gerrit.libreoffice.org/9099
Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk>
Tested-by: Miklos Vajna <vmiklos@collabora.co.uk>
-rw-r--r-- | filter/source/msfilter/msdffimp.cxx | 11 | ||||
-rw-r--r-- | include/vcl/bitmap.hxx | 6 | ||||
-rw-r--r-- | include/vcl/bitmapex.hxx | 7 | ||||
-rw-r--r-- | include/vcl/gdimtf.hxx | 2 | ||||
-rw-r--r-- | vcl/source/gdi/bitmap3.cxx | 28 | ||||
-rw-r--r-- | vcl/source/gdi/bitmapex.cxx | 4 | ||||
-rw-r--r-- | vcl/source/gdi/gdimtf.cxx | 25 |
7 files changed, 61 insertions, 22 deletions
diff --git a/filter/source/msfilter/msdffimp.cxx b/filter/source/msfilter/msdffimp.cxx index 63847b3c8bd9..472e1a5338ba 100644 --- a/filter/source/msfilter/msdffimp.cxx +++ b/filter/source/msfilter/msdffimp.cxx @@ -3817,7 +3817,12 @@ SdrObject* SvxMSDffManager::ImportGraphic( SvStream& rSt, SfxItemSet& rSet, cons if ( nContrast || nBrightness || ( nGamma != 0x10000 ) || ( eDrawMode != GRAPHICDRAWMODE_STANDARD ) ) { - if ( ( rObjData.nSpFlags & SP_FOLESHAPE ) == 0 ) + // MSO uses a different algorithm for contrast+brightness, LO applies contrast before brightness, + // while MSO apparently applies half of brightness before contrast and half after. So if only + // contrast or brightness need to be altered, the result is the same, but if both are involved, + // there's no way to map that, so just force a conversion of the image. + bool needsConversion = nContrast != 0 && nBrightness != 0; + if ( ( rObjData.nSpFlags & SP_FOLESHAPE ) == 0 && !needsConversion ) { if ( nBrightness ) rSet.Put( SdrGrafLuminanceItem( nBrightness ) ); @@ -3842,7 +3847,7 @@ SdrObject* SvxMSDffManager::ImportGraphic( SvStream& rSt, SfxItemSet& rSet, cons { BitmapEx aBitmapEx( aGraf.GetBitmapEx() ); if ( nBrightness || nContrast || ( nGamma != 0x10000 ) ) - aBitmapEx.Adjust( nBrightness, (sal_Int16)nContrast, 0, 0, 0, (double)nGamma / 0x10000, sal_False ); + aBitmapEx.Adjust( nBrightness, (sal_Int16)nContrast, 0, 0, 0, (double)nGamma / 0x10000, false, true ); if ( eDrawMode == GRAPHICDRAWMODE_GREYS ) aBitmapEx.Convert( BMP_CONVERSION_8BIT_GREYS ); else if ( eDrawMode == GRAPHICDRAWMODE_MONO ) @@ -3856,7 +3861,7 @@ SdrObject* SvxMSDffManager::ImportGraphic( SvStream& rSt, SfxItemSet& rSet, cons { GDIMetaFile aGdiMetaFile( aGraf.GetGDIMetaFile() ); if ( nBrightness || nContrast || ( nGamma != 0x10000 ) ) - aGdiMetaFile.Adjust( nBrightness, (sal_Int16)nContrast, 0, 0, 0, (double)nGamma / 0x10000, sal_False ); + aGdiMetaFile.Adjust( nBrightness, (sal_Int16)nContrast, 0, 0, 0, (double)nGamma / 0x10000, false, true ); if ( eDrawMode == GRAPHICDRAWMODE_GREYS ) aGdiMetaFile.Convert( MTF_CONVERSION_8BIT_GREYS ); else if ( eDrawMode == GRAPHICDRAWMODE_MONO ) diff --git a/include/vcl/bitmap.hxx b/include/vcl/bitmap.hxx index adf6b63785a8..621fceb80a63 100644 --- a/include/vcl/bitmap.hxx +++ b/include/vcl/bitmap.hxx @@ -779,6 +779,9 @@ public: If sal_True, invert the channel values with the logical 'not' operator @return sal_True, if the operation was completed successfully. + + @param msoBrightness + Use the same formula for brightness as used by MSOffice. */ sal_Bool Adjust( short nLuminancePercent = 0, short nContrastPercent = 0, @@ -786,7 +789,8 @@ public: short nChannelGPercent = 0, short nChannelBPercent = 0, double fGamma = 1.0, - sal_Bool bInvert = sal_False ); + bool bInvert = false, + bool msoBrightness = false ); /** Apply specified filter to the bitmap diff --git a/include/vcl/bitmapex.hxx b/include/vcl/bitmapex.hxx index da23547dfdd8..8ac6325c5a46 100644 --- a/include/vcl/bitmapex.hxx +++ b/include/vcl/bitmapex.hxx @@ -343,6 +343,10 @@ public: If sal_True, invert the channel values with the logical 'not' operator @return sal_True, if the operation was completed successfully. + + @param msoFormula + Use the same formula for brightness as used by MSOffice. + */ sal_Bool Adjust( short nLuminancePercent = 0, short nContrastPercent = 0, @@ -350,7 +354,8 @@ public: short nChannelGPercent = 0, short nChannelBPercent = 0, double fGamma = 1.0, - sal_Bool bInvert = sal_False ); + bool bInvert = false, + bool msoBrightness = false ); /** Apply specified filter to the bitmap diff --git a/include/vcl/gdimtf.hxx b/include/vcl/gdimtf.hxx index 8afdc1478211..d38f8638a6df 100644 --- a/include/vcl/gdimtf.hxx +++ b/include/vcl/gdimtf.hxx @@ -150,7 +150,7 @@ public: void Adjust( short nLuminancePercent = 0, short nContrastPercent = 0, short nChannelRPercent = 0, short nChannelGPercent = 0, short nChannelBPercent = 0, double fGamma = 1.0, - sal_Bool bInvert = sal_False + bool bInvert = false, bool msoBrightness = false ); void Convert( MtfConversion eConversion ); diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx index 5c4905a28b1e..4fbe1b8e156d 100644 --- a/vcl/source/gdi/bitmap3.cxx +++ b/vcl/source/gdi/bitmap3.cxx @@ -3250,7 +3250,7 @@ sal_Bool Bitmap::Vectorize( GDIMetaFile& rMtf, sal_uInt8 cReduce, sal_uLong nFla sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, - double fGamma, sal_Bool bInvert ) + double fGamma, bool bInvert, bool msoBrightness ) { sal_Bool bRet = sal_False; @@ -3282,8 +3282,11 @@ sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, else fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0; - // total offset = luminance offset + contrast offset - fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; + if(!msoBrightness) + // total offset = luminance offset + contrast offset + fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; + else + fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55; // channel offset = channel offset + total offset fROff = nChannelRPercent * 2.55 + fOff; @@ -3297,10 +3300,21 @@ sal_Bool Bitmap::Adjust( short nLuminancePercent, short nContrastPercent, // create mapping table for( nX = 0L; nX < 256L; nX++ ) { - cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); - cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); - cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); - + if(!msoBrightness) + { + cMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); + cMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); + cMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); + } + else + { + // LO simply uses (in a somewhat optimized form) "newcolor = (oldcolor-128)*contrast+brightness+128" + // as the formula, i.e. contrast first, brightness afterwards. MSOffice, for whatever weird reason, + // use neither first, but apparently it applies half of brightness before contrast and half afterwards. + cMapR[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fROff/2-128) * fM + 128 + fROff/2 ), 0L, 255L ); + cMapG[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fGOff/2-128) * fM + 128 + fGOff/2 ), 0L, 255L ); + cMapB[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fBOff/2-128) * fM + 128 + fBOff/2 ), 0L, 255L ); + } if( bGamma ) { cMapR[ nX ] = GAMMA( cMapR[ nX ], fGamma ); diff --git a/vcl/source/gdi/bitmapex.cxx b/vcl/source/gdi/bitmapex.cxx index 6deb1db79208..98c6b2487fb0 100644 --- a/vcl/source/gdi/bitmapex.cxx +++ b/vcl/source/gdi/bitmapex.cxx @@ -633,11 +633,11 @@ sal_Bool BitmapEx::Replace( const Color* pSearchColors, const Color* pReplaceCol sal_Bool BitmapEx::Adjust( short nLuminancePercent, short nContrastPercent, short nChannelRPercent, short nChannelGPercent, short nChannelBPercent, - double fGamma, sal_Bool bInvert ) + double fGamma, bool bInvert, bool msoBrightness ) { return( !!aBitmap ? aBitmap.Adjust( nLuminancePercent, nContrastPercent, nChannelRPercent, nChannelGPercent, nChannelBPercent, - fGamma, bInvert ) : sal_False ); + fGamma, bInvert, msoBrightness ) : false ); } sal_Bool BitmapEx::Filter( BmpFilter eFilter, const BmpFilterParam* pFilterParam, const Link* pProgress ) diff --git a/vcl/source/gdi/gdimtf.cxx b/vcl/source/gdi/gdimtf.cxx index 2e7417260c2f..12ad981083ff 100644 --- a/vcl/source/gdi/gdimtf.cxx +++ b/vcl/source/gdi/gdimtf.cxx @@ -2175,7 +2175,7 @@ void GDIMetaFile::ImplExchangeColors( ColorExchangeFnc pFncCol, const void* pCol void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent, short nChannelRPercent, short nChannelGPercent, - short nChannelBPercent, double fGamma, sal_Bool bInvert ) + short nChannelBPercent, double fGamma, bool bInvert, bool msoBrightness ) { // nothing to do? => return quickly if( nLuminancePercent || nContrastPercent || @@ -2196,8 +2196,11 @@ void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent, else fM = ( 128.0 + 1.27 * MinMax( nContrastPercent, -100L, 0L ) ) / 128.0; - // total offset = luminance offset + contrast offset - fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; + if(!msoBrightness) + // total offset = luminance offset + contrast offset + fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55 + 128.0 - fM * 128.0; + else + fOff = MinMax( nLuminancePercent, -100L, 100L ) * 2.55; // channel offset = channel offset + total offset fROff = nChannelRPercent * 2.55 + fOff; @@ -2211,10 +2214,18 @@ void GDIMetaFile::Adjust( short nLuminancePercent, short nContrastPercent, // create mapping table for( long nX = 0L; nX < 256L; nX++ ) { - aColParam.pMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); - aColParam.pMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); - aColParam.pMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); - + if(!msoBrightness) + { + aColParam.pMapR[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fROff ), 0L, 255L ); + aColParam.pMapG[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fGOff ), 0L, 255L ); + aColParam.pMapB[ nX ] = (sal_uInt8) MinMax( FRound( nX * fM + fBOff ), 0L, 255L ); + } + else + { + aColParam.pMapR[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fROff/2-128) * fM + 128 + fROff/2 ), 0L, 255L ); + aColParam.pMapG[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fGOff/2-128) * fM + 128 + fGOff/2 ), 0L, 255L ); + aColParam.pMapB[ nX ] = (sal_uInt8) MinMax( FRound( (nX+fBOff/2-128) * fM + 128 + fBOff/2 ), 0L, 255L ); + } if( bGamma ) { aColParam.pMapR[ nX ] = GAMMA( aColParam.pMapR[ nX ], fGamma ); |