PGF Console  6.21.2
PGF.cpp
Go to the documentation of this file.
1 /*
2  * PGF: A PGF-codec demonstration
3  * $Date: 2006-05-09 20:13:33 +0200 (Di, 09 Mai 2006) $
4  * $Revision: 187 $
5 
6  * This file Copyright (C) 2006 xeraina GmbH, Switzerland
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */
22 
23 // PGF.cpp : Defines the entry point for the console application.
24 //
26 // definitions
27 #define PGFConsoleVersion "6.21.02" // Major number, Minor number: Year (2) Week (2)
28 #define CurrentYear "2021"
29 //-------------------------------------------------------------------------------
30 // ROI support
31 //-------------------------------------------------------------------------------
32 #ifndef NPGFROI
33 #define __PGFROISUPPORT__ // without ROI support the program code gets simpler and smaller
34 #endif
35 
36 
37 #include <iostream>
38 #include <cmath> // or #include <math.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <ctime>
42 #include <fcntl.h>
43 #include <string>
44 
45 #if defined(__linux__) || defined(__APPLE__)
46  #define __POSIX__
47 #endif
48 
49 #ifdef __POSIX__
50  #include <libpgf/PGFimage.h>
51  #include <unistd.h> // open, close
52  #include <stdio.h>
53  #include <errno.h>
54  #include <string.h>
55 #else
56  #include "PGFimage.h"
57  #include <windows.h>
58 #endif
59 
60 // must be included after PGFimage.h to avoid type conflicts on POSIX systems
61 #include "CImage.h"
62 
64 // definitions
65 #ifdef __APPLE__
66  #define __stat64 stat
67  #define _stat64 stat
68 #elif defined __POSIX__
69  #define __stat64 stat64
70  #define _stat64 stat64
71 #endif
72 
73 
74 using namespace std;
75 
77 // static variables
78 static bool bQuiet = false;
79 static string PGFErrors[] = {
80  "no error",
81  "memory allocation was not successfull",
82  "invalid memory stream position",
83  "user break by ESC",
84  "wrong pgf version",
85  "wrong data file format",
86  "image is too small",
87  "error in zlib functions",
88  "errors related to color table size",
89  "errors in png functions",
90  "expected data cannot be read",
91 };
92 
94 static INT64 FileSize(char *filename) {
95  struct __stat64 data;
96 
97  if (_stat64(filename, &data) != -1) {
98  return data.st_size;
99  } else {
100  return 0;
101  }
102 }
103 
105 static void PSNR(const CImage& image1, const CImage& image2, bool roi, PGFRect& rect) {
106 #ifndef __PGFROISUPPORT__
107  roi;
108  rect;
109 #endif
110  ASSERT(image1.GetChannelDepth() == image2.GetChannelDepth());
111  ASSERT(image1.GetChannelDepth() == 8 || image1.GetChannelDepth() == 16);
112 
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);
117  const UINT32 w = image2.GetWidth();
118  const UINT32 h = image2.GetHeight();
119  const UINT32 size = w*h;
120  const int bypp1 = image1.GetBPP()/8; // RGB mode has 3 channels but can use 24 or 32 bits per pixel
121  const int bypp2 = image2.GetBPP()/8;
122 
123  int pitch1 = image1.GetPitch();
124  int pitch2 = image2.GetPitch();
125  double sum[MaxChannels + 1] = { 0 };
126  int tmp;
127  int cnt1 = 0, cnt2 = 0, maxValue;
128 
129  if (image1.GetChannelDepth() == 8) {
130  UINT8* rgbBuff1 = (UINT8 *)image1.GetBits();
131  UINT8* rgbBuff2 = (UINT8 *)image2.GetBits();
132  maxValue = 255;
133 
134  #ifdef __PGFROISUPPORT__
135  if (roi) {
136  ASSERT(w <= image1.GetWidth());
137  ASSERT(h <= image1.GetHeight());
138  rgbBuff1 += (image1.GetHeight() - h - rect.top)*pitch1 + rect.left*channels1;
139  }
140  #endif
141  for (UINT32 j=0; j < h; j++) {
142  cnt1 = cnt2 = 0;
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;
146  }
147  cnt1 += bypp1;
148  cnt2 += bypp2;
149  }
150  rgbBuff1 += pitch1;
151  rgbBuff2 += pitch2;
152  }
153  } else if (image1.GetChannelDepth() == 16) {
154  UINT16* rgbBuff1 = (UINT16 *)image1.GetBits();
155  UINT16* rgbBuff2 = (UINT16 *)image2.GetBits();
156 
157 #ifdef __PNMEXSUPPORT__
158  maxValue = image1.GetMaxValue();
159 #else
160  maxValue = 65535;
161 #endif
162  pitch1 /= 2;
163  pitch2 /= 2;
164 
165  #ifdef __PGFROISUPPORT__
166  if (roi) {
167  ASSERT(w <= image1.GetWidth());
168  ASSERT(h <= image1.GetHeight());
169  rgbBuff1 += (image1.GetHeight() - h - rect.top)*pitch1 + rect.left*channels1;
170  }
171  #endif
172  for (UINT32 j=0; j < h; j++) {
173  cnt1 = cnt2 = 0;
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;
177  }
178  cnt1 += bypp1;
179  cnt2 += bypp2;
180  }
181  rgbBuff1 += pitch1;
182  rgbBuff2 += pitch2;
183  }
184  } else {
185  return;
186  }
187 
188  for (int c=0; c < channels1; c++) {
189  sum[MaxChannels] += sum[c];
190  }
191 
192  // output
193  if (bQuiet) {
194  cout << 10*log10(double(maxValue)*maxValue*size*channels1/sum[MaxChannels]);
195 // cout << ((sum[MaxChannels] != 0) ? 10*log10(double(maxValue)*maxValue*size*channels1/sum[MaxChannels]) : 100);
196  for (int c=0; c < channels1; c++) {
197  cout << ';' << 10*log10(double(maxValue)*maxValue*size/sum[c]);
198  //cout << ';' << ((sum[c] != 0) ? 10*log10(double(maxValue)*maxValue*size/sum[c]) : 100);
199  }
200  cout << ';';
201  } else {
202  if (sum[MaxChannels] == 0) {
203  cout << "PSNR: lossless" << endl;
204  } else {
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]);
208  //cout << 'c' << c << ": " << ((sum[c] != 0) ? 10*log10(double(maxValue)*maxValue*size/sum[c]) : 100);
209  if (c < channels1 - 1) cout << ", ";
210  }
211  cout << ')' << endl;
212  }
213  cout << endl;
214  }
215 }
216 
218 static bool Encoding(CImage*& image, char *source, char *dest, int levels, int quality, bool roi, bool streaming, CPGFMemoryStream** memStream) {
219 #ifndef __PGFROISUPPORT__
220  ASSERT(!roi);
221  ASSERT(!streaming);
222 #endif
223  ASSERT(source);
224  ASSERT(0 <= quality && quality <= MaxQuality);
225  bool returnValue = true;
226  CPGFImage pgf;
227  PGFHeader header;
228  clock_t start = 0, mean = 0, end = 0;
229  UINT32 writtenBytes = 0;
230  CPGFStream *stream = nullptr;
231  UINT8 bpp = 0;
232 #ifdef WIN32
233  HANDLE fd = nullptr;
234 #elif defined(__POSIX__)
235  int fd = 0;
236 #endif
237 
238  if (!memStream) {
239  ASSERT(dest);
240  #ifdef WIN32
241  // no other choice to get a "HANDLE"
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;
245  fd = nullptr;
246  returnValue = false;
247  goto CleanUp;
248  }
249 
250  // create stream object
251  stream = new CPGFFileStream(fd);
252 
253  #elif defined(__POSIX__)
254  fd = open(dest, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
255  if (fd == -1) {
256  cout << "Error: Could not open destination file." << endl;
257  fd = 0;
258  returnValue = false;
259  goto CleanUp;
260  }
261 
262  // create stream object
263  stream = new CPGFFileStream(fd);
264  #endif
265  }
266 
267  if (memStream) {
268  if (!bQuiet) cout << "Encoding PGF image to memory stream (quality: " << quality << ", levels: " << levels << "): " << source << endl;
269  } else {
270  if (!bQuiet) cout << "Encoding PGF image (quality: " << quality << ", levels: " << levels << "): " << source << endl;
271  }
272  if (roi || streaming) {
273  if (memStream) {
274  cout << "PGF image will support ROI." << endl;
275  } else {
276  cout << dest << " will support ROI." << endl;
277  }
278  }
279 
280  start = clock();
281 
282  // create new image object
283  image = new CImage();
284 
285  // load image
286 #ifdef WIN32
287  if (!image->Load(source)) {
288  LPTSTR lpMsgBuf;
289  FormatMessage(
290  FORMAT_MESSAGE_ALLOCATE_BUFFER |
291  FORMAT_MESSAGE_FROM_SYSTEM |
292  FORMAT_MESSAGE_IGNORE_INSERTS,
293  nullptr,
294  GetLastError(),
295  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
296  (LPTSTR)&lpMsgBuf,
297  0,
298  nullptr
299  );
300  cerr << "Error: " << lpMsgBuf << endl;
301  LocalFree(lpMsgBuf);
302  returnValue = false;
303  goto CleanUp;
304  }
305 #elif defined(__POSIX__)
306  if (!image->Load(source) ){
307  cerr << "Error: Could not load source file." << endl;
308  returnValue = false;
309  goto CleanUp;
310  }
311 #endif
312 
313  bpp = image->GetBPP();
314  // minimum: 1-bit bitmap, maximum: 48-bit RGB (16-bit per channel)
315  if ((bpp < 1) || (bpp > 48) || (bpp == 4)) {
316  cerr << "Error: Unhandled image format." << endl;
317  returnValue = false;
318  goto CleanUp;
319  }
320 
321  ASSERT((bpp >= 1) && (bpp <= 48) && (bpp != 4));
322 
323  if (memStream) {
324  *memStream = new CPGFMemoryStream(abs(image->GetPitch())*image->GetHeight());
325  stream = *memStream;
326  }
327 
328  mean = clock();
329 
330  // optional PGF encoder configuration
331  pgf.ConfigureEncoder(true, false); // true: use openMP (if codec is compiled with openMP), false: favorSpeedOverSize
332 
333  header.width = image->GetWidth();
334  header.height = image->GetHeight();
335  header.nLevels = (UINT8)levels;
336  header.quality = (UINT8)quality;
337  header.mode = image->GetColorType();
338  header.bpp = header.channels = 0; // depend on mode and will be set automatically
339  header.usedBitsPerChannel = 0; // depend on mode and bpp and will be set automatically
340 
341  try {
342  if (bQuiet) {
343  pgf.SetHeader(header, (roi || streaming) ? PGFROI : 0);
344  } else {
345  char data[] = "This is a free text annotation.";
346  pgf.SetHeader(header, (roi || streaming) ? PGFROI : 0, (UINT8 *)data, sizeof(data));
347  }
348 
349 #ifdef __PNMEXSUPPORT__
350  if (image->GetChannelDepth() > 8) {
351  // set maximum value
352  pgf.SetMaxValue(image->GetMaxValue());
353  }
354 #endif
355 
356  // copy bits
357  UINT8* buff = (UINT8 *)image->GetBits();
358  if (pgf.Mode() == ImageModeRGB48) {
359  int map[] = { 2, 1, 0 };
360  pgf.ImportBitmap(-image->GetPitch(), &(buff[(image->GetHeight() - 1)*image->GetPitch()]), bpp, map);
361  } else {
362 #ifdef __BIG_ENDIAN__
363  int map[] = { 2, 1, 0 };
364  pgf.ImportBitmap(-image->GetPitch(), &(buff[(image->GetHeight() - 1)*image->GetPitch()]), bpp, map);
365 #else
366  pgf.ImportBitmap(-image->GetPitch(), &(buff[(image->GetHeight() - 1)*image->GetPitch()]), bpp);
367 #endif
368  }
369 
370  // update color table if image is indexed
371  if ((pgf.Mode() == ImageModeIndexedColor)) {
372  int colorTableSize = image->GetMaxColorTableEntries();
373  RGBQUAD* pColorTable = new RGBQUAD[colorTableSize];
374 
375  image->GetColorTable(0, colorTableSize, pColorTable);
376  pgf.SetColorTable(0, colorTableSize, pColorTable);
377  delete[] pColorTable;
378  }
379 
380  } catch(IOException& e) {
381  int err = e.error;
382 
383  if (err >= AppError) {
384  cerr << "Error: Importing input image failed\n(" << PGFErrors[err - AppError] << ")!" << endl;
385  } else {
386  cerr << "Error: Importing input image failed (" << err << ")!" << endl;
387  }
388  returnValue = false;
389  goto CleanUp;
390  }
391 
392  try {
393  #ifdef __PGFROISUPPORT__
394  if (streaming) {
395  // process and write header
396  writtenBytes = pgf.WriteHeader(stream);
397  if (!bQuiet) cout << "Write header [" << writtenBytes << " bytes]" << endl;
398  // encode each level separately
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;
403  }
404  } else
405  #endif __PGFROISUPPORT__
406  {
407  // write image to pgf-file
408  pgf.Write(stream, &writtenBytes);
409  }
410 
411  } catch(IOException& e) {
412  int err = e.error;
413  if (err >= AppError) {
414  cerr << "Error: Writing PGF image failed\n(" << PGFErrors[err - AppError] << ")!" << endl;
415  } else {
416  cerr << "Error: Writing PGF image failed (" << err << ")!" << endl;
417  }
418  returnValue = false;
419  goto CleanUp;
420  }
421 
422  end = clock();
423 
424 CleanUp:
425  if (memStream) {
426  // reset stream position
427  pgf.ResetStreamPos(false);
428  } else {
429  // close file
430 #ifdef WIN32
431  if (fd) CloseHandle(fd);
432 #elif defined(__POSIX__)
433  if (fd) close(fd);
434 #endif
435  delete stream;
436  }
437 
438  if (returnValue) {
439  // output: output file has to be closed before FileSize
440  double destSize = (memStream) ? writtenBytes : double(FileSize(dest));
441  double ratio = double(FileSize(source))/destSize;
442 
443  if (bQuiet) {
444  cout << double(end - mean)/CLOCKS_PER_SEC << ';' << double(end - start)/CLOCKS_PER_SEC << ';' << ratio << ';';
445  } else {
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;
450  cout << endl;
451  }
452  }
453 
454  return returnValue;
455 }
456 
458 static bool Decoding(CImage*& image, char *source, char *dest, bool roi, PGFRect& rect, bool streaming, CPGFMemoryStream** memStream) {
459 #ifndef __PGFROISUPPORT__
460  ASSERT(!roi);
461  ASSERT(!streaming);
462  rect;
463 #endif
464  ASSERT(dest);
465  bool returnValue = true;
466  CPGFImage pgf;
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;
471 #ifdef WIN32
472  HANDLE fd = nullptr;
473 #elif defined(__POSIX__)
474  int fd = 0;
475 #endif
476 
477  if (memStream) {
478  // use memory stream
479  stream = *memStream;
480  } else {
481  ASSERT(source);
482  #ifdef WIN32
483  // no other choice to get a "HANDLE"
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;
487  fd = nullptr;
488  returnValue = false;
489  goto CleanUp;
490  }
491 
492  // create stream object
493  stream = new CPGFFileStream(fd);
494 
495  #elif defined(__POSIX__)
496  fd = open(source, O_RDONLY);
497  if (fd == -1){
498  cout << "Error: Could not open source file." << endl;
499  fd = 0;
500  returnValue = false;
501  goto CleanUp;
502  }
503 
504  // create stream object
505  stream = new CPGFFileStream(fd);
506  #endif
507  }
508 
509  // optional PGF encoder configuration
510  pgf.ConfigureDecoder(true); // true: use openMP (if codec is compiled with openMP)
511 
512  if (memStream) {
513  if (!bQuiet) cout << "Decoding PGF image from memory stream." << endl;
514  } else {
515  if (!bQuiet) cout << "Decoding PGF image: " << source << endl;
516  }
517 
518  start = clock();
519  try {
520  // open pgf image
521  UINT64 startpos = stream->GetPos();
522  pgf.Open(stream);
523  if (!bQuiet) cout << "Read header and level info [" << stream->GetPos() - startpos << " bytes]" << endl;
524 
525  // read annotations
526  if (!bQuiet) {
527  UINT32 len = 0;
528  const UINT8 *data = pgf.GetUserData(len);
529  if (data && len) {
530  cout << (char *)data << endl;
531  }
532  }
533 
534  // read pgf image
535  #ifdef __PGFROISUPPORT__
536  if (pgf.ROIisSupported()) {
537  if (memStream) {
538  if (!bQuiet) cout << "PGF image supports ROI." << endl;
539  } else {
540  if (!bQuiet) cout << source << " supports ROI." << endl;
541  }
542  }
543  if (roi) {
544  pgf.Read(rect); // ROI test
545  // example of how to make a second read (with a different ROI) after resetting stream position to data
546  //pgf.ResetStreamPos(true);
547  //pgf.Read(rect);
548  } else {
549  if (streaming) {
550  // decode each level separately
551  for (int i = pgf.Levels() - 1; i >= 0; i--) {
552  if (!bQuiet) cout << "Read level " << i;
553  UINT64 pos = stream->GetPos();
554  pgf.Read(i);
555  if (!bQuiet) cout << " [" << stream->GetPos() - pos << " bytes]" << endl;
556  }
557  }
558  }
559  #else
560  cout << "PGF Console: ROI supports has been disabled." << endl;
561  #endif
562  if (!roi && !streaming) {
563  // read entire file down to level 0
564  pgf.Read();
565  }
566  sourceSize = double(stream->GetPos() - startpos);
567 
568  } catch(IOException& e) {
569  int err = e.error;
570  if (err >= AppError) {
571  cerr << "Error: Opening and reading PGF image failed\n(" << PGFErrors[err - AppError] << ")!" << endl;
572  } else {
573  cerr << "Error: Opening and reading PGF image failed (" << err << ")!" << endl;
574  }
575 
576  returnValue = false;
577  goto CleanUp;
578  }
579  mean = clock();
580 
581  // create image
582  image = new CImage();
583 #ifdef __PGFROISUPPORT__
584  if (roi) {
585  if (!image->Create(rect.Width(), rect.Height(), pgf.GetHeader()->mode)) {
586  cerr << "Decoding is not supported for this PGF color format." << endl;
587  returnValue = false;
588  goto CleanUp;
589  }
590  } else
591 #endif
592  {
593  if (!image->Create(pgf.Width(), pgf.Height(), pgf.GetHeader()->mode)) {
594  cerr << "Decoding is not supported for this PGF color format." << endl;
595  returnValue = false;
596  goto CleanUp;
597  }
598  }
599 
600  // copy bits
601  mean2 = clock();
602  buff = (UINT8 *)image->GetBits();
603  if (pgf.Mode() == ImageModeRGB48) {
604  int map[] = { 2, 1, 0 };
605  pgf.GetBitmap(-image->GetPitch(), &(buff[(image->GetHeight() - 1) * image->GetPitch()]), image->GetBPP(), map);
606  } else {
607 #ifdef __BIG_ENDIAN__
608  int map[] = { 2, 1, 0 };
609  pgf.GetBitmap(-image->GetPitch(), &(buff[(image->GetHeight() - 1) * image->GetPitch()]), image->GetBPP(), map);
610 #else
611  pgf.GetBitmap(-image->GetPitch(), &(buff[(image->GetHeight() - 1) * image->GetPitch()]), image->GetBPP());
612 #endif
613  }
614 
615  // update color table if image is indexed or bitmap
616  if ((pgf.Mode() == ImageModeIndexedColor)) {
617  // cannot get number of color table entries directly, so use 2^bitdepth
618  image->SetColorTable(0, 1 << pgf.BPP(), pgf.GetColorTable());
619  } else if (pgf.GetHeader()->mode == ImageModeBitmap) {
620  RGBQUAD bw[2];
621  bw[0].rgbRed = 255;
622  bw[0].rgbGreen = 255;
623  bw[0].rgbBlue = 255;
624  bw[1].rgbRed = 0;
625  bw[1].rgbGreen = 0;
626  bw[1].rgbBlue = 0;
627  image->SetColorTable(0, 2, bw);
628  }
629 
630  mean3 = clock();
631 
632 #ifdef __PNMEXSUPPORT__
633  if (image->GetChannelDepth() > 8) {
634  // set maximum value
635  image->SetMaxValue(pgf.GetMaxValue());
636  }
637 #endif
638 
639  // save image
640  if (image->Save(dest)) {
641  if (!bQuiet) cout << "Written image file: " << dest << endl;
642  } else {
643  cerr << "Error: Output format not supported for this color depth." << endl;
644  return false;
645  }
646 
647  end = clock();
648 
649 CleanUp:
650  if (memStream) {
651  stream->SetPos(FSFromStart, 0);
652  } else {
653  // close file
654 #ifdef WIN32
655  if (fd) CloseHandle(fd);
656 #elif defined(__POSIX__)
657  if (fd) close(fd);
658 #endif
659  delete stream;
660  }
661 
662  if (!memStream) {
663  // source has to be closed before FileSize
664  sourceSize = (double)FileSize(source);
665  }
666 
667  if (returnValue) {
668  // output
669  double ratio = double(FileSize(dest))/sourceSize;
670  if (bQuiet) {
671  cout << double(mean3 - mean2 + mean - start)/CLOCKS_PER_SEC << ';' << double(end - mean3 + mean3 - mean2 + mean - start)/CLOCKS_PER_SEC << ';' << ratio << ';';
672  } else {
673  cout << "Decoding time (reading PGF, decoding): " << double(mean3 - mean2 + mean - start)/CLOCKS_PER_SEC << " s" << endl;
674  cout << "Total time (reading PGF, decoding, writing destination): " << double(end - mean3 + mean3 - mean2 + mean - start)/CLOCKS_PER_SEC << " s" << endl;
675  cout << "Compression ratio: " << ratio << endl;
676  cout << endl;
677  }
678  }
679  return returnValue;
680 }
681 
683 static bool Measurement(char *source, char *dest, char *temp, int levels, int quality, bool roi, PGFRect& rect, bool streaming, bool useMemStream) {
684  ASSERT(source);
685  ASSERT(dest);
686  CImage *image1 = nullptr, *image2 = nullptr;
687  CPGFMemoryStream *memStream = nullptr;
688 
689  if (!bQuiet) cout << "Measuring PSNR (quality: " << quality << ", levels: " << levels << "): " << source << endl;
690  if (useMemStream) {
691  if (!bQuiet) cout << "PGF image is written into memory stream." << endl;
692  } else {
693  ASSERT(temp);
694  }
695  if (!bQuiet) cout << endl;
696 
697  if (!Encoding(image1, source, temp, levels, quality, roi, streaming, (useMemStream) ? &memStream : nullptr)) {
698  delete image1;
699  delete memStream;
700  return false;
701  }
702  if (!Decoding(image2, temp, dest, roi, rect, streaming, (useMemStream) ? &memStream : nullptr)) {
703  delete image2;
704  delete memStream;
705  return false;
706  }
707 
708  if (image1->GetChannelDepth() == 8 || image1->GetChannelDepth() == 16) {
709  // output psnr
710  PSNR(*image1, *image2, roi, rect);
711  }
712 
713  delete image1;
714  delete image2;
715  delete memStream;
716  return true;
717 }
718 
720 int main(int argc, char* argv[]) {
721  int nRetCode = 0;
722 
723  // parse arguments
724  enum Operation {Encode, Decode, Measure} op = Encode;
725  char *source=nullptr, *dest=nullptr, *temp=nullptr;
726  int levels = 0, quality = 0;
727  PGFRect rect;
728  int arg = 1; // argument 0 = pgf
729  bool bSource = true; // true: bSource, false: dest
730  bool bStreaming = false;// true: level wise writing/reading is used
731  bool bROI = false; // true: ROI is used
732  bool bMemStream = false;// true: use a memory stream during measuring
733  bool bWrongArgs = (argc < 4);
734 
735  while (!bWrongArgs && arg < argc) {
736  if (argv[arg][0] == '-') {
737  // options
738  switch(argv[arg][1]) {
739  case 'e': op = Encode; arg++; break;
740  case 'd': op = Decode; arg++; break;
741  case 'm': op = Measure;
742  if (argv[arg][2] == 'm') {
743  // -mm
744  bMemStream = true;
745  arg++;
746  } else {
747  arg++;
748  if (arg == argc) {
749  bWrongArgs = true;
750  } else {
751  temp = argv[arg]; arg++;
752  }
753  }
754  break;
755  case 'l': arg++;
756  if (arg == argc) {
757  bWrongArgs = true;
758  } else {
759  levels = atoi(argv[arg]); arg++;
760  bWrongArgs = (levels < 1) || (levels > MaxLevel);
761  }
762  break;
763  case 'q': arg++;
764  if (arg == argc) {
765  bWrongArgs = true;
766  } else {
767  quality = atoi(argv[arg]); arg++;
768  bWrongArgs = (quality < 0) || (quality > MaxQuality);
769  }
770  break;
771  #ifdef __PGFROISUPPORT__
772  case 'r': bROI = true;
773  if (argv[arg][2] == 'e') {
774  // -re[ct]
775  arg++;
776  if (arg + 4 > argc) {
777  bWrongArgs = true;
778  } else {
779  rect = PGFRect(atoi(argv[arg]), atoi(argv[arg+1]), atoi(argv[arg+2]), atoi(argv[arg+3]));
780  arg += 4;
781  }
782  } else {
783  // -r
784  arg++;
785  if (arg == argc) bWrongArgs = true;
786  }
787  break;
788  case 's': bStreaming = true; arg++; break;
789  #endif // __PGFROISUPPORT__
790  case 'v': bQuiet = true; arg++; break;
791  default: arg++; bWrongArgs = true; break;
792  }
793  } else {
794  if (bSource) {
795  source = argv[arg];
796  bSource = false;
797  } else {
798  dest = argv[arg];
799  }
800  arg++;
801  }
802  }
803  if (!bQuiet) cout << "PGF Console - Copyright (c) 2001-" CurrentYear " xeraina GmbH, Switzerland" << endl <<
804  "Console Version: " PGFConsoleVersion ", www.xeraina.ch" << endl <<
805  "libpgf Version : " PGFCodecVersion ", www.libpgf.org" << endl << endl;
806  if (bWrongArgs) {
807  if (!bQuiet) {
808  cout << "Usage: " << endl <<
809  #ifdef __PGFROISUPPORT__
810  "- Encoding: pgfconsole -e [-l levels] [-q quality] [-r] [-s] [-v] source dest" << endl <<
811  #else
812  "- Encoding: pgfconsole -e [-l levels] [-q quality] [-v] source dest" << endl <<
813  #endif
814  " Create from a source file a PGF image (dest)." << endl <<
815  " The most popular image file formats with the following image" << endl <<
816  " types are supported:" << endl <<
817  " - bitmap (1 bit)" << endl <<
818  " - grayscale (8 and 16 bit)" << endl <<
819  " - indexed color (8 bit)" << endl <<
820  " - RGB (16 [565], 24, 32, and 48 bit)" << endl <<
821  " - RGBA (32 bit)" << endl <<
822  " Options:" << endl <<
823  " -l levels Number of hierarchical levels [1.." << MaxLevel << "]. Default is 0." << endl <<
824  " 0 means the number of levels are automatically set." << endl <<
825  " -q quality Quality [0.." << MaxQuality << "]. Default is 0." << endl <<
826  " 0 means perfect quality (lossless compression)," << endl <<
827  " " << MaxQuality << " means maximum compression." << endl <<
828  #ifdef __PGFROISUPPORT__
829  " -r Region of interest (ROI) encoding scheme is used." << endl <<
830  " This encoding scheme has a slightly worse compression ratio." << endl <<
831  " -s Level wise encoding in separate writing calls." << endl <<
832  #endif
833  " -v Numbers only: All text output is reduced to numbers." << endl <<
834  endl <<
835  #ifdef __PGFROISUPPORT__
836  "- Decoding: pgfconsole -d [-rect left top width height] [-s] [-v] source dest" << endl <<
837  #else
838  "- Decoding: pgfconsole -d [-v] source dest" << endl <<
839  #endif
840  " Create from a PGF image (source) a new image (dest)." << endl <<
841  " Options:" << endl <<
842  #ifdef __PGFROISUPPORT__
843  " -rect rect Read a rectangular region of a PGF image supporting Region of" << endl <<
844  " interests (ROI). The rectangle is defined by 4 blank-separated" << endl <<
845  " positive parameters: left top width height" << endl <<
846  " -s Level wise decoding in separate reading calls." << endl <<
847  #endif
848  " -v Numbers only: All text output is reduced to numbers." << endl <<
849  endl <<
850  "- Measuring: pgfconsole -m temp-file [...] source destination" << endl <<
851  " Measure quality between source and destination bitmap." << endl <<
852  " Encode from an input image (source) a PGF image" << endl <<
853  " (temp-file) and decode from the temp-file a new output" << endl <<
854  " (destination image)." << endl <<
855  " Options:" << endl <<
856  " -mm Instead of using the option -m temp-file you can use " << endl <<
857  " the option -mm (without temp-file). The latter writes the PGF" << endl <<
858  " image into a memory stream instead of a file stream." << endl <<
859  " In both cases all encoding and decoding options are valid." << endl <<
860  endl <<
861  endl;
862  }
863  nRetCode = 2;
864  } else {
865  CImage *image = 0;
866 
867 #ifdef __PNMEXSUPPORT__
868  // register new PNM plugin
870 #endif
871 
872  switch(op) {
873  case Encode:
874  if (!Encoding(image, source, dest, levels, quality, bROI, bStreaming, nullptr)) nRetCode = 3;
875  break;
876  case Decode:
877  if (!Decoding(image, source, dest, bROI, rect, bStreaming, nullptr)) nRetCode = 4;
878  break;
879  case Measure:
880  if (!Measurement(source, dest, temp, levels, quality, bROI, rect, bStreaming, bMemStream)) nRetCode = 5;
881  break;
882  default:
883  nRetCode = 6;
884  ASSERT(false); // unhandled operation
885  }
886  if (bQuiet) cout << endl;
887 
888  delete image;
889  }
890  return nRetCode;
891 }
892 
Definition: CImage.h:58
#define CurrentYear
Definition: PGF.cpp:28
int main(int argc, char *argv[])
Definition: PGF.cpp:720
bool Load(const char *source)
Definition: CImage.cpp:127
static bool Measurement(char *source, char *dest, char *temp, int levels, int quality, bool roi, PGFRect &rect, bool streaming, bool useMemStream)
Definition: PGF.cpp:683
static void PSNR(const CImage &image1, const CImage &image2, bool roi, PGFRect &rect)
Definition: PGF.cpp:105
static void RegisterPNM()
Definition: CImage.cpp:303
unsigned char GetBPP() const
Definition: CImage.cpp:107
#define ImageModeBitmap
Definition: CImage.h:33
#define ImageModeIndexedColor
Definition: CImage.h:35
unsigned char * GetBits() const
Definition: CImage.cpp:97
unsigned char GetColorType() const
Definition: CImage.cpp:178
static INT64 FileSize(char *filename)
Definition: PGF.cpp:94
static string PGFErrors[]
Definition: PGF.cpp:79
bool Create(int width, int height, int bpp)
Definition: CImage.cpp:43
#define ImageModeRGB48
Definition: CImage.h:44
#define PGFConsoleVersion
Definition: PGF.cpp:27
static bool Decoding(CImage *&image, char *source, char *dest, bool roi, PGFRect &rect, bool streaming, CPGFMemoryStream **memStream)
Definition: PGF.cpp:458
void GetColorTable(int firstColor, int numColors, void *prgbColors)
Definition: CImage.cpp:156
static bool bQuiet
Definition: PGF.cpp:78
static bool Encoding(CImage *&image, char *source, char *dest, int levels, int quality, bool roi, bool streaming, CPGFMemoryStream **memStream)
Definition: PGF.cpp:218
void SetColorTable(int firstColor, int numColors, const void *prgbColors)
Definition: CImage.cpp:167
bool Save(const char *dest)
Definition: CImage.cpp:122
int GetMaxColorTableEntries()
Definition: CImage.cpp:151
int GetMaxValue() const
Definition: CImage.cpp:323
int GetPitch() const
Definition: CImage.cpp:102
unsigned int GetHeight() const
Definition: CImage.cpp:112
int GetChannelDepth() const
Definition: CImage.cpp:250
int GetChannels() const
Definition: CImage.cpp:276
unsigned int GetWidth() const
Definition: CImage.cpp:117
void SetMaxValue(int maxValue)
Definition: CImage.cpp:319