include/vcl/filter/PngImageWriter.hxx | 2 vcl/source/filter/png/PngImageWriter.cxx | 66 +++++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 13 deletions(-)
New commits: commit fac9dfa19b3853e4b1b6ec62baf1645a8b1194c9 Author: offtkp <[email protected]> AuthorDate: Sun Jul 17 21:42:53 2022 +0300 Commit: Tomaž Vajngerl <[email protected]> CommitDate: Tue Jul 19 10:10:37 2022 +0200 Add 32bpp export support in PngImageWriter Also added support for "Translucent" property Change-Id: I45cc3cf82ecacac08c3852ca2ad09fb8137ffc44 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137154 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <[email protected]> diff --git a/include/vcl/filter/PngImageWriter.hxx b/include/vcl/filter/PngImageWriter.hxx index 4fb11b1ca48a..c788f19bf4db 100644 --- a/include/vcl/filter/PngImageWriter.hxx +++ b/include/vcl/filter/PngImageWriter.hxx @@ -32,7 +32,7 @@ class VCL_DLLPUBLIC PngImageWriter css::uno::Reference<css::task::XStatusIndicator> mxStatusIndicator; sal_Int32 mnCompressionLevel; - bool mbInterlaced; + bool mbInterlaced, mbTranslucent; std::vector<PngChunk> maAdditionalChunks; public: diff --git a/vcl/source/filter/png/PngImageWriter.cxx b/vcl/source/filter/png/PngImageWriter.cxx index 516c21a555df..7d9221c75112 100644 --- a/vcl/source/filter/png/PngImageWriter.cxx +++ b/vcl/source/filter/png/PngImageWriter.cxx @@ -11,6 +11,7 @@ #include <png.h> #include <bitmap/BitmapWriteAccess.hxx> #include <vcl/bitmap.hxx> +#include <vcl/BitmapTools.hxx> namespace { @@ -20,7 +21,7 @@ void combineScanlineChannels(Scanline pRGBScanline, Scanline pAlphaScanline, Sca assert(pRGBScanline && "RGB scanline is null"); assert(pAlphaScanline && "Alpha scanline is null"); - for (sal_uInt32 i = 0; i < nSize; i++) + for (sal_uInt32 i = 0; i < nSize; i += 3) { *pResult++ = *pRGBScanline++; // R *pResult++ = *pRGBScanline++; // G @@ -48,8 +49,14 @@ static void lclWriteStream(png_structp pPng, png_bytep pData, png_size_t pDataSi } static bool pngWrite(SvStream& rStream, const BitmapEx& rBitmapEx, int nCompressionLevel, + bool bInterlaced, bool bTranslucent, const std::vector<PngChunk>& aAdditionalChunks) { + if (rBitmapEx.IsAlpha() && !bTranslucent) + return false; + if (rBitmapEx.IsEmpty()) + return false; + png_structp pPng = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!pPng) @@ -62,6 +69,17 @@ static bool pngWrite(SvStream& rStream, const BitmapEx& rBitmapEx, int nCompress return false; } + BitmapEx aBitmapEx; + if (rBitmapEx.GetBitmap().getPixelFormat() == vcl::PixelFormat::N32_BPP) + { + if (!vcl::bitmap::convertBitmap32To24Plus8(rBitmapEx, aBitmapEx)) + return false; + } + else + { + aBitmapEx = rBitmapEx; + } + Bitmap aBitmap; AlphaMask aAlphaMask; Bitmap::ScopedReadAccess pAccess; @@ -78,13 +96,14 @@ static bool pngWrite(SvStream& rStream, const BitmapEx& rBitmapEx, int nCompress // Set our custom stream writer png_set_write_fn(pPng, &rStream, lclWriteStream, nullptr); - aBitmap = rBitmapEx.GetBitmap(); - aAlphaMask = rBitmapEx.GetAlpha(); + aBitmap = aBitmapEx.GetBitmap(); + aAlphaMask = aBitmapEx.GetAlpha(); { + bool bCombineChannels = false; pAccess = Bitmap::ScopedReadAccess(aBitmap); pAlphaAccess = Bitmap::ScopedReadAccess(aAlphaMask); - Size aSize = rBitmapEx.GetSizePixel(); + Size aSize = aBitmapEx.GetSizePixel(); int bitDepth = -1; int colorType = -1; @@ -127,7 +146,21 @@ static bool pngWrite(SvStream& rStream, const BitmapEx& rBitmapEx, int nCompress colorType = PNG_COLOR_TYPE_RGB; bitDepth = 8; if (pAlphaAccess) + { colorType = PNG_COLOR_TYPE_RGBA; + bCombineChannels = true; + } + break; + } + case ScanlineFormat::N32BitTcBgra: + { + png_set_bgr(pPng); + [[fallthrough]]; + } + case ScanlineFormat::N32BitTcRgba: + { + colorType = PNG_COLOR_TYPE_RGBA; + bitDepth = 8; break; } default: @@ -136,9 +169,9 @@ static bool pngWrite(SvStream& rStream, const BitmapEx& rBitmapEx, int nCompress } } - if (rBitmapEx.GetPrefMapMode().GetMapUnit() == MapUnit::Map100thMM) + if (aBitmapEx.GetPrefMapMode().GetMapUnit() == MapUnit::Map100thMM) { - Size aPrefSize(rBitmapEx.GetPrefSize()); + Size aPrefSize(aBitmapEx.GetPrefSize()); sal_uInt32 nPrefSizeX = o3tl::convert(aSize.Width(), 100000, aPrefSize.Width()); sal_uInt32 nPrefSizeY = o3tl::convert(aSize.Height(), 100000, aPrefSize.Height()); png_set_pHYs(pPng, pInfo, nPrefSizeX, nPrefSizeY, 1); @@ -146,7 +179,7 @@ static bool pngWrite(SvStream& rStream, const BitmapEx& rBitmapEx, int nCompress png_set_compression_level(pPng, nCompressionLevel); - int interlaceType = PNG_INTERLACE_NONE; + int interlaceType = bInterlaced ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE; int compressionType = PNG_COMPRESSION_TYPE_DEFAULT; int filterMethod = PNG_FILTER_TYPE_DEFAULT; @@ -185,10 +218,10 @@ static bool pngWrite(SvStream& rStream, const BitmapEx& rBitmapEx, int nCompress pSourcePointer = pAccess->GetScanline(y); Scanline pFinalPointer = pSourcePointer; std::vector<std::remove_pointer_t<Scanline>> aCombinedChannels; - if (pAlphaAccess) + if (bCombineChannels) { - // Check that theres an alpha channel per 3 color/RGB channels - assert(((pAlphaAccess->GetScanlineSize() * 3) == pAccess->GetScanlineSize()) + // Check that theres at least an alpha channel per 3 color/RGB channels + assert(((pAlphaAccess->GetScanlineSize() * 3) >= pAccess->GetScanlineSize()) && "RGB and alpha channel size mismatch"); // Allocate enough size to fit all 4 channels aCombinedChannels.resize(pAlphaAccess->GetScanlineSize() @@ -196,7 +229,7 @@ static bool pngWrite(SvStream& rStream, const BitmapEx& rBitmapEx, int nCompress Scanline pAlphaPointer = pAlphaAccess->GetScanline(y); // Combine RGB and alpha channels combineScanlineChannels(pSourcePointer, pAlphaPointer, aCombinedChannels.data(), - pAlphaAccess->GetScanlineSize()); + pAccess->GetScanlineSize()); pFinalPointer = aCombinedChannels.data(); // Invert alpha channel (255 - a) png_set_invert_alpha(pPng); @@ -229,6 +262,13 @@ void PngImageWriter::setParameters(css::uno::Sequence<css::beans::PropertyValue> rValue.Value >>= mnCompressionLevel; else if (rValue.Name == "Interlaced") rValue.Value >>= mbInterlaced; + else if (rValue.Name == "Translucent") + { + tools::Long nTmp = 0; + rValue.Value >>= nTmp; + if (!nTmp) + mbTranslucent = false; + } else if (rValue.Name == "AdditionalChunks") { css::uno::Sequence<css::beans::PropertyValue> aAdditionalChunkSequence; @@ -269,12 +309,14 @@ PngImageWriter::PngImageWriter(SvStream& rStream) : mrStream(rStream) , mnCompressionLevel(6) , mbInterlaced(false) + , mbTranslucent(true) { } bool PngImageWriter::write(const BitmapEx& rBitmapEx) { - return pngWrite(mrStream, rBitmapEx, mnCompressionLevel, maAdditionalChunks); + return pngWrite(mrStream, rBitmapEx, mnCompressionLevel, mbInterlaced, mbTranslucent, + maAdditionalChunks); } } // namespace vcl
