libpgf  7.21.2
PGF - Progressive Graphics File
PGFimage.cpp
Go to the documentation of this file.
1 /*
2  * The Progressive Graphics File; http://www.libpgf.org
3  *
4  * $Date: 2007-02-03 13:04:21 +0100 (Sa, 03 Feb 2007) $
5  * $Revision: 280 $
6  *
7  * This file Copyright (C) 2006 xeraina GmbH, Switzerland
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22  */
23 
28 
29 #include "PGFimage.h"
30 #include "Decoder.h"
31 #include "Encoder.h"
32 #include "BitStream.h"
33 #include <cmath>
34 #include <cstring>
35 
36 #define YUVoffset4 8 // 2^3
37 #define YUVoffset6 32 // 2^5
38 #define YUVoffset8 128 // 2^7
39 #define YUVoffset16 32768 // 2^15
40 //#define YUVoffset31 1073741824 // 2^30
41 
43 // global methods and variables
44 #ifdef NEXCEPTIONS
45  OSError _PGF_Error_;
46 
47  OSError GetLastPGFError() {
48  OSError tmp = _PGF_Error_;
49  _PGF_Error_ = NoError;
50  return tmp;
51  }
52 #endif
53 
54 #ifdef _DEBUG
55  // allows RGB and RGBA image visualization inside Visual Studio Debugger
56  struct DebugBGRImage {
57  int width, height, pitch;
58  BYTE *data;
59  } roiimage;
60 #endif
61 
63 // Standard constructor
65  Init();
66 }
67 
70  // init pointers
71  m_decoder = nullptr;
72  m_encoder = nullptr;
73  m_levelLength = nullptr;
74 
75  // init members
76 #ifdef __PGFROISUPPORT__
77  m_streamReinitialized = false;
78 #endif
79  m_currentLevel = 0;
80  m_quant = 0;
81  m_userDataPos = 0;
82  m_downsample = false;
83  m_favorSpeedOverSize = false;
84  m_useOMPinEncoder = true;
85  m_useOMPinDecoder = true;
86  m_cb = nullptr;
87  m_cbArg = nullptr;
89  m_percent = 0;
91 
92  // init preHeader
93  memcpy(m_preHeader.magic, PGFMagic, 3);
95  m_preHeader.hSize = 0;
96 
97  // init postHeader
98  m_postHeader.userData = nullptr;
101 
102  // init channels
103  for (int i = 0; i < MaxChannels; i++) {
104  m_channel[i] = nullptr;
105  m_wtChannel[i] = nullptr;
106  }
107 
108  // set image width and height
109  for (int i = 0; i < MaxChannels; i++) {
110  m_width[0] = 0;
111  m_height[0] = 0;
112  }
113 }
114 
116 // Destructor: Destroy internal data structures.
118  m_currentLevel = -100; // unusual value used as marker in Destroy()
119  Destroy();
120 }
121 
123 // Destroy internal data structures. Object state after this is the same as after CPGFImage().
125  for (int i = 0; i < m_header.channels; i++) {
126  delete m_wtChannel[i]; // also deletes m_channel
127  }
128  delete[] m_postHeader.userData;
129  delete[] m_levelLength;
130  delete m_decoder;
131  delete m_encoder;
132 
133  if (m_currentLevel != -100) Init();
134 }
135 
137 // Open a PGF image at current stream position: read pre-header, header, levelLength, and ckeck image type.
138 // Precondition: The stream has been opened for reading.
139 // It might throw an IOException.
140 // @param stream A PGF stream
142  ASSERT(stream);
143 
144  // create decoder and read PGFPreHeader PGFHeader PGFPostHeader LevelLengths
147 
148  if (m_header.nLevels > MaxLevel) ReturnWithError(FormatCannotRead);
149 
150  // set current level
152 
153  // set image width and height
154  m_width[0] = m_header.width;
155  m_height[0] = m_header.height;
156 
157  // complete header
158  if (!CompleteHeader()) ReturnWithError(FormatCannotRead);
159 
160  // interpret quant parameter
169  m_downsample = true;
170  m_quant = m_header.quality - 1;
171  } else {
172  m_downsample = false;
174  }
175 
176  // set channel dimensions (chrominance is subsampled by factor 2)
177  if (m_downsample) {
178  for (int i=1; i < m_header.channels; i++) {
179  m_width[i] = (m_width[0] + 1) >> 1;
180  m_height[i] = (m_height[0] + 1) >> 1;
181  }
182  } else {
183  for (int i=1; i < m_header.channels; i++) {
184  m_width[i] = m_width[0];
185  m_height[i] = m_height[0];
186  }
187  }
188 
189  if (m_header.nLevels > 0) {
190  // init wavelet subbands
191  for (int i=0; i < m_header.channels; i++) {
193  }
194 
195  // used in Read when PM_Absolute
196  m_percent = pow(0.25, m_header.nLevels);
197 
198  } else {
199  // very small image: we don't use DWT and encoding
200 
201  // read channels
202  for (int c=0; c < m_header.channels; c++) {
203  const UINT32 size = m_width[c]*m_height[c];
204  m_channel[c] = new(std::nothrow) DataT[size];
205  if (!m_channel[c]) ReturnWithError(InsufficientMemory);
206 
207  // read channel data from stream
208  for (UINT32 i=0; i < size; i++) {
209  int count = DataTSize;
210  stream->Read(&count, &m_channel[c][i]);
211  if (count != DataTSize) ReturnWithError(MissingData);
212  }
213  }
214  }
215 }
216 
219  // set current codec version
221 
222  if (m_header.mode == ImageModeUnknown) {
223  // undefined mode
224  switch(m_header.bpp) {
225  case 1: m_header.mode = ImageModeBitmap; break;
226  case 8: m_header.mode = ImageModeGrayScale; break;
227  case 12: m_header.mode = ImageModeRGB12; break;
228  case 16: m_header.mode = ImageModeRGB16; break;
229  case 24: m_header.mode = ImageModeRGBColor; break;
230  case 32: m_header.mode = ImageModeRGBA; break;
231  case 48: m_header.mode = ImageModeRGB48; break;
232  default: m_header.mode = ImageModeRGBColor; break;
233  }
234  }
235  if (!m_header.bpp) {
236  // undefined bpp
237  switch(m_header.mode) {
238  case ImageModeBitmap:
239  m_header.bpp = 1;
240  break;
242  case ImageModeGrayScale:
243  m_header.bpp = 8;
244  break;
245  case ImageModeRGB12:
246  m_header.bpp = 12;
247  break;
248  case ImageModeRGB16:
249  case ImageModeGray16:
250  m_header.bpp = 16;
251  break;
252  case ImageModeRGBColor:
253  case ImageModeLabColor:
254  m_header.bpp = 24;
255  break;
256  case ImageModeRGBA:
257  case ImageModeCMYKColor:
258  case ImageModeGray32:
259  m_header.bpp = 32;
260  break;
261  case ImageModeRGB48:
262  case ImageModeLab48:
263  m_header.bpp = 48;
264  break;
265  case ImageModeCMYK64:
266  m_header.bpp = 64;
267  break;
268  default:
269  ASSERT(false);
270  m_header.bpp = 24;
271  }
272  }
273  if (m_header.mode == ImageModeRGBColor && m_header.bpp == 32) {
274  // change mode
276  }
277  if (m_header.mode == ImageModeBitmap && m_header.bpp != 1) return false;
278  if (m_header.mode == ImageModeIndexedColor && m_header.bpp != 8) return false;
279  if (m_header.mode == ImageModeGrayScale && m_header.bpp != 8) return false;
280  if (m_header.mode == ImageModeGray16 && m_header.bpp != 16) return false;
281  if (m_header.mode == ImageModeGray32 && m_header.bpp != 32) return false;
282  if (m_header.mode == ImageModeRGBColor && m_header.bpp != 24) return false;
283  if (m_header.mode == ImageModeRGBA && m_header.bpp != 32) return false;
284  if (m_header.mode == ImageModeRGB12 && m_header.bpp != 12) return false;
285  if (m_header.mode == ImageModeRGB16 && m_header.bpp != 16) return false;
286  if (m_header.mode == ImageModeRGB48 && m_header.bpp != 48) return false;
287  if (m_header.mode == ImageModeLabColor && m_header.bpp != 24) return false;
288  if (m_header.mode == ImageModeLab48 && m_header.bpp != 48) return false;
289  if (m_header.mode == ImageModeCMYKColor && m_header.bpp != 32) return false;
290  if (m_header.mode == ImageModeCMYK64 && m_header.bpp != 64) return false;
291 
292  // set number of channels
293  if (!m_header.channels) {
294  switch(m_header.mode) {
295  case ImageModeBitmap:
297  case ImageModeGrayScale:
298  case ImageModeGray16:
299  case ImageModeGray32:
300  m_header.channels = 1;
301  break;
302  case ImageModeRGBColor:
303  case ImageModeRGB12:
304  case ImageModeRGB16:
305  case ImageModeRGB48:
306  case ImageModeLabColor:
307  case ImageModeLab48:
308  m_header.channels = 3;
309  break;
310  case ImageModeRGBA:
311  case ImageModeCMYKColor:
312  case ImageModeCMYK64:
313  m_header.channels = 4;
314  break;
315  default:
316  return false;
317  }
318  }
319 
320  // store used bits per channel
321  UINT8 bpc = m_header.bpp/m_header.channels;
322  if (bpc > 31) bpc = 31;
325  }
326 
327  return true;
328 }
329 
337 const UINT8* CPGFImage::GetUserData(UINT32& cachedSize, UINT32* pTotalSize /*= nullptr*/) const {
338  cachedSize = m_postHeader.cachedUserDataLen;
339  if (pTotalSize) *pTotalSize = m_postHeader.userDataLen;
340  return m_postHeader.userData;
341 }
342 
348 void CPGFImage::Reconstruct(int level /*= 0*/) {
349  if (m_header.nLevels == 0) {
350  // image didn't use wavelet transform
351  if (level == 0) {
352  for (int i=0; i < m_header.channels; i++) {
353  ASSERT(m_wtChannel[i]);
354  m_channel[i] = m_wtChannel[i]->GetSubband(0, LL)->GetBuffer();
355  }
356  }
357  } else {
358  int currentLevel = m_header.nLevels;
359 
360  #ifdef __PGFROISUPPORT__
361  if (ROIisSupported()) {
362  // enable ROI reading
364  }
365  #endif
366 
367  while (currentLevel > level) {
368  for (int i=0; i < m_header.channels; i++) {
369  ASSERT(m_wtChannel[i]);
370  // dequantize subbands
371  if (currentLevel == m_header.nLevels) {
372  // last level also has LL band
373  m_wtChannel[i]->GetSubband(currentLevel, LL)->Dequantize(m_quant);
374  }
375  m_wtChannel[i]->GetSubband(currentLevel, HL)->Dequantize(m_quant);
376  m_wtChannel[i]->GetSubband(currentLevel, LH)->Dequantize(m_quant);
377  m_wtChannel[i]->GetSubband(currentLevel, HH)->Dequantize(m_quant);
378 
379  // inverse transform from m_wtChannel to m_channel
380  OSError err = m_wtChannel[i]->InverseTransform(currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
381  if (err != NoError) ReturnWithError(err);
382  ASSERT(m_channel[i]);
383  }
384 
385  currentLevel--;
386  }
387  }
388 }
389 
391 // Read and decode some levels of a PGF image at current stream position.
392 // A PGF image is structered in levels, numbered between 0 and Levels() - 1.
393 // Each level can be seen as a single image, containing the same content
394 // as all other levels, but in a different size (width, height).
395 // The image size at level i is double the size (width, height) of the image at level i+1.
396 // The image at level 0 contains the original size.
397 // Precondition: The PGF image has been opened with a call of Open(...).
398 // It might throw an IOException.
399 // @param level The image level of the resulting image in the internal image buffer.
400 // @param cb A pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding.
401 // @param data Data Pointer to C++ class container to host callback procedure.
402 void CPGFImage::Read(int level /*= 0*/, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) {
403  ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
404  ASSERT(m_decoder);
405 
406 #ifdef __PGFROISUPPORT__
407  if (ROIisSupported() && m_header.nLevels > 0) {
408  // new encoding scheme supporting ROI
409  PGFRect rect(0, 0, m_header.width, m_header.height);
410  Read(rect, level, cb, data);
411  return;
412  }
413 #endif
414 
415  if (m_header.nLevels == 0) {
416  if (level == 0) {
417  // the data has already been read during open
418  // now update progress
419  if (cb) {
420  if ((*cb)(1.0, true, data)) ReturnWithError(EscapePressed);
421  }
422  }
423  } else {
424  const int levelDiff = m_currentLevel - level;
425  double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
426 
427  // encoding scheme without ROI
428  while (m_currentLevel > level) {
429  for (int i=0; i < m_header.channels; i++) {
430  CWaveletTransform* wtChannel = m_wtChannel[i];
431  ASSERT(wtChannel);
432 
433  // decode file and write stream to m_wtChannel
434  if (m_currentLevel == m_header.nLevels) {
435  // last level also has LL band
437  }
438  if (m_preHeader.version & Version5) {
439  // since version 5
442  } else {
443  // until version 4
445  }
447  }
448 
449  volatile OSError error = NoError; // volatile prevents optimizations
450 #ifdef LIBPGF_USE_OPENMP
451  #pragma omp parallel for default(shared)
452 #endif
453  for (int i=0; i < m_header.channels; i++) {
454  // inverse transform from m_wtChannel to m_channel
455  if (error == NoError) {
456  OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
457  if (err != NoError) error = err;
458  }
459  ASSERT(m_channel[i]);
460  }
461  if (error != NoError) ReturnWithError(error);
462 
463  // set new level: must be done before refresh callback
464  m_currentLevel--;
465 
466  // now we have to refresh the display
467  if (m_cb) m_cb(m_cbArg);
468 
469  // now update progress
470  if (cb) {
471  percent *= 4;
472  if (m_progressMode == PM_Absolute) m_percent = percent;
473  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
474  }
475  }
476  }
477 }
478 
479 #ifdef __PGFROISUPPORT__
480 void CPGFImage::Read(PGFRect& rect, int level /*= 0*/, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) {
490  ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
491  ASSERT(m_decoder);
492 
493  if (m_header.nLevels == 0 || !ROIisSupported()) {
494  rect.left = rect.top = 0;
495  rect.right = m_header.width; rect.bottom = m_header.height;
496  Read(level, cb, data);
497  } else {
498  ASSERT(ROIisSupported());
499  // new encoding scheme supporting ROI
500  ASSERT(rect.left < m_header.width && rect.top < m_header.height);
501 
502  // check rectangle
503  if (rect.right == 0 || rect.right > m_header.width) rect.right = m_header.width;
504  if (rect.bottom == 0 || rect.bottom > m_header.height) rect.bottom = m_header.height;
505 
506  const int levelDiff = m_currentLevel - level;
507  double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
508 
509  // check level difference
510  if (levelDiff <= 0) {
511  // it is a new read call, probably with a new ROI
514  }
515 
516  // enable ROI decoding and reading
517  SetROI(rect);
518 
519  while (m_currentLevel > level) {
520  for (int i=0; i < m_header.channels; i++) {
521  CWaveletTransform* wtChannel = m_wtChannel[i];
522  ASSERT(wtChannel);
523 
524  // get number of tiles and tile indices
525  const UINT32 nTiles = wtChannel->GetNofTiles(m_currentLevel); // independent of ROI
526 
527  // decode file and write stream to m_wtChannel
528  if (m_currentLevel == m_header.nLevels) { // last level also has LL band
529  ASSERT(nTiles == 1);
532  }
533  for (UINT32 tileY=0; tileY < nTiles; tileY++) {
534  for (UINT32 tileX=0; tileX < nTiles; tileX++) {
535  // check relevance of tile
536  if (wtChannel->TileIsRelevant(m_currentLevel, tileX, tileY)) {
538  wtChannel->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
539  wtChannel->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
540  wtChannel->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
541  } else {
542  // skip tile
543  m_decoder->SkipTileBuffer();
544  }
545  }
546  }
547  }
548 
549  volatile OSError error = NoError; // volatile prevents optimizations
550 #ifdef LIBPGF_USE_OPENMP
551  #pragma omp parallel for default(shared)
552 #endif
553  for (int i=0; i < m_header.channels; i++) {
554  // inverse transform from m_wtChannel to m_channel
555  if (error == NoError) {
556  OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
557  if (err != NoError) error = err;
558  }
559  ASSERT(m_channel[i]);
560  }
561  if (error != NoError) ReturnWithError(error);
562 
563  // set new level: must be done before refresh callback
564  m_currentLevel--;
565 
566  // now we have to refresh the display
567  if (m_cb) m_cb(m_cbArg);
568 
569  // now update progress
570  if (cb) {
571  percent *= 4;
572  if (m_progressMode == PM_Absolute) m_percent = percent;
573  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
574  }
575  }
576  }
577 }
578 
584  if (m_currentLevel == 0) {
585  return m_roi;
586  } else {
587  const UINT32 rLeft = LevelSizeL(m_roi.left, m_currentLevel);
588  const UINT32 rRight = LevelSizeL(m_roi.right, m_currentLevel);
589  const UINT32 rTop = LevelSizeL(m_roi.top, m_currentLevel);
590  const UINT32 rBottom = LevelSizeL(m_roi.bottom, m_currentLevel);
591  return PGFRect(rLeft, rTop, rRight - rLeft, rBottom - rTop);
592  }
593 }
594 
598 PGFRect CPGFImage::GetAlignedROI(int c /*= 0*/) const {
599  PGFRect roi(0, 0, m_width[c], m_height[c]);
600 
601  if (ROIisSupported()) {
602  ASSERT(m_wtChannel[c]);
603 
604  roi = m_wtChannel[c]->GetAlignedROI(m_currentLevel);
605  }
606  ASSERT(roi.Width() == m_width[c]);
607  ASSERT(roi.Height() == m_height[c]);
608  return roi;
609 }
610 
615 void CPGFImage::SetROI(PGFRect rect) {
616  ASSERT(m_decoder);
617  ASSERT(ROIisSupported());
618  ASSERT(m_wtChannel[0]);
619 
620  // store ROI for a later call of GetBitmap
621  m_roi = rect;
622 
623  // enable ROI decoding
624  m_decoder->SetROI();
625 
626  // prepare wavelet channels for using ROI
627  m_wtChannel[0]->SetROI(rect);
628 
629  if (m_downsample && m_header.channels > 1) {
630  // all further channels are downsampled, therefore downsample ROI
631  rect.left >>= 1;
632  rect.top >>= 1;
633  rect.right = (rect.right + 1) >> 1;
634  rect.bottom = (rect.bottom + 1) >> 1;
635  }
636  for (int i=1; i < m_header.channels; i++) {
637  ASSERT(m_wtChannel[i]);
638  m_wtChannel[i]->SetROI(rect);
639  }
640 }
641 
642 #endif // __PGFROISUPPORT__
643 
649  ASSERT(m_decoder);
651 }
652 
660 UINT32 CPGFImage::ReadEncodedHeader(UINT8* target, UINT32 targetLen) const {
661  ASSERT(target);
662  ASSERT(targetLen > 0);
663  ASSERT(m_decoder);
664 
665  // reset stream position
667 
668  // compute number of bytes to read
669  UINT32 len = __min(targetLen, GetEncodedHeaderLength());
670 
671  // read data
672  len = m_decoder->ReadEncodedData(target, len);
673  ASSERT(len >= 0 && len <= targetLen);
674 
675  return len;
676 }
677 
682 void CPGFImage::ResetStreamPos(bool startOfData) {
683  m_currentLevel = 0;
684  if (startOfData) {
685  ASSERT(m_decoder);
687  } else {
688  if (m_decoder) {
690  } else if (m_encoder) {
692  } else {
693  ASSERT(false);
694  }
695  }
696 }
697 
707 UINT32 CPGFImage::ReadEncodedData(int level, UINT8* target, UINT32 targetLen) const {
708  ASSERT(level >= 0 && level < m_header.nLevels);
709  ASSERT(target);
710  ASSERT(targetLen > 0);
711  ASSERT(m_decoder);
712 
713  // reset stream position
715 
716  // position stream
717  UINT64 offset = 0;
718 
719  for (int i=m_header.nLevels - 1; i > level; i--) {
720  offset += m_levelLength[m_header.nLevels - 1 - i];
721  }
722  m_decoder->Skip(offset);
723 
724  // compute number of bytes to read
725  UINT32 len = __min(targetLen, GetEncodedLevelLength(level));
726 
727  // read data
728  len = m_decoder->ReadEncodedData(target, len);
729  ASSERT(len >= 0 && len <= targetLen);
730 
731  return len;
732 }
733 
738 void CPGFImage::SetMaxValue(UINT32 maxValue) {
739  const BYTE bpc = m_header.bpp/m_header.channels;
740  BYTE pot = 0;
741 
742  while(maxValue > 0) {
743  pot++;
744  maxValue >>= 1;
745  }
746  // store bits per channel
747  if (pot > bpc) pot = bpc;
748  if (pot > 31) pot = 31;
750 }
751 
757  const BYTE bpc = m_header.bpp/m_header.channels;
758 
759  if (bpc > 8) {
761  } else {
762  return bpc;
763  }
764 }
765 
768 BYTE CPGFImage::CodecMajorVersion(BYTE version) {
769  if (version & Version7) return 7;
770  if (version & Version6) return 6;
771  if (version & Version5) return 5;
772  if (version & Version2) return 2;
773  return 1;
774 }
775 
777 // Import an image from a specified image buffer.
778 // This method is usually called before Write(...) and after SetHeader(...).
779 // It might throw an IOException.
780 // The absolute value of pitch is the number of bytes of an image row.
781 // If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row).
782 // If pitch is positive, then buff points to the first row of a top-down image (first byte).
783 // The sequence of input channels in the input image buffer does not need to be the same as expected from PGF. In case of different sequences you have to
784 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
785 // If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
786 // @param pitch The number of bytes of a row of the image buffer.
787 // @param buff An image buffer.
788 // @param bpp The number of bits per pixel used in image buffer.
789 // @param channelMap A integer array containing the mapping of input channel ordering to expected channel ordering.
790 // @param cb A pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding.
791 // @param data Data Pointer to C++ class container to host callback procedure.
792 void CPGFImage::ImportBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[] /*= nullptr */, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) {
793  ASSERT(buff);
794  ASSERT(m_channel[0]);
795 
796  // color transform
797  RgbToYuv(pitch, buff, bpp, channelMap, cb, data);
798 
799  if (m_downsample) {
800  // Subsampling of the chrominance and alpha channels
801  for (int i=1; i < m_header.channels; i++) {
802  Downsample(i);
803  }
804  }
805 }
806 
808 // Bilinerar Subsampling of channel ch by a factor 2
809 // Called before Write()
810 void CPGFImage::Downsample(int ch) {
811  ASSERT(ch > 0);
812 
813  const int w = m_width[0];
814  const int w2 = w/2;
815  const int h2 = m_height[0]/2;
816  const int oddW = w%2; // don't use bool -> problems with MaxSpeed optimization
817  const int oddH = m_height[0]%2; // "
818  int loPos = 0;
819  int hiPos = w;
820  int sampledPos = 0;
821  DataT* buff = m_channel[ch]; ASSERT(buff);
822 
823  for (int i=0; i < h2; i++) {
824  for (int j=0; j < w2; j++) {
825  // compute average of pixel block
826  buff[sampledPos] = (buff[loPos] + buff[loPos + 1] + buff[hiPos] + buff[hiPos + 1]) >> 2;
827  loPos += 2; hiPos += 2;
828  sampledPos++;
829  }
830  if (oddW) {
831  buff[sampledPos] = (buff[loPos] + buff[hiPos]) >> 1;
832  loPos++; hiPos++;
833  sampledPos++;
834  }
835  loPos += w; hiPos += w;
836  }
837  if (oddH) {
838  for (int j=0; j < w2; j++) {
839  buff[sampledPos] = (buff[loPos] + buff[loPos+1]) >> 1;
840  loPos += 2; hiPos += 2;
841  sampledPos++;
842  }
843  if (oddW) {
844  buff[sampledPos] = buff[loPos];
845  }
846  }
847 
848  // downsampled image has half width and half height
849  m_width[ch] = (m_width[ch] + 1)/2;
850  m_height[ch] = (m_height[ch] + 1)/2;
851 }
852 
855  const int maxThumbnailWidth = 20*FilterSize;
856  const int m = __min(m_header.width, m_header.height);
857  int s = m;
858 
859  if (m_header.nLevels < 1 || m_header.nLevels > MaxLevel) {
860  m_header.nLevels = 1;
861  // compute a good value depending on the size of the image
862  while (s > maxThumbnailWidth) {
863  m_header.nLevels++;
864  s >>= 1;
865  }
866  }
867 
868  int levels = m_header.nLevels; // we need a signed value during level reduction
869 
870  // reduce number of levels if the image size is smaller than FilterSize*(2^levels)
871  s = FilterSize*(1 << levels); // must be at least the double filter size because of subsampling
872  while (m < s) {
873  levels--;
874  s >>= 1;
875  }
876  if (levels > MaxLevel) m_header.nLevels = MaxLevel;
877  else if (levels < 0) m_header.nLevels = 0;
878  else m_header.nLevels = (UINT8)levels;
879 
880  // used in Write when PM_Absolute
881  m_percent = pow(0.25, m_header.nLevels);
882 
883  ASSERT(0 <= m_header.nLevels && m_header.nLevels <= MaxLevel);
884 }
885 
894 void CPGFImage::SetHeader(const PGFHeader& header, BYTE flags /*=0*/, const UINT8* userData /*= 0*/, UINT32 userDataLength /*= 0*/) {
895  ASSERT(!m_decoder); // current image must be closed
896  ASSERT(header.quality <= MaxQuality);
897  ASSERT(userDataLength <= MaxUserDataSize);
898 
899  // init state
900 #ifdef __PGFROISUPPORT__
901  m_streamReinitialized = false;
902 #endif
903 
904  // init preHeader
905  memcpy(m_preHeader.magic, PGFMagic, 3);
906  m_preHeader.version = PGFVersion | flags;
908 
909  // copy header
910  memcpy(&m_header, &header, HeaderSize);
911 
912  // check quality
914 
915  // complete header
916  CompleteHeader();
917 
918  // check and set number of levels
919  ComputeLevels();
920 
921  // check for downsample
929  m_downsample = true;
930  m_quant = m_header.quality - 1;
931  } else {
932  m_downsample = false;
934  }
935 
936  // update header size and copy user data
938  // update header size
940  }
941  if (userDataLength && userData) {
942  if (userDataLength > MaxUserDataSize) userDataLength = MaxUserDataSize;
943  m_postHeader.userData = new(std::nothrow) UINT8[userDataLength];
944  if (!m_postHeader.userData) ReturnWithError(InsufficientMemory);
946  memcpy(m_postHeader.userData, userData, userDataLength);
947  // update header size
948  m_preHeader.hSize += userDataLength;
949  }
950 
951  // allocate channels
952  for (int i=0; i < m_header.channels; i++) {
953  // set current width and height
954  m_width[i] = m_header.width;
955  m_height[i] = m_header.height;
956 
957  // allocate channels
958  ASSERT(!m_channel[i]);
959  m_channel[i] = new(std::nothrow) DataT[m_header.width*m_header.height];
960  if (!m_channel[i]) {
961  if (i) i--;
962  while(i) {
963  delete[] m_channel[i]; m_channel[i] = 0;
964  i--;
965  }
966  ReturnWithError(InsufficientMemory);
967  }
968  }
969 }
970 
980  ASSERT(m_header.nLevels <= MaxLevel);
981  ASSERT(m_header.quality <= MaxQuality); // quality is already initialized
982 
983  if (m_header.nLevels > 0) {
984  volatile OSError error = NoError; // volatile prevents optimizations
985  // create new wt channels
986 #ifdef LIBPGF_USE_OPENMP
987  #pragma omp parallel for default(shared)
988 #endif
989  for (int i=0; i < m_header.channels; i++) {
990  DataT *temp = nullptr;
991  if (error == NoError) {
992  if (m_wtChannel[i]) {
993  ASSERT(m_channel[i]);
994  // copy m_channel to temp
995  int size = m_height[i]*m_width[i];
996  temp = new(std::nothrow) DataT[size];
997  if (temp) {
998  memcpy(temp, m_channel[i], size*DataTSize);
999  delete m_wtChannel[i]; // also deletes m_channel
1000  m_channel[i] = nullptr;
1001  } else {
1002  error = InsufficientMemory;
1003  }
1004  }
1005  if (error == NoError) {
1006  if (temp) {
1007  ASSERT(!m_channel[i]);
1008  m_channel[i] = temp;
1009  }
1011  if (m_wtChannel[i]) {
1012  #ifdef __PGFROISUPPORT__
1013  m_wtChannel[i]->SetROI(PGFRect(0, 0, m_width[i], m_height[i]));
1014  #endif
1015 
1016  // wavelet subband decomposition
1017  for (int l=0; error == NoError && l < m_header.nLevels; l++) {
1018  OSError err = m_wtChannel[i]->ForwardTransform(l, m_quant);
1019  if (err != NoError) error = err;
1020  }
1021  } else {
1022  delete[] m_channel[i];
1023  error = InsufficientMemory;
1024  }
1025  }
1026  }
1027  }
1028  if (error != NoError) {
1029  // free already allocated memory
1030  for (int i=0; i < m_header.channels; i++) {
1031  delete m_wtChannel[i];
1032  }
1033  ReturnWithError(error);
1034  }
1035 
1037 
1038  // create encoder, write headers and user data, but not level-length area
1041 
1042  #ifdef __PGFROISUPPORT__
1043  if (ROIisSupported()) {
1044  // new encoding scheme supporting ROI
1045  m_encoder->SetROI();
1046  }
1047  #endif
1048 
1049  } else {
1050  // very small image: we don't use DWT and encoding
1051 
1052  // create encoder, write headers and user data, but not level-length area
1054  }
1055 
1056  INT64 nBytes = m_encoder->ComputeHeaderLength();
1057  return (nBytes > 0) ? (UINT32)nBytes : 0;
1058 }
1059 
1061 // Encode and write next level of a PGF image at current stream position.
1062 // A PGF image is structered in levels, numbered between 0 and Levels() - 1.
1063 // Each level can be seen as a single image, containing the same content
1064 // as all other levels, but in a different size (width, height).
1065 // The image size at level i is double the size (width, height) of the image at level i+1.
1066 // The image at level 0 contains the original size.
1067 // It might throw an IOException.
1069  ASSERT(m_encoder);
1070  ASSERT(m_currentLevel > 0);
1071  ASSERT(m_header.nLevels > 0);
1072 
1073 #ifdef __PGFROISUPPORT__
1074  if (ROIisSupported()) {
1075  const int lastChannel = m_header.channels - 1;
1076 
1077  for (int i=0; i < m_header.channels; i++) {
1078  // get number of tiles and tile indices
1079  const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel);
1080  const UINT32 lastTile = nTiles - 1;
1081 
1082  if (m_currentLevel == m_header.nLevels) {
1083  // last level also has LL band
1084  ASSERT(nTiles == 1);
1086  m_encoder->EncodeTileBuffer(); // encode macro block with tile-end = true
1087  }
1088  for (UINT32 tileY=0; tileY < nTiles; tileY++) {
1089  for (UINT32 tileX=0; tileX < nTiles; tileX++) {
1090  // extract tile to macro block and encode already filled macro blocks with tile-end = false
1091  m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, true, tileX, tileY);
1092  m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, true, tileX, tileY);
1093  m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, true, tileX, tileY);
1094  if (i == lastChannel && tileY == lastTile && tileX == lastTile) {
1095  // all necessary data are buffered. next call of EncodeTileBuffer will write the last piece of data of the current level.
1097  }
1098  m_encoder->EncodeTileBuffer(); // encode last macro block with tile-end = true
1099  }
1100  }
1101  }
1102  } else
1103 #endif
1104  {
1105  for (int i=0; i < m_header.channels; i++) {
1106  ASSERT(m_wtChannel[i]);
1107  if (m_currentLevel == m_header.nLevels) {
1108  // last level also has LL band
1110  }
1111  //encoder.EncodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); // until version 4
1112  m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder); // since version 5
1113  m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder); // since version 5
1115  }
1116 
1117  // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level.
1119  }
1120 }
1121 
1123 // Return written levelLength bytes
1125  ASSERT(m_encoder);
1126 
1127  INT64 offset = m_encoder->ComputeOffset(); ASSERT(offset >= 0);
1128 
1129  if (offset > 0) {
1130  // update post-header size and rewrite pre-header
1131  m_preHeader.hSize += (UINT32)offset;
1133  }
1134 
1135  // write dummy levelLength into stream
1137 }
1138 
1150 UINT32 CPGFImage::WriteImage(CPGFStream* stream, CallbackPtr cb /*= nullptr*/, void *data /*= nullptr*/) {
1151  ASSERT(stream);
1152  ASSERT(m_preHeader.hSize);
1153 
1154  int levels = m_header.nLevels;
1155  double percent = pow(0.25, levels);
1156 
1157  // update post-header size, rewrite pre-header, and write dummy levelLength
1158  UINT32 nWrittenBytes = UpdatePostHeaderSize();
1159 
1160  if (levels == 0) {
1161  // for very small images: write channels uncoded
1162  for (int c=0; c < m_header.channels; c++) {
1163  const UINT32 size = m_width[c]*m_height[c];
1164 
1165  // write channel data into stream
1166  for (UINT32 i=0; i < size; i++) {
1167  int count = DataTSize;
1168  stream->Write(&count, &m_channel[c][i]);
1169  }
1170  }
1171 
1172  // now update progress
1173  if (cb) {
1174  if ((*cb)(1, true, data)) ReturnWithError(EscapePressed);
1175  }
1176 
1177  } else {
1178  // encode quantized wavelet coefficients and write to PGF file
1179  // encode subbands, higher levels first
1180  // color channels are interleaved
1181 
1182  // encode all levels
1183  for (m_currentLevel = levels; m_currentLevel > 0; ) {
1184  WriteLevel(); // decrements m_currentLevel
1185 
1186  // now update progress
1187  if (cb) {
1188  percent *= 4;
1189  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1190  }
1191  }
1192 
1193  // flush encoder and write level lengths
1194  m_encoder->Flush();
1195  }
1196 
1197  // update level lengths
1198  nWrittenBytes += m_encoder->UpdateLevelLength(); // return written image bytes
1199 
1200  // delete encoder
1201  delete m_encoder; m_encoder = nullptr;
1202 
1203  ASSERT(!m_encoder);
1204 
1205  return nWrittenBytes;
1206 }
1207 
1221 void CPGFImage::Write(CPGFStream* stream, UINT32* nWrittenBytes /*= nullptr*/, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) {
1222  ASSERT(stream);
1223  ASSERT(m_preHeader.hSize);
1224 
1225  // create wavelet transform channels and encoder
1226  UINT32 nBytes = WriteHeader(stream);
1227 
1228  // write image
1229  nBytes += WriteImage(stream, cb, data);
1230 
1231  // return written bytes
1232  if (nWrittenBytes) *nWrittenBytes += nBytes;
1233 }
1234 
1235 #ifdef __PGFROISUPPORT__
1236 // Encode and write down to given level at current stream position.
1238 // A PGF image is structered in levels, numbered between 0 and Levels() - 1.
1239 // Each level can be seen as a single image, containing the same content
1240 // as all other levels, but in a different size (width, height).
1241 // The image size at level i is double the size (width, height) of the image at level i+1.
1242 // The image at level 0 contains the original size.
1243 // Precondition: the PGF image contains a valid header (see also SetHeader(...)) and WriteHeader() has been called before.
1244 // The ROI encoding scheme is used.
1245 // It might throw an IOException.
1246 // @param level The image level of the resulting image in the internal image buffer.
1247 // @param cb A pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
1248 // @param data Data Pointer to C++ class container to host callback procedure.
1249 // @return The number of bytes written into stream.
1250 UINT32 CPGFImage::Write(int level, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) {
1251  ASSERT(m_header.nLevels > 0);
1252  ASSERT(0 <= level && level < m_header.nLevels);
1253  ASSERT(m_encoder);
1254  ASSERT(ROIisSupported());
1255 
1256  const int levelDiff = m_currentLevel - level;
1257  double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
1258  UINT32 nWrittenBytes = 0;
1259 
1260  if (m_currentLevel == m_header.nLevels) {
1261  // update post-header size, rewrite pre-header, and write dummy levelLength
1262  nWrittenBytes = UpdatePostHeaderSize();
1263  } else {
1264  // prepare for next level: save current file position, because the stream might have been reinitialized
1265  if (m_encoder->ComputeBufferLength()) {
1266  m_streamReinitialized = true;
1267  }
1268  }
1269 
1270  // encoding scheme with ROI
1271  while (m_currentLevel > level) {
1272  WriteLevel(); // decrements m_currentLevel
1273 
1274  if (m_levelLength) {
1275  nWrittenBytes += m_levelLength[m_header.nLevels - m_currentLevel - 1];
1276  }
1277 
1278  // now update progress
1279  if (cb) {
1280  percent *= 4;
1281  if (m_progressMode == PM_Absolute) m_percent = percent;
1282  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1283  }
1284  }
1285 
1286  // automatically closing
1287  if (m_currentLevel == 0) {
1288  if (!m_streamReinitialized) {
1289  // don't write level lengths, if the stream position changed inbetween two Write operations
1291  }
1292  // delete encoder
1293  delete m_encoder; m_encoder = nullptr;
1294  }
1295 
1296  return nWrittenBytes;
1297 }
1298 #endif // __PGFROISUPPORT__
1299 
1300 
1302 // Check for valid import image mode.
1303 // @param mode Image mode
1304 // @return True if an image of given mode can be imported with ImportBitmap(...)
1306  size_t size = DataTSize;
1307 
1308  if (size >= 2) {
1309  switch(mode) {
1310  case ImageModeBitmap:
1311  case ImageModeIndexedColor:
1312  case ImageModeGrayScale:
1313  case ImageModeRGBColor:
1314  case ImageModeCMYKColor:
1315  case ImageModeHSLColor:
1316  case ImageModeHSBColor:
1317  //case ImageModeDuotone:
1318  case ImageModeLabColor:
1319  case ImageModeRGB12:
1320  case ImageModeRGB16:
1321  case ImageModeRGBA:
1322  return true;
1323  }
1324  }
1325  if (size >= 3) {
1326  switch(mode) {
1327  case ImageModeGray16:
1328  case ImageModeRGB48:
1329  case ImageModeLab48:
1330  case ImageModeCMYK64:
1331  //case ImageModeDuotone16:
1332  return true;
1333  }
1334  }
1335  if (size >=4) {
1336  switch(mode) {
1337  case ImageModeGray32:
1338  return true;
1339  }
1340  }
1341  return false;
1342 }
1343 
1350 void CPGFImage::GetColorTable(UINT32 iFirstColor, UINT32 nColors, RGBQUAD* prgbColors) const {
1351  if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError);
1352 
1353  for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
1354  prgbColors[j] = m_postHeader.clut[i];
1355  }
1356 }
1357 
1364 void CPGFImage::SetColorTable(UINT32 iFirstColor, UINT32 nColors, const RGBQUAD* prgbColors) {
1365  if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError);
1366 
1367  for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
1368  m_postHeader.clut[i] = prgbColors[j];
1369  }
1370 }
1371 
1373 // Buffer transform from interleaved to channel seperated format
1374 // the absolute value of pitch is the number of bytes of an image row
1375 // if pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row)
1376 // if pitch is positive, then buff points to the first row of a top-down image (first byte)
1377 // bpp is the number of bits per pixel used in image buffer buff
1378 //
1379 // RGB is transformed into YUV format (ordering of buffer data is BGR[A])
1380 // Y = (R + 2*G + B)/4 -128
1381 // U = R - G
1382 // V = B - G
1383 //
1384 // Since PGF Codec version 2.0 images are stored in top-down direction
1385 //
1386 // The sequence of input channels in the input image buffer does not need to be the same as expected from PGF. In case of different sequences you have to
1387 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
1388 // If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
1389 void CPGFImage::RgbToYuv(int pitch, UINT8* buff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data /*=nullptr*/) {
1390  ASSERT(buff);
1391  UINT32 yPos = 0, cnt = 0;
1392  double percent = 0;
1393  const double dP = 1.0/m_header.height;
1394  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
1395 
1396  if (channelMap == nullptr) channelMap = defMap;
1397 
1398  switch(m_header.mode) {
1399  case ImageModeBitmap:
1400  {
1401  ASSERT(m_header.channels == 1);
1402  ASSERT(m_header.bpp == 1);
1403  ASSERT(bpp == 1);
1404 
1405  const UINT32 w = m_header.width;
1406  const UINT32 w2 = (m_header.width + 7)/8;
1407  DataT* y = m_channel[0]; ASSERT(y);
1408 
1409  // new unpacked version since version 7
1410  for (UINT32 h = 0; h < m_header.height; h++) {
1411  if (cb) {
1412  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1413  percent += dP;
1414  }
1415  cnt = 0;
1416  for (UINT32 j = 0; j < w2; j++) {
1417  UINT8 byte = buff[j];
1418  for (int k = 0; k < 8; k++) {
1419  UINT8 bit = (byte & 0x80) >> 7;
1420  if (cnt < w) y[yPos++] = bit;
1421  byte <<= 1;
1422  cnt++;
1423  }
1424  }
1425  buff += pitch;
1426  }
1427  /* old version: packed values: 8 pixels in 1 byte
1428  for (UINT32 h = 0; h < m_header.height; h++) {
1429  if (cb) {
1430  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1431  percent += dP;
1432  }
1433 
1434  for (UINT32 j = 0; j < w2; j++) {
1435  y[yPos++] = buff[j] - YUVoffset8;
1436  }
1437  // version 5 and 6
1438  // for (UINT32 j = w2; j < w; j++) {
1439  // y[yPos++] = YUVoffset8;
1440  //}
1441  buff += pitch;
1442  }
1443  */
1444  }
1445  break;
1446  case ImageModeIndexedColor:
1447  case ImageModeGrayScale:
1448  case ImageModeHSLColor:
1449  case ImageModeHSBColor:
1450  case ImageModeLabColor:
1451  {
1452  ASSERT(m_header.channels >= 1);
1453  ASSERT(m_header.bpp == m_header.channels*8);
1454  ASSERT(bpp%8 == 0);
1455  const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1456 
1457  for (UINT32 h=0; h < m_header.height; h++) {
1458  if (cb) {
1459  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1460  percent += dP;
1461  }
1462 
1463  cnt = 0;
1464  for (UINT32 w=0; w < m_header.width; w++) {
1465  for (int c=0; c < m_header.channels; c++) {
1466  m_channel[c][yPos] = buff[cnt + channelMap[c]] - YUVoffset8;
1467  }
1468  cnt += channels;
1469  yPos++;
1470  }
1471  buff += pitch;
1472  }
1473  }
1474  break;
1475  case ImageModeGray16:
1476  case ImageModeLab48:
1477  {
1478  ASSERT(m_header.channels >= 1);
1479  ASSERT(m_header.bpp == m_header.channels*16);
1480  ASSERT(bpp%16 == 0);
1481 
1482  UINT16 *buff16 = (UINT16 *)buff;
1483  const int pitch16 = pitch/2;
1484  const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1485  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1486  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1487 
1488  for (UINT32 h=0; h < m_header.height; h++) {
1489  if (cb) {
1490  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1491  percent += dP;
1492  }
1493 
1494  cnt = 0;
1495  for (UINT32 w=0; w < m_header.width; w++) {
1496  for (int c=0; c < m_header.channels; c++) {
1497  m_channel[c][yPos] = (buff16[cnt + channelMap[c]] >> shift) - yuvOffset16;
1498  }
1499  cnt += channels;
1500  yPos++;
1501  }
1502  buff16 += pitch16;
1503  }
1504  }
1505  break;
1506  case ImageModeRGBColor:
1507  {
1508  ASSERT(m_header.channels == 3);
1509  ASSERT(m_header.bpp == m_header.channels*8);
1510  ASSERT(bpp%8 == 0);
1511 
1512  DataT* y = m_channel[0]; ASSERT(y);
1513  DataT* u = m_channel[1]; ASSERT(u);
1514  DataT* v = m_channel[2]; ASSERT(v);
1515  const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1516  UINT8 b, g, r;
1517 
1518  for (UINT32 h=0; h < m_header.height; h++) {
1519  if (cb) {
1520  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1521  percent += dP;
1522  }
1523 
1524  cnt = 0;
1525  for (UINT32 w=0; w < m_header.width; w++) {
1526  b = buff[cnt + channelMap[0]];
1527  g = buff[cnt + channelMap[1]];
1528  r = buff[cnt + channelMap[2]];
1529  // Yuv
1530  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
1531  u[yPos] = r - g;
1532  v[yPos] = b - g;
1533  yPos++;
1534  cnt += channels;
1535  }
1536  buff += pitch;
1537  }
1538  }
1539  break;
1540  case ImageModeRGB48:
1541  {
1542  ASSERT(m_header.channels == 3);
1543  ASSERT(m_header.bpp == m_header.channels*16);
1544  ASSERT(bpp%16 == 0);
1545 
1546  UINT16 *buff16 = (UINT16 *)buff;
1547  const int pitch16 = pitch/2;
1548  const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1549  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1550  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1551 
1552  DataT* y = m_channel[0]; ASSERT(y);
1553  DataT* u = m_channel[1]; ASSERT(u);
1554  DataT* v = m_channel[2]; ASSERT(v);
1555  UINT16 b, g, r;
1556 
1557  for (UINT32 h=0; h < m_header.height; h++) {
1558  if (cb) {
1559  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1560  percent += dP;
1561  }
1562 
1563  cnt = 0;
1564  for (UINT32 w=0; w < m_header.width; w++) {
1565  b = buff16[cnt + channelMap[0]] >> shift;
1566  g = buff16[cnt + channelMap[1]] >> shift;
1567  r = buff16[cnt + channelMap[2]] >> shift;
1568  // Yuv
1569  y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
1570  u[yPos] = r - g;
1571  v[yPos] = b - g;
1572  yPos++;
1573  cnt += channels;
1574  }
1575  buff16 += pitch16;
1576  }
1577  }
1578  break;
1579  case ImageModeRGBA:
1580  case ImageModeCMYKColor:
1581  {
1582  ASSERT(m_header.channels == 4);
1583  ASSERT(m_header.bpp == m_header.channels*8);
1584  ASSERT(bpp%8 == 0);
1585  const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1586 
1587  DataT* y = m_channel[0]; ASSERT(y);
1588  DataT* u = m_channel[1]; ASSERT(u);
1589  DataT* v = m_channel[2]; ASSERT(v);
1590  DataT* a = m_channel[3]; ASSERT(a);
1591  UINT8 b, g, r;
1592 
1593  for (UINT32 h=0; h < m_header.height; h++) {
1594  if (cb) {
1595  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1596  percent += dP;
1597  }
1598 
1599  cnt = 0;
1600  for (UINT32 w=0; w < m_header.width; w++) {
1601  b = buff[cnt + channelMap[0]];
1602  g = buff[cnt + channelMap[1]];
1603  r = buff[cnt + channelMap[2]];
1604  // Yuv
1605  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
1606  u[yPos] = r - g;
1607  v[yPos] = b - g;
1608  a[yPos++] = buff[cnt + channelMap[3]] - YUVoffset8;
1609  cnt += channels;
1610  }
1611  buff += pitch;
1612  }
1613  }
1614  break;
1615  case ImageModeCMYK64:
1616  {
1617  ASSERT(m_header.channels == 4);
1618  ASSERT(m_header.bpp == m_header.channels*16);
1619  ASSERT(bpp%16 == 0);
1620 
1621  UINT16 *buff16 = (UINT16 *)buff;
1622  const int pitch16 = pitch/2;
1623  const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1624  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1625  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1626 
1627  DataT* y = m_channel[0]; ASSERT(y);
1628  DataT* u = m_channel[1]; ASSERT(u);
1629  DataT* v = m_channel[2]; ASSERT(v);
1630  DataT* a = m_channel[3]; ASSERT(a);
1631  UINT16 b, g, r;
1632 
1633  for (UINT32 h=0; h < m_header.height; h++) {
1634  if (cb) {
1635  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1636  percent += dP;
1637  }
1638 
1639  cnt = 0;
1640  for (UINT32 w=0; w < m_header.width; w++) {
1641  b = buff16[cnt + channelMap[0]] >> shift;
1642  g = buff16[cnt + channelMap[1]] >> shift;
1643  r = buff16[cnt + channelMap[2]] >> shift;
1644  // Yuv
1645  y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
1646  u[yPos] = r - g;
1647  v[yPos] = b - g;
1648  a[yPos++] = (buff16[cnt + channelMap[3]] >> shift) - yuvOffset16;
1649  cnt += channels;
1650  }
1651  buff16 += pitch16;
1652  }
1653  }
1654  break;
1655 #ifdef __PGF32SUPPORT__
1656  case ImageModeGray32:
1657  {
1658  ASSERT(m_header.channels == 1);
1659  ASSERT(m_header.bpp == 32);
1660  ASSERT(bpp == 32);
1661  ASSERT(DataTSize == sizeof(UINT32));
1662 
1663  DataT* y = m_channel[0]; ASSERT(y);
1664 
1665  UINT32 *buff32 = (UINT32 *)buff;
1666  const int pitch32 = pitch/4;
1667  const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1668  const DataT yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
1669 
1670  for (UINT32 h=0; h < m_header.height; h++) {
1671  if (cb) {
1672  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1673  percent += dP;
1674  }
1675 
1676  for (UINT32 w=0; w < m_header.width; w++) {
1677  y[yPos++] = (buff32[w] >> shift) - yuvOffset31;
1678  }
1679  buff32 += pitch32;
1680  }
1681  }
1682  break;
1683 #endif
1684  case ImageModeRGB12:
1685  {
1686  ASSERT(m_header.channels == 3);
1687  ASSERT(m_header.bpp == m_header.channels*4);
1688  ASSERT(bpp == m_header.channels*4);
1689 
1690  DataT* y = m_channel[0]; ASSERT(y);
1691  DataT* u = m_channel[1]; ASSERT(u);
1692  DataT* v = m_channel[2]; ASSERT(v);
1693 
1694  UINT8 rgb = 0, b, g, r;
1695 
1696  for (UINT32 h=0; h < m_header.height; h++) {
1697  if (cb) {
1698  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1699  percent += dP;
1700  }
1701 
1702  cnt = 0;
1703  for (UINT32 w=0; w < m_header.width; w++) {
1704  if (w%2 == 0) {
1705  // even pixel position
1706  rgb = buff[cnt];
1707  b = rgb & 0x0F;
1708  g = (rgb & 0xF0) >> 4;
1709  cnt++;
1710  rgb = buff[cnt];
1711  r = rgb & 0x0F;
1712  } else {
1713  // odd pixel position
1714  b = (rgb & 0xF0) >> 4;
1715  cnt++;
1716  rgb = buff[cnt];
1717  g = rgb & 0x0F;
1718  r = (rgb & 0xF0) >> 4;
1719  cnt++;
1720  }
1721 
1722  // Yuv
1723  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset4;
1724  u[yPos] = r - g;
1725  v[yPos] = b - g;
1726  yPos++;
1727  }
1728  buff += pitch;
1729  }
1730  }
1731  break;
1732  case ImageModeRGB16:
1733  {
1734  ASSERT(m_header.channels == 3);
1735  ASSERT(m_header.bpp == 16);
1736  ASSERT(bpp == 16);
1737 
1738  DataT* y = m_channel[0]; ASSERT(y);
1739  DataT* u = m_channel[1]; ASSERT(u);
1740  DataT* v = m_channel[2]; ASSERT(v);
1741 
1742  UINT16 *buff16 = (UINT16 *)buff;
1743  UINT16 rgb, b, g, r;
1744  const int pitch16 = pitch/2;
1745 
1746  for (UINT32 h=0; h < m_header.height; h++) {
1747  if (cb) {
1748  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1749  percent += dP;
1750  }
1751  for (UINT32 w=0; w < m_header.width; w++) {
1752  rgb = buff16[w];
1753  r = (rgb & 0xF800) >> 10; // highest 5 bits
1754  g = (rgb & 0x07E0) >> 5; // middle 6 bits
1755  b = (rgb & 0x001F) << 1; // lowest 5 bits
1756  // Yuv
1757  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset6;
1758  u[yPos] = r - g;
1759  v[yPos] = b - g;
1760  yPos++;
1761  }
1762 
1763  buff16 += pitch16;
1764  }
1765  }
1766  break;
1767  default:
1768  ASSERT(false);
1769  }
1770 }
1771 
1773 // Get image data in interleaved format: (ordering of RGB data is BGR[A])
1774 // Upsampling, YUV to RGB transform and interleaving are done here to reduce the number
1775 // of passes over the data.
1776 // The absolute value of pitch is the number of bytes of an image row of the given image buffer.
1777 // If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row).
1778 // if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte).
1779 // The sequence of output channels in the output image buffer does not need to be the same as provided by PGF. In case of different sequences you have to
1780 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode.
1781 // If your provided image buffer expects a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
1782 // It might throw an IOException.
1783 // @param pitch The number of bytes of a row of the image buffer.
1784 // @param buff An image buffer.
1785 // @param bpp The number of bits per pixel used in image buffer.
1786 // @param channelMap A integer array containing the mapping of PGF channel ordering to expected channel ordering.
1787 // @param cb A pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding.
1788 // @param data Data Pointer to C++ class container to host callback procedure.
1789 void CPGFImage::GetBitmap(int pitch, UINT8* buff, BYTE bpp, int channelMap[] /*= nullptr */, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) const {
1790  ASSERT(buff);
1791  UINT32 w = m_width[0]; // width of decoded image
1792  UINT32 h = m_height[0]; // height of decoded image
1793  UINT32 yw = w; // y-channel width
1794  UINT32 uw = m_width[1]; // u-channel width
1795  UINT32 roiOffsetX = 0;
1796  UINT32 roiOffsetY = 0;
1797  UINT32 yOffset = 0;
1798  UINT32 uOffset = 0;
1799 
1800 #ifdef __PGFROISUPPORT__
1801  const PGFRect& roi = GetAlignedROI(); // in pixels, roi is usually larger than levelRoi
1802  ASSERT(w == roi.Width() && h == roi.Height());
1803  const PGFRect levelRoi = ComputeLevelROI();
1804  ASSERT(roi.left <= levelRoi.left && levelRoi.right <= roi.right);
1805  ASSERT(roi.top <= levelRoi.top && levelRoi.bottom <= roi.bottom);
1806 
1807  if (ROIisSupported() && (levelRoi.Width() < w || levelRoi.Height() < h)) {
1808  // ROI is used
1809  w = levelRoi.Width();
1810  h = levelRoi.Height();
1811  roiOffsetX = levelRoi.left - roi.left;
1812  roiOffsetY = levelRoi.top - roi.top;
1813  yOffset = roiOffsetX + roiOffsetY*yw;
1814 
1815  if (m_downsample) {
1816  const PGFRect& downsampledRoi = GetAlignedROI(1);
1817  uOffset = levelRoi.left/2 - downsampledRoi.left + (levelRoi.top/2 - downsampledRoi.top)*m_width[1];
1818  } else {
1819  uOffset = yOffset;
1820  }
1821  }
1822 #endif
1823 
1824  const double dP = 1.0/h;
1825  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
1826  if (channelMap == nullptr) channelMap = defMap;
1827  DataT uAvg, vAvg;
1828  double percent = 0;
1829  UINT32 i, j;
1830 
1831  switch(m_header.mode) {
1832  case ImageModeBitmap:
1833  {
1834  ASSERT(m_header.channels == 1);
1835  ASSERT(m_header.bpp == 1);
1836  ASSERT(bpp == 1);
1837 
1838  const UINT32 w2 = (w + 7)/8;
1839  DataT* y = m_channel[0]; ASSERT(y);
1840 
1841  if (m_preHeader.version & Version7) {
1842  // new unpacked version has a little better compression ratio
1843  // since version 7
1844  for (i = 0; i < h; i++) {
1845  UINT32 cnt = 0;
1846  for (j = 0; j < w2; j++) {
1847  UINT8 byte = 0;
1848  for (int k = 0; k < 8; k++) {
1849  byte <<= 1;
1850  UINT8 bit = 0;
1851  if (cnt < w) {
1852  bit = y[yOffset + cnt] & 1;
1853  }
1854  byte |= bit;
1855  cnt++;
1856  }
1857  buff[j] = byte;
1858  }
1859  yOffset += yw;
1860  buff += pitch;
1861 
1862  if (cb) {
1863  percent += dP;
1864  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1865  }
1866  }
1867  } else {
1868  // old versions
1869  // packed pixels: 8 pixel in 1 byte of channel[0]
1870  if (!(m_preHeader.version & Version5)) yw = w2; // not version 5 or 6
1871  yOffset = roiOffsetX/8 + roiOffsetY*yw; // 1 byte in y contains 8 pixel values
1872  for (i = 0; i < h; i++) {
1873  for (j = 0; j < w2; j++) {
1874  buff[j] = Clamp8(y[yOffset + j] + YUVoffset8);
1875  }
1876  yOffset += yw;
1877  buff += pitch;
1878 
1879  if (cb) {
1880  percent += dP;
1881  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1882  }
1883  }
1884  }
1885  break;
1886  }
1887  case ImageModeIndexedColor:
1888  case ImageModeGrayScale:
1889  case ImageModeHSLColor:
1890  case ImageModeHSBColor:
1891  {
1892  ASSERT(m_header.channels >= 1);
1893  ASSERT(m_header.bpp == m_header.channels*8);
1894  ASSERT(bpp%8 == 0);
1895 
1896  UINT32 cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
1897 
1898  for (i=0; i < h; i++) {
1899  UINT32 yPos = yOffset;
1900  cnt = 0;
1901  for (j=0; j < w; j++) {
1902  for (UINT32 c=0; c < m_header.channels; c++) {
1903  buff[cnt + channelMap[c]] = Clamp8(m_channel[c][yPos] + YUVoffset8);
1904  }
1905  cnt += channels;
1906  yPos++;
1907  }
1908  yOffset += yw;
1909  buff += pitch;
1910 
1911  if (cb) {
1912  percent += dP;
1913  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1914  }
1915  }
1916  break;
1917  }
1918  case ImageModeGray16:
1919  {
1920  ASSERT(m_header.channels >= 1);
1921  ASSERT(m_header.bpp == m_header.channels*16);
1922 
1923  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1924  UINT32 cnt, channels;
1925 
1926  if (bpp%16 == 0) {
1927  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1928  UINT16 *buff16 = (UINT16 *)buff;
1929  int pitch16 = pitch/2;
1930  channels = bpp/16; ASSERT(channels >= m_header.channels);
1931 
1932  for (i=0; i < h; i++) {
1933  UINT32 yPos = yOffset;
1934  cnt = 0;
1935  for (j=0; j < w; j++) {
1936  for (UINT32 c=0; c < m_header.channels; c++) {
1937  buff16[cnt + channelMap[c]] = Clamp16((m_channel[c][yPos] + yuvOffset16) << shift);
1938  }
1939  cnt += channels;
1940  yPos++;
1941  }
1942  yOffset += yw;
1943  buff16 += pitch16;
1944 
1945  if (cb) {
1946  percent += dP;
1947  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1948  }
1949  }
1950  } else {
1951  ASSERT(bpp%8 == 0);
1952  const int shift = __max(0, UsedBitsPerChannel() - 8);
1953  channels = bpp/8; ASSERT(channels >= m_header.channels);
1954 
1955  for (i=0; i < h; i++) {
1956  UINT32 yPos = yOffset;
1957  cnt = 0;
1958  for (j=0; j < w; j++) {
1959  for (UINT32 c=0; c < m_header.channels; c++) {
1960  buff[cnt + channelMap[c]] = Clamp8((m_channel[c][yPos] + yuvOffset16) >> shift);
1961  }
1962  cnt += channels;
1963  yPos++;
1964  }
1965  yOffset += yw;
1966  buff += pitch;
1967 
1968  if (cb) {
1969  percent += dP;
1970  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1971  }
1972  }
1973  }
1974  break;
1975  }
1976  case ImageModeRGBColor:
1977  {
1978  ASSERT(m_header.channels == 3);
1979  ASSERT(m_header.bpp == m_header.channels*8);
1980  ASSERT(bpp%8 == 0);
1981  ASSERT(bpp >= m_header.bpp);
1982 
1983  DataT* y = m_channel[0]; ASSERT(y);
1984  DataT* u = m_channel[1]; ASSERT(u);
1985  DataT* v = m_channel[2]; ASSERT(v);
1986  UINT8 *buffg = &buff[channelMap[1]],
1987  *buffr = &buff[channelMap[2]],
1988  *buffb = &buff[channelMap[0]];
1989  UINT8 g;
1990  UINT32 cnt, channels = bpp/8;
1991 
1992  if (m_downsample) {
1993  for (i=0; i < h; i++) {
1994  UINT32 uPos = uOffset;
1995  UINT32 yPos = yOffset;
1996  cnt = 0;
1997  for (j=0; j < w; j++) {
1998  // u and v are downsampled
1999  uAvg = u[uPos];
2000  vAvg = v[uPos];
2001  // Yuv
2002  buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2003  buffr[cnt] = Clamp8(uAvg + g);
2004  buffb[cnt] = Clamp8(vAvg + g);
2005  cnt += channels;
2006  if (j & 1) uPos++;
2007  yPos++;
2008  }
2009  if (i & 1) uOffset += uw;
2010  yOffset += yw;
2011  buffb += pitch;
2012  buffg += pitch;
2013  buffr += pitch;
2014 
2015  if (cb) {
2016  percent += dP;
2017  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2018  }
2019  }
2020 
2021  } else {
2022  for (i=0; i < h; i++) {
2023  cnt = 0;
2024  UINT32 yPos = yOffset;
2025  for (j = 0; j < w; j++) {
2026  uAvg = u[yPos];
2027  vAvg = v[yPos];
2028  // Yuv
2029  buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2030  buffr[cnt] = Clamp8(uAvg + g);
2031  buffb[cnt] = Clamp8(vAvg + g);
2032  cnt += channels;
2033  yPos++;
2034  }
2035  yOffset += yw;
2036  buffb += pitch;
2037  buffg += pitch;
2038  buffr += pitch;
2039 
2040  if (cb) {
2041  percent += dP;
2042  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2043  }
2044  }
2045  }
2046  break;
2047  }
2048  case ImageModeRGB48:
2049  {
2050  ASSERT(m_header.channels == 3);
2051  ASSERT(m_header.bpp == 48);
2052 
2053  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2054 
2055  DataT* y = m_channel[0]; ASSERT(y);
2056  DataT* u = m_channel[1]; ASSERT(u);
2057  DataT* v = m_channel[2]; ASSERT(v);
2058  UINT32 cnt, channels;
2059  DataT g;
2060 
2061  if (bpp >= 48 && bpp%16 == 0) {
2062  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2063  UINT16 *buff16 = (UINT16 *)buff;
2064  int pitch16 = pitch/2;
2065  channels = bpp/16; ASSERT(channels >= m_header.channels);
2066 
2067  for (i=0; i < h; i++) {
2068  UINT32 uPos = uOffset;
2069  UINT32 yPos = yOffset;
2070  cnt = 0;
2071  for (j=0; j < w; j++) {
2072  uAvg = u[uPos];
2073  vAvg = v[uPos];
2074  // Yuv
2075  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2076  buff16[cnt + channelMap[1]] = Clamp16(g << shift);
2077  buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
2078  buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
2079  cnt += channels;
2080  if (!m_downsample || (j & 1)) uPos++;
2081  yPos++;
2082  }
2083  if (!m_downsample || (i & 1)) uOffset += uw;
2084  yOffset += yw;
2085  buff16 += pitch16;
2086 
2087  if (cb) {
2088  percent += dP;
2089  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2090  }
2091  }
2092  } else {
2093  ASSERT(bpp%8 == 0);
2094  const int shift = __max(0, UsedBitsPerChannel() - 8);
2095  channels = bpp/8; ASSERT(channels >= m_header.channels);
2096 
2097  for (i=0; i < h; i++) {
2098  UINT32 uPos = uOffset;
2099  UINT32 yPos = yOffset;
2100  cnt = 0;
2101  for (j=0; j < w; j++) {
2102  uAvg = u[uPos];
2103  vAvg = v[uPos];
2104  // Yuv
2105  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2106  buff[cnt + channelMap[1]] = Clamp8(g >> shift);
2107  buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
2108  buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
2109  cnt += channels;
2110  if (!m_downsample || (j & 1)) uPos++;
2111  yPos++;
2112  }
2113  if (!m_downsample || (i & 1)) uOffset += uw;
2114  yOffset += yw;
2115  buff += pitch;
2116 
2117  if (cb) {
2118  percent += dP;
2119  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2120  }
2121  }
2122  }
2123  break;
2124  }
2125  case ImageModeLabColor:
2126  {
2127  ASSERT(m_header.channels == 3);
2128  ASSERT(m_header.bpp == m_header.channels*8);
2129  ASSERT(bpp%8 == 0);
2130 
2131  DataT* l = m_channel[0]; ASSERT(l);
2132  DataT* a = m_channel[1]; ASSERT(a);
2133  DataT* b = m_channel[2]; ASSERT(b);
2134  UINT32 cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
2135 
2136  for (i=0; i < h; i++) {
2137  UINT32 uPos = uOffset;
2138  UINT32 yPos = yOffset;
2139  cnt = 0;
2140  for (j=0; j < w; j++) {
2141  uAvg = a[uPos];
2142  vAvg = b[uPos];
2143  buff[cnt + channelMap[0]] = Clamp8(l[yPos] + YUVoffset8);
2144  buff[cnt + channelMap[1]] = Clamp8(uAvg + YUVoffset8);
2145  buff[cnt + channelMap[2]] = Clamp8(vAvg + YUVoffset8);
2146  cnt += channels;
2147  if (!m_downsample || (j & 1)) uPos++;
2148  yPos++;
2149  }
2150  if (!m_downsample || (i & 1)) uOffset += uw;
2151  yOffset += yw;
2152  buff += pitch;
2153 
2154  if (cb) {
2155  percent += dP;
2156  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2157  }
2158  }
2159  break;
2160  }
2161  case ImageModeLab48:
2162  {
2163  ASSERT(m_header.channels == 3);
2164  ASSERT(m_header.bpp == m_header.channels*16);
2165 
2166  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2167 
2168  DataT* l = m_channel[0]; ASSERT(l);
2169  DataT* a = m_channel[1]; ASSERT(a);
2170  DataT* b = m_channel[2]; ASSERT(b);
2171  UINT32 cnt, channels;
2172 
2173  if (bpp%16 == 0) {
2174  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2175  UINT16 *buff16 = (UINT16 *)buff;
2176  int pitch16 = pitch/2;
2177  channels = bpp/16; ASSERT(channels >= m_header.channels);
2178 
2179  for (i=0; i < h; i++) {
2180  UINT32 uPos = uOffset;
2181  UINT32 yPos = yOffset;
2182  cnt = 0;
2183  for (j=0; j < w; j++) {
2184  uAvg = a[uPos];
2185  vAvg = b[uPos];
2186  buff16[cnt + channelMap[0]] = Clamp16((l[yPos] + yuvOffset16) << shift);
2187  buff16[cnt + channelMap[1]] = Clamp16((uAvg + yuvOffset16) << shift);
2188  buff16[cnt + channelMap[2]] = Clamp16((vAvg + yuvOffset16) << shift);
2189  cnt += channels;
2190  if (!m_downsample || (j & 1)) uPos++;
2191  yPos++;
2192  }
2193  if (!m_downsample || (i & 1)) uOffset += uw;
2194  yOffset += yw;
2195  buff16 += pitch16;
2196 
2197  if (cb) {
2198  percent += dP;
2199  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2200  }
2201  }
2202  } else {
2203  ASSERT(bpp%8 == 0);
2204  const int shift = __max(0, UsedBitsPerChannel() - 8);
2205  channels = bpp/8; ASSERT(channels >= m_header.channels);
2206 
2207  for (i=0; i < h; i++) {
2208  UINT32 uPos = uOffset;
2209  UINT32 yPos = yOffset;
2210  cnt = 0;
2211  for (j=0; j < w; j++) {
2212  uAvg = a[uPos];
2213  vAvg = b[uPos];
2214  buff[cnt + channelMap[0]] = Clamp8((l[yPos] + yuvOffset16) >> shift);
2215  buff[cnt + channelMap[1]] = Clamp8((uAvg + yuvOffset16) >> shift);
2216  buff[cnt + channelMap[2]] = Clamp8((vAvg + yuvOffset16) >> shift);
2217  cnt += channels;
2218  if (!m_downsample || (j & 1)) uPos++;
2219  yPos++;
2220  }
2221  if (!m_downsample || (i & 1)) uOffset += uw;
2222  yOffset += yw;
2223  buff += pitch;
2224 
2225  if (cb) {
2226  percent += dP;
2227  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2228  }
2229  }
2230  }
2231  break;
2232  }
2233  case ImageModeRGBA:
2234  case ImageModeCMYKColor:
2235  {
2236  ASSERT(m_header.channels == 4);
2237  ASSERT(m_header.bpp == m_header.channels*8);
2238  ASSERT(bpp%8 == 0);
2239 
2240  DataT* y = m_channel[0]; ASSERT(y);
2241  DataT* u = m_channel[1]; ASSERT(u);
2242  DataT* v = m_channel[2]; ASSERT(v);
2243  DataT* a = m_channel[3]; ASSERT(a);
2244  UINT8 g, aAvg;
2245  UINT32 cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
2246 
2247  for (i=0; i < h; i++) {
2248  UINT32 uPos = uOffset;
2249  UINT32 yPos = yOffset;
2250  cnt = 0;
2251  for (j=0; j < w; j++) {
2252  uAvg = u[uPos];
2253  vAvg = v[uPos];
2254  aAvg = Clamp8(a[uPos] + YUVoffset8);
2255  // Yuv
2256  buff[cnt + channelMap[1]] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2257  buff[cnt + channelMap[2]] = Clamp8(uAvg + g);
2258  buff[cnt + channelMap[0]] = Clamp8(vAvg + g);
2259  buff[cnt + channelMap[3]] = aAvg;
2260  cnt += channels;
2261  if (!m_downsample || (j & 1)) uPos++;
2262  yPos++;
2263  }
2264  if (!m_downsample || (i & 1)) uOffset += uw;
2265  yOffset += yw;
2266  buff += pitch;
2267 
2268  if (cb) {
2269  percent += dP;
2270  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2271  }
2272  }
2273  break;
2274  }
2275  case ImageModeCMYK64:
2276  {
2277  ASSERT(m_header.channels == 4);
2278  ASSERT(m_header.bpp == 64);
2279 
2280  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2281 
2282  DataT* y = m_channel[0]; ASSERT(y);
2283  DataT* u = m_channel[1]; ASSERT(u);
2284  DataT* v = m_channel[2]; ASSERT(v);
2285  DataT* a = m_channel[3]; ASSERT(a);
2286  DataT g, aAvg;
2287  UINT32 cnt, channels;
2288 
2289  if (bpp%16 == 0) {
2290  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2291  UINT16 *buff16 = (UINT16 *)buff;
2292  int pitch16 = pitch/2;
2293  channels = bpp/16; ASSERT(channels >= m_header.channels);
2294 
2295  for (i=0; i < h; i++) {
2296  UINT32 uPos = uOffset;
2297  UINT32 yPos = yOffset;
2298  cnt = 0;
2299  for (j=0; j < w; j++) {
2300  uAvg = u[uPos];
2301  vAvg = v[uPos];
2302  aAvg = a[uPos] + yuvOffset16;
2303  // Yuv
2304  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2305  buff16[cnt + channelMap[1]] = Clamp16(g << shift);
2306  buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
2307  buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
2308  buff16[cnt + channelMap[3]] = Clamp16(aAvg << shift);
2309  cnt += channels;
2310  if (!m_downsample || (j & 1)) uPos++;
2311  yPos++;
2312  }
2313  if (!m_downsample || (i & 1)) uOffset += uw;
2314  yOffset += yw;
2315  buff16 += pitch16;
2316 
2317  if (cb) {
2318  percent += dP;
2319  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2320  }
2321  }
2322  } else {
2323  ASSERT(bpp%8 == 0);
2324  const int shift = __max(0, UsedBitsPerChannel() - 8);
2325  channels = bpp/8; ASSERT(channels >= m_header.channels);
2326 
2327  for (i=0; i < h; i++) {
2328  UINT32 uPos = uOffset;
2329  UINT32 yPos = yOffset;
2330  cnt = 0;
2331  for (j=0; j < w; j++) {
2332  uAvg = u[uPos];
2333  vAvg = v[uPos];
2334  aAvg = a[uPos] + yuvOffset16;
2335  // Yuv
2336  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2337  buff[cnt + channelMap[1]] = Clamp8(g >> shift);
2338  buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
2339  buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
2340  buff[cnt + channelMap[3]] = Clamp8(aAvg >> shift);
2341  cnt += channels;
2342  if (!m_downsample || (j & 1)) uPos++;
2343  yPos++;
2344  }
2345  if (!m_downsample || (i & 1)) uOffset += uw;
2346  yOffset += yw;
2347  buff += pitch;
2348 
2349  if (cb) {
2350  percent += dP;
2351  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2352  }
2353  }
2354  }
2355  break;
2356  }
2357 #ifdef __PGF32SUPPORT__
2358  case ImageModeGray32:
2359  {
2360  ASSERT(m_header.channels == 1);
2361  ASSERT(m_header.bpp == 32);
2362 
2363  const int yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
2364  DataT* y = m_channel[0]; ASSERT(y);
2365 
2366  if (bpp == 32) {
2367  const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2368  UINT32 *buff32 = (UINT32 *)buff;
2369  int pitch32 = pitch/4;
2370 
2371  for (i=0; i < h; i++) {
2372  UINT32 yPos = yOffset;
2373  for (j = 0; j < w; j++) {
2374  buff32[j] = Clamp31((y[yPos++] + yuvOffset31) << shift);
2375  }
2376  yOffset += yw;
2377  buff32 += pitch32;
2378 
2379  if (cb) {
2380  percent += dP;
2381  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2382  }
2383  }
2384  } else if (bpp == 16) {
2385  const int usedBits = UsedBitsPerChannel();
2386  UINT16 *buff16 = (UINT16 *)buff;
2387  int pitch16 = pitch/2;
2388 
2389  if (usedBits < 16) {
2390  const int shift = 16 - usedBits;
2391  for (i=0; i < h; i++) {
2392  UINT32 yPos = yOffset;
2393  for (j = 0; j < w; j++) {
2394  buff16[j] = Clamp16((y[yPos++] + yuvOffset31) << shift);
2395  }
2396  yOffset += yw;
2397  buff16 += pitch16;
2398 
2399  if (cb) {
2400  percent += dP;
2401  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2402  }
2403  }
2404  } else {
2405  const int shift = __max(0, usedBits - 16);
2406  for (i=0; i < h; i++) {
2407  UINT32 yPos = yOffset;
2408  for (j = 0; j < w; j++) {
2409  buff16[j] = Clamp16((y[yPos++] + yuvOffset31) >> shift);
2410  }
2411  yOffset += yw;
2412  buff16 += pitch16;
2413 
2414  if (cb) {
2415  percent += dP;
2416  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2417  }
2418  }
2419  }
2420  } else {
2421  ASSERT(bpp == 8);
2422  const int shift = __max(0, UsedBitsPerChannel() - 8);
2423 
2424  for (i=0; i < h; i++) {
2425  UINT32 yPos = yOffset;
2426  for (j = 0; j < w; j++) {
2427  buff[j] = Clamp8((y[yPos++] + yuvOffset31) >> shift);
2428  }
2429  yOffset += yw;
2430  buff += pitch;
2431 
2432  if (cb) {
2433  percent += dP;
2434  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2435  }
2436  }
2437  }
2438  break;
2439  }
2440 #endif
2441  case ImageModeRGB12:
2442  {
2443  ASSERT(m_header.channels == 3);
2444  ASSERT(m_header.bpp == m_header.channels*4);
2445  ASSERT(bpp == m_header.channels*4);
2446  ASSERT(!m_downsample);
2447 
2448  DataT* y = m_channel[0]; ASSERT(y);
2449  DataT* u = m_channel[1]; ASSERT(u);
2450  DataT* v = m_channel[2]; ASSERT(v);
2451  UINT16 yval;
2452  UINT32 cnt;
2453 
2454  for (i=0; i < h; i++) {
2455  UINT32 yPos = yOffset;
2456  cnt = 0;
2457  for (j=0; j < w; j++) {
2458  // Yuv
2459  uAvg = u[yPos];
2460  vAvg = v[yPos];
2461  yval = Clamp4(y[yPos] + YUVoffset4 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2462  if (j%2 == 0) {
2463  buff[cnt] = UINT8(Clamp4(vAvg + yval) | (yval << 4));
2464  cnt++;
2465  buff[cnt] = Clamp4(uAvg + yval);
2466  } else {
2467  buff[cnt] |= Clamp4(vAvg + yval) << 4;
2468  cnt++;
2469  buff[cnt] = UINT8(yval | (Clamp4(uAvg + yval) << 4));
2470  cnt++;
2471  }
2472  yPos++;
2473  }
2474  yOffset += yw;
2475  buff += pitch;
2476 
2477  if (cb) {
2478  percent += dP;
2479  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2480  }
2481  }
2482  break;
2483  }
2484  case ImageModeRGB16:
2485  {
2486  ASSERT(m_header.channels == 3);
2487  ASSERT(m_header.bpp == 16);
2488  ASSERT(bpp == 16);
2489  ASSERT(!m_downsample);
2490 
2491  DataT* y = m_channel[0]; ASSERT(y);
2492  DataT* u = m_channel[1]; ASSERT(u);
2493  DataT* v = m_channel[2]; ASSERT(v);
2494  UINT16 yval;
2495  UINT16 *buff16 = (UINT16 *)buff;
2496  int pitch16 = pitch/2;
2497 
2498  for (i=0; i < h; i++) {
2499  UINT32 yPos = yOffset;
2500  for (j = 0; j < w; j++) {
2501  // Yuv
2502  uAvg = u[yPos];
2503  vAvg = v[yPos];
2504  yval = Clamp6(y[yPos++] + YUVoffset6 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2505  buff16[j] = (yval << 5) | ((Clamp6(uAvg + yval) >> 1) << 11) | (Clamp6(vAvg + yval) >> 1);
2506  }
2507  yOffset += yw;
2508  buff16 += pitch16;
2509 
2510  if (cb) {
2511  percent += dP;
2512  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2513  }
2514  }
2515  break;
2516  }
2517  default:
2518  ASSERT(false);
2519  }
2520 
2521 #ifdef _DEBUG
2522  // display ROI (RGB) in debugger
2523  roiimage.width = w;
2524  roiimage.height = h;
2525  if (pitch > 0) {
2526  roiimage.pitch = pitch;
2527  roiimage.data = buff;
2528  } else {
2529  roiimage.pitch = -pitch;
2530  roiimage.data = buff + (h - 1)*pitch;
2531  }
2532 #endif
2533 
2534 }
2535 
2550 void CPGFImage::GetYUV(int pitch, DataT* buff, BYTE bpp, int channelMap[] /*= nullptr*/, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) const {
2551  ASSERT(buff);
2552  const UINT32 w = m_width[0];
2553  const UINT32 h = m_height[0];
2554  const bool wOdd = (1 == w%2);
2555  const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
2556  const int pitch2 = pitch/DataTSize;
2557  const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
2558  const double dP = 1.0/h;
2559 
2560  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
2561  if (channelMap == nullptr) channelMap = defMap;
2562  int sampledPos = 0, yPos = 0;
2563  DataT uAvg, vAvg;
2564  double percent = 0;
2565  UINT32 i, j;
2566 
2567  if (m_header.channels == 3) {
2568  ASSERT(bpp%dataBits == 0);
2569 
2570  DataT* y = m_channel[0]; ASSERT(y);
2571  DataT* u = m_channel[1]; ASSERT(u);
2572  DataT* v = m_channel[2]; ASSERT(v);
2573  int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2574 
2575  for (i=0; i < h; i++) {
2576  if (i%2) sampledPos -= (w + 1)/2;
2577  cnt = 0;
2578  for (j=0; j < w; j++) {
2579  if (m_downsample) {
2580  // image was downsampled
2581  uAvg = u[sampledPos];
2582  vAvg = v[sampledPos];
2583  } else {
2584  uAvg = u[yPos];
2585  vAvg = v[yPos];
2586  }
2587  buff[cnt + channelMap[0]] = y[yPos];
2588  buff[cnt + channelMap[1]] = uAvg;
2589  buff[cnt + channelMap[2]] = vAvg;
2590  yPos++;
2591  cnt += channels;
2592  if (j%2) sampledPos++;
2593  }
2594  buff += pitch2;
2595  if (wOdd) sampledPos++;
2596 
2597  if (cb) {
2598  percent += dP;
2599  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2600  }
2601  }
2602  } else if (m_header.channels == 4) {
2603  ASSERT(m_header.bpp == m_header.channels*8);
2604  ASSERT(bpp%dataBits == 0);
2605 
2606  DataT* y = m_channel[0]; ASSERT(y);
2607  DataT* u = m_channel[1]; ASSERT(u);
2608  DataT* v = m_channel[2]; ASSERT(v);
2609  DataT* a = m_channel[3]; ASSERT(a);
2610  UINT8 aAvg;
2611  int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2612 
2613  for (i=0; i < h; i++) {
2614  if (i%2) sampledPos -= (w + 1)/2;
2615  cnt = 0;
2616  for (j=0; j < w; j++) {
2617  if (m_downsample) {
2618  // image was downsampled
2619  uAvg = u[sampledPos];
2620  vAvg = v[sampledPos];
2621  aAvg = Clamp8(a[sampledPos] + yuvOffset);
2622  } else {
2623  uAvg = u[yPos];
2624  vAvg = v[yPos];
2625  aAvg = Clamp8(a[yPos] + yuvOffset);
2626  }
2627  // Yuv
2628  buff[cnt + channelMap[0]] = y[yPos];
2629  buff[cnt + channelMap[1]] = uAvg;
2630  buff[cnt + channelMap[2]] = vAvg;
2631  buff[cnt + channelMap[3]] = aAvg;
2632  yPos++;
2633  cnt += channels;
2634  if (j%2) sampledPos++;
2635  }
2636  buff += pitch2;
2637  if (wOdd) sampledPos++;
2638 
2639  if (cb) {
2640  percent += dP;
2641  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2642  }
2643  }
2644  }
2645 }
2646 
2661 void CPGFImage::ImportYUV(int pitch, DataT *buff, BYTE bpp, int channelMap[] /*= nullptr*/, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) {
2662  ASSERT(buff);
2663  const double dP = 1.0/m_header.height;
2664  const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
2665  const int pitch2 = pitch/DataTSize;
2666  const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
2667 
2668  int yPos = 0, cnt = 0;
2669  double percent = 0;
2670  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
2671 
2672  if (channelMap == nullptr) channelMap = defMap;
2673 
2674  if (m_header.channels == 3) {
2675  ASSERT(bpp%dataBits == 0);
2676 
2677  DataT* y = m_channel[0]; ASSERT(y);
2678  DataT* u = m_channel[1]; ASSERT(u);
2679  DataT* v = m_channel[2]; ASSERT(v);
2680  const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2681 
2682  for (UINT32 h=0; h < m_header.height; h++) {
2683  if (cb) {
2684  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2685  percent += dP;
2686  }
2687 
2688  cnt = 0;
2689  for (UINT32 w=0; w < m_header.width; w++) {
2690  y[yPos] = buff[cnt + channelMap[0]];
2691  u[yPos] = buff[cnt + channelMap[1]];
2692  v[yPos] = buff[cnt + channelMap[2]];
2693  yPos++;
2694  cnt += channels;
2695  }
2696  buff += pitch2;
2697  }
2698  } else if (m_header.channels == 4) {
2699  ASSERT(bpp%dataBits == 0);
2700 
2701  DataT* y = m_channel[0]; ASSERT(y);
2702  DataT* u = m_channel[1]; ASSERT(u);
2703  DataT* v = m_channel[2]; ASSERT(v);
2704  DataT* a = m_channel[3]; ASSERT(a);
2705  const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2706 
2707  for (UINT32 h=0; h < m_header.height; h++) {
2708  if (cb) {
2709  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2710  percent += dP;
2711  }
2712 
2713  cnt = 0;
2714  for (UINT32 w=0; w < m_header.width; w++) {
2715  y[yPos] = buff[cnt + channelMap[0]];
2716  u[yPos] = buff[cnt + channelMap[1]];
2717  v[yPos] = buff[cnt + channelMap[2]];
2718  a[yPos] = buff[cnt + channelMap[3]] - yuvOffset;
2719  yPos++;
2720  cnt += channels;
2721  }
2722  buff += pitch2;
2723  }
2724  }
2725 
2726  if (m_downsample) {
2727  // Subsampling of the chrominance and alpha channels
2728  for (int i=1; i < m_header.channels; i++) {
2729  Downsample(i);
2730  }
2731  }
2732 }
2733 
void Open(CPGFStream *stream)
Definition: PGFimage.cpp:141
void SetColorTable(UINT32 iFirstColor, UINT32 nColors, const RGBQUAD *prgbColors)
Definition: PGFimage.cpp:1364
OSError InverseTransform(int level, UINT32 *width, UINT32 *height, DataT **data)
#define ImageModeIndexedColor
Definition: PGFplatform.h:100
virtual void Read(int *count, void *buffer)=0
void Read(int level=0, CallbackPtr cb=nullptr, void *data=nullptr)
Definition: PGFimage.cpp:402
bool m_favorSpeedOverSize
favor encoding speed over compression ratio
Definition: PGFimage.h:536
UINT64 m_userDataPos
stream position of user data
Definition: PGFimage.h:531
bool m_useOMPinDecoder
use Open MP in decoder
Definition: PGFimage.h:538
UINT8 version
PGF version.
Definition: PGFtypes.h:115
#define ImageModeRGB12
Definition: PGFplatform.h:117
UINT8 mode
image mode according to Adobe's image modes
Definition: PGFtypes.h:159
#define ImageModeHSBColor
Definition: PGFplatform.h:104
UINT32 ReadEncodedHeader(UINT8 *target, UINT32 targetLen) const
Definition: PGFimage.cpp:660
#define YUVoffset16
Definition: PGFimage.cpp:39
Definition: PGFtypes.h:99
#define PGFVersion
current standard version
Definition: PGFtypes.h:76
void GetYUV(int pitch, DataT *buff, BYTE bpp, int channelMap[]=nullptr, CallbackPtr cb=nullptr, void *data=nullptr) const
Definition: PGFimage.cpp:2550
void Dequantize(int quantParam)
Definition: Subband.cpp:154
DataT * GetBuffer()
Definition: Subband.h:107
const UINT8 * GetUserData(UINT32 &cachedSize, UINT32 *pTotalSize=nullptr) const
Definition: PGFimage.cpp:337
virtual void Write(int *count, void *buffer)=0
#define MaxChannels
maximum number of (color) channels
Definition: PGFtypes.h:64
Abstract stream base class.
Definition: PGFstream.h:39
BYTE UsedBitsPerChannel() const
Definition: PGFimage.cpp:756
void GetBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=nullptr, CallbackPtr cb=nullptr, void *data=nullptr) const
Definition: PGFimage.cpp:1789
UINT32 width
image width in pixels
Definition: PGFtypes.h:153
#define PGFYear
Definition: PGFtypes.h:45
void ExtractTile(CEncoder &encoder, bool tile=false, UINT32 tileX=0, UINT32 tileY=0)
Definition: Subband.cpp:177
#define ColorTableSize
Definition: PGFtypes.h:282
#define PGFMajorNumber
Definition: PGFtypes.h:44
UINT32 ReadEncodedData(int level, UINT8 *target, UINT32 targetLen) const
Definition: PGFimage.cpp:707
INT32 DataT
Definition: PGFtypes.h:269
UINT32 userDataLen
user data size in bytes (not part of file header)
Definition: PGFtypes.h:172
#define ImageModeRGBA
Definition: PGFplatform.h:115
CDecoder * m_decoder
PGF decoder.
Definition: PGFimage.h:523
UINT8 * userData
user data of size userDataLen (optional part of file header)
Definition: PGFtypes.h:171
UINT32 GetEncodedLevelLength(int level) const
Definition: PGFimage.h:367
void ImportYUV(int pitch, DataT *buff, BYTE bpp, int channelMap[]=nullptr, CallbackPtr cb=nullptr, void *data=nullptr)
Definition: PGFimage.cpp:2661
PGFHeader m_header
PGF file header.
Definition: PGFimage.h:529
bool m_streamReinitialized
stream has been reinitialized
Definition: PGFimage.h:540
void WriteLevel()
Definition: PGFimage.cpp:1068
void DecodeInterleaved(CWaveletTransform *wtChannel, int level, int quantParam)
Definition: Decoder.cpp:333
bool CompleteHeader()
Definition: PGFimage.cpp:218
BYTE m_quant
quantization parameter
Definition: PGFimage.h:534
#define DataTSize
Definition: PGFtypes.h:283
const UINT32 FilterSize
#define HeaderSize
Definition: PGFtypes.h:281
#define ImageModeLabColor
Definition: PGFplatform.h:107
void * m_cbArg
refresh callback argument
Definition: PGFimage.h:546
DataT * m_channel[MaxChannels]
untransformed channels in YUV format
Definition: PGFimage.h:522
PGFPreHeader m_preHeader
PGF pre-header.
Definition: PGFimage.h:528
void SetStreamPosToData()
Resets stream position to beginning of data block.
Definition: Decoder.h:144
UINT32 GetEncodedHeaderLength() const
Definition: Decoder.h:136
static UINT32 LevelSizeL(UINT32 size, int level)
Definition: PGFimage.h:499
UINT8 nLevels
number of FWT transforms
Definition: PGFtypes.h:155
#define ImageModeGray16
Definition: PGFplatform.h:108
UINT32 right
Definition: PGFtypes.h:226
UINT32 WriteLevelLength(UINT32 *&levelLength)
Definition: Encoder.cpp:177
UINT8 usedBitsPerChannel
number of used bits per channel in 16- and 32-bit per channel modes
Definition: PGFtypes.h:160
void SetROI(PGFRect rect)
const RGBQUAD * GetColorTable() const
Definition: PGFimage.h:330
PGF wavelet transform.
#define PGFMagic
PGF identification.
Definition: PGFtypes.h:61
PGFRect GetAlignedROI(int c=0) const
UINT32 WriteImage(CPGFStream *stream, CallbackPtr cb=nullptr, void *data=nullptr)
Definition: PGFimage.cpp:1150
PGF header.
Definition: PGFtypes.h:151
#define ImageModeLab48
Definition: PGFplatform.h:110
#define Version6
hSize in PGFPreHeader uses 32 bits instead of 16 bits
Definition: PGFtypes.h:72
UINT32 cachedUserDataLen
cached user data size in bytes (not part of file header)
Definition: PGFtypes.h:173
static BYTE CodecMajorVersion(BYTE version=PGFVersion)
Return major version.
Definition: PGFimage.cpp:768
UINT16 Clamp6(DataT v) const
Definition: PGFimage.h:566
#define ImageModeCMYKColor
Definition: PGFplatform.h:102
OSError ForwardTransform(int level, int quant)
#define ColorTableLen
size of color lookup table (clut)
Definition: PGFtypes.h:66
#define MaxLevel
maximum number of transform levels
Definition: PGFtypes.h:62
void UpdatePostHeaderSize(PGFPreHeader preHeader)
Definition: Encoder.cpp:160
ProgressMode m_progressMode
progress mode used in Read and Write; PM_Relative is default mode
Definition: PGFimage.h:548
#define ImageModeGrayScale
Definition: PGFplatform.h:99
CWaveletTransform * m_wtChannel[MaxChannels]
wavelet transformed color channels
Definition: PGFimage.h:521
UINT8 bpp
bits per pixel
Definition: PGFtypes.h:157
void PlaceTile(CDecoder &decoder, int quantParam, bool tile=false, UINT32 tileX=0, UINT32 tileY=0)
Definition: Subband.cpp:203
char magic[3]
PGF identification = "PGF".
Definition: PGFtypes.h:114
PGFPostHeader m_postHeader
PGF post-header.
Definition: PGFimage.h:530
#define YUVoffset6
Definition: PGFimage.cpp:37
UINT32 Clamp31(DataT v) const
Definition: PGFimage.h:576
void ComputeLevels()
Definition: PGFimage.cpp:854
UINT16 Clamp16(DataT v) const
Definition: PGFimage.h:573
void Init()
Definition: PGFimage.cpp:69
INT64 ComputeBufferLength() const
Definition: Encoder.h:179
UINT32 Height() const
Definition: PGFtypes.h:259
bool m_downsample
chrominance channels are downsampled
Definition: PGFimage.h:535
Definition: PGFtypes.h:99
PGF decoder.
Definition: Decoder.h:46
#define __max(x, y)
Definition: PGFplatform.h:92
PGF decoder class.
#define DownsampleThreshold
if quality is larger than this threshold than downsampling is used
Definition: PGFtypes.h:65
UINT32 * m_levelLength
length of each level in bytes; first level starts immediately after this array
Definition: PGFimage.h:525
UINT32 WriteHeader(CPGFStream *stream)
Definition: PGFimage.cpp:979
#define PGFWeek
Definition: PGFtypes.h:46
UINT32 hSize
total size of PGFHeader, [ColorTable], and [UserData] in bytes (since Version 6: 4 Bytes)
Definition: PGFtypes.h:124
UINT32 m_width[MaxChannels]
width of each channel at current level
Definition: PGFimage.h:526
#define Version2
data structure PGFHeader of major version 2
Definition: PGFtypes.h:68
#define ImageModeGray32
Definition: PGFplatform.h:116
PGF encoder class.
Definition: PGFtypes.h:99
CPGFImage()
Standard constructor.
Definition: PGFimage.cpp:64
CSubband * GetSubband(int level, Orientation orientation)
#define __min(x, y)
Definition: PGFplatform.h:91
UINT32 top
Definition: PGFtypes.h:226
void SetStreamPosToStart()
Resets stream position to beginning of PGF pre-header.
Definition: Encoder.h:188
void SetHeader(const PGFHeader &header, BYTE flags=0, const UINT8 *userData=0, UINT32 userDataLength=0)
Definition: PGFimage.cpp:894
void Skip(UINT64 offset)
Definition: Decoder.cpp:449
bool ROIisSupported() const
Definition: PGFimage.h:466
void Flush()
Definition: Encoder.cpp:310
#define ImageModeUnknown
Definition: PGFplatform.h:119
void GetNextMacroBlock()
Definition: Decoder.cpp:477
#define MaxQuality
maximum quality
Definition: PGFtypes.h:94
bool m_useOMPinEncoder
use Open MP in encoder
Definition: PGFimage.h:537
UINT32 left
Definition: PGFtypes.h:226
INT64 ComputeHeaderLength() const
Definition: Encoder.h:174
virtual ~CPGFImage()
Destructor.
Definition: PGFimage.cpp:117
Definition: PGFtypes.h:99
UINT32 UpdateLevelLength()
Definition: Encoder.cpp:202
void Reconstruct(int level=0)
Definition: PGFimage.cpp:348
UINT8 Clamp8(DataT v) const
Definition: PGFimage.h:569
void Destroy()
Definition: PGFimage.cpp:124
UINT8 Clamp4(DataT v) const
Definition: PGFimage.h:563
UINT32 ReadEncodedData(UINT8 *target, UINT32 len) const
Definition: Decoder.cpp:246
void FavorSpeedOverSize()
Encoder favors speed over compression size.
Definition: Encoder.h:121
UINT32 GetEncodedHeaderLength() const
Definition: PGFimage.cpp:648
#define ImageModeRGBColor
Definition: PGFplatform.h:101
UINT32 m_userDataPolicy
user data (metadata) policy during open
Definition: PGFimage.h:533
#define ImageModeHSLColor
Definition: PGFplatform.h:103
#define ImageModeBitmap
Definition: PGFplatform.h:98
double m_percent
progress [0..1]
Definition: PGFimage.h:547
#define Version7
Codec major and minor version number stored in PGFHeader.
Definition: PGFtypes.h:73
UINT8 channels
number of channels
Definition: PGFtypes.h:158
void RgbToYuv(int pitch, UINT8 *rgbBuff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data)
Definition: PGFimage.cpp:1389
void ImportBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=nullptr, CallbackPtr cb=nullptr, void *data=nullptr)
Definition: PGFimage.cpp:792
void ResetStreamPos(bool startOfData)
Definition: PGFimage.cpp:682
void SetMaxValue(UINT32 maxValue)
Definition: PGFimage.cpp:738
Rectangle.
Definition: PGFtypes.h:225
RefreshCB m_cb
pointer to refresh callback procedure
Definition: PGFimage.h:545
static bool ImportIsSupported(BYTE mode)
Definition: PGFimage.cpp:1305
#define MaxUserDataSize
Definition: PGFtypes.h:284
CEncoder * m_encoder
PGF encoder.
Definition: PGFimage.h:524
PGFVersionNumber version
codec version number: (since Version 7)
Definition: PGFtypes.h:161
UINT32 Width() const
Definition: PGFtypes.h:256
void SetStreamPosToStart()
Resets stream position to beginning of PGF pre-header.
Definition: Decoder.h:140
#define ImageModeCMYK64
Definition: PGFplatform.h:111
INT64 ComputeOffset() const
Definition: Encoder.h:184
#define YUVoffset4
Definition: PGFimage.cpp:36
#define ImageModeRGB16
Definition: PGFplatform.h:118
void Downsample(int nChannel)
Definition: PGFimage.cpp:810
int m_currentLevel
transform level of current image
Definition: PGFimage.h:532
UINT8 quality
quantization parameter: 0=lossless, 4=standard, 6=poor quality
Definition: PGFtypes.h:156
#define YUVoffset8
Definition: PGFimage.cpp:38
PGFRect ComputeLevelROI() const
UINT32 height
image height in pixels
Definition: PGFtypes.h:154
RGBQUAD clut[ColorTableLen]
color table for indexed color images (optional part of file header)
Definition: PGFtypes.h:170
#define ImageModeRGB48
Definition: PGFplatform.h:109
void Write(CPGFStream *stream, UINT32 *nWrittenBytes=nullptr, CallbackPtr cb=nullptr, void *data=nullptr)
Definition: PGFimage.cpp:1221
version number stored in header since major version 7
Definition: PGFtypes.h:132
UINT32 bottom
Definition: PGFtypes.h:226
#define Version5
new coding scheme since major version 5
Definition: PGFtypes.h:71
UINT32 m_height[MaxChannels]
height of each channel at current level
Definition: PGFimage.h:527
UINT32 UpdatePostHeaderSize()
Definition: PGFimage.cpp:1124
PGF encoder.
Definition: Encoder.h:46
PGFRect m_roi
region of interest
Definition: PGFimage.h:541
PGF image class.
void SetEncodedLevel(int currentLevel)
Definition: Encoder.h:162