Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GDALExpandPackedBitsToByteAt0Or255() and GDALExpandPackedBitsToByteAt0Or1() #11612

Merged
merged 3 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions autotest/cpp/test_gdal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5124,4 +5124,72 @@ TEST_F(test_gdal, GDALTranspose2D_Byte_optims)
}
}

TEST_F(test_gdal, GDALExpandPackedBitsToByteAt0Or1)
{
unsigned next = 1;
const auto badRand = [&next]()
{
next = static_cast<unsigned>(static_cast<uint64_t>(next) * 1103515245 +
12345);
return next;
};

constexpr int BITS_PER_BYTE = 8;
constexpr int SSE_REGISTER_SIZE_IN_BYTES = 16;
constexpr int LESS_THAN_8BITS = 5;
std::vector<GByte> expectedOut(SSE_REGISTER_SIZE_IN_BYTES * BITS_PER_BYTE +
BITS_PER_BYTE + LESS_THAN_8BITS);
std::vector<GByte> in((expectedOut.size() + BITS_PER_BYTE - 1) /
BITS_PER_BYTE);
for (int i = 0; i < static_cast<int>(expectedOut.size()); ++i)
{
expectedOut[i] = (badRand() % 2) == 0 ? 0 : 1;
if (expectedOut[i])
{
in[i / BITS_PER_BYTE] = static_cast<GByte>(
in[i / BITS_PER_BYTE] |
(1 << (BITS_PER_BYTE - 1 - (i % BITS_PER_BYTE))));
}
}

std::vector<GByte> out(expectedOut.size());
GDALExpandPackedBitsToByteAt0Or1(in.data(), out.data(), out.size());

EXPECT_EQ(out, expectedOut);
}

TEST_F(test_gdal, GDALExpandPackedBitsToByteAt0Or255)
{
unsigned next = 1;
const auto badRand = [&next]()
{
next = static_cast<unsigned>(static_cast<uint64_t>(next) * 1103515245 +
12345);
return next;
};

constexpr int BITS_PER_BYTE = 8;
constexpr int SSE_REGISTER_SIZE_IN_BYTES = 16;
constexpr int LESS_THAN_8BITS = 5;
std::vector<GByte> expectedOut(SSE_REGISTER_SIZE_IN_BYTES * BITS_PER_BYTE +
BITS_PER_BYTE + LESS_THAN_8BITS);
std::vector<GByte> in((expectedOut.size() + BITS_PER_BYTE - 1) /
BITS_PER_BYTE);
for (int i = 0; i < static_cast<int>(expectedOut.size()); ++i)
{
expectedOut[i] = (badRand() % 2) == 0 ? 0 : 255;
if (expectedOut[i])
{
in[i / BITS_PER_BYTE] = static_cast<GByte>(
in[i / BITS_PER_BYTE] |
(1 << (BITS_PER_BYTE - 1 - (i % BITS_PER_BYTE))));
}
}

std::vector<GByte> out(expectedOut.size());
GDALExpandPackedBitsToByteAt0Or255(in.data(), out.data(), out.size());

EXPECT_EQ(out, expectedOut);
}

} // namespace
91 changes: 9 additions & 82 deletions frmts/gtiff/gtiffoddbitsband.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,60 +515,6 @@ CPLErr GTiffOddBitsBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
/* IReadBlock() */
/************************************************************************/

static void ExpandPacked8ToByte1(const GByte *const CPL_RESTRICT pabySrc,
GByte *const CPL_RESTRICT pabyDest,
GPtrDiff_t nBytes)
{
for (decltype(nBytes) i = 0, j = 0; i < nBytes; i++, j += 8)
{
const GByte byVal = pabySrc[i];
pabyDest[j + 0] = (byVal >> 7) & 0x1;
pabyDest[j + 1] = (byVal >> 6) & 0x1;
pabyDest[j + 2] = (byVal >> 5) & 0x1;
pabyDest[j + 3] = (byVal >> 4) & 0x1;
pabyDest[j + 4] = (byVal >> 3) & 0x1;
pabyDest[j + 5] = (byVal >> 2) & 0x1;
pabyDest[j + 6] = (byVal >> 1) & 0x1;
pabyDest[j + 7] = (byVal >> 0) & 0x1;
}
}

