From e912a446210fdae61be3fc04d20d90488cedcdf6 Mon Sep 17 00:00:00 2001 From: Caolán McNamara Date: Fri, 20 May 2022 17:30:49 +0100 Subject: tiff: use more complicated apis to need a smaller buffer during read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit while the split alpha persists as a thing Change-Id: I17b37650e66ae8bd4aa42b953cd39fcfe7ac80ee Reviewed-on: https://gerrit.libreoffice.org/c/core/+/134696 Tested-by: Jenkins Reviewed-by: Caolán McNamara --- vcl/source/filter/itiff/itiff.cxx | 125 ++++++++++++++++++++++++++++---------- 1 file changed, 94 insertions(+), 31 deletions(-) diff --git a/vcl/source/filter/itiff/itiff.cxx b/vcl/source/filter/itiff/itiff.cxx index 8bce9e705b35..8fa61c4509b5 100644 --- a/vcl/source/filter/itiff/itiff.cxx +++ b/vcl/source/filter/itiff/itiff.cxx @@ -36,11 +36,38 @@ namespace { SvStream& rStream; tsize_t nSize; + + tileContigRoutine pOrigContig; + tileSeparateRoutine pOrigSeparate; + BitmapWriteAccess* pWriteAccess; + BitmapWriteAccess* pAlphaAccess; + std::vector aBuffer; + Context(SvStream& rInStream, tsize_t nInSize) : rStream(rInStream) , nSize(nInSize) + , pOrigContig(nullptr) + , pOrigSeparate(nullptr) + , pWriteAccess(nullptr) + , pAlphaAccess(nullptr) { } + + void SetPixels(uint32_t x, uint32_t y, uint32_t w, uint32_t h) + { + const uint32_t* pSrc = aBuffer.data(); + + for (uint32_t nRow = 0; nRow < h; ++nRow) + { + for (uint32_t nCol = 0; nCol < w; ++nCol) + { + pWriteAccess->SetPixel(y + nRow, x + nCol, + Color(TIFFGetR(*pSrc), TIFFGetG(*pSrc), TIFFGetB(*pSrc))); + pAlphaAccess->SetPixelIndex(y + nRow, x + nCol, 255 - TIFFGetA(*pSrc)); + ++pSrc; + } + } + } }; } @@ -90,6 +117,34 @@ static toff_t tiff_size(thandle_t handle) return pContext->nSize; } +static void putContigPixel(TIFFRGBAImage* img, uint32_t* /*raster*/, + uint32_t x, uint32_t y, uint32_t w, uint32_t h, + int32_t fromskew, int32_t toskew, + unsigned char* cp) +{ + Context* pContext = static_cast(TIFFClientdata(img->tif)); + + pContext->aBuffer.resize(w * h); + (pContext->pOrigContig)(img, pContext->aBuffer.data(), 0, 0, w, h, + fromskew, toskew, cp); + + pContext->SetPixels(x, y, w, h); +} + +static void putSeparatePixel(TIFFRGBAImage* img, uint32_t* /*raster*/, + uint32_t x, uint32_t y, uint32_t w, uint32_t h, + int32_t fromskew, int32_t toskew, + unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a) +{ + Context* pContext = static_cast(TIFFClientdata(img->tif)); + + pContext->aBuffer.resize(w * h); + (pContext->pOrigSeparate)(img, pContext->aBuffer.data(), 0, 0, w, h, + fromskew, toskew, r, g, b, a); + + pContext->SetPixels(x, y, w, h); +} + bool ImportTiffGraphicImport(SvStream& rTIFF, Graphic& rGraphic) { Context aContext(rTIFF, rTIFF.remainingSize()); @@ -110,43 +165,51 @@ bool ImportTiffGraphicImport(SvStream& rTIFF, Graphic& rGraphic) TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); - size_t npixels = w * h; - uint32_t* raster = static_cast(_TIFFmalloc(npixels * sizeof (uint32_t))); - if (raster) + Bitmap bitmap(Size(w, h), vcl::PixelFormat::N24_BPP); + AlphaMask bitmapAlpha(Size(w, h)); + + BitmapScopedWriteAccess access(bitmap); + AlphaScopedWriteAccess accessAlpha(bitmapAlpha); + + aContext.pWriteAccess = access.get(); + aContext.pAlphaAccess = accessAlpha.get(); + + char emsg[1024] = ""; + TIFFRGBAImage img; + bool bOk = false; + // Expanded out TIFFReadRGBAImageOriented to create this block then + // inserted custom "put" methods to write (via a limited size buffer) + // into the final Bitmap incrementally + if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, 1, emsg)) { - if (TIFFReadRGBAImageOriented(tif, w, h, raster, ORIENTATION_TOPLEFT, 1)) + img.req_orientation = ORIENTATION_TOPLEFT; + assert(!TIFFIsTiled(img.tif)); + if (!TIFFIsTiled(img.tif)) { - Bitmap bitmap(Size(w, h), vcl::PixelFormat::N24_BPP); - AlphaMask bitmapAlpha(Size(w, h)); - - BitmapScopedWriteAccess access(bitmap); - AlphaScopedWriteAccess accessAlpha(bitmapAlpha); + aContext.pOrigContig = img.put.contig; + img.put.contig = putContigPixel; + } + else + { + aContext.pOrigSeparate = img.put.separate; + img.put.separate = putSeparatePixel; + } - for (tools::Long y = 0; y < access->Height(); ++y) - { - const uint32_t* src = raster + w * y; - for (tools::Long x = 0; x < access->Width(); ++x) - { - sal_uInt8 r = TIFFGetR(*src); - sal_uInt8 g = TIFFGetG(*src); - sal_uInt8 b = TIFFGetB(*src); - sal_uInt8 a = TIFFGetA(*src); - access->SetPixel(y, x, Color(r, g, b)); - accessAlpha->SetPixelIndex(y, x, 255 - a); - ++src; - } - } + bOk = TIFFRGBAImageGet(&img, nullptr, w, img.height); + TIFFRGBAImageEnd(&img); + } - access.reset(); - accessAlpha.reset(); + access.reset(); + accessAlpha.reset(); - BitmapEx aBitmapEx(bitmap, bitmapAlpha); - AnimationBitmap aAnimationBitmap(aBitmapEx, Point(0, 0), aBitmapEx.GetSizePixel(), - ANIMATION_TIMEOUT_ON_CLICK, Disposal::Back); - aAnimation.Insert(aAnimationBitmap); - } - _TIFFfree(raster); + if (bOk) + { + BitmapEx aBitmapEx(bitmap, bitmapAlpha); + AnimationBitmap aAnimationBitmap(aBitmapEx, Point(0, 0), aBitmapEx.GetSizePixel(), + ANIMATION_TIMEOUT_ON_CLICK, Disposal::Back); + aAnimation.Insert(aAnimationBitmap); } + } while (TIFFReadDirectory(tif)); TIFFClose(tif); -- cgit v1.2.3