27 #define PGFConsoleVersion "7.21.07" // Major number, Minor number: Year (2) Week (2) 28 #define CurrentYear "2021" 33 #define __PGFROISUPPORT__ // without ROI support the program code gets simpler and smaller 39 #include <sys/types.h> 45 #if defined(__linux__) || defined(__APPLE__) 50 #include <libpgf/PGFimage.h> 68 #elif defined __POSIX__ 69 #define __stat64 stat64 70 #define _stat64 stat64 81 "memory allocation was not successfull",
82 "invalid memory stream position",
85 "wrong data file format",
87 "error in zlib functions",
88 "errors related to color table size",
89 "errors in png functions",
90 "expected data cannot be read",
97 if (_stat64(filename, &data) != -1) {
106 #ifndef __PGFROISUPPORT__ 113 const int channels1 = image1.
GetChannels(); ASSERT(channels1 <= MaxChannels);
114 #pragma warning(disable: 4189) 115 const int channels2 = image2.
GetChannels(); ASSERT(channels2 <= MaxChannels);
116 ASSERT(channels1 == channels2);
119 const UINT32 size = w*h;
120 const int bypp1 = image1.
GetBPP()/8;
121 const int bypp2 = image2.
GetBPP()/8;
125 double sum[MaxChannels + 1] = { 0 };
127 int cnt1 = 0, cnt2 = 0, maxValue;
130 UINT8* rgbBuff1 = (UINT8 *)image1.
GetBits();
131 UINT8* rgbBuff2 = (UINT8 *)image2.
GetBits();
134 #ifdef __PGFROISUPPORT__ 138 rgbBuff1 += (image1.
GetHeight() - h - rect.top)*pitch1 + rect.left*channels1;
141 for (UINT32 j=0; j < h; j++) {
143 for (UINT32 i=0; i < w; i++) {
144 for (
int c=0; c < channels1; c++) {
145 tmp = rgbBuff2[cnt2 + c] - rgbBuff1[cnt1 + c]; sum[c] += tmp*tmp;
154 UINT16* rgbBuff1 = (UINT16 *)image1.
GetBits();
155 UINT16* rgbBuff2 = (UINT16 *)image2.
GetBits();
157 #ifdef __PNMEXSUPPORT__ 165 #ifdef __PGFROISUPPORT__ 169 rgbBuff1 += (image1.
GetHeight() - h - rect.top)*pitch1 + rect.left*channels1;
172 for (UINT32 j=0; j < h; j++) {
174 for (UINT32 i=0; i < w; i++) {
175 for (
int c=0; c < channels1; c++) {
176 tmp = rgbBuff2[cnt2 + c] - rgbBuff1[cnt1 + c]; sum[c] += tmp*tmp;
188 for (
int c=0; c < channels1; c++) {
189 sum[MaxChannels] += sum[c];
194 cout << 10*log10(
double(maxValue)*maxValue*size*channels1/sum[MaxChannels]);
196 for (
int c=0; c < channels1; c++) {
197 cout <<
';' << 10*log10(
double(maxValue)*maxValue*size/sum[c]);
202 if (sum[MaxChannels] == 0) {
203 cout <<
"PSNR: lossless" << endl;
205 cout <<
"PSNR: " << 10*log10(
double(maxValue)*maxValue*size*channels1/sum[MaxChannels]) <<
" (";
206 for (
int c=0; c < channels1; c++) {
207 cout <<
'c' << c <<
": " << 10*log10(
double(maxValue)*maxValue*size/sum[c]);
209 if (c < channels1 - 1) cout <<
", ";
218 static bool Encoding(
CImage*& image,
char *source,
char *dest,
int levels,
int quality,
bool roi,
bool streaming, CPGFMemoryStream** memStream) {
219 #ifndef __PGFROISUPPORT__ 224 ASSERT(0 <= quality && quality <= MaxQuality);
225 bool returnValue =
true;
228 clock_t start = 0, mean = 0, end = 0;
229 UINT32 writtenBytes = 0;
230 CPGFStream *stream =
nullptr;
234 #elif defined(__POSIX__) 242 fd = CreateFile(dest, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
243 if (fd == INVALID_HANDLE_VALUE) {
244 cerr <<
"Error: Could not open destination file." << endl;
251 stream =
new CPGFFileStream(fd);
253 #elif defined(__POSIX__) 254 fd = open(dest, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
256 cout <<
"Error: Could not open destination file." << endl;
263 stream =
new CPGFFileStream(fd);
268 if (!
bQuiet) cout <<
"Encoding PGF image to memory stream (quality: " << quality <<
", levels: " << levels <<
"): " << source << endl;
270 if (!
bQuiet) cout <<
"Encoding PGF image (quality: " << quality <<
", levels: " << levels <<
"): " << source << endl;
272 if (roi || streaming) {
274 cout <<
"PGF image will support ROI." << endl;
276 cout << dest <<
" will support ROI." << endl;
287 if (!image->
Load(source)) {
290 FORMAT_MESSAGE_ALLOCATE_BUFFER |
291 FORMAT_MESSAGE_FROM_SYSTEM |
292 FORMAT_MESSAGE_IGNORE_INSERTS,
295 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
300 cerr <<
"Error: " << lpMsgBuf << endl;
305 #elif defined(__POSIX__) 306 if (!image->
Load(source) ){
307 cerr <<
"Error: Could not load source file." << endl;
315 if ((bpp < 1) || (bpp > 48) || (bpp == 4)) {
316 cerr <<
"Error: Unhandled image format." << endl;
321 ASSERT((bpp >= 1) && (bpp <= 48) && (bpp != 4));
331 pgf.ConfigureEncoder(
true,
false);
335 header.nLevels = (UINT8)levels;
336 header.quality = (UINT8)quality;
338 header.bpp = header.channels = 0;
339 header.usedBitsPerChannel = 0;
343 pgf.SetHeader(header, (roi || streaming) ? PGFROI : 0);
345 char data[] =
"This is a free text annotation.";
346 pgf.SetHeader(header, (roi || streaming) ? PGFROI : 0, (UINT8 *)data,
sizeof(data));
349 #ifdef __PNMEXSUPPORT__ 357 UINT8* buff = (UINT8 *)image->
GetBits();
359 int map[] = { 2, 1, 0 };
362 #ifdef __BIG_ENDIAN__ 363 int map[] = { 2, 1, 0 };
373 RGBQUAD* pColorTable =
new RGBQUAD[colorTableSize];
376 pgf.SetColorTable(0, colorTableSize, pColorTable);
377 delete[] pColorTable;
380 }
catch(IOException& e) {
383 if (err >= AppError) {
384 cerr <<
"Error: Importing input image failed\n(" <<
PGFErrors[err - AppError] <<
")!" << endl;
386 cerr <<
"Error: Importing input image failed (" << err <<
")!" << endl;
393 #ifdef __PGFROISUPPORT__ 396 writtenBytes = pgf.WriteHeader(stream);
397 if (!
bQuiet) cout <<
"Write header [" << writtenBytes <<
" bytes]" << endl;
399 for(
int i = pgf.Levels() - 1; i >= 0; i--) {
400 UINT32 size = pgf.Write(i);
401 if (!
bQuiet) cout <<
"Write level " << i <<
" [" << size <<
" bytes]" << endl;
402 writtenBytes += size;
405 #endif __PGFROISUPPORT__ 408 pgf.Write(stream, &writtenBytes);
411 }
catch(IOException& e) {
413 if (err >= AppError) {
414 cerr <<
"Error: Writing PGF image failed\n(" <<
PGFErrors[err - AppError] <<
")!" << endl;
416 cerr <<
"Error: Writing PGF image failed (" << err <<
")!" << endl;
427 pgf.ResetStreamPos(
false);
431 if (fd) CloseHandle(fd);
432 #elif defined(__POSIX__) 440 double destSize = (memStream) ? writtenBytes :
double(
FileSize(dest));
441 double ratio = double(
FileSize(source))/destSize;
444 cout << double(end - mean)/CLOCKS_PER_SEC <<
';' << double(end - start)/CLOCKS_PER_SEC <<
';' << ratio <<
';';
446 cout <<
"Written bytes: " << writtenBytes << endl;
447 cout <<
"Encoding time (encoding, writing PGF): " << double(end - mean)/CLOCKS_PER_SEC <<
" s" << endl;
448 cout <<
"Total time (reading source, encoding, writing PGF): " << double(end - start)/CLOCKS_PER_SEC <<
" s" << endl;
449 cout <<
"Compression ratio: " << ratio << endl;
458 static bool Decoding(
CImage*& image,
char *source,
char *dest,
int level,
bool roi, PGFRect& rect,
bool streaming, CPGFMemoryStream** memStream) {
459 #ifndef __PGFROISUPPORT__ 465 bool returnValue =
true;
467 clock_t start = 0, mean = 0, mean2 = 0, mean3 = 0, end = 0;
468 CPGFStream *stream =
nullptr;
469 UINT8* buff =
nullptr;
470 double sourceSize = 0;
473 #elif defined(__POSIX__) 484 fd = CreateFile(source, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
485 if (fd == INVALID_HANDLE_VALUE) {
486 cerr <<
"Error: Could not open source file." << endl;
493 stream =
new CPGFFileStream(fd);
495 #elif defined(__POSIX__) 496 fd = open(source, O_RDONLY);
498 cout <<
"Error: Could not open source file." << endl;
505 stream =
new CPGFFileStream(fd);
510 pgf.ConfigureDecoder(
true);
513 if (!
bQuiet) cout <<
"Decoding PGF image from memory stream." << endl;
515 if (!
bQuiet) cout <<
"Decoding PGF image: " << source << endl;
521 UINT64 startpos = stream->GetPos();
523 if (!
bQuiet) cout <<
"Read header and level info [" << stream->GetPos() - startpos <<
" bytes]" << endl;
528 const UINT8 *data = pgf.GetUserData(len);
530 cout << (
char *)data << endl;
535 #ifdef __PGFROISUPPORT__ 536 if (pgf.ROIisSupported()) {
538 if (!
bQuiet) cout <<
"PGF image supports ROI." << endl;
540 if (!
bQuiet) cout << source <<
" supports ROI." << endl;
542 if (!
bQuiet && roi) cout <<
"Decode ROI (" << rect.left <<
"," << rect.top <<
"," << rect.Width() <<
"," << rect.Height() <<
")"<< endl;
545 pgf.Read(rect, level);
549 for (
int i = pgf.Levels() - 1; i >= 0; i--) {
550 if (!
bQuiet) cout <<
"Read level " << i;
551 UINT64 pos = stream->GetPos();
553 if (!
bQuiet) cout <<
" [" << stream->GetPos() - pos <<
" bytes]" << endl;
558 cout <<
"PGF Console: ROI supports has been disabled." << endl;
560 if (!roi && !streaming) {
563 sourceSize = double(stream->GetPos() - startpos);
565 }
catch(IOException& e) {
567 if (err >= AppError) {
568 cerr <<
"Error: Opening and reading PGF image failed\n(" <<
PGFErrors[err - AppError] <<
")!" << endl;
570 cerr <<
"Error: Opening and reading PGF image failed (" << err <<
")!" << endl;
580 #ifdef __PGFROISUPPORT__ 582 const PGFRect r = pgf.ComputeLevelROI();
583 if (!image->
Create(r.Width(), r.Height(), pgf.Mode())) {
584 cerr <<
"Decoding is not supported for this PGF color format." << endl;
591 if (!image->
Create(pgf.Width(level), pgf.Height(level), pgf.Mode())) {
592 cerr <<
"Decoding is not supported for this PGF color format." << endl;
600 buff = (UINT8 *)image->
GetBits();
602 int map[] = { 2, 1, 0 };
605 #ifdef __BIG_ENDIAN__ 606 int map[] = { 2, 1, 0 };
616 image->
SetColorTable(0, 1 << pgf.BPP(), pgf.GetColorTable());
620 bw[0].rgbGreen = 255;
630 #ifdef __PNMEXSUPPORT__ 638 if (image->
Save(dest)) {
639 if (!
bQuiet) cout <<
"Written image file: " << dest << endl;
641 cerr <<
"Error: Output format not supported for this color depth." << endl;
657 stream->SetPos(FSFromStart, 0);
661 if (fd) CloseHandle(fd);
662 #elif defined(__POSIX__) 670 sourceSize = (double)
FileSize(source);
675 double ratio = double(
FileSize(dest))/sourceSize;
677 cout << double(mean3 - mean2 + mean - start)/CLOCKS_PER_SEC <<
';' << double(end - mean3 + mean3 - mean2 + mean - start)/CLOCKS_PER_SEC <<
';' << ratio <<
';';
680 cout <<
"Decoding time (reading PGF, decoding): " << double(mean3 - mean2 + mean - start)/CLOCKS_PER_SEC <<
" s" << endl;
682 cout <<
"Decoding time (reading PGF down to level " << level <<
", decoding): " << double(mean3 - mean2 + mean - start)/CLOCKS_PER_SEC <<
" s" << endl;
684 cout <<
"Total time (reading PGF, decoding, writing destination): " << double(end - mean3 + mean3 - mean2 + mean - start)/CLOCKS_PER_SEC <<
" s" << endl;
685 cout <<
"Compression ratio: " << ratio << endl;
693 static bool Measurement(
char *source,
char *dest,
char *temp,
int levels,
int level,
int quality,
bool roi, PGFRect& rect,
bool streaming,
bool useMemStream) {
696 CImage *image1 =
nullptr, *image2 =
nullptr;
697 CPGFMemoryStream *memStream =
nullptr;
699 if (!
bQuiet) cout <<
"Measuring PSNR (quality: " << quality <<
", levels: " << levels <<
"): " << source << endl;
701 if (!
bQuiet) cout <<
"PGF image is written into memory stream." << endl;
705 if (!
bQuiet) cout << endl;
707 if (!
Encoding(image1, source, temp, levels, quality, roi, streaming, (useMemStream) ? &memStream :
nullptr)) {
712 if (!
Decoding(image2, temp, dest, level, roi, rect, streaming, (useMemStream) ? &memStream :
nullptr)) {
720 PSNR(*image1, *image2, roi, rect);
730 int main(
int argc,
char* argv[]) {
734 enum Operation {Encode, Decode, Measure} op = Encode;
735 char *source=
nullptr, *dest=
nullptr, *temp=
nullptr;
736 int level = 0, levels = 0, quality = 0;
740 bool bStreaming =
false;
742 bool bMemStream =
false;
743 bool bWrongArgs = (argc < 4);
745 while (!bWrongArgs && arg < argc) {
746 if (argv[arg][0] ==
'-') {
748 switch(argv[arg][1]) {
749 case 'e': op = Encode; arg++;
break;
750 case 'd': op = Decode; arg++;
break;
751 case 'm': op = Measure;
752 if (argv[arg][2] ==
'm') {
761 temp = argv[arg]; arg++;
766 if (argv[arg][2] ==
'e') {
772 level = atoi(argv[arg]); arg++;
773 bWrongArgs = (level < 1) || (level > MaxLevel);
781 levels = atoi(argv[arg]); arg++;
782 bWrongArgs = (levels < 1) || (levels > MaxLevel);
790 quality = atoi(argv[arg]); arg++;
791 bWrongArgs = (quality < 0) || (quality > MaxQuality);
794 #ifdef __PGFROISUPPORT__ 795 case 'r': bROI =
true;
796 if (argv[arg][2] ==
'e') {
799 if (arg + 4 > argc) {
802 rect = PGFRect(atoi(argv[arg]), atoi(argv[arg+1]), atoi(argv[arg+2]), atoi(argv[arg+3]));
808 if (arg == argc) bWrongArgs =
true;
811 case 's': bStreaming =
true; arg++;
break;
812 #endif // __PGFROISUPPORT__ 813 case 'v':
bQuiet =
true; arg++;
break;
814 default: arg++; bWrongArgs =
true;
break;
826 if (!
bQuiet) cout <<
"PGF Console - Copyright (c) 2001-" CurrentYear " xeraina GmbH, Switzerland" << endl <<
828 "libpgf Version : " PGFCodecVersion
", www.libpgf.org" << endl << endl;
831 cout <<
"Usage: " << endl <<
832 #ifdef __PGFROISUPPORT__ 833 "- Encoding: pgfconsole -e [-l levels] [-q quality] [-r] [-s] [-v] source dest" << endl <<
835 "- Encoding: pgfconsole -e [-l levels] [-q quality] [-v] source dest" << endl <<
837 " Create from a source file a PGF image (dest)." << endl <<
838 " The most popular image file formats with the following image" << endl <<
839 " types are supported:" << endl <<
840 " - bitmap (1 bit)" << endl <<
841 " - grayscale (8 and 16 bit)" << endl <<
842 " - indexed color (8 bit)" << endl <<
843 " - RGB (16 [565], 24, 32, and 48 bit)" << endl <<
844 " - RGBA (32 bit)" << endl <<
845 " Options:" << endl <<
846 " -l levels Number of hierarchical levels [1.." << MaxLevel <<
"]. Default is 0." << endl <<
847 " 0 means the number of levels are automatically set." << endl <<
848 " -q quality Quality [0.." << MaxQuality <<
"]. Default is 0." << endl <<
849 " 0 means perfect quality (lossless compression)," << endl <<
850 " " << MaxQuality <<
" means maximum compression." << endl <<
851 #ifdef __PGFROISUPPORT__ 852 " -r Region of interest (ROI) encoding scheme is used." << endl <<
853 " This encoding scheme has a slightly worse compression ratio." << endl <<
854 " -s Level wise encoding in separate writing calls." << endl <<
856 " -v Numbers only: All text output is reduced to numbers." << endl <<
858 #ifdef __PGFROISUPPORT__ 859 "- Decoding: pgfconsole -d [-lev level] [-rect left top width height] [-s] [-v] source dest" << endl <<
861 "- Decoding: pgfconsole -d [-v] source dest" << endl <<
863 " Create from a PGF image (source) a new image (dest)." << endl <<
864 " Options:" << endl <<
865 " -lev level The image level of the resulting image. Default is 0." << endl <<
866 #ifdef __PGFROISUPPORT__ 867 " -rect rect Read a rectangular region of a PGF image supporting Region of" << endl <<
868 " interests (ROI). The rectangle is defined by 4 blank-separated" << endl <<
869 " positive parameters: left top width height" << endl <<
870 " -s Level wise decoding in separate reading calls." << endl <<
872 " -v Numbers only: All text output is reduced to numbers." << endl <<
874 "- Measuring: pgfconsole -m temp-file [...] source destination" << endl <<
875 " Measure quality between source and destination bitmap." << endl <<
876 " Encode from an input image (source) a PGF image" << endl <<
877 " (temp-file) and decode from the temp-file a new output" << endl <<
878 " (destination image)." << endl <<
879 " Options:" << endl <<
880 " -mm Instead of using the option -m temp-file you can use " << endl <<
881 " the option -mm (without temp-file). The latter writes the PGF" << endl <<
882 " image into a memory stream instead of a file stream." << endl <<
883 " In both cases all encoding and decoding options are valid." << endl <<
891 #ifdef __PNMEXSUPPORT__ 898 if (!
Encoding(image, source, dest, levels, quality, bROI, bStreaming,
nullptr)) nRetCode = 3;
901 if (!
Decoding(image, source, dest, level, bROI, rect, bStreaming,
nullptr)) nRetCode = 4;
904 if (!
Measurement(source, dest, temp, levels, level, quality, bROI, rect, bStreaming, bMemStream)) nRetCode = 5;
int main(int argc, char *argv[])
bool Load(const char *source)
static bool Measurement(char *source, char *dest, char *temp, int levels, int level, int quality, bool roi, PGFRect &rect, bool streaming, bool useMemStream)
static void PSNR(const CImage &image1, const CImage &image2, bool roi, PGFRect &rect)
static void RegisterPNM()
unsigned char GetBPP() const
#define ImageModeIndexedColor
unsigned char * GetBits() const
unsigned char GetColorType() const
static INT64 FileSize(char *filename)
static string PGFErrors[]
bool Create(int width, int height, int bpp)
#define PGFConsoleVersion
static bool Decoding(CImage *&image, char *source, char *dest, int level, bool roi, PGFRect &rect, bool streaming, CPGFMemoryStream **memStream)
void GetColorTable(int firstColor, int numColors, void *prgbColors)
static bool Encoding(CImage *&image, char *source, char *dest, int levels, int quality, bool roi, bool streaming, CPGFMemoryStream **memStream)
void SetColorTable(int firstColor, int numColors, const void *prgbColors)
bool Save(const char *dest)
int GetMaxColorTableEntries()
unsigned int GetHeight() const
int GetChannelDepth() const
unsigned int GetWidth() const
void SetMaxValue(int maxValue)