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