#if defined(__GNUC__) || defined(_MSC_VER)
// Signedness of char implementation dependent, so be explicit.
// Assumes 2-complement integer types and sign extension of right shifting
// GCC guarantees such:
// https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation
static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
{
return static_cast<GByte>(static_cast<signed char>(byVal << (7 - nBit)) >>
7);
}
#else
// Portable way
static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
{
return (byVal & (1 << nBit)) ? 255 : 0;
}
#endif

static void ExpandPacked8ToByte255(const GByte *const CPL_RESTRICT pabySrc,
GByte *const CPL_RESTRICT pabyDest,
GPtrDiff_t nBytes)
{
for (decltype(nBytes) i = 0, j = 0; i < nBytes; i++, j += 8)
{
const GByte byVal = pabySrc[i];
pabyDest[j + 0] = ExtractBitAndConvertTo255(byVal, 7);
pabyDest[j + 1] = ExtractBitAndConvertTo255(byVal, 6);
pabyDest[j + 2] = ExtractBitAndConvertTo255(byVal, 5);
pabyDest[j + 3] = ExtractBitAndConvertTo255(byVal, 4);
pabyDest[j + 4] = ExtractBitAndConvertTo255(byVal, 3);
pabyDest[j + 5] = ExtractBitAndConvertTo255(byVal, 2);
pabyDest[j + 6] = ExtractBitAndConvertTo255(byVal, 1);
pabyDest[j + 7] = ExtractBitAndConvertTo255(byVal, 0);
}
}

CPLErr GTiffOddBitsBand::IReadBlock(int nBlockXOff, int nBlockYOff,
void *pImage)

Expand Down Expand Up @@ -608,43 +554,24 @@ CPLErr GTiffOddBitsBand::IReadBlock(int nBlockXOff, int nBlockYOff,
(m_poGDS->nBands == 1 ||
m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE))
{
/* --------------------------------------------------------------------
*/
/* Translate 1bit data to eight bit. */
/* --------------------------------------------------------------------
*/
GPtrDiff_t iDstOffset = 0;
const GByte *const CPL_RESTRICT m_pabyBlockBuf =
m_poGDS->m_pabyBlockBuf;
// Translate 1bit data to eight bit.
const GByte *CPL_RESTRICT pabySrc = m_poGDS->m_pabyBlockBuf;
GByte *CPL_RESTRICT pabyDest = static_cast<GByte *>(pImage);

for (int iLine = 0; iLine < nBlockYSize; ++iLine)
{
GPtrDiff_t iSrcOffsetByte =
static_cast<GPtrDiff_t>((nBlockXSize + 7) >> 3) * iLine;

if (!m_poGDS->m_bPromoteTo8Bits)
if (m_poGDS->m_bPromoteTo8Bits)
{
ExpandPacked8ToByte1(m_pabyBlockBuf + iSrcOffsetByte,
pabyDest + iDstOffset, nBlockXSize / 8);
GDALExpandPackedBitsToByteAt0Or255(pabySrc, pabyDest,
nBlockXSize);
}
else
{
ExpandPacked8ToByte255(m_pabyBlockBuf + iSrcOffsetByte,
pabyDest + iDstOffset, nBlockXSize / 8);
}
GPtrDiff_t iSrcOffsetBit = (iSrcOffsetByte + nBlockXSize / 8) * 8;
iDstOffset += nBlockXSize & ~0x7;
const GByte bSetVal = m_poGDS->m_bPromoteTo8Bits ? 255 : 1;
for (int iPixel = nBlockXSize & ~0x7; iPixel < nBlockXSize;
++iPixel, ++iSrcOffsetBit)
{
if (m_pabyBlockBuf[iSrcOffsetBit >> 3] &
(0x80 >> (iSrcOffsetBit & 0x7)))
static_cast<GByte *>(pImage)[iDstOffset++] = bSetVal;
else
static_cast<GByte *>(pImage)[iDstOffset++] = 0;
GDALExpandPackedBitsToByteAt0Or1(pabySrc, pabyDest,
nBlockXSize);
}
pabySrc += (nBlockXSize + 7) / 8;
pabyDest += nBlockXSize;
}
}
/* -------------------------------------------------------------------- */
Expand Down
64 changes: 6 additions & 58 deletions frmts/libertiff/libertiffdataset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1166,28 +1166,6 @@ FloatingPointHorizPredictorDecode(std::vector<uint8_t> &tmpBuffer,
return true;
}

