summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2022-05-20 17:30:49 +0100
committerCaolán McNamara <caolanm@redhat.com>2022-05-21 15:59:10 +0200
commite912a446210fdae61be3fc04d20d90488cedcdf6 (patch)
treebb3ac9742e87b0faff6dc1d31c77f1ee27b189a8
parent052a6c9e5e2c5e4a4d1e3b3d91ca6464939ebbab (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.cxx125
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);