#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
#include <chrono>
#include <cfloat>
#include "../LercLib/include/Lerc_c_api.h"
#include "../LercLib/include/Lerc_types.h"
using namespace std;
using namespace std::chrono;
typedef unsigned char Byte; typedef unsigned int uint32;
enum lerc_DataType { dt_char = 0, dt_uchar, dt_short, dt_ushort, dt_int, dt_uint, dt_float, dt_double };
void BlobInfo_Print(const uint32* infoArr);
bool BlobInfo_Equal(const uint32* infoArr, uint32 nDepth, uint32 nCols, uint32 nRows, uint32 nBands, uint32 dataType);
#ifdef TestLegacyData
bool ReadListFile(const string& listFn, vector<string>& fnVec);
bool ReadFile(const string& fn, Byte* pBuffer, size_t bufferSize, size_t& nBytesRead);
bool WriteDecodedTile(const string& fn, int nMasks, const Byte* pValidBytes, int nDepth, int w, int h, int nBands, int bpp, const void* pArr);
bool ReadDecodedTile(const string& fn, int& nMasks, Byte* pValidBytes, int& nDepth, int& w, int& h, int& nBands, int& bpp, void* pArr);
bool CompareTwoTiles(int nMasks, const Byte* pValidBytes, int nDepth, int w, int h, int nBands, int bpp, const void* pArr,
int nMasks2, const Byte* pValidBytes2, int nDepth2, int w2, int h2, int nBands2, int bpp2, const void* pArr2, int dt);
#endif
int main(int argc, char* arcv[])
{
const int infoArrSize = (int)LercNS::InfoArrOrder::_last;
const int dataRangeArrSize = (int)LercNS::DataRangeArrOrder::_last;
lerc_status hr(0);
uint32 infoArr[infoArrSize];
double dataRangeArr[dataRangeArrSize];
high_resolution_clock::time_point t0, t1;
#ifndef TestLegacyData
{
int h = 512;
int w = 512;
float* zImg = new float[w * h];
memset(zImg, 0, w * h * sizeof(float));
Byte* maskByteImg = new Byte[w * h];
memset(maskByteImg, 1, w * h);
for (int k = 0, i = 0; i < h; i++)
for (int j = 0; j < w; j++, k++)
{
zImg[k] = sqrt((float)(i * i + j * j)); zImg[k] += rand() % 20;
if (j % 100 == 0 || i % 100 == 0) maskByteImg[k] = 0;
}
double maxZErrorWanted = 0.1;
double eps = 0.0001; double maxZError = maxZErrorWanted - eps;
uint32 numBytesNeeded = 0;
uint32 numBytesWritten = 0;
hr = lerc_computeCompressedSize((void*)zImg, (uint32)dt_float, 1, w, h, 1,
1, maskByteImg, maxZError, &numBytesNeeded);
if (hr)
cout << "lerc_computeCompressedSize(...) failed" << endl;
uint32 numBytesBlob = numBytesNeeded;
Byte* pLercBlob = new Byte[numBytesBlob];
t0 = high_resolution_clock::now();
hr = lerc_encode((void*)zImg, (uint32)dt_float, 1, w, h, 1,
1, maskByteImg, maxZError, pLercBlob, numBytesBlob, &numBytesWritten);
if (hr)
cout << "lerc_encode(...) failed" << endl;
t1 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(t1 - t0).count();
double ratio = w * h * (0.125 + sizeof(float)) / numBytesBlob;
cout << "sample 1 compression ratio = " << ratio << ", encode time = " << duration << " ms" << endl;
if ((hr = lerc_getBlobInfo(pLercBlob, numBytesBlob, infoArr, dataRangeArr, infoArrSize, dataRangeArrSize)))
cout << "lerc_getBlobInfo(...) failed" << endl;
BlobInfo_Print(infoArr);
if (!BlobInfo_Equal(infoArr, 1, w, h, 1, (uint32)dt_float))
cout << "got wrong lerc info" << endl;
float* zImg2 = new float[w * h];
memset(zImg2, 0, w * h * sizeof(float));
Byte* maskByteImg2 = new Byte[w * h];
memset(maskByteImg2, 0, w * h);
t0 = high_resolution_clock::now();
hr = lerc_decode(pLercBlob, numBytesBlob,
1, maskByteImg2, 1, w, h, 1, (uint32)dt_float, (void*)zImg2);
if (hr)
cout << "lerc_decode(...) failed" << endl;
t1 = high_resolution_clock::now();
duration = duration_cast<milliseconds>(t1 - t0).count();
double maxDelta = 0;
for (int k = 0, i = 0; i < h; i++)
for (int j = 0; j < w; j++, k++)
{
if (maskByteImg2[k] != maskByteImg[k])
cout << "Error in main: decoded valid bytes differ from encoded valid bytes" << endl;
if (maskByteImg2[k])
{
double delta = abs((double)zImg2[k] - (double)zImg[k]);
if (delta > maxDelta)
maxDelta = delta;
}
}
cout << "max z error per pixel = " << maxDelta << ", decode time = " << duration << " ms" << endl;
cout << endl;
delete[] zImg;
delete[] zImg2;
delete[] maskByteImg;
delete[] maskByteImg2;
delete[] pLercBlob;
}
{
int h = 713;
int w = 257;
Byte* byteImg = new Byte[3 * w * h];
memset(byteImg, 0, 3 * w * h);
for (int k = 0, i = 0; i < h; i++)
for (int j = 0; j < w; j++, k++)
for (int m = 0; m < 3; m++)
byteImg[k * 3 + m] = rand() % 30;
uint32 numBytesWritten = 0;
uint32 numBytesBlob = (3 * w * h) * 2; Byte* pLercBlob = new Byte[numBytesBlob];
t0 = high_resolution_clock::now();
hr = lerc_encode((void*)byteImg, (uint32)dt_uchar, 3, w, h, 1,
0, nullptr, 0, pLercBlob, numBytesBlob, &numBytesWritten);
if (hr)
cout << "lerc_encode(...) failed" << endl;
t1 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(t1 - t0).count();
numBytesBlob = numBytesWritten;
double ratio = 3 * w * h / (double)numBytesBlob;
cout << "sample 2 compression ratio = " << ratio << ", encode time = " << duration << " ms" << endl;
if ((hr = lerc_getBlobInfo(pLercBlob, numBytesBlob, infoArr, dataRangeArr, infoArrSize, dataRangeArrSize)))
cout << "lerc_getBlobInfo(...) failed" << endl;
BlobInfo_Print(infoArr);
if (!BlobInfo_Equal(infoArr, 3, w, h, 1, (uint32)dt_uchar))
cout << "got wrong lerc info" << endl;
vector<double> zMinVec(3, 0), zMaxVec(3, 0);
if ((hr = lerc_getDataRanges(pLercBlob, numBytesBlob, 3, 1, &zMinVec[0], &zMaxVec[0])))
cout << "lerc_getDataRanges(...) failed" << endl;
Byte* byteImg2 = new Byte[3 * w * h];
memset(byteImg2, 0, 3 * w * h);
t0 = high_resolution_clock::now();
if ((hr = lerc_decode(pLercBlob, numBytesBlob, 0, nullptr, 3, w, h, 1, (uint32)dt_uchar, (void*)byteImg2)))
cout << "lerc_decode(...) failed" << endl;
t1 = high_resolution_clock::now();
duration = duration_cast<milliseconds>(t1 - t0).count();
int maxDelta = 0;
for (int k = 0, i = 0; i < h; i++)
for (int j = 0; j < w; j++, k++)
for (int m = 0; m < 3; m++)
{
int delta = abs((int)byteImg2[k * 3 + m] - (int)byteImg[k * 3 + m]);
if (delta > maxDelta)
maxDelta = delta;
}
cout << "max z error per pixel = " << maxDelta << ", decode time = " << duration << " ms" << endl;
cout << endl;
delete[] byteImg;
delete[] byteImg2;
delete[] pLercBlob;
}
{
int h = 128;
int w = 257;
float* fImg = new float[4 * w * h];
memset(fImg, 0, 4 * w * h * sizeof(float));
for (int iBand = 0; iBand < 4; iBand++)
{
float* arr = &fImg[iBand * w * h];
for (int k = 0, i = 0; i < h; i++)
for (int j = 0; j < w; j++, k++)
{
arr[k] = sqrt((float)(i * i + j * j)); arr[k] += rand() % 20;
if (iBand != 2 && rand() > 0.5 * RAND_MAX) arr[k] = NAN;
}
}
uint32 numBytesNeeded = 0;
uint32 numBytesWritten = 0;
hr = lerc_computeCompressedSize((void*)fImg, (uint32)dt_float, 1, w, h, 4,
0, nullptr, 0, &numBytesNeeded);
if (hr)
cout << "lerc_computeCompressedSize(...) failed" << endl;
uint32 numBytesBlob = numBytesNeeded;
Byte* pLercBlob = new Byte[numBytesBlob];
t0 = high_resolution_clock::now();
hr = lerc_encode((void*)fImg, (uint32)dt_float, 1, w, h, 4,
0, nullptr, 0, pLercBlob, numBytesBlob, &numBytesWritten);
if (hr)
cout << "lerc_encode(...) failed" << endl;
t1 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(t1 - t0).count();
double ratio = 4 * w * h * sizeof(float) / (double)numBytesBlob;
cout << "sample 3 compression ratio = " << ratio << ", encode time = " << duration << " ms" << endl;
if ((hr = lerc_getBlobInfo(pLercBlob, numBytesBlob, infoArr, dataRangeArr, infoArrSize, dataRangeArrSize)))
cout << "lerc_getBlobInfo(...) failed" << endl;
BlobInfo_Print(infoArr);
if (!BlobInfo_Equal(infoArr, 1, w, h, 4, (uint32)dt_float))
cout << "got wrong lerc info" << endl;
float* fImg2 = new float[4 * w * h];
memset(fImg2, 0, 4 * w * h * sizeof(float));
t0 = high_resolution_clock::now();
int nMasks = infoArr[(int)LercNS::InfoArrOrder::nMasks];
Byte* maskByteImg2 = nullptr;
if (nMasks > 0) {
maskByteImg2 = new Byte[nMasks * w * h];
memset(maskByteImg2, 0, nMasks * w * h);
}
if ((hr = lerc_decode(pLercBlob, numBytesBlob, nMasks, maskByteImg2, 1, w, h, 4, (uint32)dt_float, (void*)fImg2)))
cout << "lerc_decode(...) failed" << endl;
t1 = high_resolution_clock::now();
duration = duration_cast<milliseconds>(t1 - t0).count();
double maxDelta = 0;
for (int iBand = 0; iBand < 4; iBand++)
{
const float* arr = &fImg[iBand * w * h];
const float* arr2 = &fImg2[iBand * w * h];
const Byte* mask = (nMasks == 4) ? &maskByteImg2[iBand * w * h]
: ((nMasks == 1) ? maskByteImg2 : nullptr);
for (int k = 0, i = 0; i < h; i++)
for (int j = 0; j < w; j++, k++)
if (!mask || mask[k])
{
double delta = abs((double)arr2[k] - (double)arr[k]);
if (delta > maxDelta || std::isnan(delta))
maxDelta = delta;
}
}
cout << "max z error per pixel = " << maxDelta << ", decode time = " << duration << " ms" << endl;
cout << endl;
delete[] fImg;
delete[] fImg2;
delete[] maskByteImg2;
delete[] pLercBlob;
}
{
int h = 128;
int w = 65;
const int nBands = 2;
const int nDepth = 2; int nValues = nDepth * w * h * nBands;
float noDataVal = FLT_MAX;
double maxZErr = 0.001;
Byte bUsesNoDataArr[nBands] = { 1, 0 };
double noDataArr[nBands] = { noDataVal, 0 };
float* fImg = new float[nValues];
memset(fImg, 0, nValues * sizeof(float));
for (int iBand = 0; iBand < nBands; iBand++)
{
float* arr = &fImg[nDepth * w * h * iBand];
for (int k = 0, i = 0; i < h; i++)
for (int j = 0; j < w; j++, k++)
{
int m = k * nDepth;
arr[m] = sqrt((float)(i * i + j * j)); arr[m] += rand() % 20;
arr[m + 1] = arr[m];
if (iBand == 0 && rand() > 0.5 * RAND_MAX) arr[m] = noDataVal;
}
}
uint32 numBytesNeeded = 0;
uint32 numBytesWritten = 0;
hr = lerc_computeCompressedSize_4D((void*)fImg, (uint32)dt_float, nDepth, w, h, nBands,
0, nullptr, maxZErr, &numBytesNeeded, bUsesNoDataArr, noDataArr);
if (hr)
cout << "lerc_computeCompressedSize(...) failed" << endl;
uint32 numBytesBlob = numBytesNeeded;
Byte* pLercBlob = new Byte[numBytesBlob];
t0 = high_resolution_clock::now();
hr = lerc_encode_4D((void*)fImg, (uint32)dt_float, nDepth, w, h, nBands,
0, nullptr, maxZErr, pLercBlob, numBytesBlob, &numBytesWritten, bUsesNoDataArr, noDataArr);
if (hr)
cout << "lerc_encode(...) failed" << endl;
t1 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(t1 - t0).count();
double ratio = nValues * sizeof(float) / (double)numBytesBlob;
cout << "sample 4 compression ratio = " << ratio << ", encode time = " << duration << " ms" << endl;
if ((hr = lerc_getBlobInfo(pLercBlob, numBytesBlob, infoArr, dataRangeArr, infoArrSize, dataRangeArrSize)))
cout << "lerc_getBlobInfo(...) failed" << endl;
BlobInfo_Print(infoArr);
if (!BlobInfo_Equal(infoArr, nDepth, w, h, nBands, (uint32)dt_float))
cout << "got wrong lerc info" << endl;
float* fImg2 = new float[nValues];
memset(fImg2, 0, nValues * sizeof(float));
t0 = high_resolution_clock::now();
int nMasks = infoArr[(int)LercNS::InfoArrOrder::nMasks]; int nUsesNoData = infoArr[(int)LercNS::InfoArrOrder::nUsesNoDataValue];
Byte* maskByteImg2 = nullptr;
if (nMasks > 0)
{
maskByteImg2 = new Byte[nMasks * w * h];
memset(maskByteImg2, 0, nMasks * w * h);
}
vector<Byte> bUsesNoDataVec(nBands, 0);
vector<double> noDataVec(nBands, 0);
hr = lerc_decode_4D(pLercBlob, numBytesBlob, nMasks, maskByteImg2, nDepth, w, h, nBands, (uint32)dt_float, (void*)fImg2,
&bUsesNoDataVec[0], &noDataVec[0]);
if (hr)
cout << "lerc_decode(...) failed" << endl;
t1 = high_resolution_clock::now();
duration = duration_cast<milliseconds>(t1 - t0).count();
double maxDelta = 0;
bool bNoDataValueHasChanged = false;
for (int iBand = 0; iBand < nBands; iBand++)
{
if (bUsesNoDataVec[iBand]) {
if (!bUsesNoDataArr[iBand]) printf("Error: band %d changed from not using noData to using noData!\n", iBand);
if (noDataVec[iBand] != noDataArr[iBand])
printf("Error: noData value changed for band %d!\n", iBand);
}
const float* arr = &fImg[nDepth * w * h * iBand];
const float* arr2 = &fImg2[nDepth * w * h * iBand];
const Byte* mask = (nMasks == nBands) ? &maskByteImg2[iBand * w * h]
: ((nMasks == 1) ? maskByteImg2 : nullptr);
for (int k = 0, i = 0; i < h; i++)
for (int j = 0; j < w; j++, k++)
if (!mask || mask[k])
{
int m0 = k * nDepth;
for (int m = m0; m < m0 + nDepth; m++)
{
double delta = abs((double)arr2[m] - (double)arr[m]);
if (bUsesNoDataVec[iBand] && (arr[m] == noDataVal) && delta > 0)
bNoDataValueHasChanged = true;
if (delta > maxDelta)
maxDelta = delta;
}
}
}
if (bNoDataValueHasChanged)
cout << "Error: some noData value has changed!" << endl;
cout << "max z error per pixel = " << maxDelta << ", decode time = " << duration << " ms" << endl;
cout << endl;
delete[] fImg;
delete[] fImg2;
delete[] maskByteImg2;
delete[] pLercBlob;
}
#endif
#ifdef TestLegacyData
size_t lercBufferSize = 8 * 1024 * 1024; Byte* pLercBuffer = new Byte[lercBufferSize];
double totalDecodeTime = 0;
vector<string> fnVec;
string path = "D:/GitHub/LercOpenSource_v2.5/testData/"; string pathDecoded = "C:/Temp/LercDecodedTiles/";
#ifdef USE_EMSCRIPTEN
path = "PreLoadedFiles/LercBlobs/";
pathDecoded = "PreLoadedFiles/DecodedTiles/";
#endif
string listFn = path + "_list.txt";
if (!ReadListFile(listFn, fnVec))
cout << "Read file " << listFn << " failed." << endl;
for (size_t n = 0; n < fnVec.size(); n++)
{
string fn = path;
fn += fnVec[n];
size_t fileSize = 0;
if (!ReadFile(fn, pLercBuffer, lercBufferSize, fileSize))
{
cout << "Read file " << fn << " failed." << endl;
continue;
}
if ((hr = lerc_getBlobInfo(pLercBuffer, (uint32)fileSize, infoArr, dataRangeArr, infoArrSize, dataRangeArrSize)))
cout << "lerc_getBlobInfo(...) failed" << endl;
{
int codecVersion = infoArr[0];
uint32 dt = infoArr[1];
int nDepth = infoArr[2];
int w = infoArr[3];
int h = infoArr[4];
int nBands = infoArr[5];
int nMasks = infoArr[(int)LercNS::InfoArrOrder::nMasks]; int nUsesNoData = infoArr[(int)LercNS::InfoArrOrder::nUsesNoDataValue];
double zMin = dataRangeArr[0];
double zMax = dataRangeArr[1];
const int bpp[] = { 1, 1, 2, 2, 4, 4, 4, 8 };
Byte* pDstArr = new Byte[nBands * w * h * nDepth * bpp[dt]];
Byte* pValidBytes = new Byte[nMasks * w * h];
Byte* pUsesNoData = new Byte[nBands];
double* pNoDataVal = new double[nBands];
t0 = high_resolution_clock::now();
string resultMsg = "ok";
if ((hr = lerc_decode_4D(pLercBuffer, (uint32)fileSize, nMasks, pValidBytes, nDepth, w, h, nBands, dt, (void*)pDstArr, pUsesNoData, pNoDataVal)))
resultMsg = "FAILED";
t1 = high_resolution_clock::now();
auto duration = duration_cast<milliseconds>(t1 - t0).count();
totalDecodeTime += duration;
printf("codec = %1d, nDepth = %1d, w = %4d, h = %4d, nBands = %1d, nMasks = %1d, usesNoData = %1d, dt = %1d, min = %10.4lf, max = %16.4lf, time = %4d ms, %s : %s\n",
codecVersion, nDepth, w, h, nBands, nMasks, nUsesNoData ? 1 : 0, dt, zMin, zMax, (int)duration, resultMsg.c_str(), fnVec[n].c_str());
string fnDec = pathDecoded;
string s = fnVec[n];
replace(s.begin(), s.end(), '/', '_');
fnDec += s;
#ifdef DumpDecodedTiles
if (!WriteDecodedTile(fnDec, nMasks, pValidBytes, nDepth, w, h, nBands, bpp[dt], pDstArr))
printf("Write decoded Lerc tile failed for %s\n", fnDec.c_str());
#endif
#ifdef CompareAgainstDumpedTiles
Byte* pDstArr2 = new Byte[nBands * w * h * nDepth * bpp[dt]];
Byte* pValidBytes2 = new Byte[nMasks * w * h];
int nMasks2(0), nDepth2(0), w2(0), h2(0), nBands2(0), bpp2(0);
if (!ReadDecodedTile(fnDec, nMasks2, pValidBytes2, nDepth2, w2, h2, nBands2, bpp2, pDstArr2))
printf("Read decoded Lerc tile failed for %s\n", fnDec.c_str());
if (!CompareTwoTiles(nMasks, pValidBytes, nDepth, w, h, nBands, bpp[dt], pDstArr,
nMasks2, pValidBytes2, nDepth2, w2, h2, nBands2, bpp2, pDstArr2, dt))
printf("Compare two Lerc tiles failed for %s vs %s\n", fnVec[n].c_str(), fnDec.c_str());
delete[] pDstArr2;
delete[] pValidBytes2;
#endif
delete[] pDstArr;
delete[] pValidBytes;
delete[] pUsesNoData;
delete[] pNoDataVal;
}
}
delete[] pLercBuffer;
printf("Total decode time = %d ms", (int)totalDecodeTime);
#endif
printf("\npress ENTER\n");
getchar();
return 0;
}
void BlobInfo_Print(const uint32* infoArr)
{
const uint32* ia = infoArr;
printf("version = %d, dataType = %d, nDepth = %d, nCols = %d, nRows = %d, nBands = %d, \
nValidPixels = %d, blobSize = %d, nMasks = %d, nDepth = %d, nUsesNoDataValue = %d\n",
ia[0], ia[1], ia[2], ia[3], ia[4], ia[5], ia[6], ia[7], ia[8], ia[9], ia[10]);
}
bool BlobInfo_Equal(const uint32* infoArr, uint32 nDepth, uint32 nCols, uint32 nRows, uint32 nBands, uint32 dataType)
{
const uint32* ia = infoArr;
return ia[1] == dataType && ia[2] == nDepth && ia[3] == nCols && ia[4] == nRows && ia[5] == nBands;
}
#ifdef TestLegacyData
bool ReadListFile(const string& listFn, vector<string>& fnVec)
{
FILE* fp = fopen(listFn.c_str(), "r");
if (!fp)
{
printf("Cannot open file %s\n", listFn.c_str());
return false;
}
char buffer[1024];
int num = 0;
int rv = fscanf(fp, "%d", &num);
for (int i = 0; i < num; i++)
{
rv = fscanf(fp, "%s", buffer);
string s = buffer;
fnVec.push_back(s);
}
fclose(fp);
return true;
}
bool ReadFile(const string& fn, Byte* pBuffer, size_t bufferSize, size_t& nBytesRead)
{
nBytesRead = 0;
FILE* fp = fopen(fn.c_str(), "rb");
if (!fp)
{
printf("Cannot open file %s\n", fn.c_str());
return false;
}
fseek(fp, 0, SEEK_END);
size_t fileSize = ftell(fp); fclose(fp);
fp = 0;
if (fileSize > bufferSize)
{
printf("Lerc blob size %d > buffer size of %d\n", (uint32)fileSize, (uint32)bufferSize);
return false;
}
fp = fopen(fn.c_str(), "rb");
nBytesRead = fread(pBuffer, 1, fileSize, fp); fclose(fp);
return nBytesRead == fileSize;
}
bool WriteDecodedTile(const string& fn, int nMasks, const Byte* pValidBytes, int nDepth, int w, int h, int nBands, int bpp, const void* pArr)
{
FILE* fp = fopen(fn.c_str(), "wb");
if (!fp)
{
printf("Cannot open file %s\n", fn.c_str());
return false;
}
int dimensions[] = { nMasks, nDepth, w, h, nBands, bpp };
fwrite(dimensions, 1, 6 * sizeof(int), fp);
if (nMasks > 0)
fwrite(pValidBytes, 1, nMasks * w * h, fp);
fwrite(pArr, 1, nBands * w * h * nDepth * bpp, fp);
fclose(fp);
return true;
}
bool ReadDecodedTile(const string& fn, int& nMasks, Byte* pValidBytes, int& nDepth, int& w, int& h, int& nBands, int& bpp, void* pArr)
{
FILE* fp = fopen(fn.c_str(), "rb");
if (!fp)
{
printf("Cannot open file %s\n", fn.c_str());
return false;
}
int dims[6] = { 0 };
size_t nbRead = fread(dims, 1, 6 * sizeof(int), fp);
nMasks = dims[0];
nDepth = dims[1];
w = dims[2];
h = dims[3];
nBands = dims[4];
bpp = dims[5];
if (nMasks > 0)
nbRead += fread(pValidBytes, 1, nMasks * w * h, fp);
nbRead += fread(pArr, 1, nBands * w * h * nDepth * bpp, fp);
fclose(fp);
return true;
}
bool CompareTwoTiles(int nMasks, const Byte* pValidBytes, int nDepth, int w, int h, int nBands, int bpp, const void* pArr,
int nMasks2, const Byte* pValidBytes2, int nDepth2, int w2, int h2, int nBands2, int bpp2, const void* pArr2, int dt)
{
if (nMasks2 != nMasks || nDepth2 != nDepth || w2 != w || h2 != h || nBands2 != nBands || bpp2 != bpp)
{
printf("Tile dimensions differ.\n");
return false;
}
if (0 != memcmp(pValidBytes2, pValidBytes, nMasks * w * h))
{
printf("Valid byte masks differ.\n");
return false;
}
double maxDelta(0);
for (int iBand = 0; iBand < nBands; iBand++)
{
const Byte* mask = (nMasks == nBands) ? &pValidBytes[iBand * w * h] : (nMasks == 1 ? pValidBytes : nullptr);
for (int k = 0, i = 0; i < h; i++)
{
for (int j = 0; j < w; j++, k++)
{
if (!mask || mask[k])
{
for (int m = 0; m < nDepth; m++)
{
int index = (iBand * w * h + k) * nDepth + m;
double delta = 0;
const Byte* ptr = (const Byte*)pArr + index * bpp;
const Byte* ptr2 = (const Byte*)pArr2 + index * bpp;
if (dt <= 5)
{
if (0 != memcmp(ptr, ptr2, bpp))
{
printf("Data differ.\n");
return false;
}
}
else if (dt == 6)
{
float x(0), x2(0);
memcpy(&x, ptr, bpp);
memcpy(&x2, ptr2, bpp);
delta = fabs(x2 - x);
}
else if (dt == 7)
{
double x(0), x2(0);
memcpy(&x, ptr, bpp);
memcpy(&x2, ptr2, bpp);
delta = fabs(x2 - x);
}
if (delta > maxDelta)
maxDelta = delta;
}
}
}
}
}
if (maxDelta > 0)
{
printf("Valid pixel values differ, max delta = %lf.\n", maxDelta);
return false;
}
return true;
}
#endif