libpgf  7.15.32
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  if (startOfData) {
684  ASSERT(m_decoder);
686  } else {
687  if (m_decoder) {
689  } else if (m_encoder) {
691  } else {
692  ASSERT(false);
693  }
694  }
695 }
696 
706 UINT32 CPGFImage::ReadEncodedData(int level, UINT8* target, UINT32 targetLen) const {
707  ASSERT(level >= 0 && level < m_header.nLevels);
708  ASSERT(target);
709  ASSERT(targetLen > 0);
710  ASSERT(m_decoder);
711 
712  // reset stream position
714 
715  // position stream
716  UINT64 offset = 0;
717 
718  for (int i=m_header.nLevels - 1; i > level; i--) {
719  offset += m_levelLength[m_header.nLevels - 1 - i];
720  }
721  m_decoder->Skip(offset);
722 
723  // compute number of bytes to read
724  UINT32 len = __min(targetLen, GetEncodedLevelLength(level));
725 
726  // read data
727  len = m_decoder->ReadEncodedData(target, len);
728  ASSERT(len >= 0 && len <= targetLen);
729 
730  return len;
731 }
732 
737 void CPGFImage::SetMaxValue(UINT32 maxValue) {
738  const BYTE bpc = m_header.bpp/m_header.channels;
739  BYTE pot = 0;
740 
741  while(maxValue > 0) {
742  pot++;
743  maxValue >>= 1;
744  }
745  // store bits per channel
746  if (pot > bpc) pot = bpc;
747  if (pot > 31) pot = 31;
749 }
750 
756  const BYTE bpc = m_header.bpp/m_header.channels;
757 
758  if (bpc > 8) {
760  } else {
761  return bpc;
762  }
763 }
764 
767 BYTE CPGFImage::CodecMajorVersion(BYTE version) {
768  if (version & Version7) return 7;
769  if (version & Version6) return 6;
770  if (version & Version5) return 5;
771  if (version & Version2) return 2;
772  return 1;
773 }
774 
776 // Import an image from a specified image buffer.
777 // This method is usually called before Write(...) and after SetHeader(...).
778 // It might throw an IOException.
779 // The absolute value of pitch is the number of bytes of an image row.
780 // If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row).
781 // If pitch is positive, then buff points to the first row of a top-down image (first byte).
782 // 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
783 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
784 // If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
785 // @param pitch The number of bytes of a row of the image buffer.
786 // @param buff An image buffer.
787 // @param bpp The number of bits per pixel used in image buffer.
788 // @param channelMap A integer array containing the mapping of input channel ordering to expected channel ordering.
789 // @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.
790 // @param data Data Pointer to C++ class container to host callback procedure.
791 void CPGFImage::ImportBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[] /*= nullptr */, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) {
792  ASSERT(buff);
793  ASSERT(m_channel[0]);
794 
795  // color transform
796  RgbToYuv(pitch, buff, bpp, channelMap, cb, data);
797 
798  if (m_downsample) {
799  // Subsampling of the chrominance and alpha channels
800  for (int i=1; i < m_header.channels; i++) {
801  Downsample(i);
802  }
803  }
804 }
805 
807 // Bilinerar Subsampling of channel ch by a factor 2
808 // Called before Write()
809 void CPGFImage::Downsample(int ch) {
810  ASSERT(ch > 0);
811 
812  const int w = m_width[0];
813  const int w2 = w/2;
814  const int h2 = m_height[0]/2;
815  const int oddW = w%2; // don't use bool -> problems with MaxSpeed optimization
816  const int oddH = m_height[0]%2; // "
817  int loPos = 0;
818  int hiPos = w;
819  int sampledPos = 0;
820  DataT* buff = m_channel[ch]; ASSERT(buff);
821 
822  for (int i=0; i < h2; i++) {
823  for (int j=0; j < w2; j++) {
824  // compute average of pixel block
825  buff[sampledPos] = (buff[loPos] + buff[loPos + 1] + buff[hiPos] + buff[hiPos + 1]) >> 2;
826  loPos += 2; hiPos += 2;
827  sampledPos++;
828  }
829  if (oddW) {
830  buff[sampledPos] = (buff[loPos] + buff[hiPos]) >> 1;
831  loPos++; hiPos++;
832  sampledPos++;
833  }
834  loPos += w; hiPos += w;
835  }
836  if (oddH) {
837  for (int j=0; j < w2; j++) {
838  buff[sampledPos] = (buff[loPos] + buff[loPos+1]) >> 1;
839  loPos += 2; hiPos += 2;
840  sampledPos++;
841  }
842  if (oddW) {
843  buff[sampledPos] = buff[loPos];
844  }
845  }
846 
847  // downsampled image has half width and half height
848  m_width[ch] = (m_width[ch] + 1)/2;
849  m_height[ch] = (m_height[ch] + 1)/2;
850 }
851 
854  const int maxThumbnailWidth = 20*FilterSize;
855  const int m = __min(m_header.width, m_header.height);
856  int s = m;
857 
858  if (m_header.nLevels < 1 || m_header.nLevels > MaxLevel) {
859  m_header.nLevels = 1;
860  // compute a good value depending on the size of the image
861  while (s > maxThumbnailWidth) {
862  m_header.nLevels++;
863  s >>= 1;
864  }
865  }
866 
867  int levels = m_header.nLevels; // we need a signed value during level reduction
868 
869  // reduce number of levels if the image size is smaller than FilterSize*(2^levels)
870  s = FilterSize*(1 << levels); // must be at least the double filter size because of subsampling
871  while (m < s) {
872  levels--;
873  s >>= 1;
874  }
875  if (levels > MaxLevel) m_header.nLevels = MaxLevel;
876  else if (levels < 0) m_header.nLevels = 0;
877  else m_header.nLevels = (UINT8)levels;
878 
879  // used in Write when PM_Absolute
880  m_percent = pow(0.25, m_header.nLevels);
881 
882  ASSERT(0 <= m_header.nLevels && m_header.nLevels <= MaxLevel);
883 }
884 
893 void CPGFImage::SetHeader(const PGFHeader& header, BYTE flags /*=0*/, const UINT8* userData /*= 0*/, UINT32 userDataLength /*= 0*/) {
894  ASSERT(!m_decoder); // current image must be closed
895  ASSERT(header.quality <= MaxQuality);
896  ASSERT(userDataLength <= MaxUserDataSize);
897 
898  // init state
899 #ifdef __PGFROISUPPORT__
900  m_streamReinitialized = false;
901 #endif
902 
903  // init preHeader
904  memcpy(m_preHeader.magic, PGFMagic, 3);
905  m_preHeader.version = PGFVersion | flags;
907 
908  // copy header
909  memcpy(&m_header, &header, HeaderSize);
910 
911  // check quality
913 
914  // complete header
915  CompleteHeader();
916 
917  // check and set number of levels
918  ComputeLevels();
919 
920  // check for downsample
928  m_downsample = true;
929  m_quant = m_header.quality - 1;
930  } else {
931  m_downsample = false;
933  }
934 
935  // update header size and copy user data
937  // update header size
939  }
940  if (userDataLength && userData) {
941  if (userDataLength > MaxUserDataSize) userDataLength = MaxUserDataSize;
942  m_postHeader.userData = new(std::nothrow) UINT8[userDataLength];
943  if (!m_postHeader.userData) ReturnWithError(InsufficientMemory);
945  memcpy(m_postHeader.userData, userData, userDataLength);
946  // update header size
947  m_preHeader.hSize += userDataLength;
948  }
949 
950  // allocate channels
951  for (int i=0; i < m_header.channels; i++) {
952  // set current width and height
953  m_width[i] = m_header.width;
954  m_height[i] = m_header.height;
955 
956  // allocate channels
957  ASSERT(!m_channel[i]);
958  m_channel[i] = new(std::nothrow) DataT[m_header.width*m_header.height];
959  if (!m_channel[i]) {
960  if (i) i--;
961  while(i) {
962  delete[] m_channel[i]; m_channel[i] = 0;
963  i--;
964  }
965  ReturnWithError(InsufficientMemory);
966  }
967  }
968 }
969 
979  ASSERT(m_header.nLevels <= MaxLevel);
980  ASSERT(m_header.quality <= MaxQuality); // quality is already initialized
981 
982  if (m_header.nLevels > 0) {
983  volatile OSError error = NoError; // volatile prevents optimizations
984  // create new wt channels
985 #ifdef LIBPGF_USE_OPENMP
986  #pragma omp parallel for default(shared)
987 #endif
988  for (int i=0; i < m_header.channels; i++) {
989  DataT *temp = nullptr;
990  if (error == NoError) {
991  if (m_wtChannel[i]) {
992  ASSERT(m_channel[i]);
993  // copy m_channel to temp
994  int size = m_height[i]*m_width[i];
995  temp = new(std::nothrow) DataT[size];
996  if (temp) {
997  memcpy(temp, m_channel[i], size*DataTSize);
998  delete m_wtChannel[i]; // also deletes m_channel
999  m_channel[i] = nullptr;
1000  } else {
1001  error = InsufficientMemory;
1002  }
1003  }
1004  if (error == NoError) {
1005  if (temp) {
1006  ASSERT(!m_channel[i]);
1007  m_channel[i] = temp;
1008  }
1010  if (m_wtChannel[i]) {
1011  #ifdef __PGFROISUPPORT__
1012  m_wtChannel[i]->SetROI(PGFRect(0, 0, m_width[i], m_height[i]));
1013  #endif
1014 
1015  // wavelet subband decomposition
1016  for (int l=0; error == NoError && l < m_header.nLevels; l++) {
1017  OSError err = m_wtChannel[i]->ForwardTransform(l, m_quant);
1018  if (err != NoError) error = err;
1019  }
1020  } else {
1021  delete[] m_channel[i];
1022  error = InsufficientMemory;
1023  }
1024  }
1025  }
1026  }
1027  if (error != NoError) {
1028  // free already allocated memory
1029  for (int i=0; i < m_header.channels; i++) {
1030  delete m_wtChannel[i];
1031  }
1032  ReturnWithError(error);
1033  }
1034 
1036 
1037  // create encoder, write headers and user data, but not level-length area
1040 
1041  #ifdef __PGFROISUPPORT__
1042  if (ROIisSupported()) {
1043  // new encoding scheme supporting ROI
1044  m_encoder->SetROI();
1045  }
1046  #endif
1047 
1048  } else {
1049  // very small image: we don't use DWT and encoding
1050 
1051  // create encoder, write headers and user data, but not level-length area
1053  }
1054 
1055  INT64 nBytes = m_encoder->ComputeHeaderLength();
1056  return (nBytes > 0) ? (UINT32)nBytes : 0;
1057 }
1058 
1060 // Encode and write next level of a PGF image at current stream position.
1061 // A PGF image is structered in levels, numbered between 0 and Levels() - 1.
1062 // Each level can be seen as a single image, containing the same content
1063 // as all other levels, but in a different size (width, height).
1064 // The image size at level i is double the size (width, height) of the image at level i+1.
1065 // The image at level 0 contains the original size.
1066 // It might throw an IOException.
1068  ASSERT(m_encoder);
1069  ASSERT(m_currentLevel > 0);
1070  ASSERT(m_header.nLevels > 0);
1071 
1072 #ifdef __PGFROISUPPORT__
1073  if (ROIisSupported()) {
1074  const int lastChannel = m_header.channels - 1;
1075 
1076  for (int i=0; i < m_header.channels; i++) {
1077  // get number of tiles and tile indices
1078  const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel);
1079  const UINT32 lastTile = nTiles - 1;
1080 
1081  if (m_currentLevel == m_header.nLevels) {
1082  // last level also has LL band
1083  ASSERT(nTiles == 1);
1085  m_encoder->EncodeTileBuffer(); // encode macro block with tile-end = true
1086  }
1087  for (UINT32 tileY=0; tileY < nTiles; tileY++) {
1088  for (UINT32 tileX=0; tileX < nTiles; tileX++) {
1089  // extract tile to macro block and encode already filled macro blocks with tile-end = false
1090  m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, true, tileX, tileY);
1091  m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, true, tileX, tileY);
1092  m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, true, tileX, tileY);
1093  if (i == lastChannel && tileY == lastTile && tileX == lastTile) {
1094  // all necessary data are buffered. next call of EncodeTileBuffer will write the last piece of data of the current level.
1096  }
1097  m_encoder->EncodeTileBuffer(); // encode last macro block with tile-end = true
1098  }
1099  }
1100  }
1101  } else
1102 #endif
1103  {
1104  for (int i=0; i < m_header.channels; i++) {
1105  ASSERT(m_wtChannel[i]);
1106  if (m_currentLevel == m_header.nLevels) {
1107  // last level also has LL band
1109  }
1110  //encoder.EncodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); // until version 4
1111  m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder); // since version 5
1112  m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder); // since version 5
1114  }
1115 
1116  // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level.
1118  }
1119 }
1120 
1122 // Return written levelLength bytes
1124  ASSERT(m_encoder);
1125 
1126  INT64 offset = m_encoder->ComputeOffset(); ASSERT(offset >= 0);
1127 
1128  if (offset > 0) {
1129  // update post-header size and rewrite pre-header
1130  m_preHeader.hSize += (UINT32)offset;
1132  }
1133 
1134  // write dummy levelLength into stream
1136 }
1137 
1149 UINT32 CPGFImage::WriteImage(CPGFStream* stream, CallbackPtr cb /*= nullptr*/, void *data /*= nullptr*/) {
1150  ASSERT(stream);
1151  ASSERT(m_preHeader.hSize);
1152 
1153  int levels = m_header.nLevels;
1154  double percent = pow(0.25, levels);
1155 
1156  // update post-header size, rewrite pre-header, and write dummy levelLength
1157  UINT32 nWrittenBytes = UpdatePostHeaderSize();
1158 
1159  if (levels == 0) {
1160  // for very small images: write channels uncoded
1161  for (int c=0; c < m_header.channels; c++) {
1162  const UINT32 size = m_width[c]*m_height[c];
1163 
1164  // write channel data into stream
1165  for (UINT32 i=0; i < size; i++) {
1166  int count = DataTSize;
1167  stream->Write(&count, &m_channel[c][i]);
1168  }
1169  }
1170 
1171  // now update progress
1172  if (cb) {
1173  if ((*cb)(1, true, data)) ReturnWithError(EscapePressed);
1174  }
1175 
1176  } else {
1177  // encode quantized wavelet coefficients and write to PGF file
1178  // encode subbands, higher levels first
1179  // color channels are interleaved
1180 
1181  // encode all levels
1182  for (m_currentLevel = levels; m_currentLevel > 0; ) {
1183  WriteLevel(); // decrements m_currentLevel
1184 
1185  // now update progress
1186  if (cb) {
1187  percent *= 4;
1188  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1189  }
1190  }
1191 
1192  // flush encoder and write level lengths
1193  m_encoder->Flush();
1194  }
1195 
1196  // update level lengths
1197  nWrittenBytes += m_encoder->UpdateLevelLength(); // return written image bytes
1198 
1199  // delete encoder
1200  delete m_encoder; m_encoder = nullptr;
1201 
1202  ASSERT(!m_encoder);
1203 
1204  return nWrittenBytes;
1205 }
1206 
1220 void CPGFImage::Write(CPGFStream* stream, UINT32* nWrittenBytes /*= nullptr*/, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) {
1221  ASSERT(stream);
1222  ASSERT(m_preHeader.hSize);
1223 
1224  // create wavelet transform channels and encoder
1225  UINT32 nBytes = WriteHeader(stream);
1226 
1227  // write image
1228  nBytes += WriteImage(stream, cb, data);
1229 
1230  // return written bytes
1231  if (nWrittenBytes) *nWrittenBytes += nBytes;
1232 }
1233 
1234 #ifdef __PGFROISUPPORT__
1235 // Encode and write down to given level at current stream position.
1237 // A PGF image is structered in levels, numbered between 0 and Levels() - 1.
1238 // Each level can be seen as a single image, containing the same content
1239 // as all other levels, but in a different size (width, height).
1240 // The image size at level i is double the size (width, height) of the image at level i+1.
1241 // The image at level 0 contains the original size.
1242 // Precondition: the PGF image contains a valid header (see also SetHeader(...)) and WriteHeader() has been called before.
1243 // The ROI encoding scheme is used.
1244 // It might throw an IOException.
1245 // @param level The image level of the resulting image in the internal image buffer.
1246 // @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.
1247 // @param data Data Pointer to C++ class container to host callback procedure.
1248 // @return The number of bytes written into stream.
1249 UINT32 CPGFImage::Write(int level, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) {
1250  ASSERT(m_header.nLevels > 0);
1251  ASSERT(0 <= level && level < m_header.nLevels);
1252  ASSERT(m_encoder);
1253  ASSERT(ROIisSupported());
1254 
1255  const int levelDiff = m_currentLevel - level;
1256  double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
1257  UINT32 nWrittenBytes = 0;
1258 
1259  if (m_currentLevel == m_header.nLevels) {
1260  // update post-header size, rewrite pre-header, and write dummy levelLength
1261  nWrittenBytes = UpdatePostHeaderSize();
1262  } else {
1263  // prepare for next level: save current file position, because the stream might have been reinitialized
1264  if (m_encoder->ComputeBufferLength()) {
1265  m_streamReinitialized = true;
1266  }
1267  }
1268 
1269  // encoding scheme with ROI
1270  while (m_currentLevel > level) {
1271  WriteLevel(); // decrements m_currentLevel
1272 
1273  if (m_levelLength) {
1274  nWrittenBytes += m_levelLength[m_header.nLevels - m_currentLevel - 1];
1275  }
1276 
1277  // now update progress
1278  if (cb) {
1279  percent *= 4;
1280  if (m_progressMode == PM_Absolute) m_percent = percent;
1281  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1282  }
1283  }
1284 
1285  // automatically closing
1286  if (m_currentLevel == 0) {
1287  if (!m_streamReinitialized) {
1288  // don't write level lengths, if the stream position changed inbetween two Write operations
1290  }
1291  // delete encoder
1292  delete m_encoder; m_encoder = nullptr;
1293  }
1294 
1295  return nWrittenBytes;
1296 }
1297 #endif // __PGFROISUPPORT__
1298 
1299 
1301 // Check for valid import image mode.
1302 // @param mode Image mode
1303 // @return True if an image of given mode can be imported with ImportBitmap(...)
1305  size_t size = DataTSize;
1306 
1307  if (size >= 2) {
1308  switch(mode) {
1309  case ImageModeBitmap:
1310  case ImageModeIndexedColor:
1311  case ImageModeGrayScale:
1312  case ImageModeRGBColor:
1313  case ImageModeCMYKColor:
1314  case ImageModeHSLColor:
1315  case ImageModeHSBColor:
1316  //case ImageModeDuotone:
1317  case ImageModeLabColor:
1318  case ImageModeRGB12:
1319  case ImageModeRGB16:
1320  case ImageModeRGBA:
1321  return true;
1322  }
1323  }
1324  if (size >= 3) {
1325  switch(mode) {
1326  case ImageModeGray16:
1327  case ImageModeRGB48:
1328  case ImageModeLab48:
1329  case ImageModeCMYK64:
1330  //case ImageModeDuotone16:
1331  return true;
1332  }
1333  }
1334  if (size >=4) {
1335  switch(mode) {
1336  case ImageModeGray32:
1337  return true;
1338  }
1339  }
1340  return false;
1341 }
1342 
1349 void CPGFImage::GetColorTable(UINT32 iFirstColor, UINT32 nColors, RGBQUAD* prgbColors) const {
1350  if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError);
1351 
1352  for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
1353  prgbColors[j] = m_postHeader.clut[i];
1354  }
1355 }
1356 
1363 void CPGFImage::SetColorTable(UINT32 iFirstColor, UINT32 nColors, const RGBQUAD* prgbColors) {
1364  if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError);
1365 
1366  for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
1367  m_postHeader.clut[i] = prgbColors[j];
1368  }
1369 }
1370 
1372 // Buffer transform from interleaved to channel seperated format
1373 // the absolute value of pitch is the number of bytes of an image row
1374 // if pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row)
1375 // if pitch is positive, then buff points to the first row of a top-down image (first byte)
1376 // bpp is the number of bits per pixel used in image buffer buff
1377 //
1378 // RGB is transformed into YUV format (ordering of buffer data is BGR[A])
1379 // Y = (R + 2*G + B)/4 -128
1380 // U = R - G
1381 // V = B - G
1382 //
1383 // Since PGF Codec version 2.0 images are stored in top-down direction
1384 //
1385 // 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
1386 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
1387 // If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
1388 void CPGFImage::RgbToYuv(int pitch, UINT8* buff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data /*=nullptr*/) {
1389  ASSERT(buff);
1390  UINT32 yPos = 0, cnt = 0;
1391  double percent = 0;
1392  const double dP = 1.0/m_header.height;
1393  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
1394 
1395  if (channelMap == nullptr) channelMap = defMap;
1396 
1397  switch(m_header.mode) {
1398  case ImageModeBitmap:
1399  {
1400  ASSERT(m_header.channels == 1);
1401  ASSERT(m_header.bpp == 1);
1402  ASSERT(bpp == 1);
1403 
1404  const UINT32 w = m_header.width;
1405  const UINT32 w2 = (m_header.width + 7)/8;
1406  DataT* y = m_channel[0]; ASSERT(y);
1407 
1408  // new unpacked version since version 7
1409  for (UINT32 h = 0; h < m_header.height; h++) {
1410  if (cb) {
1411  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1412  percent += dP;
1413  }
1414  cnt = 0;
1415  for (UINT32 j = 0; j < w2; j++) {
1416  UINT8 byte = buff[j];
1417  for (int k = 0; k < 8; k++) {
1418  UINT8 bit = (byte & 0x80) >> 7;
1419  if (cnt < w) y[yPos++] = bit;
1420  byte <<= 1;
1421  cnt++;
1422  }
1423  }
1424  buff += pitch;
1425  }
1426  /* old version: packed values: 8 pixels in 1 byte
1427  for (UINT32 h = 0; h < m_header.height; h++) {
1428  if (cb) {
1429  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1430  percent += dP;
1431  }
1432 
1433  for (UINT32 j = 0; j < w2; j++) {
1434  y[yPos++] = buff[j] - YUVoffset8;
1435  }
1436  // version 5 and 6
1437  // for (UINT32 j = w2; j < w; j++) {
1438  // y[yPos++] = YUVoffset8;
1439  //}
1440  buff += pitch;
1441  }
1442  */
1443  }
1444  break;
1445  case ImageModeIndexedColor:
1446  case ImageModeGrayScale:
1447  case ImageModeHSLColor:
1448  case ImageModeHSBColor:
1449  case ImageModeLabColor:
1450  {
1451  ASSERT(m_header.channels >= 1);
1452  ASSERT(m_header.bpp == m_header.channels*8);
1453  ASSERT(bpp%8 == 0);
1454  const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1455 
1456  for (UINT32 h=0; h < m_header.height; h++) {
1457  if (cb) {
1458  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1459  percent += dP;
1460  }
1461 
1462  cnt = 0;
1463  for (UINT32 w=0; w < m_header.width; w++) {
1464  for (int c=0; c < m_header.channels; c++) {
1465  m_channel[c][yPos] = buff[cnt + channelMap[c]] - YUVoffset8;
1466  }
1467  cnt += channels;
1468  yPos++;
1469  }
1470  buff += pitch;
1471  }
1472  }
1473  break;
1474  case ImageModeGray16:
1475  case ImageModeLab48:
1476  {
1477  ASSERT(m_header.channels >= 1);
1478  ASSERT(m_header.bpp == m_header.channels*16);
1479  ASSERT(bpp%16 == 0);
1480 
1481  UINT16 *buff16 = (UINT16 *)buff;
1482  const int pitch16 = pitch/2;
1483  const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1484  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1485  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1486 
1487  for (UINT32 h=0; h < m_header.height; h++) {
1488  if (cb) {
1489  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1490  percent += dP;
1491  }
1492 
1493  cnt = 0;
1494  for (UINT32 w=0; w < m_header.width; w++) {
1495  for (int c=0; c < m_header.channels; c++) {
1496  m_channel[c][yPos] = (buff16[cnt + channelMap[c]] >> shift) - yuvOffset16;
1497  }
1498  cnt += channels;
1499  yPos++;
1500  }
1501  buff16 += pitch16;
1502  }
1503  }
1504  break;
1505  case ImageModeRGBColor:
1506  {
1507  ASSERT(m_header.channels == 3);
1508  ASSERT(m_header.bpp == m_header.channels*8);
1509  ASSERT(bpp%8 == 0);
1510 
1511  DataT* y = m_channel[0]; ASSERT(y);
1512  DataT* u = m_channel[1]; ASSERT(u);
1513  DataT* v = m_channel[2]; ASSERT(v);
1514  const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1515  UINT8 b, g, r;
1516 
1517  for (UINT32 h=0; h < m_header.height; h++) {
1518  if (cb) {
1519  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1520  percent += dP;
1521  }
1522 
1523  cnt = 0;
1524  for (UINT32 w=0; w < m_header.width; w++) {
1525  b = buff[cnt + channelMap[0]];
1526  g = buff[cnt + channelMap[1]];
1527  r = buff[cnt + channelMap[2]];
1528  // Yuv
1529  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
1530  u[yPos] = r - g;
1531  v[yPos] = b - g;
1532  yPos++;
1533  cnt += channels;
1534  }
1535  buff += pitch;
1536  }
1537  }
1538  break;
1539  case ImageModeRGB48:
1540  {
1541  ASSERT(m_header.channels == 3);
1542  ASSERT(m_header.bpp == m_header.channels*16);
1543  ASSERT(bpp%16 == 0);
1544 
1545  UINT16 *buff16 = (UINT16 *)buff;
1546  const int pitch16 = pitch/2;
1547  const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1548  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1549  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1550 
1551  DataT* y = m_channel[0]; ASSERT(y);
1552  DataT* u = m_channel[1]; ASSERT(u);
1553  DataT* v = m_channel[2]; ASSERT(v);
1554  UINT16 b, g, r;
1555 
1556  for (UINT32 h=0; h < m_header.height; h++) {
1557  if (cb) {
1558  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1559  percent += dP;
1560  }
1561 
1562  cnt = 0;
1563  for (UINT32 w=0; w < m_header.width; w++) {
1564  b = buff16[cnt + channelMap[0]] >> shift;
1565  g = buff16[cnt + channelMap[1]] >> shift;
1566  r = buff16[cnt + channelMap[2]] >> shift;
1567  // Yuv
1568  y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
1569  u[yPos] = r - g;
1570  v[yPos] = b - g;
1571  yPos++;
1572  cnt += channels;
1573  }
1574  buff16 += pitch16;
1575  }
1576  }
1577  break;
1578  case ImageModeRGBA:
1579  case ImageModeCMYKColor:
1580  {
1581  ASSERT(m_header.channels == 4);
1582  ASSERT(m_header.bpp == m_header.channels*8);
1583  ASSERT(bpp%8 == 0);
1584  const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1585 
1586  DataT* y = m_channel[0]; ASSERT(y);
1587  DataT* u = m_channel[1]; ASSERT(u);
1588  DataT* v = m_channel[2]; ASSERT(v);
1589  DataT* a = m_channel[3]; ASSERT(a);
1590  UINT8 b, g, r;
1591 
1592  for (UINT32 h=0; h < m_header.height; h++) {
1593  if (cb) {
1594  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1595  percent += dP;
1596  }
1597 
1598  cnt = 0;
1599  for (UINT32 w=0; w < m_header.width; w++) {
1600  b = buff[cnt + channelMap[0]];
1601  g = buff[cnt + channelMap[1]];
1602  r = buff[cnt + channelMap[2]];
1603  // Yuv
1604  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
1605  u[yPos] = r - g;
1606  v[yPos] = b - g;
1607  a[yPos++] = buff[cnt + channelMap[3]] - YUVoffset8;
1608  cnt += channels;
1609  }
1610  buff += pitch;
1611  }
1612  }
1613  break;
1614  case ImageModeCMYK64:
1615  {
1616  ASSERT(m_header.channels == 4);
1617  ASSERT(m_header.bpp == m_header.channels*16);
1618  ASSERT(bpp%16 == 0);
1619 
1620  UINT16 *buff16 = (UINT16 *)buff;
1621  const int pitch16 = pitch/2;
1622  const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1623  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1624  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1625 
1626  DataT* y = m_channel[0]; ASSERT(y);
1627  DataT* u = m_channel[1]; ASSERT(u);
1628  DataT* v = m_channel[2]; ASSERT(v);
1629  DataT* a = m_channel[3]; ASSERT(a);
1630  UINT16 b, g, r;
1631 
1632  for (UINT32 h=0; h < m_header.height; h++) {
1633  if (cb) {
1634  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1635  percent += dP;
1636  }
1637 
1638  cnt = 0;
1639  for (UINT32 w=0; w < m_header.width; w++) {
1640  b = buff16[cnt + channelMap[0]] >> shift;
1641  g = buff16[cnt + channelMap[1]] >> shift;
1642  r = buff16[cnt + channelMap[2]] >> shift;
1643  // Yuv
1644  y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
1645  u[yPos] = r - g;
1646  v[yPos] = b - g;
1647  a[yPos++] = (buff16[cnt + channelMap[3]] >> shift) - yuvOffset16;
1648  cnt += channels;
1649  }
1650  buff16 += pitch16;
1651  }
1652  }
1653  break;
1654 #ifdef __PGF32SUPPORT__
1655  case ImageModeGray32:
1656  {
1657  ASSERT(m_header.channels == 1);
1658  ASSERT(m_header.bpp == 32);
1659  ASSERT(bpp == 32);
1660  ASSERT(DataTSize == sizeof(UINT32));
1661 
1662  DataT* y = m_channel[0]; ASSERT(y);
1663 
1664  UINT32 *buff32 = (UINT32 *)buff;
1665  const int pitch32 = pitch/4;
1666  const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1667  const DataT yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
1668 
1669  for (UINT32 h=0; h < m_header.height; h++) {
1670  if (cb) {
1671  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1672  percent += dP;
1673  }
1674 
1675  for (UINT32 w=0; w < m_header.width; w++) {
1676  y[yPos++] = (buff32[w] >> shift) - yuvOffset31;
1677  }
1678  buff32 += pitch32;
1679  }
1680  }
1681  break;
1682 #endif
1683  case ImageModeRGB12:
1684  {
1685  ASSERT(m_header.channels == 3);
1686  ASSERT(m_header.bpp == m_header.channels*4);
1687  ASSERT(bpp == m_header.channels*4);
1688 
1689  DataT* y = m_channel[0]; ASSERT(y);
1690  DataT* u = m_channel[1]; ASSERT(u);
1691  DataT* v = m_channel[2]; ASSERT(v);
1692 
1693  UINT8 rgb = 0, b, g, r;
1694 
1695  for (UINT32 h=0; h < m_header.height; h++) {
1696  if (cb) {
1697  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1698  percent += dP;
1699  }
1700 
1701  cnt = 0;
1702  for (UINT32 w=0; w < m_header.width; w++) {
1703  if (w%2 == 0) {
1704  // even pixel position
1705  rgb = buff[cnt];
1706  b = rgb & 0x0F;
1707  g = (rgb & 0xF0) >> 4;
1708  cnt++;
1709  rgb = buff[cnt];
1710  r = rgb & 0x0F;
1711  } else {
1712  // odd pixel position
1713  b = (rgb & 0xF0) >> 4;
1714  cnt++;
1715  rgb = buff[cnt];
1716  g = rgb & 0x0F;
1717  r = (rgb & 0xF0) >> 4;
1718  cnt++;
1719  }
1720 
1721  // Yuv
1722  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset4;
1723  u[yPos] = r - g;
1724  v[yPos] = b - g;
1725  yPos++;
1726  }
1727  buff += pitch;
1728  }
1729  }
1730  break;
1731  case ImageModeRGB16:
1732  {
1733  ASSERT(m_header.channels == 3);
1734  ASSERT(m_header.bpp == 16);
1735  ASSERT(bpp == 16);
1736 
1737  DataT* y = m_channel[0]; ASSERT(y);
1738  DataT* u = m_channel[1]; ASSERT(u);
1739  DataT* v = m_channel[2]; ASSERT(v);
1740 
1741  UINT16 *buff16 = (UINT16 *)buff;
1742  UINT16 rgb, b, g, r;
1743  const int pitch16 = pitch/2;
1744 
1745  for (UINT32 h=0; h < m_header.height; h++) {
1746  if (cb) {
1747  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1748  percent += dP;
1749  }
1750  for (UINT32 w=0; w < m_header.width; w++) {
1751  rgb = buff16[w];
1752  r = (rgb & 0xF800) >> 10; // highest 5 bits
1753  g = (rgb & 0x07E0) >> 5; // middle 6 bits
1754  b = (rgb & 0x001F) << 1; // lowest 5 bits
1755  // Yuv
1756  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset6;
1757  u[yPos] = r - g;
1758  v[yPos] = b - g;
1759  yPos++;
1760  }
1761 
1762  buff16 += pitch16;
1763  }
1764  }
1765  break;
1766  default:
1767  ASSERT(false);
1768  }
1769 }
1770 
1772 // Get image data in interleaved format: (ordering of RGB data is BGR[A])
1773 // Upsampling, YUV to RGB transform and interleaving are done here to reduce the number
1774 // of passes over the data.
1775 // The absolute value of pitch is the number of bytes of an image row of the given image buffer.
1776 // If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row).
1777 // if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte).
1778 // 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
1779 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode.
1780 // If your provided image buffer expects a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
1781 // It might throw an IOException.
1782 // @param pitch The number of bytes of a row of the image buffer.
1783 // @param buff An image buffer.
1784 // @param bpp The number of bits per pixel used in image buffer.
1785 // @param channelMap A integer array containing the mapping of PGF channel ordering to expected channel ordering.
1786 // @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.
1787 // @param data Data Pointer to C++ class container to host callback procedure.
1788 void CPGFImage::GetBitmap(int pitch, UINT8* buff, BYTE bpp, int channelMap[] /*= nullptr */, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) const {
1789  ASSERT(buff);
1790  UINT32 w = m_width[0]; // width of decoded image
1791  UINT32 h = m_height[0]; // height of decoded image
1792  UINT32 yw = w; // y-channel width
1793  UINT32 uw = m_width[1]; // u-channel width
1794  UINT32 roiOffsetX = 0;
1795  UINT32 roiOffsetY = 0;
1796  UINT32 yOffset = 0;
1797  UINT32 uOffset = 0;
1798 
1799 #ifdef __PGFROISUPPORT__
1800  const PGFRect& roi = GetAlignedROI(); // in pixels, roi is usually larger than levelRoi
1801  ASSERT(w == roi.Width() && h == roi.Height());
1802  const PGFRect levelRoi = ComputeLevelROI();
1803  ASSERT(roi.left <= levelRoi.left && levelRoi.right <= roi.right);
1804  ASSERT(roi.top <= levelRoi.top && levelRoi.bottom <= roi.bottom);
1805 
1806  if (ROIisSupported() && (levelRoi.Width() < w || levelRoi.Height() < h)) {
1807  // ROI is used
1808  w = levelRoi.Width();
1809  h = levelRoi.Height();
1810  roiOffsetX = levelRoi.left - roi.left;
1811  roiOffsetY = levelRoi.top - roi.top;
1812  yOffset = roiOffsetX + roiOffsetY*yw;
1813 
1814  if (m_downsample) {
1815  const PGFRect& downsampledRoi = GetAlignedROI(1);
1816  uOffset = levelRoi.left/2 - downsampledRoi.left + (levelRoi.top/2 - downsampledRoi.top)*m_width[1];
1817  } else {
1818  uOffset = yOffset;
1819  }
1820  }
1821 #endif
1822 
1823  const double dP = 1.0/h;
1824  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
1825  if (channelMap == nullptr) channelMap = defMap;
1826  DataT uAvg, vAvg;
1827  double percent = 0;
1828  UINT32 i, j;
1829 
1830  switch(m_header.mode) {
1831  case ImageModeBitmap:
1832  {
1833  ASSERT(m_header.channels == 1);
1834  ASSERT(m_header.bpp == 1);
1835  ASSERT(bpp == 1);
1836 
1837  const UINT32 w2 = (w + 7)/8;
1838  DataT* y = m_channel[0]; ASSERT(y);
1839 
1840  if (m_preHeader.version & Version7) {
1841  // new unpacked version has a little better compression ratio
1842  // since version 7
1843  for (i = 0; i < h; i++) {
1844  UINT32 cnt = 0;
1845  for (j = 0; j < w2; j++) {
1846  UINT8 byte = 0;
1847  for (int k = 0; k < 8; k++) {
1848  byte <<= 1;
1849  UINT8 bit = 0;
1850  if (cnt < w) {
1851  bit = y[yOffset + cnt] & 1;
1852  }
1853  byte |= bit;
1854  cnt++;
1855  }
1856  buff[j] = byte;
1857  }
1858  yOffset += yw;
1859  buff += pitch;
1860 
1861  if (cb) {
1862  percent += dP;
1863  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1864  }
1865  }
1866  } else {
1867  // old versions
1868  // packed pixels: 8 pixel in 1 byte of channel[0]
1869  if (!(m_preHeader.version & Version5)) yw = w2; // not version 5 or 6
1870  yOffset = roiOffsetX/8 + roiOffsetY*yw; // 1 byte in y contains 8 pixel values
1871  for (i = 0; i < h; i++) {
1872  for (j = 0; j < w2; j++) {
1873  buff[j] = Clamp8(y[yOffset + j] + YUVoffset8);
1874  }
1875  yOffset += yw;
1876  buff += pitch;
1877 
1878  if (cb) {
1879  percent += dP;
1880  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1881  }
1882  }
1883  }
1884  break;
1885  }
1886  case ImageModeIndexedColor:
1887  case ImageModeGrayScale:
1888  case ImageModeHSLColor:
1889  case ImageModeHSBColor:
1890  {
1891  ASSERT(m_header.channels >= 1);
1892  ASSERT(m_header.bpp == m_header.channels*8);
1893  ASSERT(bpp%8 == 0);
1894 
1895  UINT32 cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
1896 
1897  for (i=0; i < h; i++) {
1898  UINT32 yPos = yOffset;
1899  cnt = 0;
1900  for (j=0; j < w; j++) {
1901  for (UINT32 c=0; c < m_header.channels; c++) {
1902  buff[cnt + channelMap[c]] = Clamp8(m_channel[c][yPos] + YUVoffset8);
1903  }
1904  cnt += channels;
1905  yPos++;
1906  }
1907  yOffset += yw;
1908  buff += pitch;
1909 
1910  if (cb) {
1911  percent += dP;
1912  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1913  }
1914  }
1915  break;
1916  }
1917  case ImageModeGray16:
1918  {
1919  ASSERT(m_header.channels >= 1);
1920  ASSERT(m_header.bpp == m_header.channels*16);
1921 
1922  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1923  UINT32 cnt, channels;
1924 
1925  if (bpp%16 == 0) {
1926  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1927  UINT16 *buff16 = (UINT16 *)buff;
1928  int pitch16 = pitch/2;
1929  channels = bpp/16; ASSERT(channels >= m_header.channels);
1930 
1931  for (i=0; i < h; i++) {
1932  UINT32 yPos = yOffset;
1933  cnt = 0;
1934  for (j=0; j < w; j++) {
1935  for (UINT32 c=0; c < m_header.channels; c++) {
1936  buff16[cnt + channelMap[c]] = Clamp16((m_channel[c][yPos] + yuvOffset16) << shift);
1937  }
1938  cnt += channels;
1939  yPos++;
1940  }
1941  yOffset += yw;
1942  buff16 += pitch16;
1943 
1944  if (cb) {
1945  percent += dP;
1946  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1947  }
1948  }
1949  } else {
1950  ASSERT(bpp%8 == 0);
1951  const int shift = __max(0, UsedBitsPerChannel() - 8);
1952  channels = bpp/8; ASSERT(channels >= m_header.channels);
1953 
1954  for (i=0; i < h; i++) {
1955  UINT32 yPos = yOffset;
1956  cnt = 0;
1957  for (j=0; j < w; j++) {
1958  for (UINT32 c=0; c < m_header.channels; c++) {
1959  buff[cnt + channelMap[c]] = Clamp8((m_channel[c][yPos] + yuvOffset16) >> shift);
1960  }
1961  cnt += channels;
1962  yPos++;
1963  }
1964  yOffset += yw;
1965  buff += pitch;
1966 
1967  if (cb) {
1968  percent += dP;
1969  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1970  }
1971  }
1972  }
1973  break;
1974  }
1975  case ImageModeRGBColor:
1976  {
1977  ASSERT(m_header.channels == 3);
1978  ASSERT(m_header.bpp == m_header.channels*8);
1979  ASSERT(bpp%8 == 0);
1980  ASSERT(bpp >= m_header.bpp);
1981 
1982  DataT* y = m_channel[0]; ASSERT(y);
1983  DataT* u = m_channel[1]; ASSERT(u);
1984  DataT* v = m_channel[2]; ASSERT(v);
1985  UINT8 *buffg = &buff[channelMap[1]],
1986  *buffr = &buff[channelMap[2]],
1987  *buffb = &buff[channelMap[0]];
1988  UINT8 g;
1989  UINT32 cnt, channels = bpp/8;
1990 
1991  if (m_downsample) {
1992  for (i=0; i < h; i++) {
1993  UINT32 uPos = uOffset;
1994  UINT32 yPos = yOffset;
1995  cnt = 0;
1996  for (j=0; j < w; j++) {
1997  // u and v are downsampled
1998  uAvg = u[uPos];
1999  vAvg = v[uPos];
2000  // Yuv
2001  buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2002  buffr[cnt] = Clamp8(uAvg + g);
2003  buffb[cnt] = Clamp8(vAvg + g);
2004  cnt += channels;
2005  if (j & 1) uPos++;
2006  yPos++;
2007  }
2008  if (i & 1) uOffset += uw;
2009  yOffset += yw;
2010  buffb += pitch;
2011  buffg += pitch;
2012  buffr += pitch;
2013 
2014  if (cb) {
2015  percent += dP;
2016  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2017  }
2018  }
2019 
2020  } else {
2021  for (i=0; i < h; i++) {
2022  cnt = 0;
2023  UINT32 yPos = yOffset;
2024  for (j = 0; j < w; j++) {
2025  uAvg = u[yPos];
2026  vAvg = v[yPos];
2027  // Yuv
2028  buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2029  buffr[cnt] = Clamp8(uAvg + g);
2030  buffb[cnt] = Clamp8(vAvg + g);
2031  cnt += channels;
2032  yPos++;
2033  }
2034  yOffset += yw;
2035  buffb += pitch;
2036  buffg += pitch;
2037  buffr += pitch;
2038 
2039  if (cb) {
2040  percent += dP;
2041  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2042  }
2043  }
2044  }
2045  break;
2046  }
2047  case ImageModeRGB48:
2048  {
2049  ASSERT(m_header.channels == 3);
2050  ASSERT(m_header.bpp == 48);
2051 
2052  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2053 
2054  DataT* y = m_channel[0]; ASSERT(y);
2055  DataT* u = m_channel[1]; ASSERT(u);
2056  DataT* v = m_channel[2]; ASSERT(v);
2057  UINT32 cnt, channels;
2058  DataT g;
2059 
2060  if (bpp >= 48 && bpp%16 == 0) {
2061  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2062  UINT16 *buff16 = (UINT16 *)buff;
2063  int pitch16 = pitch/2;
2064  channels = bpp/16; ASSERT(channels >= m_header.channels);
2065 
2066  for (i=0; i < h; i++) {
2067  UINT32 uPos = uOffset;
2068  UINT32 yPos = yOffset;
2069  cnt = 0;
2070  for (j=0; j < w; j++) {
2071  uAvg = u[uPos];
2072  vAvg = v[uPos];
2073  // Yuv
2074  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2075  buff16[cnt + channelMap[1]] = Clamp16(g << shift);
2076  buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
2077  buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
2078  cnt += channels;
2079  if (!m_downsample || (j & 1)) uPos++;
2080  yPos++;
2081  }
2082  if (!m_downsample || (i & 1)) uOffset += uw;
2083  yOffset += yw;
2084  buff16 += pitch16;
2085 
2086  if (cb) {
2087  percent += dP;
2088  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2089  }
2090  }
2091  } else {
2092  ASSERT(bpp%8 == 0);
2093  const int shift = __max(0, UsedBitsPerChannel() - 8);
2094  channels = bpp/8; ASSERT(channels >= m_header.channels);
2095 
2096  for (i=0; i < h; i++) {
2097  UINT32 uPos = uOffset;
2098  UINT32 yPos = yOffset;
2099  cnt = 0;
2100  for (j=0; j < w; j++) {
2101  uAvg = u[uPos];
2102  vAvg = v[uPos];
2103  // Yuv
2104  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2105  buff[cnt + channelMap[1]] = Clamp8(g >> shift);
2106  buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
2107  buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
2108  cnt += channels;
2109  if (!m_downsample || (j & 1)) uPos++;
2110  yPos++;
2111  }
2112  if (!m_downsample || (i & 1)) uOffset += uw;
2113  yOffset += yw;
2114  buff += pitch;
2115 
2116  if (cb) {
2117  percent += dP;
2118  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2119  }
2120  }
2121  }
2122  break;
2123  }
2124  case ImageModeLabColor:
2125  {
2126  ASSERT(m_header.channels == 3);
2127  ASSERT(m_header.bpp == m_header.channels*8);
2128  ASSERT(bpp%8 == 0);
2129 
2130  DataT* l = m_channel[0]; ASSERT(l);
2131  DataT* a = m_channel[1]; ASSERT(a);
2132  DataT* b = m_channel[2]; ASSERT(b);
2133  UINT32 cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
2134 
2135  for (i=0; i < h; i++) {
2136  UINT32 uPos = uOffset;
2137  UINT32 yPos = yOffset;
2138  cnt = 0;
2139  for (j=0; j < w; j++) {
2140  uAvg = a[uPos];
2141  vAvg = b[uPos];
2142  buff[cnt + channelMap[0]] = Clamp8(l[yPos] + YUVoffset8);
2143  buff[cnt + channelMap[1]] = Clamp8(uAvg + YUVoffset8);
2144  buff[cnt + channelMap[2]] = Clamp8(vAvg + YUVoffset8);
2145  cnt += channels;
2146  if (!m_downsample || (j & 1)) uPos++;
2147  yPos++;
2148  }
2149  if (!m_downsample || (i & 1)) uOffset += uw;
2150  yOffset += yw;
2151  buff += pitch;
2152 
2153  if (cb) {
2154  percent += dP;
2155  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2156  }
2157  }
2158  break;
2159  }
2160  case ImageModeLab48:
2161  {
2162  ASSERT(m_header.channels == 3);
2163  ASSERT(m_header.bpp == m_header.channels*16);
2164 
2165  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2166 
2167  DataT* l = m_channel[0]; ASSERT(l);
2168  DataT* a = m_channel[1]; ASSERT(a);
2169  DataT* b = m_channel[2]; ASSERT(b);
2170  UINT32 cnt, channels;
2171 
2172  if (bpp%16 == 0) {
2173  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2174  UINT16 *buff16 = (UINT16 *)buff;
2175  int pitch16 = pitch/2;
2176  channels = bpp/16; ASSERT(channels >= m_header.channels);
2177 
2178  for (i=0; i < h; i++) {
2179  UINT32 uPos = uOffset;
2180  UINT32 yPos = yOffset;
2181  cnt = 0;
2182  for (j=0; j < w; j++) {
2183  uAvg = a[uPos];
2184  vAvg = b[uPos];
2185  buff16[cnt + channelMap[0]] = Clamp16((l[yPos] + yuvOffset16) << shift);
2186  buff16[cnt + channelMap[1]] = Clamp16((uAvg + yuvOffset16) << shift);
2187  buff16[cnt + channelMap[2]] = Clamp16((vAvg + yuvOffset16) << shift);
2188  cnt += channels;
2189  if (!m_downsample || (j & 1)) uPos++;
2190  yPos++;
2191  }
2192  if (!m_downsample || (i & 1)) uOffset += uw;
2193  yOffset += yw;
2194  buff16 += pitch16;
2195 
2196  if (cb) {
2197  percent += dP;
2198  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2199  }
2200  }
2201  } else {
2202  ASSERT(bpp%8 == 0);
2203  const int shift = __max(0, UsedBitsPerChannel() - 8);
2204  channels = bpp/8; ASSERT(channels >= m_header.channels);
2205 
2206  for (i=0; i < h; i++) {
2207  UINT32 uPos = uOffset;
2208  UINT32 yPos = yOffset;
2209  cnt = 0;
2210  for (j=0; j < w; j++) {
2211  uAvg = a[uPos];
2212  vAvg = b[uPos];
2213  buff[cnt + channelMap[0]] = Clamp8((l[yPos] + yuvOffset16) >> shift);
2214  buff[cnt + channelMap[1]] = Clamp8((uAvg + yuvOffset16) >> shift);
2215  buff[cnt + channelMap[2]] = Clamp8((vAvg + yuvOffset16) >> shift);
2216  cnt += channels;
2217  if (!m_downsample || (j & 1)) uPos++;
2218  yPos++;
2219  }
2220  if (!m_downsample || (i & 1)) uOffset += uw;
2221  yOffset += yw;
2222  buff += pitch;
2223 
2224  if (cb) {
2225  percent += dP;
2226  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2227  }
2228  }
2229  }
2230  break;
2231  }
2232  case ImageModeRGBA:
2233  case ImageModeCMYKColor:
2234  {
2235  ASSERT(m_header.channels == 4);
2236  ASSERT(m_header.bpp == m_header.channels*8);
2237  ASSERT(bpp%8 == 0);
2238 
2239  DataT* y = m_channel[0]; ASSERT(y);
2240  DataT* u = m_channel[1]; ASSERT(u);
2241  DataT* v = m_channel[2]; ASSERT(v);
2242  DataT* a = m_channel[3]; ASSERT(a);
2243  UINT8 g, aAvg;
2244  UINT32 cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
2245 
2246  for (i=0; i < h; i++) {
2247  UINT32 uPos = uOffset;
2248  UINT32 yPos = yOffset;
2249  cnt = 0;
2250  for (j=0; j < w; j++) {
2251  uAvg = u[uPos];
2252  vAvg = v[uPos];
2253  aAvg = Clamp8(a[uPos] + YUVoffset8);
2254  // Yuv
2255  buff[cnt + channelMap[1]] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2256  buff[cnt + channelMap[2]] = Clamp8(uAvg + g);
2257  buff[cnt + channelMap[0]] = Clamp8(vAvg + g);
2258  buff[cnt + channelMap[3]] = aAvg;
2259  cnt += channels;
2260  if (!m_downsample || (j & 1)) uPos++;
2261  yPos++;
2262  }
2263  if (!m_downsample || (i & 1)) uOffset += uw;
2264  yOffset += yw;
2265  buff += pitch;
2266 
2267  if (cb) {
2268  percent += dP;
2269  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2270  }
2271  }
2272  break;
2273  }
2274  case ImageModeCMYK64:
2275  {
2276  ASSERT(m_header.channels == 4);
2277  ASSERT(m_header.bpp == 64);
2278 
2279  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2280 
2281  DataT* y = m_channel[0]; ASSERT(y);
2282  DataT* u = m_channel[1]; ASSERT(u);
2283  DataT* v = m_channel[2]; ASSERT(v);
2284  DataT* a = m_channel[3]; ASSERT(a);
2285  DataT g, aAvg;
2286  UINT32 cnt, channels;
2287 
2288  if (bpp%16 == 0) {
2289  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2290  UINT16 *buff16 = (UINT16 *)buff;
2291  int pitch16 = pitch/2;
2292  channels = bpp/16; ASSERT(channels >= m_header.channels);
2293 
2294  for (i=0; i < h; i++) {
2295  UINT32 uPos = uOffset;
2296  UINT32 yPos = yOffset;
2297  cnt = 0;
2298  for (j=0; j < w; j++) {
2299  uAvg = u[uPos];
2300  vAvg = v[uPos];
2301  aAvg = a[uPos] + yuvOffset16;
2302  // Yuv
2303  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2304  buff16[cnt + channelMap[1]] = Clamp16(g << shift);
2305  buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
2306  buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
2307  buff16[cnt + channelMap[3]] = Clamp16(aAvg << shift);
2308  cnt += channels;
2309  if (!m_downsample || (j & 1)) uPos++;
2310  yPos++;
2311  }
2312  if (!m_downsample || (i & 1)) uOffset += uw;
2313  yOffset += yw;
2314  buff16 += pitch16;
2315 
2316  if (cb) {
2317  percent += dP;
2318  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2319  }
2320  }
2321  } else {
2322  ASSERT(bpp%8 == 0);
2323  const int shift = __max(0, UsedBitsPerChannel() - 8);
2324  channels = bpp/8; ASSERT(channels >= m_header.channels);
2325 
2326  for (i=0; i < h; i++) {
2327  UINT32 uPos = uOffset;
2328  UINT32 yPos = yOffset;
2329  cnt = 0;
2330  for (j=0; j < w; j++) {
2331  uAvg = u[uPos];
2332  vAvg = v[uPos];
2333  aAvg = a[uPos] + yuvOffset16;
2334  // Yuv
2335  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2336  buff[cnt + channelMap[1]] = Clamp8(g >> shift);
2337  buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
2338  buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
2339  buff[cnt + channelMap[3]] = Clamp8(aAvg >> shift);
2340  cnt += channels;
2341  if (!m_downsample || (j & 1)) uPos++;
2342  yPos++;
2343  }
2344  if (!m_downsample || (i & 1)) uOffset += uw;
2345  yOffset += yw;
2346  buff += pitch;
2347 
2348  if (cb) {
2349  percent += dP;
2350  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2351  }
2352  }
2353  }
2354  break;
2355  }
2356 #ifdef __PGF32SUPPORT__
2357  case ImageModeGray32:
2358  {
2359  ASSERT(m_header.channels == 1);
2360  ASSERT(m_header.bpp == 32);
2361 
2362  const int yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
2363  DataT* y = m_channel[0]; ASSERT(y);
2364 
2365  if (bpp == 32) {
2366  const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2367  UINT32 *buff32 = (UINT32 *)buff;
2368  int pitch32 = pitch/4;
2369 
2370  for (i=0; i < h; i++) {
2371  UINT32 yPos = yOffset;
2372  for (j = 0; j < w; j++) {
2373  buff32[j] = Clamp31((y[yPos++] + yuvOffset31) << shift);
2374  }
2375  yOffset += yw;
2376  buff32 += pitch32;
2377 
2378  if (cb) {
2379  percent += dP;
2380  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2381  }
2382  }
2383  } else if (bpp == 16) {
2384  const int usedBits = UsedBitsPerChannel();
2385  UINT16 *buff16 = (UINT16 *)buff;
2386  int pitch16 = pitch/2;
2387 
2388  if (usedBits < 16) {
2389  const int shift = 16 - usedBits;
2390  for (i=0; i < h; i++) {
2391  UINT32 yPos = yOffset;
2392  for (j = 0; j < w; j++) {
2393  buff16[j] = Clamp16((y[yPos++] + yuvOffset31) << shift);
2394  }
2395  yOffset += yw;
2396  buff16 += pitch16;
2397 
2398  if (cb) {
2399  percent += dP;
2400  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2401  }
2402  }
2403  } else {
2404  const int shift = __max(0, usedBits - 16);
2405  for (i=0; i < h; i++) {
2406  UINT32 yPos = yOffset;
2407  for (j = 0; j < w; j++) {
2408  buff16[j] = Clamp16((y[yPos++] + yuvOffset31) >> shift);
2409  }
2410  yOffset += yw;
2411  buff16 += pitch16;
2412 
2413  if (cb) {
2414  percent += dP;
2415  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2416  }
2417  }
2418  }
2419  } else {
2420  ASSERT(bpp == 8);
2421  const int shift = __max(0, UsedBitsPerChannel() - 8);
2422 
2423  for (i=0; i < h; i++) {
2424  UINT32 yPos = yOffset;
2425  for (j = 0; j < w; j++) {
2426  buff[j] = Clamp8((y[yPos++] + yuvOffset31) >> shift);
2427  }
2428  yOffset += yw;
2429  buff += pitch;
2430 
2431  if (cb) {
2432  percent += dP;
2433  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2434  }
2435  }
2436  }
2437  break;
2438  }
2439 #endif
2440  case ImageModeRGB12:
2441  {
2442  ASSERT(m_header.channels == 3);
2443  ASSERT(m_header.bpp == m_header.channels*4);
2444  ASSERT(bpp == m_header.channels*4);
2445  ASSERT(!m_downsample);
2446 
2447  DataT* y = m_channel[0]; ASSERT(y);
2448  DataT* u = m_channel[1]; ASSERT(u);
2449  DataT* v = m_channel[2]; ASSERT(v);
2450  UINT16 yval;
2451  UINT32 cnt;
2452 
2453  for (i=0; i < h; i++) {
2454  UINT32 yPos = yOffset;
2455  cnt = 0;
2456  for (j=0; j < w; j++) {
2457  // Yuv
2458  uAvg = u[yPos];
2459  vAvg = v[yPos];
2460  yval = Clamp4(y[yPos] + YUVoffset4 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2461  if (j%2 == 0) {
2462  buff[cnt] = UINT8(Clamp4(vAvg + yval) | (yval << 4));
2463  cnt++;
2464  buff[cnt] = Clamp4(uAvg + yval);
2465  } else {
2466  buff[cnt] |= Clamp4(vAvg + yval) << 4;
2467  cnt++;
2468  buff[cnt] = UINT8(yval | (Clamp4(uAvg + yval) << 4));
2469  cnt++;
2470  }
2471  yPos++;
2472  }
2473  yOffset += yw;
2474  buff += pitch;
2475 
2476  if (cb) {
2477  percent += dP;
2478  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2479  }
2480  }
2481  break;
2482  }
2483  case ImageModeRGB16:
2484  {
2485  ASSERT(m_header.channels == 3);
2486  ASSERT(m_header.bpp == 16);
2487  ASSERT(bpp == 16);
2488  ASSERT(!m_downsample);
2489 
2490  DataT* y = m_channel[0]; ASSERT(y);
2491  DataT* u = m_channel[1]; ASSERT(u);
2492  DataT* v = m_channel[2]; ASSERT(v);
2493  UINT16 yval;
2494  UINT16 *buff16 = (UINT16 *)buff;
2495  int pitch16 = pitch/2;
2496 
2497  for (i=0; i < h; i++) {
2498  UINT32 yPos = yOffset;
2499  for (j = 0; j < w; j++) {
2500  // Yuv
2501  uAvg = u[yPos];
2502  vAvg = v[yPos];
2503  yval = Clamp6(y[yPos++] + YUVoffset6 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2504  buff16[j] = (yval << 5) | ((Clamp6(uAvg + yval) >> 1) << 11) | (Clamp6(vAvg + yval) >> 1);
2505  }
2506  yOffset += yw;
2507  buff16 += pitch16;
2508 
2509  if (cb) {
2510  percent += dP;
2511  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2512  }
2513  }
2514  break;
2515  }
2516  default:
2517  ASSERT(false);
2518  }
2519 
2520 #ifdef _DEBUG
2521  // display ROI (RGB) in debugger
2522  roiimage.width = w;
2523  roiimage.height = h;
2524  if (pitch > 0) {
2525  roiimage.pitch = pitch;
2526  roiimage.data = buff;
2527  } else {
2528  roiimage.pitch = -pitch;
2529  roiimage.data = buff + (h - 1)*pitch;
2530  }
2531 #endif
2532 
2533 }
2534 
2549 void CPGFImage::GetYUV(int pitch, DataT* buff, BYTE bpp, int channelMap[] /*= nullptr*/, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) const {
2550  ASSERT(buff);
2551  const UINT32 w = m_width[0];
2552  const UINT32 h = m_height[0];
2553  const bool wOdd = (1 == w%2);
2554  const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
2555  const int pitch2 = pitch/DataTSize;
2556  const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
2557  const double dP = 1.0/h;
2558 
2559  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
2560  if (channelMap == nullptr) channelMap = defMap;
2561  int sampledPos = 0, yPos = 0;
2562  DataT uAvg, vAvg;
2563  double percent = 0;
2564  UINT32 i, j;
2565 
2566  if (m_header.channels == 3) {
2567  ASSERT(bpp%dataBits == 0);
2568 
2569  DataT* y = m_channel[0]; ASSERT(y);
2570  DataT* u = m_channel[1]; ASSERT(u);
2571  DataT* v = m_channel[2]; ASSERT(v);
2572  int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2573 
2574  for (i=0; i < h; i++) {
2575  if (i%2) sampledPos -= (w + 1)/2;
2576  cnt = 0;
2577  for (j=0; j < w; j++) {
2578  if (m_downsample) {
2579  // image was downsampled
2580  uAvg = u[sampledPos];
2581  vAvg = v[sampledPos];
2582  } else {
2583  uAvg = u[yPos];
2584  vAvg = v[yPos];
2585  }
2586  buff[cnt + channelMap[0]] = y[yPos];
2587  buff[cnt + channelMap[1]] = uAvg;
2588  buff[cnt + channelMap[2]] = vAvg;
2589  yPos++;
2590  cnt += channels;
2591  if (j%2) sampledPos++;
2592  }
2593  buff += pitch2;
2594  if (wOdd) sampledPos++;
2595 
2596  if (cb) {
2597  percent += dP;
2598  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2599  }
2600  }
2601  } else if (m_header.channels == 4) {
2602  ASSERT(m_header.bpp == m_header.channels*8);
2603  ASSERT(bpp%dataBits == 0);
2604 
2605  DataT* y = m_channel[0]; ASSERT(y);
2606  DataT* u = m_channel[1]; ASSERT(u);
2607  DataT* v = m_channel[2]; ASSERT(v);
2608  DataT* a = m_channel[3]; ASSERT(a);
2609  UINT8 aAvg;
2610  int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2611 
2612  for (i=0; i < h; i++) {
2613  if (i%2) sampledPos -= (w + 1)/2;
2614  cnt = 0;
2615  for (j=0; j < w; j++) {
2616  if (m_downsample) {
2617  // image was downsampled
2618  uAvg = u[sampledPos];
2619  vAvg = v[sampledPos];
2620  aAvg = Clamp8(a[sampledPos] + yuvOffset);
2621  } else {
2622  uAvg = u[yPos];
2623  vAvg = v[yPos];
2624  aAvg = Clamp8(a[yPos] + yuvOffset);
2625  }
2626  // Yuv
2627  buff[cnt + channelMap[0]] = y[yPos];
2628  buff[cnt + channelMap[1]] = uAvg;
2629  buff[cnt + channelMap[2]] = vAvg;
2630  buff[cnt + channelMap[3]] = aAvg;
2631  yPos++;
2632  cnt += channels;
2633  if (j%2) sampledPos++;
2634  }
2635  buff += pitch2;
2636  if (wOdd) sampledPos++;
2637 
2638  if (cb) {
2639  percent += dP;
2640  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2641  }
2642  }
2643  }
2644 }
2645 
2660 void CPGFImage::ImportYUV(int pitch, DataT *buff, BYTE bpp, int channelMap[] /*= nullptr*/, CallbackPtr cb /*= nullptr*/, void *data /*=nullptr*/) {
2661  ASSERT(buff);
2662  const double dP = 1.0/m_header.height;
2663  const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
2664  const int pitch2 = pitch/DataTSize;
2665  const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
2666 
2667  int yPos = 0, cnt = 0;
2668  double percent = 0;
2669  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
2670 
2671  if (channelMap == nullptr) channelMap = defMap;
2672 
2673  if (m_header.channels == 3) {
2674  ASSERT(bpp%dataBits == 0);
2675 
2676  DataT* y = m_channel[0]; ASSERT(y);
2677  DataT* u = m_channel[1]; ASSERT(u);
2678  DataT* v = m_channel[2]; ASSERT(v);
2679  const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2680 
2681  for (UINT32 h=0; h < m_header.height; h++) {
2682  if (cb) {
2683  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2684  percent += dP;
2685  }
2686 
2687  cnt = 0;
2688  for (UINT32 w=0; w < m_header.width; w++) {
2689  y[yPos] = buff[cnt + channelMap[0]];
2690  u[yPos] = buff[cnt + channelMap[1]];
2691  v[yPos] = buff[cnt + channelMap[2]];
2692  yPos++;
2693  cnt += channels;
2694  }
2695  buff += pitch2;
2696  }
2697  } else if (m_header.channels == 4) {
2698  ASSERT(bpp%dataBits == 0);
2699 
2700  DataT* y = m_channel[0]; ASSERT(y);
2701  DataT* u = m_channel[1]; ASSERT(u);
2702  DataT* v = m_channel[2]; ASSERT(v);
2703  DataT* a = m_channel[3]; ASSERT(a);
2704  const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2705 
2706  for (UINT32 h=0; h < m_header.height; h++) {
2707  if (cb) {
2708  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2709  percent += dP;
2710  }
2711 
2712  cnt = 0;
2713  for (UINT32 w=0; w < m_header.width; w++) {
2714  y[yPos] = buff[cnt + channelMap[0]];
2715  u[yPos] = buff[cnt + channelMap[1]];
2716  v[yPos] = buff[cnt + channelMap[2]];
2717  a[yPos] = buff[cnt + channelMap[3]] - yuvOffset;
2718  yPos++;
2719  cnt += channels;
2720  }
2721  buff += pitch2;
2722  }
2723  }
2724 
2725  if (m_downsample) {
2726  // Subsampling of the chrominance and alpha channels
2727  for (int i=1; i < m_header.channels; i++) {
2728  Downsample(i);
2729  }
2730  }
2731 }
2732 
void Open(CPGFStream *stream)
Definition: PGFimage.cpp:141
void SetColorTable(UINT32 iFirstColor, UINT32 nColors, const RGBQUAD *prgbColors)
Definition: PGFimage.cpp:1363
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&#39;s image modes
Definition: PGFtypes.h:158
#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:2549
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:755
void GetBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=nullptr, CallbackPtr cb=nullptr, void *data=nullptr) const
Definition: PGFimage.cpp:1788
UINT32 width
image width in pixels
Definition: PGFtypes.h:152
#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:275
#define PGFMajorNumber
Definition: PGFtypes.h:44
UINT32 ReadEncodedData(int level, UINT8 *target, UINT32 targetLen) const
Definition: PGFimage.cpp:706
INT32 DataT
Definition: PGFtypes.h:262
UINT32 userDataLen
user data size in bytes (not part of file header)
Definition: PGFtypes.h:171
#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:170
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:2660
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:1067
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:276
const UINT32 FilterSize
#define HeaderSize
Definition: PGFtypes.h:274
#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:154
#define ImageModeGray16
Definition: PGFplatform.h:108
UINT32 right
Definition: PGFtypes.h:258
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:159
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:1149
PGF header.
Definition: PGFtypes.h:150
#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:172
static BYTE CodecMajorVersion(BYTE version=PGFVersion)
Return major version.
Definition: PGFimage.cpp:767
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:156
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:853
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:250
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:978
#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:258
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:893
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:258
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:157
void RgbToYuv(int pitch, UINT8 *rgbBuff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data)
Definition: PGFimage.cpp:1388
void ImportBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=nullptr, CallbackPtr cb=nullptr, void *data=nullptr)
Definition: PGFimage.cpp:791
void ResetStreamPos(bool startOfData)
Definition: PGFimage.cpp:682
void SetMaxValue(UINT32 maxValue)
Definition: PGFimage.cpp:737
Rectangle.
Definition: PGFtypes.h:222
RefreshCB m_cb
pointer to refresh callback procedure
Definition: PGFimage.h:545
static bool ImportIsSupported(BYTE mode)
Definition: PGFimage.cpp:1304
#define MaxUserDataSize
Definition: PGFtypes.h:277
CEncoder * m_encoder
PGF encoder.
Definition: PGFimage.h:524
PGFVersionNumber version
codec version number: (since Version 7)
Definition: PGFtypes.h:160
UINT32 Width() const
Definition: PGFtypes.h:248
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:809
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:155
#define YUVoffset8
Definition: PGFimage.cpp:38
PGFRect ComputeLevelROI() const
UINT32 height
image height in pixels
Definition: PGFtypes.h:153
RGBQUAD clut[ColorTableLen]
color table for indexed color images (optional part of file header)
Definition: PGFtypes.h:169
#define ImageModeRGB48
Definition: PGFplatform.h:109
void Write(CPGFStream *stream, UINT32 *nWrittenBytes=nullptr, CallbackPtr cb=nullptr, void *data=nullptr)
Definition: PGFimage.cpp:1220
version number stored in header since major version 7
Definition: PGFtypes.h:132
UINT32 bottom
Definition: PGFtypes.h:258
#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:1123
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