diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2016-06-21 14:34:45 +0800 |
---|---|---|
committer | Jan Holesovsky <kendy@collabora.com> | 2016-06-23 09:43:17 +0000 |
commit | ebad0ff6da52d3f3bf9ca026ed2699df0673ce76 (patch) | |
tree | fe88b0c83b75a87cffaac72f31b77cf2d450f323 | |
parent | e2cc303ee8bbb0029dd095833ae93d84ec9d73c0 (diff) |
tdf#100451 convert texture buffer to 1-bit and 4-bit palette buffer
OpenGL doesn't support palettes so when the texture is created,
the bitmap buffer is converted to 24-bit RGB. This works nice for
showing the bitmaps on screen. The problem arises when we want to
read the bitmap buffer back (like in a PDF export) as we have to
convert that back to 1-bit or 4-bit palette bitmap buffer. For 4-bit
this was not implemented yet, on the other hand for 1-bit it was
implemented but it didn't take palette into account so the bitmap
was not correct (inverted).
This commit introduces a ScanlineWriter which handles writing
RGB colors to 1-bit and 4-bit palette scanlines. The class sets
up the masks and shifts needed to place the color information
at the correct place in a byte. It also automatically converts a
RGB to palette index.
Change-Id: Ie66ca8cecff40c1252072ba95196ef65ba787f4c
Reviewed-on: https://gerrit.libreoffice.org/26532
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Tomaž Vajngerl <quikee@gmail.com>
Reviewed-on: https://gerrit.libreoffice.org/26534
Reviewed-by: Jan Holesovsky <kendy@collabora.com>
Tested-by: Jan Holesovsky <kendy@collabora.com>
-rw-r--r-- | vcl/opengl/salbmp.cxx | 92 |
1 files changed, 66 insertions, 26 deletions
diff --git a/vcl/opengl/salbmp.cxx b/vcl/opengl/salbmp.cxx index 87fc54225020..58909b48e2e0 100644 --- a/vcl/opengl/salbmp.cxx +++ b/vcl/opengl/salbmp.cxx @@ -412,7 +412,48 @@ void lclInstantiateTexture(OpenGLTexture& rTexture, const int nWidth, const int rTexture = OpenGLTexture (nWidth, nHeight, nFormat, nType, pData); } -} +// Write color information for 1 and 4 bit palette bitmap scanlines. +class ScanlineWriter +{ + BitmapPalette& maPalette; + sal_uInt8 mnColorsPerByte; // number of colors that are stored in one byte + sal_uInt8 mnColorBitSize; // number of bits a color takes + sal_uInt8 mnColorBitMask; // bit mask used to isolate the color + sal_uInt8* mpCurrentScanline; + long mnX; + +public: + ScanlineWriter(BitmapPalette& aPalette, sal_Int8 nColorsPerByte) + : maPalette(aPalette) + , mnColorsPerByte(nColorsPerByte) + , mnColorBitSize(8 / mnColorsPerByte) // bit size is number of bit in a byte divided by number of colors per byte (8 / 2 = 4 for 4-bit) + , mnColorBitMask((1 << mnColorBitSize) - 1) // calculate the bit mask from the bit size + , mpCurrentScanline(nullptr) + , mnX(0) + {} + + inline void writeRGB(sal_uInt8 nR, sal_uInt8 nG, sal_uInt8 nB) + { + // calculate to which index we will write + long nScanlineIndex = mnX / mnColorsPerByte; + + // calculate the number of shifts to get the color information to the right place + long nShift = (8 - mnColorBitSize) - ((mnX % mnColorsPerByte) * mnColorBitSize); + + sal_uInt16 nColorIndex = maPalette.GetBestIndex(BitmapColor(nR, nG, nB)); + mpCurrentScanline[nScanlineIndex] &= ~(mnColorBitMask << nShift); // clear + mpCurrentScanline[nScanlineIndex] |= (nColorIndex & mnColorBitMask) << nShift; // set + mnX++; + } + + inline void nextLine(sal_uInt8* pScanline) + { + mnX = 0; + mpCurrentScanline = pScanline; + } +}; + +} // end anonymous namespace Size OpenGLSalBitmap::GetSize() const { @@ -559,43 +600,43 @@ bool OpenGLSalBitmap::ReadTexture() #endif return true; } - else if (mnBits == 1) - { // convert buffers from 24-bit RGB to 1-bit Mask + else if (mnBits == 1 || mnBits == 4) + { // convert buffers from 24-bit RGB to 1 or 4-bit buffer std::vector<sal_uInt8> aBuffer(mnWidth * mnHeight * 3); sal_uInt8* pBuffer = aBuffer.data(); determineTextureFormat(24, nFormat, nType); maTexture.Read(nFormat, nType, pBuffer); + sal_uInt16 nSourceBytesPerRow = lclBytesPerRow(24, mnWidth); - int nShift = 7; - size_t nIndex = 0; - - sal_uInt8* pCurrent = pBuffer; + std::unique_ptr<ScanlineWriter> pWriter; + switch(mnBits) + { + case 1: + pWriter.reset(new ScanlineWriter(maPalette, 8)); + break; + case 4: + default: + pWriter.reset(new ScanlineWriter(maPalette, 2)); + break; + } for (int y = 0; y < mnHeight; ++y) { + sal_uInt8* pSource = &pBuffer[y * nSourceBytesPerRow]; + sal_uInt8* pDestination = &pData[y * mnBytesPerRow]; + + pWriter->nextLine(pDestination); + for (int x = 0; x < mnWidth; ++x) { - if (nShift < 0) - { - nShift = 7; - nIndex++; - pData[nIndex] = 0; - } - - sal_uInt8 nR = *pCurrent++; - sal_uInt8 nG = *pCurrent++; - sal_uInt8 nB = *pCurrent++; + // read source + sal_uInt8 nR = *pSource++; + sal_uInt8 nG = *pSource++; + sal_uInt8 nB = *pSource++; - if (nR > 0 && nG > 0 && nB > 0) - { - pData[nIndex] |= (1 << nShift); - } - nShift--; + pWriter->writeRGB(nR, nG, nB); } - nShift = 7; - nIndex++; - pData[nIndex] = 0; } return true; } @@ -604,7 +645,6 @@ bool OpenGLSalBitmap::ReadTexture() << mnWidth << "x" << mnHeight << "- unimplemented bit depth: " << mnBits); return false; - } sal_uInt16 OpenGLSalBitmap::GetBitCount() const |