charls-1.0/0000755000265600020320000000000011556213767011767 5ustar tilleaadmincharls-1.0/test/0000755000265600020320000000000011556213767012746 5ustar tilleaadmincharls-1.0/test/time.h0000644000265600020320000000027311464353324014047 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef TEST_TIME #define TEST_TIME double getTime(); #endif charls-1.0/test/util.cpp0000644000265600020320000000705211464353324014423 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #include "config.h" #include #include #include "../interface.h" #include "../util.h" #include "../streams.h" #include "util.h" #include "time.h" bool IsMachineLittleEndian() { int a = 0xFF000001; char* chars = reinterpret_cast(&a); return chars[0] == 0x01; } void FixEndian(std::vector* rgbyte, bool littleEndianData) { if (littleEndianData == IsMachineLittleEndian()) return; for (size_t i = 0; i < rgbyte->size()-1; i += 2) { std::swap((*rgbyte)[i], (*rgbyte)[i + 1]); } } bool ReadFile(SZC strName, std::vector* pvec, int ioffs, int bytes) { FILE* pfile = fopen(strName, "rb"); if( !pfile ) { fprintf( stderr, "Could not open %s\n", strName ); return false; } fseek(pfile, 0, SEEK_END); int cbyteFile = ftell(pfile); if (ioffs < 0) { assert(bytes != 0); ioffs = cbyteFile - bytes; } if (bytes == 0) { bytes = cbyteFile -ioffs; } fseek(pfile, ioffs, SEEK_SET); pvec->resize(bytes); size_t bytesRead = fread(&(*pvec)[0],1, pvec->size(), pfile); fclose(pfile); return bytesRead == pvec->size(); } void WriteFile(SZC strName, std::vector& vec) { FILE* pfile = fopen(strName, "wb"); if( !pfile ) { fprintf( stderr, "Could not open %s\n", strName ); return; } fwrite(&vec[0],1, vec.size(), pfile); fclose(pfile); } void TestRoundTrip(const char* strName, std::vector& rgbyteRaw, Size size, int cbit, int ccomp) { std::vector rgbyteCompressed(size.cx *size.cy * ccomp * cbit / 4); std::vector rgbyteOut(size.cx * size.cy * ((cbit + 7) / 8) * ccomp); double dblstart = getTime(); JlsParameters info = JlsParameters(); info.components = ccomp; info.bitspersample = cbit; info.height = size.cy; info.width = size.cx; if (ccomp == 4) { info.ilv = ILV_LINE; } else if (ccomp == 3) { info.ilv = ILV_LINE; info.colorTransform = COLORXFORM_HP1; } size_t compressedLength; JLS_ERROR err = JpegLsEncode(&rgbyteCompressed[0], rgbyteCompressed.size(), &compressedLength, &rgbyteRaw[0], rgbyteOut.size(), &info); assert(err == OK); double dwtimeEncodeComplete = getTime(); err = JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), &rgbyteCompressed[0], int(compressedLength), NULL); assert(err == OK); double bitspersample = compressedLength * 8 * 1.0 / (ccomp *size.cy * size.cx); double dwtimeDecodeComplete = getTime(); std::cout << "RoundTrip test for: " << strName << "\n\r"; double decodeTime = dwtimeDecodeComplete - dwtimeEncodeComplete; double symbolRate = (ccomp *size.cy * size.cx)/(1000.0 * decodeTime); printf("Size:%4ldx%4ld Encode:%7.2f Decode:%7.2f Bps:%5.2f Decode rate:%5.1f M/s \n\r", size.cx, size.cy, dwtimeEncodeComplete - dblstart, dwtimeDecodeComplete - dwtimeEncodeComplete, bitspersample, symbolRate); BYTE* pbyteOut = &rgbyteOut[0]; for (size_t i = 0; i < rgbyteOut.size(); ++i) { if (rgbyteRaw[i] != pbyteOut[i]) { assert(false); break; } } } void TestFile(SZC strName, int ioffs, Size size2, int cbit, int ccomp, bool littleEndianFile) { int byteCount = size2.cx * size2.cy * ccomp * ((cbit + 7)/8); std::vector rgbyteUncompressed; if (!ReadFile(strName, &rgbyteUncompressed, ioffs, byteCount)) return; if (cbit > 8) { FixEndian(&rgbyteUncompressed, littleEndianFile); } TestRoundTrip(strName, rgbyteUncompressed, size2, cbit, ccomp); } charls-1.0/test/performance.cpp0000644000265600020320000000437011464353324015747 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #include "config.h" #include #include #include "../interface.h" #include "../util.h" #include "../defaulttraits.h" #include "../losslesstraits.h" #include "../colortransform.h" #include "../streams.h" #include "../processline.h" #include "util.h" void TestFile16BitAs12(SZC strName, int ioffs, Size size2, int ccomp, bool littleEndianFile) { std::vector rgbyteUncompressed; if (!ReadFile(strName, &rgbyteUncompressed, ioffs)) return; FixEndian(&rgbyteUncompressed, littleEndianFile); USHORT* pushort = (USHORT*)&rgbyteUncompressed[0]; for (int i = 0; i < (int)rgbyteUncompressed.size()/2; ++i) { pushort[i] = pushort[i] >> 4; } TestRoundTrip(strName, rgbyteUncompressed, size2, 12, ccomp); } void TestPerformance() { TestFile("test/bad.raw", 0, Size(512, 512), 8, 1); // RGBA image (This is a common PNG sample) TestFile("test/alphatest.raw", 0, Size(380, 287), 8, 4); Size size1024 = Size(1024, 1024); Size size512 = Size(512, 512); // 16 bit mono TestFile("test/MR2_UNC", 1728, size1024, 16, 1, true); // 8 bit mono TestFile("test/0015.raw", 0, size1024, 8, 1); TestFile("test/lena8b.raw", 0, size512, 8, 1); // 8 bit color TestFile("test/desktop.ppm", 40, Size(1280,1024), 8, 3); // 12 bit RGB TestFile("test/SIEMENS-MR-RGB-16Bits.dcm", -1, Size(192,256), 12, 3, true); TestFile16BitAs12("test/DSC_5455.raw", 142949, Size(300,200), 3, true); // 16 bit RGB TestFile("test/DSC_5455.raw", 142949, Size(300,200), 16, 3, true); } void TestLargeImagePerformance() { TestFile("test/rgb8bit/artificial.ppm", 17, Size(3072,2048), 8, 3); TestFile("test/rgb8bit/bridge.ppm", 17, Size(2749,4049), 8, 3); TestFile("test/rgb8bit/flower_foveon.ppm", 17, Size(2268,1512), 8, 3); //TestFile("test/rgb8bit/big_building.ppm", 17, Size(7216,5412), 8, 3); // TestFile("test/rgb16bit/bridge.ppm", 19, Size(2749,4049), 16, 3, true); } void PerformanceTests() { printf("Test Perf\r\n"); TestPerformance(); #ifndef _DEBUG printf("Test Large Images Performance\r\n"); TestLargeImagePerformance(); #endif }charls-1.0/test/dicomsamples.cpp0000644000265600020320000000443111464353324016124 0ustar tilleaadmin #include "config.h" #include #include #include "util.h" #include "../interface.h" int findstring(std::vector& container, BYTE* bytesToFind, unsigned int bytesLength) { for (unsigned int i=0; i < container.size() - bytesLength; ++i) { for (unsigned int j=0; j < bytesLength; ++j) { if (bytesToFind[j] != container[i + j]) goto next; } return i; next:; } return -1; } #define COUNT(x) (sizeof(x)/sizeof(x[0])) void TestDicomSampleImage(const char* name) { std::vector data; bool success = ReadFile(name, &data, 9); ASSERT(success); BYTE pixeldataStart[] = { 0x00, 0x00, 0x01, 0x00, 0xFF, 0xD8, 0xFF, 0xF7 }; int offset = findstring(data, pixeldataStart, COUNT(pixeldataStart)); data.erase(data.begin(), data.begin() + offset - 4); // remove the dicom fragment headers (in the concerned images they occur every 64k) for (unsigned int i = 0; i < data.size(); i+= 64 * 1024) { data.erase(data.begin() + i, data.begin() + i + 8); } JlsParameters info; JLS_ERROR error = JpegLsReadHeader(&data[0], data.size(), &info); // 0xFE, 0xFF, 0x00, 0xE0, 0x00, 0x00, 0x01, 0x00 std::vector dataUnc; dataUnc.resize(info.bytesperline * info.height); error = JpegLsDecode(&dataUnc[0], dataUnc.size(), &data[0], data.size(), NULL); ASSERT(error == OK); std::cout << "."; } void TestDicomWG4Images() { TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/XA1_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/CT2_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/MG1_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/MR1_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/MR2_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/MR3_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/MR4_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/NM1_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/RG1_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/RG2_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/RG3_JLSL"); TestDicomSampleImage("test/compsamples_jpegls/IMAGES/JLSL/SC1_JLSL"); } charls-1.0/test/CMakeLists.txt0000644000265600020320000000012311464353322015470 0ustar tilleaadmin# test for charlls #add_library(CharLS STATIC IMPORTED) link_directories (..)charls-1.0/test/main.cpp0000644000265600020320000001413311464353324014370 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #include "config.h" #include #include #include "../interface.h" #include "../util.h" #include "../defaulttraits.h" #include "../losslesstraits.h" #include "../colortransform.h" #include "../streams.h" #include "../processline.h" #include "util.h" typedef const char* SZC; bool ScanFile(SZC strNameEncoded, std::vector* rgbyteFile, JlsParameters* info) { if (!ReadFile(strNameEncoded, rgbyteFile)) { assert(false); return false; } JLS_ERROR err = JpegLsReadHeader(&((*rgbyteFile)[0]), rgbyteFile->size(), info); assert(err == OK); return err == OK; } void TestTraits16bit() { DefaultTraitsT traits1 = DefaultTraitsT(4095,0); LosslessTraitsT traits2 = LosslessTraitsT(); assert(traits1.LIMIT == traits2.LIMIT); assert(traits1.MAXVAL == traits2.MAXVAL); assert(traits1.RESET == traits2.RESET); assert(traits1.bpp == traits2.bpp); assert(traits1.qbpp == traits2.qbpp); for (int i = -4096; i < 4096; ++i) { assert(traits1.ModRange(i) == traits2.ModRange(i)); assert(traits1.ComputeErrVal(i) == traits2.ComputeErrVal(i)); } for (int i = -8095; i < 8095; ++i) { assert(traits1.CorrectPrediction(i) == traits2.CorrectPrediction(i)); assert(traits1.IsNear(i,2) == traits2.IsNear(i,2)); } } void TestTraits8bit() { DefaultTraitsT traits1 = DefaultTraitsT(255,0); LosslessTraitsT traits2 = LosslessTraitsT(); assert(traits1.LIMIT == traits2.LIMIT); assert(traits1.MAXVAL == traits2.MAXVAL); assert(traits1.RESET == traits2.RESET); assert(traits1.bpp == traits2.bpp); assert(traits1.qbpp == traits2.qbpp); for (int i = -255; i < 255; ++i) { assert(traits1.ModRange(i) == traits2.ModRange(i)); assert(traits1.ComputeErrVal(i) == traits2.ComputeErrVal(i)); } for (int i = -255; i < 512; ++i) { assert(traits1.CorrectPrediction(i) == traits2.CorrectPrediction(i)); assert(traits1.IsNear(i,2) == traits2.IsNear(i,2)); } } void TestNoiseImage() { srand(21344); Size size2 = Size(1024, 1024); std::vector rgbyteNoise(size2.cx * size2.cy); for (int line = 0; line rgbyteEncoded; ScanFile("test/conformance/T8C2E3.JLS", &rgbyteEncoded, &info); std::vector rgbyteDecoded(info.width * info.height * info.components); info.outputBgr = true; JLS_ERROR err = JpegLsDecode(&rgbyteDecoded[0], rgbyteDecoded.size(), &rgbyteEncoded[0], rgbyteEncoded.size(), &info); assert(err == OK); assert(rgbyteDecoded[0] == 0x69); assert(rgbyteDecoded[1] == 0x77); assert(rgbyteDecoded[2] == 0xa1); assert(rgbyteDecoded[info.width * 6 + 3] == 0x2d); assert(rgbyteDecoded[info.width * 6 + 4] == 0x43); assert(rgbyteDecoded[info.width * 6 + 5] == 0x4d); } void TestTooSmallOutputBuffer() { std::vector rgbyteCompressed; if (!ReadFile("test/lena8b.jls", &rgbyteCompressed, 0)) return; std::vector rgbyteOut(512 * 511); JLS_ERROR error = JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), &rgbyteCompressed[0], int(rgbyteCompressed.size()), NULL); assert(error == UncompressedBufferTooSmall); } void TestDecodeRect() { std::vector rgbyteCompressed; JlsParameters info; if (!ScanFile("test/lena8b.jls", &rgbyteCompressed, &info)) return; std::vector rgbyteOutFull(info.width*info.height*info.components); JLS_ERROR error = JpegLsDecode(&rgbyteOutFull[0], rgbyteOutFull.size(), &rgbyteCompressed[0], int(rgbyteCompressed.size()), NULL); assert(error == OK); JlsRect rect = { 128, 128, 256, 1 }; std::vector rgbyteOut(rect.Width * rect.Height); rgbyteOut.push_back(0x1f); error = JpegLsDecodeRect(&rgbyteOut[0], rgbyteOut.size(), &rgbyteCompressed[0], int(rgbyteCompressed.size()), rect, NULL); assert(error == OK); assert(memcmp(&rgbyteOutFull[rect.X + rect.Y*512], &rgbyteOut[0], rect.Width * rect.Height) == 0); assert(rgbyteOut[rect.Width * rect.Height] == 0x1f); } void TestColorTransforms_HpImages(); void TestConformance(); void TestSampleAnnexH3(); void PerformanceTests(); void DamagedBitstreamTests(); void TestDicomWG4Images(); void UnitTest() { TestDecodeRect(); printf("Test Traits\r\n"); TestTraits16bit(); TestTraits8bit(); printf("Windows bitmap BGR/BGRA output\r\n"); TestBgr(); TestBgra(); printf("Test Small buffer\r\n"); TestTooSmallOutputBuffer(); printf("Test Conformance\r\n"); TestConformance(); printf("Test Color transform equivalence on HP images\r\n"); TestColorTransforms_HpImages(); printf("Test Annex H3\r\n"); TestSampleAnnexH3(); TestNoiseImage(); } int main(int argc, char* argv[]) { if (argc == 1) { printf("CharLS test runner.\r\nOptions: -unittest, -bitstreamdamage, -performance, -dontwait\r\n"); return 0; } bool wait = true; for (int i = 1; i < argc; ++i) { std::string str = argv[i]; if (str.compare("-unittest") == 0) { UnitTest(); continue; } if (str.compare("-bitstreamdamage") == 0) { DamagedBitstreamTests(); continue; } if (str.compare("-performance") == 0) { PerformanceTests(); continue; } if (str.compare("-dicom") == 0) { TestDicomWG4Images(); continue; } if (str.compare("-dontwait") == 0) { wait = false; continue; } printf("Option not understood: %s\r\n", argv[i]); break; } if (wait) { char c; std::cin >> c; return 0; } } charls-1.0/test/test.vcproj0000644000265600020320000002057411464353324015152 0ustar tilleaadmin charls-1.0/test/stdafx.cpp0000644000265600020320000000000011464353324014721 0ustar tilleaadmincharls-1.0/test/util.h0000644000265600020320000000133211464353324014063 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef TEST_UTIL #define TEST_UTIL #include "../util.h" typedef const char* SZC; void FixEndian(std::vector* rgbyte, bool littleEndianData); bool ReadFile(SZC strName, std::vector* pvec, int ioffs = 0, int bytes = 0); void TestFile(SZC strName, int ioffs, Size size2, int cbit, int ccomp, bool littleEndianFile = false); void TestRoundTrip(const char* strName, std::vector& rgbyteRaw, Size size, int cbit, int ccomp); void WriteFile(SZC strName, std::vector& vec); void DecompressFile(SZC strNameEncoded, SZC strNameRaw, int ioffs, bool bcheckEncode = true); #endif charls-1.0/test/compliance.cpp0000644000265600020320000001542011464353322015554 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #include "config.h" #include "../interface.h" #include "../util.h" #include "../streams.h" #include #include #include "util.h" void Triplet2Planar(std::vector& rgbyte, Size size) { std::vector rgbytePlanar(rgbyte.size()); int cbytePlane = size.cx * size.cy; for (int index = 0; index < cbytePlane; index++) { rgbytePlanar[index] = rgbyte[index * 3 + 0]; rgbytePlanar[index + 1*cbytePlane] = rgbyte[index * 3 + 1]; rgbytePlanar[index + 2*cbytePlane] = rgbyte[index * 3 + 2]; } std::swap(rgbyte, rgbytePlanar); } void Triplet2Line(std::vector& rgbyte, Size size) { std::vector rgbyteInterleaved(rgbyte.size()); int cbyteLine = size.cx; for (int line = 0; line < size.cy; ++line) { const BYTE* pbyteLineIn = &rgbyte[line * size.cx * 3]; BYTE* pbyteLineOut = &rgbyteInterleaved[line * size.cx * 3]; for (int index = 0; index < cbyteLine; index++) { pbyteLineOut[index] = pbyteLineIn[index * 3 + 0]; pbyteLineOut[index + 1*cbyteLine] = pbyteLineIn[index * 3 + 1]; pbyteLineOut[index + 2*cbyteLine] = pbyteLineIn[index * 3 + 2]; } } std::swap(rgbyte, rgbyteInterleaved); } void TestCompliance(const BYTE* compressedBytes, int compressedLength, const BYTE* rgbyteRaw, int cbyteRaw, bool bcheckEncode) { JlsParameters info = JlsParameters(); JLS_ERROR err = JpegLsReadHeader(compressedBytes, compressedLength, &info); assert(err == OK); if (bcheckEncode) { err = JpegLsVerifyEncode(&rgbyteRaw[0], cbyteRaw, compressedBytes, compressedLength); assert(err == OK); } std::vector rgbyteCompressed(info.height *info.width* 4); std::vector rgbyteOut(info.height *info.width * ((info.bitspersample + 7) / 8) * info.components); err = JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), compressedBytes, compressedLength, NULL); assert(err == OK); if (info.allowedlossyerror == 0) { BYTE* pbyteOut = &rgbyteOut[0]; for (int i = 0; i < cbyteRaw; ++i) { if (rgbyteRaw[i] != pbyteOut[i]) { assert(false); break; } } } } void DecompressFile(SZC strNameEncoded, SZC strNameRaw, int ioffs, bool bcheckEncode) { std::cout << "Conformance test:" << strNameEncoded << "\n\r"; std::vector rgbyteFile; if (!ReadFile(strNameEncoded, &rgbyteFile)) return; JlsParameters metadata; if (JpegLsReadHeader(&rgbyteFile[0], rgbyteFile.size(), &metadata) != OK) { assert(false); return; } std::vector rgbyteRaw; if (!ReadFile(strNameRaw, &rgbyteRaw, ioffs)) return; if (metadata.bitspersample > 8) { FixEndian(&rgbyteRaw, false); } Size size = Size(metadata.width, metadata.height); if (metadata.ilv == ILV_NONE && metadata.components == 3) { Triplet2Planar(rgbyteRaw, Size(metadata.width, metadata.height)); } TestCompliance(&rgbyteFile[0], rgbyteFile.size(), &rgbyteRaw[0], rgbyteRaw.size(), bcheckEncode); } BYTE palettisedDataH10[] = { 0xFF, 0xD8, //Start of image (SOI) marker 0xFF, 0xF7, //Start of JPEG-LS frame (SOF 55) marker – marker segment follows 0x00, 0x0B, //Length of marker segment = 11 bytes including the length field 0x02, //P = Precision = 2 bits per sample 0x00, 0x04, //Y = Number of lines = 4 0x00, 0x03, //X = Number of columns = 3 0x01, //Nf = Number of components in the frame = 1 0x01, //C1 = Component ID = 1 (first and only component) 0x11, //Sub-sampling: H1 = 1, V1 = 1 0x00, //Tq1 = 0 (this field is always 0) 0xFF, 0xF8, //LSE – JPEG-LS preset parameters marker 0x00, 0x11, //Length of marker segment = 17 bytes including the length field 0x02, //ID = 2, mapping table 0x05, //TID = 5 Table identifier (arbitrary) 0x03, //Wt = 3 Width of table entry 0xFF, 0xFF, 0xFF, //Entry for index 0 0xFF, 0x00, 0x00, //Entry for index 1 0x00, 0xFF, 0x00, //Entry for index 2 0x00, 0x00, 0xFF, //Entry for index 3 0xFF, 0xDA, //Start of scan (SOS) marker 0x00, 0x08, //Length of marker segment = 8 bytes including the length field 0x01, //Ns = Number of components for this scan = 1 0x01, //C1 = Component ID = 1 0x05, //Tm 1 = Mapping table identifier = 5 0x00, //NEAR = 0 (near-lossless max error) 0x00, //ILV = 0 (interleave mode = non-interleaved) 0x00, //Al = 0, Ah = 0 (no point transform) 0xDB, 0x95, 0xF0, //3 bytes of compressed image data 0xFF, 0xD9 //End of image (EOI) marker }; const BYTE rgbyte[] = { 0, 0, 90, 74, 68, 50, 43, 205, 64, 145, 145, 145, 100, 145, 145, 145}; const BYTE rgbyteComp[] = { 0xFF, 0xD8, 0xFF, 0xF7, 0x00, 0x0B, 0x08, 0x00, 0x04, 0x00, 0x04, 0x01, 0x01, 0x11, 0x00, 0xFF, 0xDA, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x6C, 0x80, 0x20, 0x8E, 0x01, 0xC0, 0x00, 0x00, 0x57, 0x40, 0x00, 0x00, 0x6E, 0xE6, 0x00, 0x00, 0x01, 0xBC, 0x18, 0x00, 0x00, 0x05, 0xD8, 0x00, 0x00, 0x91, 0x60, 0xFF, 0xD9}; void TestSampleAnnexH3() { Size size = Size(4,4); std::vector vecRaw(16); memcpy(&vecRaw[0], rgbyte, 16); // TestJls(vecRaw, size, 8, 1, ILV_NONE, rgbyteComp, sizeof(rgbyteComp), false); } void TestColorTransforms_HpImages() { DecompressFile("test/jlsimage/banny_normal.jls", "test/jlsimage/banny.ppm",38, false); DecompressFile("test/jlsimage/banny_Hp1.jls", "test/jlsimage/banny.ppm",38, false); DecompressFile("test/jlsimage/banny_Hp2.jls", "test/jlsimage/banny.ppm",38, false); DecompressFile("test/jlsimage/banny_Hp3.jls", "test/jlsimage/banny.ppm",38, false); } void TestConformance() { // Test 1 DecompressFile("test/conformance/T8C0E0.JLS", "test/conformance/TEST8.PPM",15); // Test 2 DecompressFile("test/conformance/T8C1E0.JLS", "test/conformance/TEST8.PPM",15); // Test 3 DecompressFile("test/conformance/T8C2E0.JLS", "test/conformance/TEST8.PPM", 15); // Test 4 DecompressFile("test/conformance/T8C0E3.JLS", "test/conformance/TEST8.PPM",15); // Test 5 DecompressFile("test/conformance/T8C1E3.JLS", "test/conformance/TEST8.PPM",15); // Test 6 DecompressFile("test/conformance/T8C2E3.JLS", "test/conformance/TEST8.PPM",15); // Test 7 // Test 8 // Test 9 DecompressFile("test/conformance/T8NDE0.JLS", "test/conformance/TEST8BS2.PGM",15); // Test 10 DecompressFile("test/conformance/T8NDE3.JLS", "test/conformance/TEST8BS2.PGM",15); // Test 11 DecompressFile("test/conformance/T16E0.JLS", "test/conformance/TEST16.PGM",16); // Test 12 DecompressFile("test/conformance/T16E3.JLS", "test/conformance/TEST16.PGM",16); // additional, Lena compressed with other codec (UBC?), vfy with CharLS DecompressFile("test/lena8b.jls", "test/lena8b.raw",0); } charls-1.0/test/config.h0000644000265600020320000000070111464353322014350 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef TEST_CONFIG #define TEST_CONFIG #if defined(_MSC_VER) #pragma warning (disable: 4996) #endif // enable ASSERT() on linux #ifndef _WIN32 #ifndef _DEBUG #define _DEBUG #endif #else #include #endif #include typedef unsigned char BYTE; typedef unsigned short USHORT; #endif charls-1.0/test/time.cpp0000644000265600020320000000130211464353324014374 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // // for best accuracy, getTime is implemented platform dependent. // to avoid a global include of windows.h, this is a separete file. #include "config.h" #if defined(_WIN32) #include double getTime() { LARGE_INTEGER time; ::QueryPerformanceCounter(&time); LARGE_INTEGER freq; ::QueryPerformanceFrequency(&freq); return double(time.LowPart) * 1000.0/double(freq.LowPart); } #else #include double getTime() { timeval t; gettimeofday(&t, 0); return (t.tv_sec * 1000000.0 + t.tv_usec) / 1000.0; } #endif charls-1.0/test/bitstreamdamage.cpp0000644000265600020320000000630111464353322016571 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #include "config.h" #include #include #include "../interface.h" #include "../util.h" #include "../defaulttraits.h" #include "../losslesstraits.h" #include "../colortransform.h" #include "../streams.h" #include "../processline.h" #include "util.h" void TestDamagedBitStream1() { std::vector rgbyteCompressed; if (!ReadFile("test/incorrect_images/InfiniteLoopFFMPEG.jls", &rgbyteCompressed, 0)) return; std::vector rgbyteOut(256 * 256 * 2); JLS_ERROR error = JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), &rgbyteCompressed[0], int(rgbyteCompressed.size()), NULL); assert(error == InvalidCompressedData); } void TestDamagedBitStream2() { std::vector rgbyteCompressed; if (!ReadFile("test/lena8b.jls", &rgbyteCompressed, 0)) return; rgbyteCompressed.resize(900); rgbyteCompressed.resize(40000,3); std::vector rgbyteOut(512 * 512); JLS_ERROR error = JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), &rgbyteCompressed[0], int(rgbyteCompressed.size()), NULL); assert(error == InvalidCompressedData); } void TestDamagedBitStream3() { std::vector rgbyteCompressed; if (!ReadFile("test/lena8b.jls", &rgbyteCompressed, 0)) return; rgbyteCompressed[300] = 0xFF; rgbyteCompressed[301] = 0xFF; std::vector rgbyteOut(512 * 512); JLS_ERROR error = JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), &rgbyteCompressed[0], int(rgbyteCompressed.size()), NULL); assert(error == InvalidCompressedData); } void TestFileWithRandomHeaderDamage(SZC filename) { std::vector rgbyteCompressedOrg; if (!ReadFile(filename, &rgbyteCompressedOrg, 0)) return; srand(102347325); std::vector rgbyteOut(512 * 512); for (int i = 0; i < 40; ++i) { std::vector rgbyteCompressedTest(rgbyteCompressedOrg); std::vector errors(10,0); for (int j = 0; j < 20; ++j) { rgbyteCompressedTest[i] = (BYTE)rand(); rgbyteCompressedTest[i+1] = (BYTE)rand(); rgbyteCompressedTest[i+2] = (BYTE)rand(); rgbyteCompressedTest[i+3] = (BYTE)rand(); JLS_ERROR error = JpegLsDecode(&rgbyteOut[0], rgbyteOut.size(), &rgbyteCompressedTest[0], int(rgbyteCompressedTest.size()), NULL); errors[error] = errors[error] + 1; } std::cout << "With garbage input at index " << i << ": "; for(unsigned int error = 0; error < errors.size(); ++error) { if (errors[error] == 0) continue; std::cout << errors[error] << "x error (" << error << "); "; } std::cout << "\r\n"; } } void TestRandomMalformedHeader() { TestFileWithRandomHeaderDamage("test/conformance/T8C0E0.JLS"); TestFileWithRandomHeaderDamage("test/conformance/T8C1E0.JLS"); TestFileWithRandomHeaderDamage("test/conformance/T8C2E0.JLS"); } void DamagedBitstreamTests() { printf("Test Damaged bitstream\r\n"); TestDamagedBitStream1(); TestDamagedBitStream2(); TestDamagedBitStream3(); printf("Begin random malformed bitstream tests: \r\n"); TestRandomMalformedHeader(); printf("End randommalformed bitstream tests: \r\n"); } charls-1.0/header.cpp0000644000265600020320000003037211556213767013730 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #include "config.h" #include "util.h" #include "header.h" #include "streams.h" #include "decoderstrategy.h" #include "encoderstrategy.h" #include // JFIF\0 BYTE jfifID[] = {'J','F','I','F','\0'}; bool IsDefault(const JlsCustomParameters* pcustom) { if (pcustom->MAXVAL != 0) return false; if (pcustom->T1 != 0) return false; if (pcustom->T2 != 0) return false; if (pcustom->T3 != 0) return false; if (pcustom->RESET != 0) return false; return true; } LONG CLAMP(LONG i, LONG j, LONG MAXVAL) { if (i > MAXVAL || i < j) return j; return i; } JlsCustomParameters ComputeDefault(LONG MAXVAL, LONG NEAR) { JlsCustomParameters preset = JlsCustomParameters(); LONG FACTOR = (MIN(MAXVAL, 4095) + 128)/256; preset.T1 = CLAMP(FACTOR * (BASIC_T1 - 2) + 2 + 3*NEAR, NEAR + 1, MAXVAL); preset.T2 = CLAMP(FACTOR * (BASIC_T2 - 3) + 3 + 5*NEAR, preset.T1, MAXVAL); preset.T3 = CLAMP(FACTOR * (BASIC_T3 - 4) + 4 + 7*NEAR, preset.T2, MAXVAL); preset.MAXVAL = MAXVAL; preset.RESET = BASIC_RESET; return preset; } JLS_ERROR CheckParameterCoherent(const JlsParameters* pparams) { if (pparams->bitspersample < 6 || pparams->bitspersample > 16) return ParameterValueNotSupported; if (pparams->ilv < 0 || pparams->ilv > 2) throw JlsException(InvalidCompressedData); if (pparams->bitspersample < 6 || pparams->bitspersample > 16) return ParameterValueNotSupported; switch (pparams->components) { case 4: return pparams->ilv == ILV_SAMPLE ? ParameterValueNotSupported : OK; case 3: return OK; case 1: return pparams->ilv != ILV_NONE ? ParameterValueNotSupported : OK; case 0: return InvalidJlsParameters; default: return pparams->ilv != ILV_NONE ? ParameterValueNotSupported : OK; } } // // JpegMarkerSegment // class JpegMarkerSegment : public JpegSegment { public: JpegMarkerSegment(BYTE marker, std::vector vecbyte) { _marker = marker; std::swap(_vecbyte, vecbyte); } virtual void Write(JLSOutputStream* pstream) { pstream->WriteByte(0xFF); pstream->WriteByte(_marker); pstream->WriteWord(USHORT(_vecbyte.size() + 2)); pstream->WriteBytes(_vecbyte); } BYTE _marker; std::vector _vecbyte; }; // // push_back() // void push_back(std::vector& vec, USHORT value) { vec.push_back(BYTE(value / 0x100)); vec.push_back(BYTE(value % 0x100)); } // // CreateMarkerStartOfFrame() // JpegSegment* CreateMarkerStartOfFrame(Size size, LONG bitsPerSample, LONG ccomp) { std::vector vec; vec.push_back(static_cast(bitsPerSample)); push_back(vec, static_cast(size.cy)); push_back(vec, static_cast(size.cx)); // components vec.push_back(static_cast(ccomp)); for (BYTE component = 0; component < ccomp; component++) { // rescaling vec.push_back(component + 1); vec.push_back(0x11); //"Tq1" reserved, 0 vec.push_back(0); } return new JpegMarkerSegment(JPEG_SOF, vec); } // // ctor() // JLSOutputStream::JLSOutputStream() : _bCompare(false), _pdata(NULL), _cbyteOffset(0), _cbyteLength(0), _icompLast(0) { } // // dtor() // JLSOutputStream::~JLSOutputStream() { for (size_t i = 0; i < _segments.size(); ++i) { delete _segments[i]; } _segments.empty(); } // // Init() // void JLSOutputStream::Init(Size size, LONG bitsPerSample, LONG ccomp) { _segments.push_back(CreateMarkerStartOfFrame(size, bitsPerSample, ccomp)); } void JLSOutputStream::AddColorTransform(int i) { std::vector rgbyteXform; rgbyteXform.push_back('m'); rgbyteXform.push_back('r'); rgbyteXform.push_back('f'); rgbyteXform.push_back('x'); rgbyteXform.push_back((BYTE)i); _segments.push_back(new JpegMarkerSegment(JPEG_APP8, rgbyteXform)); } // // Write() // size_t JLSOutputStream::Write(BYTE* pdata, size_t cbyteLength) { _pdata = pdata; _cbyteLength = cbyteLength; WriteByte(0xFF); WriteByte(JPEG_SOI); for (size_t i = 0; i < _segments.size(); ++i) { _segments[i]->Write(this); } //_bCompare = false; WriteByte(0xFF); WriteByte(JPEG_EOI); return _cbyteOffset; } JLSInputStream::JLSInputStream(const BYTE* pdata, size_t cbyteLength) : _pdata(pdata), _cbyteOffset(0), _cbyteLength(cbyteLength), _bCompare(false), _info(), _rect() { } // // Read() // void JLSInputStream::Read(void* pvoid, size_t cbyteAvailable) { ReadHeader(); JLS_ERROR error = CheckParameterCoherent(&_info); if (error != OK) throw JlsException(error); ReadPixels(pvoid, cbyteAvailable); } // // ReadPixels() // void JLSInputStream::ReadPixels(void* pvoid, size_t cbyteAvailable) { if (_rect.Width <= 0) { _rect.Width = _info.width; _rect.Height = _info.height; } int64_t cbytePlane = (int64_t)(_rect.Width) * _rect.Height * ((_info.bitspersample + 7)/8); if (int64_t(cbyteAvailable) < cbytePlane * _info.components) throw JlsException(UncompressedBufferTooSmall); int scancount = _info.ilv == ILV_NONE ? _info.components : 1; BYTE* pbyte = (BYTE*)pvoid; for (LONG scan = 0; scan < scancount; ++scan) { ReadScan(pbyte); pbyte += cbytePlane; } } // ReadNBytes() // void JLSInputStream::ReadNBytes(std::vector& dst, int byteCount) { for (int i = 0; i < byteCount; ++i) { dst.push_back((char)ReadByte()); } } // // ReadHeader() // void JLSInputStream::ReadHeader() { if (ReadByte() != 0xFF) throw JlsException(InvalidCompressedData); if (ReadByte() != JPEG_SOI) throw JlsException(InvalidCompressedData); for (;;) { if (ReadByte() != 0xFF) throw JlsException(InvalidCompressedData); BYTE marker = (BYTE)ReadByte(); size_t cbyteStart = _cbyteOffset; LONG cbyteMarker = ReadWord(); switch (marker) { case JPEG_SOS: ReadStartOfScan(); break; case JPEG_SOF: ReadStartOfFrame(); break; case JPEG_COM: ReadComment(); break; case JPEG_LSE: ReadPresetParameters(); break; case JPEG_APP0: ReadJfif(); break; case JPEG_APP7: ReadColorSpace(); break; case JPEG_APP8: ReadColorXForm(); break; // Other tags not supported (among which DNL DRI) default: throw JlsException(ImageTypeNotSupported); } if (marker == JPEG_SOS) { _cbyteOffset = cbyteStart - 2; return; } _cbyteOffset = cbyteStart + cbyteMarker; } } JpegMarkerSegment* EncodeStartOfScan(const JlsParameters* pparams, LONG icomponent) { BYTE itable = 0; std::vector rgbyte; if (icomponent < 0) { rgbyte.push_back((BYTE)pparams->components); for (LONG icomponent = 0; icomponent < pparams->components; ++icomponent ) { rgbyte.push_back(BYTE(icomponent + 1)); rgbyte.push_back(itable); } } else { rgbyte.push_back(1); rgbyte.push_back((BYTE)icomponent); rgbyte.push_back(itable); } rgbyte.push_back(BYTE(pparams->allowedlossyerror)); rgbyte.push_back(BYTE(pparams->ilv)); rgbyte.push_back(0); // transform return new JpegMarkerSegment(JPEG_SOS, rgbyte); } JpegMarkerSegment* CreateLSE(const JlsCustomParameters* pcustom) { std::vector rgbyte; rgbyte.push_back(1); push_back(rgbyte, (USHORT)pcustom->MAXVAL); push_back(rgbyte, (USHORT)pcustom->T1); push_back(rgbyte, (USHORT)pcustom->T2); push_back(rgbyte, (USHORT)pcustom->T3); push_back(rgbyte, (USHORT)pcustom->RESET); return new JpegMarkerSegment(JPEG_LSE, rgbyte); } // // ReadPresetParameters() // void JLSInputStream::ReadPresetParameters() { LONG type = ReadByte(); switch (type) { case 1: { _info.custom.MAXVAL = ReadWord(); _info.custom.T1 = ReadWord(); _info.custom.T2 = ReadWord(); _info.custom.T3 = ReadWord(); _info.custom.RESET = ReadWord(); return; } } } // // ReadStartOfScan() // void JLSInputStream::ReadStartOfScan() { LONG ccomp = ReadByte(); for (LONG i = 0; i < ccomp; ++i) { ReadByte(); ReadByte(); } _info.allowedlossyerror = ReadByte(); _info.ilv = interleavemode(ReadByte()); if(_info.bytesperline == 0) { int width = _rect.Width != 0 ? _rect.Width : _info.width; int components = _info.ilv == ILV_NONE ? 1 : _info.components; _info.bytesperline = components * width * ((_info.bitspersample + 7)/8); } } // // ReadComment() // void JLSInputStream::ReadComment() {} // // ReadJfif() // void JLSInputStream::ReadJfif() { for(int i = 0; i < (int)sizeof(jfifID); i++) { if(jfifID[i] != ReadByte()) return; } _info.jfif.Ver = ReadWord(); // DPI or DPcm _info.jfif.units = ReadByte(); _info.jfif.XDensity = ReadWord(); _info.jfif.YDensity = ReadWord(); // thumbnail _info.jfif.Xthumb = ReadByte(); _info.jfif.Ythumb = ReadByte(); if(_info.jfif.Xthumb > 0 && _info.jfif.pdataThumbnail) { std::vector tempbuff((char*)_info.jfif.pdataThumbnail, (char*)_info.jfif.pdataThumbnail+3*_info.jfif.Xthumb*_info.jfif.Ythumb); ReadNBytes(tempbuff, 3*_info.jfif.Xthumb*_info.jfif.Ythumb); } } // // CreateJFIF() // JpegMarkerSegment* CreateJFIF(const JfifParameters* jfif) { std::vector rgbyte; for(int i = 0; i < (int)sizeof(jfifID); i++) { rgbyte.push_back(jfifID[i]); } push_back(rgbyte, (USHORT)jfif->Ver); rgbyte.push_back(jfif->units); push_back(rgbyte, (USHORT)jfif->XDensity); push_back(rgbyte, (USHORT)jfif->YDensity); // thumbnail rgbyte.push_back((BYTE)jfif->Xthumb); rgbyte.push_back((BYTE)jfif->Ythumb); if(jfif->Xthumb > 0) { if(jfif->pdataThumbnail) throw JlsException(InvalidJlsParameters); rgbyte.insert(rgbyte.end(), (BYTE*)jfif->pdataThumbnail, (BYTE*)jfif->pdataThumbnail+3*jfif->Xthumb*jfif->Ythumb ); } return new JpegMarkerSegment(JPEG_APP0, rgbyte); } // // ReadStartOfFrame() // void JLSInputStream::ReadStartOfFrame() { _info.bitspersample = ReadByte(); int cline = ReadWord(); int ccol = ReadWord(); _info.width = ccol; _info.height = cline; _info.components= ReadByte(); } // // ReadByte() // BYTE JLSInputStream::ReadByte() { if (_cbyteOffset >= _cbyteLength) throw JlsException(InvalidCompressedData); return _pdata[_cbyteOffset++]; } // // ReadWord() // int JLSInputStream::ReadWord() { int i = ReadByte() * 256; return i + ReadByte(); } void JLSInputStream::ReadScan(void* pvout) { std::auto_ptr qcodec = JlsCodecFactory().GetCodec(_info, _info.custom); _cbyteOffset += qcodec->DecodeScan(pvout, _rect, _pdata + _cbyteOffset, _cbyteLength - _cbyteOffset, _bCompare); } class JpegImageDataSegment: public JpegSegment { public: JpegImageDataSegment(const void* pvoidRaw, const JlsParameters& info, LONG icompStart, int ccompScan) : _ccompScan(ccompScan), _icompStart(icompStart), _pvoidRaw(pvoidRaw), _info(info) { } void Write(JLSOutputStream* pstream) { JlsParameters info = _info; info.components = _ccompScan; std::auto_ptr qcodec =JlsCodecFactory().GetCodec(info, _info.custom); size_t cbyteWritten = qcodec->EncodeScan((BYTE*)_pvoidRaw, pstream->GetPos(), pstream->GetLength(), pstream->_bCompare ? pstream->GetPos() : NULL); pstream->Seek(cbyteWritten); } int _ccompScan; LONG _icompStart; const void* _pvoidRaw; JlsParameters _info; }; void JLSOutputStream::AddScan(const void* compareData, const JlsParameters* pparams) { if (pparams->jfif.Ver) { _segments.push_back(CreateJFIF(&pparams->jfif)); } if (!IsDefault(&pparams->custom)) { _segments.push_back(CreateLSE(&pparams->custom)); } else if (pparams->bitspersample > 12) { JlsCustomParameters preset = ComputeDefault((1 << pparams->bitspersample) - 1, pparams->allowedlossyerror); _segments.push_back(CreateLSE(&preset)); } _icompLast += 1; _segments.push_back(EncodeStartOfScan(pparams,pparams->ilv == ILV_NONE ? _icompLast : -1)); Size size = Size(pparams->width, pparams->height); int ccomp = pparams->ilv == ILV_NONE ? 1 : pparams->components; _segments.push_back(new JpegImageDataSegment(compareData, *pparams, _icompLast, ccomp)); } // // ReadColorSpace() // void JLSInputStream::ReadColorSpace() {} // // ReadColorXForm() // void JLSInputStream::ReadColorXForm() { std::vector sourceTag; ReadNBytes(sourceTag, 4); if(strncmp(&sourceTag[0],"mrfx", 4) != 0) return; int xform = ReadByte(); switch(xform) { case COLORXFORM_NONE: case COLORXFORM_HP1: case COLORXFORM_HP2: case COLORXFORM_HP3: _info.colorTransform = xform; return; case COLORXFORM_RGB_AS_YUV_LOSSY: case COLORXFORM_MATRIX: throw JlsException(ImageTypeNotSupported); default: throw JlsException(InvalidCompressedData); } } charls-1.0/scan.h0000644000265600020320000005605411556213767013076 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_SCAN #define CHARLS_SCAN #include "lookuptable.h" // This file contains the code for handling a "scan". Usually an image is encoded as a single scan. #ifdef _MSC_VER #pragma warning (disable: 4127) #endif extern CTable decodingTables[16]; extern std::vector rgquant8Ll; extern std::vector rgquant10Ll; extern std::vector rgquant12Ll; extern std::vector rgquant16Ll; // // Apply // inlinehint LONG ApplySign(LONG i, LONG sign) { return (sign ^ i) - sign; } // Two alternatives for GetPredictedValue() (second is slightly faster due to reduced branching) #if 0 inlinehint LONG GetPredictedValue(LONG Ra, LONG Rb, LONG Rc) { if (Ra < Rb) { if (Rc < Ra) return Rb; if (Rc > Rb) return Ra; } else { if (Rc < Rb) return Ra; if (Rc > Ra) return Rb; } return Ra + Rb - Rc; } #else inlinehint LONG GetPredictedValue(LONG Ra, LONG Rb, LONG Rc) { // sign trick reduces the number of if statements (branches) LONG sgn = BitWiseSign(Rb - Ra); // is Ra between Rc and Rb? if ((sgn ^ (Rc - Ra)) < 0) { return Rb; } else if ((sgn ^ (Rb - Rc)) < 0) { return Ra; } // default case, valid if Rc element of [Ra,Rb] return Ra + Rb - Rc; } #endif inlinehint LONG UnMapErrVal(LONG mappedError) { //LONG sign = ~((mappedError & 1) - 1); LONG sign = LONG(mappedError << (LONG_BITCOUNT-1)) >> (LONG_BITCOUNT-1); return sign ^ (mappedError >> 1); } inlinehint LONG GetMappedErrVal(LONG Errval) { LONG mappedError = (Errval >> (LONG_BITCOUNT-2)) ^ (2 * Errval); return mappedError; } inlinehint LONG ComputeContextID(LONG Q1, LONG Q2, LONG Q3) { return (Q1*9 + Q2)*9 + Q3; } // // // template class JlsCodec : public STRATEGY { public: typedef typename TRAITS::PIXEL PIXEL; typedef typename TRAITS::SAMPLE SAMPLE; public: JlsCodec(const TRAITS& inTraits, const JlsParameters& info) : STRATEGY(info), traits(inTraits), _rect(), _width(0), T1(0), T2(0), T3(0), _RUNindex(0), _pquant(0), _bCompare(0) { if (Info().ilv == ILV_NONE) { Info().components = 1; } } void SetPresets(const JlsCustomParameters& presets) { JlsCustomParameters presetDefault = ComputeDefault(traits.MAXVAL, traits.NEAR); InitParams(presets.T1 != 0 ? presets.T1 : presetDefault.T1, presets.T2 != 0 ? presets.T2 : presetDefault.T2, presets.T3 != 0 ? presets.T3 : presetDefault.T3, presets.RESET != 0 ? presets.RESET : presetDefault.RESET); } bool IsInterleaved() { if (Info().ilv == ILV_NONE) return false; if (Info().components == 1) return false; return true; } JlsParameters& Info() { return STRATEGY::_info; } signed char QuantizeGratientOrg(LONG Di); inlinehint LONG QuantizeGratient(LONG Di) { ASSERT(QuantizeGratientOrg(Di) == *(_pquant + Di)); return *(_pquant + Di); } void InitQuantizationLUT(); LONG DecodeValue(LONG k, LONG limit, LONG qbpp); inlinehint void EncodeMappedValue(LONG k, LONG mappedError, LONG limit); void IncrementRunIndex() { _RUNindex = MIN(31,_RUNindex + 1); } void DecrementRunIndex() { _RUNindex = MAX(0,_RUNindex - 1); } LONG DecodeRIError(CContextRunMode& ctx); Triplet DecodeRIPixel(Triplet Ra, Triplet Rb); SAMPLE DecodeRIPixel(LONG Ra, LONG Rb); LONG DecodeRunPixels(PIXEL Ra, PIXEL* ptype, LONG cpixelMac); LONG DoRunMode(LONG index, DecoderStrategy*); void EncodeRIError(CContextRunMode& ctx, LONG Errval); SAMPLE EncodeRIPixel(LONG x, LONG Ra, LONG Rb); Triplet EncodeRIPixel(Triplet x, Triplet Ra, Triplet Rb); void EncodeRunPixels(LONG runLength, bool bEndofline); LONG DoRunMode(LONG index, EncoderStrategy*); inlinehint SAMPLE DoRegular(LONG Qs, LONG, LONG pred, DecoderStrategy*); inlinehint SAMPLE DoRegular(LONG Qs, LONG x, LONG pred, EncoderStrategy*); void DoLine(SAMPLE* pdummy); void DoLine(Triplet* pdummy); void DoScan(BYTE* compressedBytes, size_t compressedLength); public: ProcessLine* CreateProcess(void* pvoidOut); void InitDefault(); void InitParams(LONG t1, LONG t2, LONG t3, LONG nReset); size_t EncodeScan(const void* rawData, void* pvoidOut, size_t compressedLength, void* pvoidCompare); size_t DecodeScan(void* rawData, const JlsRect& size, const void* compressedData, size_t compressedLength, bool bCompare); protected: // codec parameters TRAITS traits; JlsRect _rect; int _width; LONG T1; LONG T2; LONG T3; // compression context JlsContext _contexts[365]; CContextRunMode _contextRunmode[2]; LONG _RUNindex; PIXEL* _previousLine; // previous line ptr PIXEL* _currentLine; // current line ptr // quantization lookup table signed char* _pquant; std::vector _rgquant; // debugging bool _bCompare; }; // Encode/decode a single sample. Performancewise the #1 important functions template typename TRAITS::SAMPLE JlsCodec::DoRegular(LONG Qs, LONG, LONG pred, DecoderStrategy*) { LONG sign = BitWiseSign(Qs); JlsContext& ctx = _contexts[ApplySign(Qs, sign)]; LONG k = ctx.GetGolomb(); LONG Px = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign)); LONG ErrVal; const Code& code = decodingTables[k].Get(STRATEGY::PeekByte()); if (code.GetLength() != 0) { STRATEGY::Skip(code.GetLength()); ErrVal = code.GetValue(); ASSERT(abs(ErrVal) < 65535); } else { ErrVal = UnMapErrVal(DecodeValue(k, traits.LIMIT, traits.qbpp)); if (abs(ErrVal) > 65535) throw JlsException(InvalidCompressedData); } ErrVal = ErrVal ^ ((traits.NEAR == 0) ? ctx.GetErrorCorrection(k) : 0); ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET); ErrVal = ApplySign(ErrVal, sign); return traits.ComputeReconstructedSample(Px, ErrVal); } template typename TRAITS::SAMPLE JlsCodec::DoRegular(LONG Qs, LONG x, LONG pred, EncoderStrategy*) { LONG sign = BitWiseSign(Qs); JlsContext& ctx = _contexts[ApplySign(Qs, sign)]; LONG k = ctx.GetGolomb(); LONG Px = traits.CorrectPrediction(pred + ApplySign(ctx.C, sign)); LONG ErrVal = traits.ComputeErrVal(ApplySign(x - Px, sign)); EncodeMappedValue(k, GetMappedErrVal(ctx.GetErrorCorrection(k | traits.NEAR) ^ ErrVal), traits.LIMIT); ctx.UpdateVariables(ErrVal, traits.NEAR, traits.RESET); ASSERT(traits.IsNear(traits.ComputeReconstructedSample(Px, ApplySign(ErrVal, sign)), x)); return static_cast(traits.ComputeReconstructedSample(Px, ApplySign(ErrVal, sign))); } // Functions to build tables used to decode short golomb codes. inlinehint std::pair CreateEncodedValue(LONG k, LONG mappedError) { LONG highbits = mappedError >> k; return std::make_pair(highbits + k + 1, (LONG(1) << k) | (mappedError & ((LONG(1) << k) - 1))); } CTable InitTable(LONG k) { CTable table; for (short nerr = 0; ; nerr++) { // Q is not used when k != 0 LONG merrval = GetMappedErrVal(nerr);//, k, -1); std::pair paircode = CreateEncodedValue(k, merrval); if (paircode.first > CTable::cbit) break; Code code = Code( nerr, short(paircode.first) ); table.AddEntry(BYTE(paircode.second), code); } for (short nerr = -1; ; nerr--) { // Q is not used when k != 0 LONG merrval = GetMappedErrVal(nerr);//, k, -1); std::pair paircode = CreateEncodedValue(k, merrval); if (paircode.first > CTable::cbit) break; Code code = Code(nerr, short(paircode.first)); table.AddEntry(BYTE(paircode.second), code); } return table; } // Encoding/decoding of golomb codes template LONG JlsCodec::DecodeValue(LONG k, LONG limit, LONG qbpp) { LONG highbits = STRATEGY::ReadHighbits(); if (highbits >= limit - (qbpp + 1)) return STRATEGY::ReadValue(qbpp) + 1; if (k == 0) return highbits; return (highbits << k) + STRATEGY::ReadValue(k); } template inlinehint void JlsCodec::EncodeMappedValue(LONG k, LONG mappedError, LONG limit) { LONG highbits = mappedError >> k; if (highbits < limit - traits.qbpp - 1) { if (highbits + 1 > 31) { STRATEGY::AppendToBitStream(0, highbits / 2); highbits = highbits - highbits / 2; } STRATEGY::AppendToBitStream(1, highbits + 1); STRATEGY::AppendToBitStream((mappedError & ((1 << k) - 1)), k); return; } if (limit - traits.qbpp > 31) { STRATEGY::AppendToBitStream(0, 31); STRATEGY::AppendToBitStream(1, limit - traits.qbpp - 31); } else { STRATEGY::AppendToBitStream(1, limit - traits.qbpp); } STRATEGY::AppendToBitStream((mappedError - 1) & ((1 << traits.qbpp) - 1), traits.qbpp); } // Sets up a lookup table to "Quantize" sample difference. template void JlsCodec::InitQuantizationLUT() { // for lossless mode with default parameters, we have precomputed te luts for bitcounts 8,10,12 and 16 if (traits.NEAR == 0 && traits.MAXVAL == (1 << traits.bpp) - 1) { JlsCustomParameters presets = ComputeDefault(traits.MAXVAL, traits.NEAR); if (presets.T1 == T1 && presets.T2 == T2 && presets.T3 == T3) { if (traits.bpp == 8) { _pquant = &rgquant8Ll[rgquant8Ll.size() / 2 ]; return; } if (traits.bpp == 10) { _pquant = &rgquant10Ll[rgquant10Ll.size() / 2 ]; return; } if (traits.bpp == 12) { _pquant = &rgquant12Ll[rgquant12Ll.size() / 2 ]; return; } if (traits.bpp == 16) { _pquant = &rgquant16Ll[rgquant16Ll.size() / 2 ]; return; } } } LONG RANGE = 1 << traits.bpp; _rgquant.resize(RANGE * 2); _pquant = &_rgquant[RANGE]; for (LONG i = -RANGE; i < RANGE; ++i) { _pquant[i] = QuantizeGratientOrg(i); } } template signed char JlsCodec::QuantizeGratientOrg(LONG Di) { if (Di <= -T3) return -4; if (Di <= -T2) return -3; if (Di <= -T1) return -2; if (Di < -traits.NEAR) return -1; if (Di <= traits.NEAR) return 0; if (Di < T1) return 1; if (Di < T2) return 2; if (Di < T3) return 3; return 4; } // RI = Run interruption: functions that handle the sample terminating a run. template LONG JlsCodec::DecodeRIError(CContextRunMode& ctx) { LONG k = ctx.GetGolomb(); LONG EMErrval = DecodeValue(k, traits.LIMIT - J[_RUNindex]-1, traits.qbpp); LONG Errval = ctx.ComputeErrVal(EMErrval + ctx._nRItype, k); ctx.UpdateVariables(Errval, EMErrval); return Errval; } template void JlsCodec::EncodeRIError(CContextRunMode& ctx, LONG Errval) { LONG k = ctx.GetGolomb(); bool map = ctx.ComputeMap(Errval, k); LONG EMErrval = 2 * abs(Errval) - ctx._nRItype - map; ASSERT(Errval == ctx.ComputeErrVal(EMErrval + ctx._nRItype, k)); EncodeMappedValue(k, EMErrval, traits.LIMIT-J[_RUNindex]-1); ctx.UpdateVariables(Errval, EMErrval); } template Triplet JlsCodec::DecodeRIPixel(Triplet Ra, Triplet Rb) { LONG Errval1 = DecodeRIError(_contextRunmode[0]); LONG Errval2 = DecodeRIError(_contextRunmode[0]); LONG Errval3 = DecodeRIError(_contextRunmode[0]); return Triplet(traits.ComputeReconstructedSample(Rb.v1, Errval1 * Sign(Rb.v1 - Ra.v1)), traits.ComputeReconstructedSample(Rb.v2, Errval2 * Sign(Rb.v2 - Ra.v2)), traits.ComputeReconstructedSample(Rb.v3, Errval3 * Sign(Rb.v3 - Ra.v3))); } template Triplet JlsCodec::EncodeRIPixel(Triplet x, Triplet Ra, Triplet Rb) { LONG errval1 = traits.ComputeErrVal(Sign(Rb.v1 - Ra.v1) * (x.v1 - Rb.v1)); EncodeRIError(_contextRunmode[0], errval1); LONG errval2 = traits.ComputeErrVal(Sign(Rb.v2 - Ra.v2) * (x.v2 - Rb.v2)); EncodeRIError(_contextRunmode[0], errval2); LONG errval3 = traits.ComputeErrVal(Sign(Rb.v3 - Ra.v3) * (x.v3 - Rb.v3)); EncodeRIError(_contextRunmode[0], errval3); return Triplet(traits.ComputeReconstructedSample(Rb.v1, errval1 * Sign(Rb.v1 - Ra.v1)), traits.ComputeReconstructedSample(Rb.v2, errval2 * Sign(Rb.v2 - Ra.v2)), traits.ComputeReconstructedSample(Rb.v3, errval3 * Sign(Rb.v3 - Ra.v3))); } template typename TRAITS::SAMPLE JlsCodec::DecodeRIPixel(LONG Ra, LONG Rb) { if (abs(Ra - Rb) <= traits.NEAR) { LONG ErrVal = DecodeRIError(_contextRunmode[1]); return static_cast(traits.ComputeReconstructedSample(Ra, ErrVal)); } else { LONG ErrVal = DecodeRIError(_contextRunmode[0]); return static_cast(traits.ComputeReconstructedSample(Rb, ErrVal * Sign(Rb - Ra))); } } template typename TRAITS::SAMPLE JlsCodec::EncodeRIPixel(LONG x, LONG Ra, LONG Rb) { if (abs(Ra - Rb) <= traits.NEAR) { LONG ErrVal = traits.ComputeErrVal(x - Ra); EncodeRIError(_contextRunmode[1], ErrVal); return static_cast(traits.ComputeReconstructedSample(Ra, ErrVal)); } else { LONG ErrVal = traits.ComputeErrVal((x - Rb) * Sign(Rb - Ra)); EncodeRIError(_contextRunmode[0], ErrVal); return static_cast(traits.ComputeReconstructedSample(Rb, ErrVal * Sign(Rb - Ra))); } } // RunMode: Functions that handle run-length encoding template void JlsCodec::EncodeRunPixels(LONG runLength, bool endOfLine) { while (runLength >= LONG(1 << J[_RUNindex])) { STRATEGY::AppendOnesToBitStream(1); runLength = runLength - LONG(1 << J[_RUNindex]); IncrementRunIndex(); } if (endOfLine) { if (runLength != 0) { STRATEGY::AppendOnesToBitStream(1); } } else { STRATEGY::AppendToBitStream(runLength, J[_RUNindex] + 1); // leading 0 + actual remaining length } } template LONG JlsCodec::DecodeRunPixels(PIXEL Ra, PIXEL* startPos, LONG cpixelMac) { LONG index = 0; while (STRATEGY::ReadBit()) { int count = MIN(1 << J[_RUNindex], int(cpixelMac - index)); index += count; ASSERT(index <= cpixelMac); if (count == (1 << J[_RUNindex])) { IncrementRunIndex(); } if (index == cpixelMac) break; } if (index != cpixelMac) { // incomplete run index += (J[_RUNindex] > 0) ? STRATEGY::ReadValue(J[_RUNindex]) : 0; } if (index > cpixelMac) throw JlsException(InvalidCompressedData); for (LONG i = 0; i < index; ++i) { startPos[i] = Ra; } return index; } template LONG JlsCodec::DoRunMode(LONG index, EncoderStrategy*) { LONG ctypeRem = _width - index; PIXEL* ptypeCurX = _currentLine + index; PIXEL* ptypePrevX = _previousLine + index; PIXEL Ra = ptypeCurX[-1]; LONG runLength = 0; while (traits.IsNear(ptypeCurX[runLength],Ra)) { ptypeCurX[runLength] = Ra; runLength++; if (runLength == ctypeRem) break; } EncodeRunPixels(runLength, runLength == ctypeRem); if (runLength == ctypeRem) return runLength; ptypeCurX[runLength] = EncodeRIPixel(ptypeCurX[runLength], Ra, ptypePrevX[runLength]); DecrementRunIndex(); return runLength + 1; } template LONG JlsCodec::DoRunMode(LONG startIndex, DecoderStrategy*) { PIXEL Ra = _currentLine[startIndex-1]; LONG runLength = DecodeRunPixels(Ra, _currentLine + startIndex, _width - startIndex); LONG endIndex = startIndex + runLength; if (endIndex == _width) return endIndex - startIndex; // run interruption PIXEL Rb = _previousLine[endIndex]; _currentLine[endIndex] = DecodeRIPixel(Ra, Rb); DecrementRunIndex(); return endIndex - startIndex + 1; } // DoLine: Encodes/Decodes a scanline of samples template void JlsCodec::DoLine(SAMPLE*) { LONG index = 0; LONG Rb = _previousLine[index-1]; LONG Rd = _previousLine[index]; while(index < _width) { LONG Ra = _currentLine[index -1]; LONG Rc = Rb; Rb = Rd; Rd = _previousLine[index + 1]; LONG Qs = ComputeContextID(QuantizeGratient(Rd - Rb), QuantizeGratient(Rb - Rc), QuantizeGratient(Rc - Ra)); if (Qs != 0) { _currentLine[index] = DoRegular(Qs, _currentLine[index], GetPredictedValue(Ra, Rb, Rc), (STRATEGY*)(NULL)); index++; } else { index += DoRunMode(index, (STRATEGY*)(NULL)); Rb = _previousLine[index-1]; Rd = _previousLine[index]; } } } // DoLine: Encodes/Decodes a scanline of triplets in ILV_SAMPLE mode template void JlsCodec::DoLine(Triplet*) { LONG index = 0; while(index < _width) { Triplet Ra = _currentLine[index -1]; Triplet Rc = _previousLine[index-1]; Triplet Rb = _previousLine[index]; Triplet Rd = _previousLine[index + 1]; LONG Qs1 = ComputeContextID(QuantizeGratient(Rd.v1 - Rb.v1), QuantizeGratient(Rb.v1 - Rc.v1), QuantizeGratient(Rc.v1 - Ra.v1)); LONG Qs2 = ComputeContextID(QuantizeGratient(Rd.v2 - Rb.v2), QuantizeGratient(Rb.v2 - Rc.v2), QuantizeGratient(Rc.v2 - Ra.v2)); LONG Qs3 = ComputeContextID(QuantizeGratient(Rd.v3 - Rb.v3), QuantizeGratient(Rb.v3 - Rc.v3), QuantizeGratient(Rc.v3 - Ra.v3)); if (Qs1 == 0 && Qs2 == 0 && Qs3 == 0) { index += DoRunMode(index, (STRATEGY*)(NULL)); } else { Triplet Rx; Rx.v1 = DoRegular(Qs1, _currentLine[index].v1, GetPredictedValue(Ra.v1, Rb.v1, Rc.v1), (STRATEGY*)(NULL)); Rx.v2 = DoRegular(Qs2, _currentLine[index].v2, GetPredictedValue(Ra.v2, Rb.v2, Rc.v2), (STRATEGY*)(NULL)); Rx.v3 = DoRegular(Qs3, _currentLine[index].v3, GetPredictedValue(Ra.v3, Rb.v3, Rc.v3), (STRATEGY*)(NULL)); _currentLine[index] = Rx; index++; } } } // DoScan: Encodes or decodes a scan. // In ILV_SAMPLE mode, multiple components are handled in DoLine // In ILV_LINE mode, a call do DoLine is made for every component // In ILV_NONE mode, DoScan is called for each component template void JlsCodec::DoScan(BYTE* compressedBytes, size_t compressedLength) { _width = Info().width; STRATEGY::Init(compressedBytes, compressedLength); LONG pixelstride = _width + 4; int components = Info().ilv == ILV_LINE ? Info().components : 1; std::vector vectmp(2 * components * pixelstride); std::vector rgRUNindex(components); for (LONG line = 0; line < Info().height; ++line) { _previousLine = &vectmp[1]; _currentLine = &vectmp[1 + components * pixelstride]; if ((line & 1) == 1) { std::swap(_previousLine, _currentLine); } STRATEGY::OnLineBegin(_width, _currentLine, pixelstride); for (int component = 0; component < components; ++component) { _RUNindex = rgRUNindex[component]; // initialize edge pixels used for prediction _previousLine[_width] = _previousLine[_width - 1]; _currentLine[-1] = _previousLine[0]; DoLine((PIXEL*) NULL); // dummy arg for overload resolution rgRUNindex[component] = _RUNindex; _previousLine += pixelstride; _currentLine += pixelstride; } if (_rect.Y <= line && line < _rect.Y + _rect.Height) { STRATEGY::OnLineEnd(_rect.Width, _currentLine + _rect.X - (components * pixelstride), pixelstride); } } STRATEGY::EndScan(); } // Factory function for ProcessLine objects to copy/transform unencoded pixels to/from our scanline buffers. template ProcessLine* JlsCodec::CreateProcess(void* pvoidOut) { if (!IsInterleaved()) return new PostProcesSingleComponent(pvoidOut, Info(), sizeof(typename TRAITS::PIXEL)); if (Info().colorTransform == 0) return new ProcessTransformed >(pvoidOut, Info(), TransformNone()); if ((Info().bitspersample == sizeof(SAMPLE)*8)) { switch(Info().colorTransform) { case COLORXFORM_HP1 : return new ProcessTransformed >(pvoidOut, Info(), TransformHp1()); break; case COLORXFORM_HP2 : return new ProcessTransformed >(pvoidOut, Info(), TransformHp2()); break; case COLORXFORM_HP3 : return new ProcessTransformed >(pvoidOut, Info(), TransformHp3()); break; default: throw JlsException(UnsupportedColorTransform); } } else if (Info().bitspersample > 8) { int shift = 16 - Info().bitspersample; switch(Info().colorTransform) { case COLORXFORM_HP1 : return new ProcessTransformed > >(pvoidOut, Info(), TransformShifted >(shift)); break; case COLORXFORM_HP2 : return new ProcessTransformed > >(pvoidOut, Info(), TransformShifted >(shift)); break; case COLORXFORM_HP3 : return new ProcessTransformed > >(pvoidOut, Info(), TransformShifted >(shift)); break; default: throw JlsException(UnsupportedColorTransform); } } throw JlsException(UnsupportedBitDepthForTransform); } // Setup codec for encoding and calls DoScan template size_t JlsCodec::EncodeScan(const void* rawData, void* compressedData, size_t compressedLength, void* pvoidCompare) { STRATEGY::_processLine = std::auto_ptr(CreateProcess(const_cast(rawData))); BYTE* compressedBytes = static_cast(compressedData); if (pvoidCompare != NULL) { STRATEGY::_qdecoder = std::auto_ptr(new JlsCodec(traits, Info())); STRATEGY::_qdecoder->Init((BYTE*)pvoidCompare, compressedLength); } DoScan(compressedBytes, compressedLength); return STRATEGY::GetLength(); } // Setup codec for decoding and calls DoScan template size_t JlsCodec::DecodeScan(void* rawData, const JlsRect& rect, const void* compressedData, size_t compressedLength, bool bCompare) { STRATEGY::_processLine = std::auto_ptr(CreateProcess(rawData)); BYTE* compressedBytes = const_cast(static_cast(compressedData)); _bCompare = bCompare; BYTE rgbyte[20]; size_t readBytes = 0; ::memcpy(rgbyte, compressedBytes, 4); readBytes += 4; size_t cbyteScanheader = rgbyte[3] - 2; if (cbyteScanheader > sizeof(rgbyte)) throw JlsException(InvalidCompressedData); ::memcpy(rgbyte, compressedBytes, cbyteScanheader); readBytes += cbyteScanheader; _rect = rect; DoScan(compressedBytes + readBytes, compressedLength - readBytes); return STRATEGY::GetCurBytePos() - compressedBytes; } // Initialize the codec data structures. Depends on JPEG-LS parameters like T1-T3. template void JlsCodec::InitParams(LONG t1, LONG t2, LONG t3, LONG nReset) { T1 = t1; T2 = t2; T3 = t3; InitQuantizationLUT(); LONG A = MAX(2, (traits.RANGE + 32)/64); for (unsigned int Q = 0; Q < sizeof(_contexts) / sizeof(_contexts[0]); ++Q) { _contexts[Q] = JlsContext(A); } _contextRunmode[0] = CContextRunMode(MAX(2, (traits.RANGE + 32)/64), 0, nReset); _contextRunmode[1] = CContextRunMode(MAX(2, (traits.RANGE + 32)/64), 1, nReset); _RUNindex = 0; } #endif charls-1.0/lookuptable.h0000644000265600020320000000176711556213767014474 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_LOOKUPTABLE #define CHARLS_LOOKUPTABLE // Tables for fast decoding of short Golomb Codes. struct Code { Code() { } Code(LONG value, LONG length) : _value(value), _length(length) { } LONG GetValue() const { return _value; } LONG GetLength() const { return _length; } LONG _value; LONG _length; }; class CTable { public: enum { cbit = 8 } ; CTable() { ::memset(rgtype, 0, sizeof(rgtype)); } void AddEntry(BYTE bvalue, Code c); inlinehint const Code& Get(LONG value) { return rgtype[value]; } private: Code rgtype[1 << cbit]; }; // // AddEntry // void CTable::AddEntry(BYTE bvalue, Code c) { LONG length = c.GetLength(); ASSERT(length <= cbit); for (LONG i = 0; i < LONG(1) << (cbit - length); ++i) { ASSERT(rgtype[(bvalue << (cbit - length)) + i].GetLength() == 0); rgtype[(bvalue << (cbit - length)) + i] = c; } } #endif charls-1.0/publictypes.h0000644000265600020320000000233411556213767014505 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_PUBLICTYPES #define CHARLS_PUBLICTYPES #include "config.h" enum JLS_ERROR { OK = 0, InvalidJlsParameters, ParameterValueNotSupported, UncompressedBufferTooSmall, CompressedBufferTooSmall, InvalidCompressedData, TooMuchCompressedData, ImageTypeNotSupported, UnsupportedBitDepthForTransform, UnsupportedColorTransform }; enum interleavemode { ILV_NONE = 0, ILV_LINE = 1, ILV_SAMPLE = 2 }; struct JlsCustomParameters { int MAXVAL; int T1; int T2; int T3; int RESET; }; struct JlsRect { int X, Y; int Width, Height; }; struct JfifParameters { int Ver; char units; int XDensity; int YDensity; short Xthumb; short Ythumb; void* pdataThumbnail; // user must set buffer which size is Xthumb*Ythumb*3(RGB) before JpegLsDecode() }; struct JlsParameters { int width; int height; int bitspersample; int bytesperline; // for [source (at encoding)][decoded (at decoding)] pixel image in user buffer int components; int allowedlossyerror; enum interleavemode ilv; int colorTransform; char outputBgr; struct JlsCustomParameters custom; struct JfifParameters jfif; }; #endif charls-1.0/header.h0000644000265600020320000000235411556213767013374 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_HEADER #define CHARLS_HEADER #include "streams.h" #define JPEG_SOI 0xD8 #define JPEG_EOI 0xD9 #define JPEG_SOS 0xDA #define JPEG_SOF 0xF7 #define JPEG_LSE 0xF8 #define JPEG_DNL 0xDC #define JPEG_DRI 0xDD #define JPEG_RSTm 0xD0 #define JPEG_COM 0xFE #define JPEG_APP0 0xE0 // JFIF #define JPEG_APP7 0xE7 // colorspace #define JPEG_APP8 0xE8 // colorXForm // Default bin sizes for JPEG-LS statistical modeling. Can be overriden at compression time, however this is rarely done. const int BASIC_T1 = 3; const int BASIC_T2 = 7; const int BASIC_T3 = 21; const LONG BASIC_RESET = 64; class JLSOutputStream; template class JlsCodecFactory { public: std::auto_ptr GetCodec(const JlsParameters& info, const JlsCustomParameters&); private: STRATEGY* GetCodecImpl(const JlsParameters& info); }; JLS_ERROR CheckParameterCoherent(const JlsParameters* pparams); JlsCustomParameters ComputeDefault(LONG MAXVAL, LONG NEAR); // // JpegSegment // class JpegSegment { protected: JpegSegment() {} public: virtual ~JpegSegment() {} virtual void Write(JLSOutputStream* pstream) = 0; }; #endif charls-1.0/losslesstraits.h0000644000265600020320000000523511556213767015243 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_LOSSLESSTRAITS #define CHARLS_LOSSLESSTRAITS #include "header.h" // // optimized trait classes for lossless compression of 8 bit color and 8/16 bit monochrome images. // This class is assumes MAXVAL correspond to a whole number of bits, and no custom RESET value is set when encoding. // The point of this is to have the most optimized code for the most common and most demanding scenario. template struct LosslessTraitsImplT { typedef sample SAMPLE; enum { NEAR = 0, bpp = bitsperpixel, qbpp = bitsperpixel, RANGE = (1 << bpp), MAXVAL= (1 << bpp) - 1, LIMIT = 2 * (bitsperpixel + MAX(8,bitsperpixel)), RESET = BASIC_RESET }; static inlinehint LONG ComputeErrVal(LONG d) { return ModRange(d); } static inlinehint bool IsNear(LONG lhs, LONG rhs) { return lhs == rhs; } static inlinehint LONG ModRange(LONG Errval) { return LONG(Errval << (LONG_BITCOUNT - bpp)) >> (LONG_BITCOUNT - bpp); } static inlinehint SAMPLE ComputeReconstructedSample(LONG Px, LONG ErrVal) { return SAMPLE(MAXVAL & (Px + ErrVal)); } static inlinehint LONG CorrectPrediction(LONG Pxc) { if ((Pxc & MAXVAL) == Pxc) return Pxc; return (~(Pxc >> (LONG_BITCOUNT-1))) & MAXVAL; } }; template struct LosslessTraitsT : public LosslessTraitsImplT { typedef SAMPLE PIXEL; }; template<> struct LosslessTraitsT : public LosslessTraitsImplT { typedef SAMPLE PIXEL; static inlinehint signed char ModRange(LONG Errval) { return (signed char)Errval; } static inlinehint LONG ComputeErrVal(LONG d) { return (signed char)(d); } static inlinehint BYTE ComputeReconstructedSample(LONG Px, LONG ErrVal) { return BYTE(Px + ErrVal); } }; template<> struct LosslessTraitsT : public LosslessTraitsImplT { typedef SAMPLE PIXEL; static inlinehint short ModRange(LONG Errval) { return short(Errval); } static inlinehint LONG ComputeErrVal(LONG d) { return short(d); } static inlinehint SAMPLE ComputeReconstructedSample(LONG Px, LONG ErrVal) { return SAMPLE(Px + ErrVal); } }; template struct LosslessTraitsT,bpp> : public LosslessTraitsImplT { typedef Triplet PIXEL; static inlinehint bool IsNear(LONG lhs, LONG rhs) { return lhs == rhs; } static inlinehint bool IsNear(PIXEL lhs, PIXEL rhs) { return lhs == rhs; } static inlinehint SAMPLE ComputeReconstructedSample(LONG Px, LONG ErrVal) { return SAMPLE(Px + ErrVal); } }; #endif charls-1.0/plainc/0000755000265600020320000000000011464353322013223 5ustar tilleaadmincharls-1.0/plainc/plainc.vcproj0000644000265600020320000000712511464353322015723 0ustar tilleaadmin charls-1.0/plainc/plainc.c0000644000265600020320000000011011464353322014625 0ustar tilleaadmin#include #include "../interface.h" void main() { }charls-1.0/streams.h0000644000265600020320000000603511556213767013622 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_STREAMS #define CHARLS_STREAMS #include #include #include "util.h" // This file defines JPEG-LS streams: The header and the actual pixel data. Header markers have fixed length, the pixeldata not. class JpegSegment; enum JPEGLS_ColorXForm { // default (RGB) COLORXFORM_NONE = 0, // Color transforms as defined by HP COLORXFORM_HP1, COLORXFORM_HP2, COLORXFORM_HP3, // Defined by HP but not supported by CharLS COLORXFORM_RGB_AS_YUV_LOSSY, COLORXFORM_MATRIX }; // // JLSOutputStream: minimal implementation to write JPEG header streams // class JLSOutputStream { friend class JpegMarkerSegment; friend class JpegImageDataSegment; public: JLSOutputStream(); virtual ~JLSOutputStream(); void Init(Size size, LONG bitsPerSample, LONG ccomp); void AddScan(const void* compareData, const JlsParameters* pparams); void AddLSE(const JlsCustomParameters* pcustom); void AddColorTransform(int i); size_t GetBytesWritten() { return _cbyteOffset; } size_t GetLength() { return _cbyteLength - _cbyteOffset; } size_t Write(BYTE* pdata, size_t cbyteLength); void EnableCompare(bool bCompare) { _bCompare = bCompare; } private: BYTE* GetPos() const { return _pdata + _cbyteOffset; } void WriteByte(BYTE val) { ASSERT(!_bCompare || _pdata[_cbyteOffset] == val); _pdata[_cbyteOffset++] = val; } void WriteBytes(const std::vector& rgbyte) { for (size_t i = 0; i < rgbyte.size(); ++i) { WriteByte(rgbyte[i]); } } void WriteWord(USHORT val) { WriteByte(BYTE(val / 0x100)); WriteByte(BYTE(val % 0x100)); } void Seek(size_t byteCount) { _cbyteOffset += byteCount; } bool _bCompare; private: BYTE* _pdata; size_t _cbyteOffset; size_t _cbyteLength; LONG _icompLast; std::vector _segments; }; // // JLSInputStream: minimal implementation to read JPEG header streams // class JLSInputStream { public: JLSInputStream(const BYTE* pdata, size_t cbyteLength); size_t GetBytesRead() { return _cbyteOffset; } const JlsParameters& GetMetadata() const { return _info; } const JlsCustomParameters& GetCustomPreset() const { return _info.custom; } void Read(void* pvoid, size_t cbyteAvailable); void ReadHeader(); void EnableCompare(bool bCompare) { _bCompare = bCompare; } void SetInfo(JlsParameters* info) { _info = *info; } void SetRect(JlsRect rect) { _rect = rect; } private: void ReadPixels(void* pvoid, size_t cbyteAvailable); void ReadScan(void*); void ReadStartOfScan(); void ReadPresetParameters(); void ReadComment(); void ReadStartOfFrame(); BYTE ReadByte(); int ReadWord(); void ReadNBytes(std::vector& dst, int byteCount); // JFIF void ReadJfif(); // Color Transform Application Markers & Code Stream (HP extension) void ReadColorSpace(); void ReadColorXForm(); private: const BYTE* _pdata; size_t _cbyteOffset; size_t _cbyteLength; bool _bCompare; JlsParameters _info; JlsRect _rect; }; #endif charls-1.0/CharLS.sln0000644000265600020320000000552211464353322013613 0ustar tilleaadminMicrosoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CharLS", "CharLS.vcproj", "{524BE26D-FC60-4BC4-9100-128A0502FFF7}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcproj", "{3E349E7B-30C2-4791-81B7-1108014291B7}" ProjectSection(ProjectDependencies) = postProject {524BE26D-FC60-4BC4-9100-128A0502FFF7} = {524BE26D-FC60-4BC4-9100-128A0502FFF7} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plainc", "plainc\plainc.vcproj", "{1FB6C79F-9A01-41A4-9278-F666DEF6D4C6}" ProjectSection(ProjectDependencies) = postProject {524BE26D-FC60-4BC4-9100-128A0502FFF7} = {524BE26D-FC60-4BC4-9100-128A0502FFF7} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Debug|x64 = Debug|x64 Release|Win32 = Release|Win32 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {524BE26D-FC60-4BC4-9100-128A0502FFF7}.Debug|Win32.ActiveCfg = Debug|Win32 {524BE26D-FC60-4BC4-9100-128A0502FFF7}.Debug|Win32.Build.0 = Debug|Win32 {524BE26D-FC60-4BC4-9100-128A0502FFF7}.Debug|x64.ActiveCfg = Debug|x64 {524BE26D-FC60-4BC4-9100-128A0502FFF7}.Debug|x64.Build.0 = Debug|x64 {524BE26D-FC60-4BC4-9100-128A0502FFF7}.Release|Win32.ActiveCfg = Release|Win32 {524BE26D-FC60-4BC4-9100-128A0502FFF7}.Release|Win32.Build.0 = Release|Win32 {524BE26D-FC60-4BC4-9100-128A0502FFF7}.Release|x64.ActiveCfg = Release|x64 {524BE26D-FC60-4BC4-9100-128A0502FFF7}.Release|x64.Build.0 = Release|x64 {3E349E7B-30C2-4791-81B7-1108014291B7}.Debug|Win32.ActiveCfg = Debug|Win32 {3E349E7B-30C2-4791-81B7-1108014291B7}.Debug|Win32.Build.0 = Debug|Win32 {3E349E7B-30C2-4791-81B7-1108014291B7}.Debug|x64.ActiveCfg = Debug|x64 {3E349E7B-30C2-4791-81B7-1108014291B7}.Debug|x64.Build.0 = Debug|x64 {3E349E7B-30C2-4791-81B7-1108014291B7}.Release|Win32.ActiveCfg = Release|Win32 {3E349E7B-30C2-4791-81B7-1108014291B7}.Release|Win32.Build.0 = Release|Win32 {3E349E7B-30C2-4791-81B7-1108014291B7}.Release|x64.ActiveCfg = Release|x64 {3E349E7B-30C2-4791-81B7-1108014291B7}.Release|x64.Build.0 = Release|x64 {1FB6C79F-9A01-41A4-9278-F666DEF6D4C6}.Debug|Win32.ActiveCfg = Debug|Win32 {1FB6C79F-9A01-41A4-9278-F666DEF6D4C6}.Debug|Win32.Build.0 = Debug|Win32 {1FB6C79F-9A01-41A4-9278-F666DEF6D4C6}.Debug|x64.ActiveCfg = Debug|Win32 {1FB6C79F-9A01-41A4-9278-F666DEF6D4C6}.Release|Win32.ActiveCfg = Release|Win32 {1FB6C79F-9A01-41A4-9278-F666DEF6D4C6}.Release|Win32.Build.0 = Release|Win32 {1FB6C79F-9A01-41A4-9278-F666DEF6D4C6}.Release|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal charls-1.0/encoderstrategy.h0000644000265600020320000000562011556213767015345 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_ENCODERSTRATEGY #define CHARLS_ENCODERSTRATEGY #include "processline.h" #include "decoderstrategy.h" // Implements encoding to stream of bits. In encoding mode JpegLsCodec inherits from EncoderStrategy class EncoderStrategy { public: explicit EncoderStrategy(const JlsParameters& info) : _qdecoder(0), _info(info), _processLine(0), valcurrent(0), bitpos(0), _isFFWritten(false), _bytesWritten(0) { } virtual ~EncoderStrategy() { } LONG PeekByte(); void OnLineBegin(LONG cpixel, void* ptypeBuffer, LONG pixelStride) { _processLine->NewLineRequested(ptypeBuffer, cpixel, pixelStride); } void OnLineEnd(LONG /*cpixel*/, void* /*ptypeBuffer*/, LONG /*pixelStride*/) { } virtual void SetPresets(const JlsCustomParameters& presets) = 0; virtual size_t EncodeScan(const void* pvoid, void* pvoidOut, size_t byteCount, void* pvoidCompare) = 0; protected: void Init(BYTE* compressedBytes, size_t byteCount) { bitpos = 32; valcurrent = 0; _position = compressedBytes; _compressedLength = byteCount; } void AppendToBitStream(LONG value, LONG length) { ASSERT(length < 32 && length >= 0); ASSERT((_qdecoder.get() == NULL) || (length == 0 && value == 0) ||( _qdecoder->ReadLongValue(length) == value)); #ifndef NDEBUG if (length < 32) { int mask = (1 << (length)) - 1; ASSERT((value | mask) == mask); } #endif bitpos -= length; if (bitpos >= 0) { valcurrent = valcurrent | (value << bitpos); return; } valcurrent |= value >> -bitpos; Flush(); ASSERT(bitpos >=0); valcurrent |= value << bitpos; } void EndScan() { Flush(); // if a 0xff was written, Flush() will force one unset bit anyway if (_isFFWritten) AppendToBitStream(0, (bitpos - 1) % 8); else AppendToBitStream(0, bitpos % 8); Flush(); ASSERT(bitpos == 0x20); } void Flush() { for (LONG i = 0; i < 4; ++i) { if (bitpos >= 32) break; if (_isFFWritten) { // insert highmost bit *_position = BYTE(valcurrent >> 25); valcurrent = valcurrent << 7; bitpos += 7; _isFFWritten = false; } else { *_position = BYTE(valcurrent >> 24); valcurrent = valcurrent << 8; bitpos += 8; _isFFWritten = *_position == 0xFF; } _position++; _compressedLength--; _bytesWritten++; } } size_t GetLength() { return _bytesWritten - (bitpos -32)/8; } inlinehint void AppendOnesToBitStream(LONG length) { AppendToBitStream((1 << length) - 1, length); } std::auto_ptr _qdecoder; protected: JlsParameters _info; std::auto_ptr _processLine; private: unsigned int valcurrent; LONG bitpos; size_t _compressedLength; // encoding BYTE* _position; bool _isFFWritten; size_t _bytesWritten; }; #endif charls-1.0/CMakeLists.txt0000644000265600020320000000164311556213767014533 0ustar tilleaadminproject(charls) cmake_minimum_required(VERSION 2.6) # When user specify build type do not override settings: IF(NOT CMAKE_BUILD_TYPE) # The following compiler option are only meant for GCC: IF(CMAKE_COMPILER_IS_GNUCC) # the following is optimization micrmanagement that made better code for x86 # SET(CMAKE_CXX_FLAGS "-D NDEBUG -O3 -Wall -Wextra -pedantic -fvisibility=hidden -fomit-frame-pointer -momit-leaf-frame-pointer -fweb -ftracer" ) SET(CMAKE_CXX_FLAGS "-D NDEBUG -O3" ) ENDIF(CMAKE_COMPILER_IS_GNUCC) ENDIF(NOT CMAKE_BUILD_TYPE) OPTION(charls_BUILD_SHARED_LIBS "Build CharLS with shared libraries." OFF) SET(BUILD_SHARED_LIBS ${charls_BUILD_SHARED_LIBS}) add_library(CharLS header.cpp interface.cpp jpegls.cpp ) add_executable(charlstest test/main.cpp test/time.cpp test/util.cpp test/bitstreamdamage.cpp test/compliance.cpp test/performance.cpp test/dicomsamples.cpp) target_link_libraries (charlstest CharLS) charls-1.0/jpegls.cpp0000644000265600020320000001077511556213767013771 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #include "config.h" #include "util.h" #include "streams.h" #include "header.h" #include #include #include #include #include "decoderstrategy.h" #include "encoderstrategy.h" #include "context.h" #include "contextrunmode.h" #include "lookuptable.h" signed char* JlsContext::_tableC = CreateTableC(); // As defined in the JPEG-LS standard // used to determine how large runs should be encoded at a time. const int J[32] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15}; #include "losslesstraits.h" #include "defaulttraits.h" #include "scan.h" signed char QuantizeGratientOrg(const JlsCustomParameters& preset, LONG NEAR, LONG Di) { if (Di <= -preset.T3) return -4; if (Di <= -preset.T2) return -3; if (Di <= -preset.T1) return -2; if (Di < -NEAR) return -1; if (Di <= NEAR) return 0; if (Di < preset.T1) return 1; if (Di < preset.T2) return 2; if (Di < preset.T3) return 3; return 4; } std::vector CreateQLutLossless(LONG cbit) { JlsCustomParameters preset = ComputeDefault((1 << cbit) - 1, 0); LONG range = preset.MAXVAL + 1; std::vector lut(range * 2); for (LONG diff = -range; diff < range; diff++) { lut[range + diff] = QuantizeGratientOrg(preset, 0,diff); } return lut; } // Lookup tables to replace code with lookup tables. // To avoid threading issues, all tables are created when the program is loaded. // Lookup table: decode symbols that are smaller or equal to 8 bit (16 tables for each value of k) CTable decodingTables[16] = { InitTable(0), InitTable(1), InitTable(2), InitTable(3), InitTable(4), InitTable(5), InitTable(6), InitTable(7), InitTable(8), InitTable(9), InitTable(10), InitTable(11), InitTable(12), InitTable(13), InitTable(14),InitTable(15) }; // Lookup tables: sample differences to bin indexes. std::vector rgquant8Ll = CreateQLutLossless(8); std::vector rgquant10Ll = CreateQLutLossless(10); std::vector rgquant12Ll = CreateQLutLossless(12); std::vector rgquant16Ll = CreateQLutLossless(16); template std::auto_ptr JlsCodecFactory::GetCodec(const JlsParameters& info, const JlsCustomParameters& presets) { STRATEGY* pstrategy = NULL; if (presets.RESET != 0 && presets.RESET != BASIC_RESET) { DefaultTraitsT traits((1 << info.bitspersample) - 1, info.allowedlossyerror); traits.MAXVAL = presets.MAXVAL; traits.RESET = presets.RESET; pstrategy = new JlsCodec, STRATEGY>(traits, info); } else { pstrategy = GetCodecImpl(info); } if (pstrategy != NULL) { pstrategy->SetPresets(presets); } return std::auto_ptr(pstrategy); } template STRATEGY* CreateCodec(const TRAITS& t, const STRATEGY*,const JlsParameters& info) { return new JlsCodec(t, info); } template STRATEGY* JlsCodecFactory::GetCodecImpl(const JlsParameters& info) { STRATEGY* s = 0; if (info.ilv == ILV_SAMPLE && info.components != 3) return NULL; #ifndef DISABLE_SPECIALIZATIONS // optimized lossless versions common formats if (info.allowedlossyerror == 0) { if (info.ilv == ILV_SAMPLE) { if (info.bitspersample == 8) return CreateCodec(LosslessTraitsT,8>(), s, info); } else { switch (info.bitspersample) { case 8: return CreateCodec(LosslessTraitsT(), s, info); case 12: return CreateCodec(LosslessTraitsT(), s, info); case 16: return CreateCodec(LosslessTraitsT(), s, info); } } } #endif int maxval = (1 << info.bitspersample) - 1; if (info.bitspersample <= 8) { if (info.ilv == ILV_SAMPLE) return CreateCodec(DefaultTraitsT >(maxval, info.allowedlossyerror), s, info); return CreateCodec(DefaultTraitsT((1 << info.bitspersample) - 1, info.allowedlossyerror), s, info); } else if (info.bitspersample <= 16) { if (info.ilv == ILV_SAMPLE) return CreateCodec(DefaultTraitsT >(maxval, info.allowedlossyerror), s, info); return CreateCodec(DefaultTraitsT(maxval, info.allowedlossyerror), s, info); } return NULL; } template class JlsCodecFactory; template class JlsCodecFactory; charls-1.0/stdafx.cpp0000644000265600020320000000000011556213767013752 0ustar tilleaadmincharls-1.0/context.h0000644000265600020320000000332411556213767013626 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_CONTEXT #define CHARLS_CONTEXT // // JlsContext: a JPEG-LS context with it's current statistics. // struct JlsContext { public: JlsContext() {} JlsContext(LONG a) : A(a), B(0), C(0), N(1) { } LONG A; LONG B; short C; short N; inlinehint LONG GetErrorCorrection(LONG k) const { if (k != 0) return 0; return BitWiseSign(2 * B + N - 1); } inlinehint void UpdateVariables(LONG errorValue, LONG NEAR, LONG NRESET) { ASSERT(N != 0); // For performance work on copies of A,B,N (compiler will use registers). int b = B + errorValue * (2 * NEAR + 1); int a = A + abs(errorValue); int n = N; ASSERT(a < 65536 * 256); ASSERT(abs(b) < 65536 * 256); if (n == NRESET) { a = a >> 1; b = b >> 1; n = n >> 1; } n = n + 1; if (b + n <= 0) { b = b + n; if (b <= -n) { b = -n + 1; } C = _tableC[C - 1]; } else if (b > 0) { b = b - n; if (b > 0) { b = 0; } C = _tableC[C + 1]; } A = a; B = b; N = (short)n; ASSERT(N != 0); } inlinehint LONG GetGolomb() const { LONG Ntest = N; LONG Atest = A; LONG k = 0; for(; (Ntest << k) < Atest; k++) { ASSERT(k <= 32); }; return k; } static signed char* CreateTableC() { static std::vector rgtableC; rgtableC.reserve(256 + 2); rgtableC.push_back(-128); for (int i = -128; i < 128; i++) { rgtableC.push_back(char(i)); } rgtableC.push_back(127); signed char* pZero = &rgtableC[128 + 1]; ASSERT(pZero[0] == 0); return pZero; } private: static signed char* _tableC; }; #endif charls-1.0/colortransform.h0000644000265600020320000001006311556213767015212 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_COLORTRANSFORM #define CHARLS_COLORTRANSFORM // // This file defines simple classes that define (lossless) color transforms. // They are invoked in processline.h to convert between decoded values and the internal line buffers. // Color transforms work best for computer generated images. // template struct TransformNoneImpl { typedef sample SAMPLE; inlinehint Triplet operator() (int v1, int v2, int v3) { return Triplet(v1, v2, v3); } }; template struct TransformNone : public TransformNoneImpl { typedef struct TransformNoneImpl INVERSE; }; template struct TransformHp1 { enum { RANGE = 1 << sizeof(sample)*8 }; typedef sample SAMPLE; struct INVERSE { INVERSE(const TransformHp1&) {}; inlinehint Triplet operator() (int v1, int v2, int v3) { return Triplet(v1 + v2 - RANGE/2, v2, v3 + v2 - RANGE/2); } }; inlinehint Triplet operator() (int R, int G, int B) { Triplet hp1; hp1.v2 = SAMPLE(G); hp1.v1 = SAMPLE(R - G + RANGE/2); hp1.v3 = SAMPLE(B - G + RANGE/2); return hp1; } }; template struct TransformHp2 { enum { RANGE = 1 << sizeof(sample)*8 }; typedef sample SAMPLE; struct INVERSE { INVERSE(const TransformHp2&) {}; inlinehint Triplet operator() (int v1, int v2, int v3) { Triplet rgb; rgb.R = SAMPLE(v1 + v2 - RANGE/2); // new R rgb.G = SAMPLE(v2); // new G rgb.B = SAMPLE(v3 + ((rgb.R + rgb.G) >> 1) - RANGE/2); // new B return rgb; } }; inlinehint Triplet operator() (int R, int G, int B) { return Triplet(R - G + RANGE/2, G, B - ((R+G )>>1) - RANGE/2); } }; template struct TransformHp3 { enum { RANGE = 1 << sizeof(sample)*8 }; typedef sample SAMPLE; struct INVERSE { INVERSE(const TransformHp3&) {}; inlinehint Triplet operator() (int v1, int v2, int v3) { int G = v1 - ((v3 + v2)>>2) + RANGE/4; Triplet rgb; rgb.R = SAMPLE(v3 + G - RANGE/2); // new R rgb.G = SAMPLE(G); // new G rgb.B = SAMPLE(v2 + G - RANGE/2); // new B return rgb; } }; inlinehint Triplet operator() (int R, int G, int B) { Triplet hp3; hp3.v2 = SAMPLE(B - G + RANGE/2); hp3.v3 = SAMPLE(R - G + RANGE/2); hp3.v1 = SAMPLE(G + ((hp3.v2 + hp3.v3)>>2)) - RANGE/4; return hp3; } }; // Transform class that shifts bits towards the high bit when bitcount is not 8 or 16 // needed to make the HP color transforms work correctly. template struct TransformShifted { typedef typename TRANSFORM::SAMPLE SAMPLE; struct INVERSE { INVERSE(const TransformShifted& transform) : _shift(transform._shift), _inverseTransform(transform._colortransform) {} inlinehint Triplet operator() (int v1, int v2, int v3) { Triplet result = _inverseTransform(v1 << _shift, v2 << _shift, v3 << _shift); return Triplet(result.R >> _shift, result.G >> _shift, result.B >> _shift); } inlinehint Quad operator() (int v1, int v2, int v3, int v4) { Triplet result = _inverseTransform(v1 << _shift, v2 << _shift, v3 << _shift); return Quad(result.R >> _shift, result.G >> _shift, result.B >> _shift, v4); } int _shift; typename TRANSFORM::INVERSE _inverseTransform; }; TransformShifted(int shift) : _shift(shift) { } inlinehint Triplet operator() (int R, int G, int B) { Triplet result = _colortransform(R << _shift, G << _shift, B << _shift); return Triplet(result.R >> _shift, result.G >> _shift, result.B >> _shift); } inlinehint Quad operator() (int R, int G, int B, int A) { Triplet result = _colortransform(R << _shift, G << _shift, B << _shift); return Quad(result.R >> _shift, result.G >> _shift, result.B >> _shift, A); } int _shift; TRANSFORM _colortransform; }; #endif charls-1.0/CharLS.vcproj0000644000265600020320000002710311464353322014321 0ustar tilleaadmin charls-1.0/util.h0000644000265600020320000000422611556213767013121 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_UTIL #define CHARLS_UTIL #include #include #include "publictypes.h" #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif inline LONG log_2(LONG n) { LONG x = 0; while (n > (LONG(1) << x)) { ++x; } return x; } struct Size { Size(LONG width, LONG height) : cx(width), cy(height) {} LONG cx; LONG cy; }; inline LONG Sign(LONG n) { return (n >> (LONG_BITCOUNT-1)) | 1;} inline LONG BitWiseSign(LONG i) { return i >> (LONG_BITCOUNT-1); } template struct Triplet { Triplet() : v1(0), v2(0), v3(0) {} Triplet(LONG x1, LONG x2, LONG x3) : v1((SAMPLE)x1), v2((SAMPLE)x2), v3((SAMPLE)x3) {} union { SAMPLE v1; SAMPLE R; }; union { SAMPLE v2; SAMPLE G; }; union { SAMPLE v3; SAMPLE B; }; }; inline bool operator==(const Triplet& lhs, const Triplet& rhs) { return lhs.v1 == rhs.v1 && lhs.v2 == rhs.v2 && lhs.v3 == rhs.v3; } inline bool operator!=(const Triplet& lhs, const Triplet& rhs) { return !(lhs == rhs); } template struct Quad : public Triplet { Quad() : v4(0) {} Quad(Triplet triplet, LONG alpha) : Triplet(triplet), A((sample)alpha) {} union { sample v4; sample A; }; }; template struct FromBigEndian { }; template <> struct FromBigEndian<4> { inlinehint static unsigned int Read(BYTE* pbyte) { return (pbyte[0] << 24) + (pbyte[1] << 16) + (pbyte[2] << 8) + (pbyte[3] << 0); } }; template <> struct FromBigEndian<8> { inlinehint static uint64_t Read(BYTE* pbyte) { return (uint64_t(pbyte[0]) << 56) + (uint64_t(pbyte[1]) << 48) + (uint64_t(pbyte[2]) << 40) + (uint64_t(pbyte[3]) << 32) + (uint64_t(pbyte[4]) << 24) + (uint64_t(pbyte[5]) << 16) + (uint64_t(pbyte[6]) << 8) + (uint64_t(pbyte[7]) << 0); } }; class JlsException { public: JlsException(JLS_ERROR error) : _error(error) { } JLS_ERROR _error; }; #endif charls-1.0/decoderstrategy.h0000644000265600020320000001233711556213767015336 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_DECODERSTATEGY #define CHARLS_DECODERSTATEGY #include "streams.h" #include "processline.h" #include "config.h" #include "util.h" // Implements encoding to stream of bits. In encoding mode JpegLsCodec inherits from EncoderStrategy class DecoderStrategy { public: DecoderStrategy(const JlsParameters& info) : _info(info), _processLine(0), _readCache(0), _validBits(0), _position(0) { } virtual ~DecoderStrategy() { } virtual void SetPresets(const JlsCustomParameters& presets) = 0; virtual size_t DecodeScan(void* outputData, const JlsRect& size, const void* compressedData, size_t byteCount, bool bCheck) = 0; void Init(BYTE* compressedBytes, size_t byteCount) { _validBits = 0; _readCache = 0; _position = compressedBytes; _endPosition = compressedBytes + byteCount; _nextFFPosition = FindNextFF(); MakeValid(); } inlinehint void Skip(LONG length) { _validBits -= length; _readCache = _readCache << length; } void OnLineBegin(LONG /*cpixel*/, void* /*ptypeBuffer*/, LONG /*pixelStride*/) {} void OnLineEnd(LONG pixelCount, const void* ptypeBuffer, LONG pixelStride) { _processLine->NewLineDecoded(ptypeBuffer, pixelCount, pixelStride); } void EndScan() { if ((*_position) != 0xFF) { ReadBit(); if ((*_position) != 0xFF) throw JlsException(TooMuchCompressedData); } if (_readCache != 0) throw JlsException(TooMuchCompressedData); } inlinehint bool OptimizedRead() { // Easy & fast: if there is no 0xFF byte in sight, we can read without bitstuffing if (_position < _nextFFPosition - (sizeof(bufType)-1)) { _readCache |= FromBigEndian::Read(_position) >> _validBits; int bytesToRead = (bufferbits - _validBits) >> 3; _position += bytesToRead; _validBits += bytesToRead * 8; ASSERT(_validBits >= bufferbits - 8); return true; } return false; } typedef size_t bufType; enum { bufferbits = sizeof( bufType ) * 8 }; void MakeValid() { ASSERT(_validBits <=bufferbits - 8); if (OptimizedRead()) return; do { if (_position >= _endPosition) { if (_validBits <= 0) throw JlsException(InvalidCompressedData); return; } bufType valnew = _position[0]; if (valnew == 0xFF) { // JPEG bitstream rule: no FF may be followed by 0x80 or higher if (_position == _endPosition - 1 || (_position[1] & 0x80) != 0) { if (_validBits <= 0) throw JlsException(InvalidCompressedData); return; } } _readCache |= valnew << (bufferbits - 8 - _validBits); _position += 1; _validBits += 8; if (valnew == 0xFF) { _validBits--; } } while (_validBits < bufferbits - 8); _nextFFPosition = FindNextFF(); return; } BYTE* FindNextFF() { BYTE* pbyteNextFF = _position; while (pbyteNextFF < _endPosition) { if (*pbyteNextFF == 0xFF) { break; } pbyteNextFF++; } return pbyteNextFF; } BYTE* GetCurBytePos() const { LONG validBits = _validBits; BYTE* compressedBytes = _position; for (;;) { LONG cbitLast = compressedBytes[-1] == 0xFF ? 7 : 8; if (validBits < cbitLast ) return compressedBytes; validBits -= cbitLast; compressedBytes--; } } inlinehint LONG ReadValue(LONG length) { if (_validBits < length) { MakeValid(); if (_validBits < length) throw JlsException(InvalidCompressedData); } ASSERT(length != 0 && length <= _validBits); ASSERT(length < 32); LONG result = LONG(_readCache >> (bufferbits - length)); Skip(length); return result; } inlinehint LONG PeekByte() { if (_validBits < 8) { MakeValid(); } return _readCache >> (bufferbits - 8); } inlinehint bool ReadBit() { if (_validBits <= 0) { MakeValid(); } bool bSet = (_readCache & (bufType(1) << (bufferbits - 1))) != 0; Skip(1); return bSet; } inlinehint LONG Peek0Bits() { if (_validBits < 16) { MakeValid(); } bufType valTest = _readCache; for (LONG count = 0; count < 16; count++) { if ((valTest & (bufType(1) << (bufferbits - 1))) != 0) return count; valTest <<= 1; } return -1; } inlinehint LONG ReadHighbits() { LONG count = Peek0Bits(); if (count >= 0) { Skip(count + 1); return count; } Skip(15); for (LONG highbits = 15; ; highbits++) { if (ReadBit()) return highbits; } } LONG ReadLongValue(LONG length) { if (length <= 24) return ReadValue(length); return (ReadValue(length - 24) << 24) + ReadValue(24); } protected: JlsParameters _info; std::auto_ptr _processLine; private: // decoding bufType _readCache; LONG _validBits; BYTE* _position; BYTE* _nextFFPosition; BYTE* _endPosition; }; #endif charls-1.0/charls.def0000644000265600020320000000021311464353322013705 0ustar tilleaadminLIBRARY "CharLS" EXPORTS JpegLsEncode JpegLsDecode JpegLsDecodeRect JpegLsReadHeader JpegLsVerifyEncodecharls-1.0/config.h0000644000265600020320000000240411556213767013405 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_CONFIG #define CHARLS_CONFIG #ifdef NDEBUG # ifndef ASSERT # define ASSERT(t) { } # define assert(t) { } # endif #else #include #define ASSERT(t) assert(t) #endif #if defined(_WIN32) #ifdef _MSC_VER #pragma warning (disable:4512) #endif #endif #ifdef __GNUC__ #include #else typedef long long int64_t; typedef unsigned long long uint64_t; #endif // Typedef used by Charls for the default integral type. // charls will work correctly with 64 or 32 bit. typedef long LONG; enum constants { LONG_BITCOUNT = sizeof(LONG)*8 }; typedef unsigned char BYTE; typedef unsigned short USHORT; #undef NEAR #ifndef inlinehint # ifdef _MSC_VER # ifdef NDEBUG # define inlinehint __forceinline # else # define inlinehint # endif # elif defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0) # define inlinehint inline # else # define inlinehint inline # endif #endif #if defined(i386) || defined(__i386__) || defined(_M_IX86) || defined(__amd64__) || defined(_M_X64) #define ARCH_HAS_UNALIGNED_MEM_ACCESS /* TODO define this symbol for more architectures */ #endif #endif charls-1.0/defaulttraits.h0000644000265600020320000000506611556213767015022 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_DEFAULTTRAITS #define CHARLS_DEFAULTTRAITS // Default traits that support all JPEG LS parameters: custom limit, near, maxval (not power of 2) // This traits class is used to initialize a coder/decoder. // The coder/decoder also delegates some functions to the traits class. // This is to allow the traits class to replace the default implementation here with optimized specific implementations. // This is done for lossless coding/decoding: see losslesstraits.h template struct DefaultTraitsT { public: typedef sample SAMPLE; typedef pixel PIXEL; LONG MAXVAL; LONG RANGE; LONG NEAR; LONG qbpp; LONG bpp; LONG LIMIT; LONG RESET; DefaultTraitsT(const DefaultTraitsT& src) : MAXVAL(src.MAXVAL), RANGE(src.RANGE), NEAR(src.NEAR), qbpp(src.qbpp), bpp(src.bpp), LIMIT(src.LIMIT), RESET(src.RESET) { } DefaultTraitsT(LONG max, LONG jls_near) { NEAR = jls_near; MAXVAL = max; RANGE = (MAXVAL + 2 * NEAR )/(2 * NEAR + 1) + 1; bpp = log_2(max); LIMIT = 2 * (bpp + MAX(8,bpp)); qbpp = log_2(RANGE); RESET = BASIC_RESET; } inlinehint LONG ComputeErrVal(LONG e) const { LONG q = Quantize(e); return ModRange(q); } inlinehint SAMPLE ComputeReconstructedSample(LONG Px, LONG ErrVal) { return FixReconstructedValue(Px + DeQuantize(ErrVal)); } inlinehint bool IsNear(LONG lhs, LONG rhs) const { return abs(lhs-rhs) <=NEAR; } bool IsNear(Triplet lhs, Triplet rhs) const { return abs(lhs.v1-rhs.v1) <=NEAR && abs(lhs.v2-rhs.v2) <=NEAR && abs(lhs.v3-rhs.v3) <=NEAR; } inlinehint LONG CorrectPrediction(LONG Pxc) const { if ((Pxc & MAXVAL) == Pxc) return Pxc; return (~(Pxc >> (LONG_BITCOUNT-1))) & MAXVAL; } inlinehint LONG ModRange(LONG Errval) const { ASSERT(abs(Errval) <= RANGE); if (Errval < 0) Errval = Errval + RANGE; if (Errval >= ((RANGE + 1) / 2)) Errval = Errval - RANGE; ASSERT(abs(Errval) <= RANGE/2); return Errval; } private: LONG Quantize(LONG Errval) const { if (Errval > 0) return (Errval + NEAR) / (2 * NEAR + 1); else return - (NEAR - Errval) / (2 * NEAR + 1); } inlinehint LONG DeQuantize(LONG Errval) const { return Errval * (2 * NEAR + 1); } inlinehint SAMPLE FixReconstructedValue(LONG val) const { if (val < -NEAR) val = val + RANGE*(2*NEAR+1); else if (val > MAXVAL + NEAR) val = val - RANGE*(2*NEAR+1); return SAMPLE(CorrectPrediction(val)); } }; #endif charls-1.0/License.txt0000644000265600020320000000273411556213767014120 0ustar tilleaadminCopyright (c) 2007-2010, Jan de Vaan All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of my employer, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. charls-1.0/processline.h0000644000265600020320000001462411556213767014475 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_PROCESSLINE #define CHARLS_PROCESSLINE #include "colortransform.h" // // This file defines the ProcessLine base class, its derivitives and helper functions. // During coding/decoding, CharLS process one line at a time. The different Processline implementations // convert the uncompressed format to and from the internal format for encoding. // Conversions include color transforms, line interleaved vs sample interleaved, masking out unused bits, // accounting for line padding etc. // This mechanism could be used to encode/decode images as they are received. // class ProcessLine { public: virtual ~ProcessLine() {} virtual void NewLineDecoded(const void* pSrc, int pixelCount, int bytesperline) = 0; virtual void NewLineRequested(void* pSrc, int pixelCount, int bytesperline) = 0; }; class PostProcesSingleComponent : public ProcessLine { public: PostProcesSingleComponent(void* pbyteOutput, const JlsParameters& info, int bytesPerPixel) : _pbyteOutput((BYTE*)pbyteOutput), _bytesPerPixel(bytesPerPixel), _bytesPerLine(info.bytesperline) { } void NewLineRequested(void* pDst, int pixelCount, int /*byteStride*/) { ::memcpy(pDst, _pbyteOutput, pixelCount * _bytesPerPixel); _pbyteOutput += _bytesPerLine; } void NewLineDecoded(const void* pSrc, int pixelCount, int /*byteStride*/) { ::memcpy(_pbyteOutput, pSrc, pixelCount * _bytesPerPixel); _pbyteOutput += _bytesPerLine; } private: BYTE* _pbyteOutput; int _bytesPerPixel; int _bytesPerLine; }; template void TransformLineToQuad(const SAMPLE* ptypeInput, LONG pixelStrideIn, Quad* pbyteBuffer, LONG pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); Quad* ptypeBuffer = (Quad*)pbyteBuffer; for (int x = 0; x < cpixel; ++x) { Quad pixel(transform(ptypeInput[x], ptypeInput[x + pixelStrideIn], ptypeInput[x + 2*pixelStrideIn]),ptypeInput[x + 3*pixelStrideIn]) ; ptypeBuffer[x] = pixel; } } template void TransformQuadToLine(const Quad* pbyteInput, LONG pixelStrideIn, SAMPLE* ptypeBuffer, LONG pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); const Quad* ptypeBufferIn = (Quad*)pbyteInput; for (int x = 0; x < cpixel; ++x) { Quad color = ptypeBufferIn[x]; Quad colorTranformed(transform(color.v1, color.v2, color.v3), color.v4); ptypeBuffer[x] = colorTranformed.v1; ptypeBuffer[x + pixelStride] = colorTranformed.v2; ptypeBuffer[x + 2 *pixelStride] = colorTranformed.v3; ptypeBuffer[x + 3 *pixelStride] = colorTranformed.v4; } } template void TransformRgbToBgr(SAMPLE* pDest, int samplesPerPixel, int pixelCount) { for (int i = 0; i < pixelCount; ++i) { std::swap(pDest[0], pDest[2]); pDest += samplesPerPixel; } } template void TransformLine(Triplet* pDest, const Triplet* pSrc, int pixelCount, TRANSFORM& transform) { for (int i = 0; i < pixelCount; ++i) { pDest[i] = transform(pSrc[i].v1, pSrc[i].v2, pSrc[i].v3); } } template void TransformLineToTriplet(const SAMPLE* ptypeInput, LONG pixelStrideIn, Triplet* pbyteBuffer, LONG pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); Triplet* ptypeBuffer = (Triplet*)pbyteBuffer; for (int x = 0; x < cpixel; ++x) { ptypeBuffer[x] = transform(ptypeInput[x], ptypeInput[x + pixelStrideIn], ptypeInput[x + 2*pixelStrideIn]); } } template void TransformTripletToLine(const Triplet* pbyteInput, LONG pixelStrideIn, SAMPLE* ptypeBuffer, LONG pixelStride, TRANSFORM& transform) { int cpixel = MIN(pixelStride, pixelStrideIn); const Triplet* ptypeBufferIn = (Triplet*)pbyteInput; for (int x = 0; x < cpixel; ++x) { Triplet color = ptypeBufferIn[x]; Triplet colorTranformed = transform(color.v1, color.v2, color.v3); ptypeBuffer[x] = colorTranformed.v1; ptypeBuffer[x + pixelStride] = colorTranformed.v2; ptypeBuffer[x + 2 *pixelStride] = colorTranformed.v3; } } template class ProcessTransformed : public ProcessLine { typedef typename TRANSFORM::SAMPLE SAMPLE; ProcessTransformed(const ProcessTransformed&) {} public: ProcessTransformed(void* pbyteOutput, const JlsParameters& info, TRANSFORM transform) : _pbyteOutput((BYTE*)pbyteOutput), _info(info), _templine(info.width * info.components), _transform(transform), _inverseTransform(transform) { // ASSERT(_info.components == sizeof(TRIPLET)/sizeof(TRIPLET::SAMPLE)); } void NewLineRequested(void* pDst, int pixelCount, int stride) { SAMPLE* pLine = (SAMPLE*)_pbyteOutput; if (_info.outputBgr) { pLine = &_templine[0]; memcpy(pLine, _pbyteOutput, sizeof(Triplet)*pixelCount); TransformRgbToBgr(pLine, _info.components, pixelCount); } if (_info.components == 3) { if (_info.ilv == ILV_SAMPLE) { TransformLine((Triplet*)pDst, (const Triplet*)pLine, pixelCount, _transform); } else { TransformTripletToLine((const Triplet*)pLine, pixelCount, (SAMPLE*)pDst, stride, _transform); } } else if (_info.components == 4 && _info.ilv == ILV_LINE) { TransformQuadToLine((const Quad*)pLine, pixelCount, (SAMPLE*)pDst, stride, _transform); } _pbyteOutput += _info.bytesperline; } void NewLineDecoded(const void* pSrc, int pixelCount, int byteStride) { if (_info.components == 3) { if (_info.ilv == ILV_SAMPLE) { TransformLine((Triplet*)_pbyteOutput, (const Triplet*)pSrc, pixelCount, _inverseTransform); } else { TransformLineToTriplet((const SAMPLE*)pSrc, byteStride, (Triplet*)_pbyteOutput, pixelCount, _inverseTransform); } } else if (_info.components == 4 && _info.ilv == ILV_LINE) { TransformLineToQuad((const SAMPLE*)pSrc, byteStride, (Quad*)_pbyteOutput, pixelCount, _inverseTransform); } if (_info.outputBgr) { TransformRgbToBgr(_pbyteOutput, _info.components, pixelCount); } _pbyteOutput += _info.bytesperline; } private: BYTE* _pbyteOutput; const JlsParameters& _info; std::vector _templine; TRANSFORM _transform; typename TRANSFORM::INVERSE _inverseTransform; }; #endif charls-1.0/contextrunmode.h0000644000265600020320000000313111556213767015214 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef CHARLS_CONTEXTRUNMODE #define CHARLS_CONTEXTRUNMODE // Implements statistical modelling for the run mode context. // Computes model dependent parameters like the golomb code lengths struct CContextRunMode { CContextRunMode(LONG a, LONG nRItype, LONG nReset) : A(a), N(1), Nn(0), _nRItype(nRItype), _nReset((BYTE)nReset) { } LONG A; BYTE N; BYTE Nn; LONG _nRItype; BYTE _nReset; CContextRunMode() {} inlinehint LONG GetGolomb() const { LONG Ntest = N; LONG TEMP = A + (N >> 1) * _nRItype; LONG k = 0; for(; Ntest < TEMP; k++) { Ntest <<= 1; ASSERT(k <= 32); }; return k; } void UpdateVariables(LONG Errval, LONG EMErrval) { if (Errval < 0) { Nn = Nn + 1; } A = A + ((EMErrval + 1 - _nRItype) >> 1); if (N == _nReset) { A = A >> 1; N = N >> 1; Nn = Nn >> 1; } N = N + 1; } inlinehint LONG ComputeErrVal(LONG temp, LONG k) { bool map = temp & 1; LONG errvalabs = (temp + map) / 2; if ((k != 0 || (2 * Nn >= N)) == map) { ASSERT(map == ComputeMap(-errvalabs, k)); return -errvalabs; } ASSERT(map == ComputeMap(errvalabs, k)); return errvalabs; } bool ComputeMap(LONG Errval, LONG k) const { if ((k == 0) && (Errval > 0) && (2 * Nn < N)) return 1; else if ((Errval < 0) && (2 * Nn >= N)) return 1; else if ((Errval < 0) && (k != 0)) return 1; return 0; } inlinehint LONG ComputeMapNegativeE(LONG k) const { return k != 0 || (2 * Nn >= N ); } }; #endif charls-1.0/interface.cpp0000644000265600020320000001150311556213767014433 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // //implement correct linkage for win32 dlls #if defined(_WIN32) #define CHARLS_IMEXPORT(returntype) __declspec(dllexport) returntype __stdcall #endif #include "config.h" #include "util.h" #include "interface.h" #include "header.h" JLS_ERROR CheckInput(const void* compressedData, size_t compressedLength, const void* uncompressedData, size_t uncompressedLength, const JlsParameters* pparams) { if (pparams == NULL) return InvalidJlsParameters; if (compressedLength == 0) return InvalidJlsParameters; if (compressedData == NULL) return InvalidJlsParameters; if (uncompressedData == NULL) return InvalidJlsParameters; if (pparams->width < 1 || pparams->width > 65535) return ParameterValueNotSupported; if (pparams->height < 1 || pparams->height > 65535) return ParameterValueNotSupported; int bytesperline = pparams->bytesperline < 0 ? -pparams->bytesperline : pparams->bytesperline; if (uncompressedLength < size_t(bytesperline * pparams->height)) return InvalidJlsParameters; return CheckParameterCoherent(pparams); } extern "C" { CHARLS_IMEXPORT(JLS_ERROR) JpegLsEncode(void* compressedData, size_t compressedLength, size_t* pcbyteWritten, const void* uncompressedData, size_t uncompressedLength, struct JlsParameters* pparams) { JlsParameters info = *pparams; if(info.bytesperline == 0) { info.bytesperline = info.width * ((info.bitspersample + 7)/8); if (info.ilv != ILV_NONE) { info.bytesperline *= info.components; } } JLS_ERROR parameterError = CheckInput(compressedData, compressedLength, uncompressedData, uncompressedLength, &info); if (parameterError != OK) return parameterError; if (pcbyteWritten == NULL) return InvalidJlsParameters; Size size = Size(info.width, info.height); JLSOutputStream stream; stream.Init(size, info.bitspersample, info.components); if (info.colorTransform != 0) { stream.AddColorTransform(info.colorTransform); } if (info.ilv == ILV_NONE) { LONG cbyteComp = size.cx*size.cy*((info.bitspersample +7)/8); for (LONG component = 0; component < info.components; ++component) { const BYTE* compareData = static_cast(uncompressedData) + component*cbyteComp; stream.AddScan(compareData, &info); } } else { stream.AddScan(uncompressedData, &info); } stream.Write((BYTE*)compressedData, compressedLength); *pcbyteWritten = stream.GetBytesWritten(); return OK; } CHARLS_IMEXPORT(JLS_ERROR) JpegLsDecode(void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength, JlsParameters* info) { JLSInputStream reader((BYTE*)compressedData, compressedLength); if(info != NULL) { reader.SetInfo(info); } try { reader.Read(uncompressedData, uncompressedLength); return OK; } catch (JlsException& e) { return e._error; } } CHARLS_IMEXPORT(JLS_ERROR) JpegLsDecodeRect(void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength, JlsRect roi, JlsParameters* info) { JLSInputStream reader((BYTE*)compressedData, compressedLength); if(info != NULL) { reader.SetInfo(info); } reader.SetRect(roi); try { reader.Read(uncompressedData, uncompressedLength); return OK; } catch (JlsException& e) { return e._error; } } CHARLS_IMEXPORT(JLS_ERROR) JpegLsVerifyEncode(const void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength) { JlsParameters info = JlsParameters(); JLS_ERROR error = JpegLsReadHeader(compressedData, compressedLength, &info); if (error != OK) return error; error = CheckInput(compressedData, compressedLength, uncompressedData, uncompressedLength, &info); if (error != OK) return error; Size size = Size(info.width, info.height); JLSOutputStream stream; stream.Init(size, info.bitspersample, info.components); if (info.ilv == ILV_NONE) { LONG cbyteComp = size.cx*size.cy*((info.bitspersample +7)/8); for (LONG component = 0; component < info.components; ++component) { const BYTE* compareData = static_cast(uncompressedData) + component*cbyteComp; stream.AddScan(compareData, &info); } } else { stream.AddScan(uncompressedData, &info); } std::vector rgbyteCompressed(compressedLength + 16); memcpy(&rgbyteCompressed[0], compressedData, compressedLength); stream.EnableCompare(true); stream.Write(&rgbyteCompressed[0], compressedLength); return OK; } CHARLS_IMEXPORT(JLS_ERROR) JpegLsReadHeader(const void* compressedData, size_t compressedLength, JlsParameters* pparams) { try { JLSInputStream reader((BYTE*)compressedData, compressedLength); reader.ReadHeader(); JlsParameters info = reader.GetMetadata(); *pparams = info; return OK; } catch (JlsException& e) { return e._error; } } } charls-1.0/interface.h0000644000265600020320000000261411556213767014103 0ustar tilleaadmin// // (C) Jan de Vaan 2007-2010, all rights reserved. See the accompanying "License.txt" for licensed use. // #ifndef JLS_INTERFACE #define JLS_INTERFACE #include "publictypes.h" #if defined(_WIN32) #ifndef CHARLS_IMEXPORT #define CHARLS_IMEXPORT(returntype) __declspec(dllimport) returntype __stdcall #endif #else #ifndef CHARLS_IMEXPORT #define CHARLS_IMEXPORT(returntype) returntype #endif #endif /* _WIN32 */ #ifdef __cplusplus extern "C" { #endif CHARLS_IMEXPORT(enum JLS_ERROR) JpegLsEncode(void* compressedData, size_t compressedLength, size_t* pcbyteWritten, const void* uncompressedData, size_t uncompressedLength, struct JlsParameters* pparams); CHARLS_IMEXPORT(enum JLS_ERROR) JpegLsDecode(void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength, struct JlsParameters* info); CHARLS_IMEXPORT(enum JLS_ERROR) JpegLsDecodeRect(void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength, struct JlsRect rect, struct JlsParameters* info); CHARLS_IMEXPORT(enum JLS_ERROR) JpegLsReadHeader(const void* compressedData, size_t compressedLength, struct JlsParameters* pparams); CHARLS_IMEXPORT(enum JLS_ERROR) JpegLsVerifyEncode(const void* uncompressedData, size_t uncompressedLength, const void* compressedData, size_t compressedLength); #ifdef __cplusplus } #endif #endif