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