/************************************************************************/
/* ExtractBitAndConvertTo255() */
/************************************************************************/

#if defined(__GNUC__) || defined(_MSC_VER)
// Signedness of char implementation dependent, so be explicit.
// Assumes 2-complement integer types and sign extension of right shifting
// GCC guarantees such:
// https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation
static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
{
return static_cast<GByte>(static_cast<signed char>(byVal << (7 - nBit)) >>
7);
}
#else
// Portable way
static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
{
return (byVal & (1 << nBit)) ? 255 : 0;
}
#endif

/************************************************************************/
/* ReadBlock() */
/************************************************************************/
Expand Down Expand Up @@ -1582,51 +1560,21 @@ bool LIBERTIFFDataset::ReadBlock(GByte *pabyBlockData, int nBlockXOff,
if (m_image->bitsPerSample() == 1)
{
const GByte *CPL_RESTRICT pabySrc = abyDecompressedStrile.data();
const GByte val = m_bExpand1To255 ? 255 : 1;
GByte *CPL_RESTRICT pabyDst = bufferForOneBitExpansion.data();
for (int iY = 0; iY < nBlockActualYSize; ++iY)
{
int iX = 0;
if (m_bExpand1To255)
{
for (; iX + 7 < nBlockXSize;
iX += 8, ++pabySrc, pabyDst += 8)
{
const GByte srcByte = *pabySrc;
pabyDst[0] = ExtractBitAndConvertTo255(srcByte, 7);
pabyDst[1] = ExtractBitAndConvertTo255(srcByte, 6);
pabyDst[2] = ExtractBitAndConvertTo255(srcByte, 5);
pabyDst[3] = ExtractBitAndConvertTo255(srcByte, 4);
pabyDst[4] = ExtractBitAndConvertTo255(srcByte, 3);
pabyDst[5] = ExtractBitAndConvertTo255(srcByte, 2);
pabyDst[6] = ExtractBitAndConvertTo255(srcByte, 1);
pabyDst[7] = ExtractBitAndConvertTo255(srcByte, 0);
}
GDALExpandPackedBitsToByteAt0Or255(pabySrc, pabyDst,
nBlockXSize);
}
else
{
for (; iX + 7 < nBlockXSize;
iX += 8, ++pabySrc, pabyDst += 8)
{
const int srcByte = *pabySrc;
pabyDst[0] = (srcByte >> 7) & 1;
pabyDst[1] = (srcByte >> 6) & 1;
pabyDst[2] = (srcByte >> 5) & 1;
pabyDst[3] = (srcByte >> 4) & 1;
pabyDst[4] = (srcByte >> 3) & 1;
pabyDst[5] = (srcByte >> 2) & 1;
pabyDst[6] = (srcByte >> 1) & 1;
pabyDst[7] = (srcByte >> 0) & 1;
}
}
if (iX < nBlockXSize)
{
for (; iX < nBlockXSize; ++iX, ++pabyDst)
{
*pabyDst = (*pabySrc & (0x80 >> (iX % 8))) ? val : 0;
}
++pabySrc;
GDALExpandPackedBitsToByteAt0Or1(pabySrc, pabyDst,
nBlockXSize);
}
pabySrc += (nBlockXSize + 7) / 8;
pabyDst += nBlockXSize;
}

std::swap(abyDecompressedStrile, bufferForOneBitExpansion);
Expand Down
8 changes: 8 additions & 0 deletions gcore/gdal_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -4493,6 +4493,14 @@ int CPL_DLL GDALReadTabFile2(const char *pszBaseFilename,
void CPL_DLL GDALCopyRasterIOExtraArg(GDALRasterIOExtraArg *psDestArg,
GDALRasterIOExtraArg *psSrcArg);

void CPL_DLL GDALExpandPackedBitsToByteAt0Or1(
const GByte *CPL_RESTRICT pabyInput, GByte *CPL_RESTRICT pabyOutput,
size_t nInputBits);

void CPL_DLL GDALExpandPackedBitsToByteAt0Or255(
const GByte *CPL_RESTRICT pabyInput, GByte *CPL_RESTRICT pabyOutput,
size_t nInputBits);

CPL_C_END

std::unique_ptr<GDALDataset> CPL_DLL
Expand Down
Loading
Loading