diff options
author | Caolán McNamara <caolanm@redhat.com> | 2022-05-20 17:30:49 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2022-05-21 15:59:10 +0200 |
commit | e912a446210fdae61be3fc04d20d90488cedcdf6 (patch) | |
tree | bb3ac9742e87b0faff6dc1d31c77f1ee27b189a8 | |
parent | 052a6c9e5e2c5e4a4d1e3b3d91ca6464939ebbab (diff) |
tiff: use more complicated apis to need a smaller buffer during read
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 <caolanm@redhat.com>
-rw-r--r-- | vcl/source/filter/itiff/itiff.cxx | 125 |
1 files 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<uint32_t> 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<Context*>(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<Context*>(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<uint32_t*>(_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); |