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