libpgf  6.12.24
PGF - Progressive Graphics File
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CPGFImage Class Reference

PGF main class. More...

#include <PGFimage.h>

Public Member Functions

 CPGFImage ()
 
virtual ~CPGFImage ()
 
virtual void Close ()
 
virtual void Destroy ()
 
void Open (CPGFStream *stream) THROW_
 
bool IsOpen () const
 
void Read (int level=0, CallbackPtr cb=NULL, void *data=NULL) THROW_
 
void Read (PGFRect &rect, int level=0, CallbackPtr cb=NULL, void *data=NULL) THROW_
 
void ReadPreview () THROW_
 
void Reconstruct (int level=0) THROW_
 
void GetBitmap (int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) const THROW_
 
void GetYUV (int pitch, DataT *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) const THROW_
 
void ImportBitmap (int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_
 
void ImportYUV (int pitch, DataT *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_
 
void Write (CPGFStream *stream, UINT32 *nWrittenBytes=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_
 
UINT32 WriteHeader (CPGFStream *stream) THROW_
 
UINT32 WriteImage (CPGFStream *stream, CallbackPtr cb=NULL, void *data=NULL) THROW_
 
UINT32 Write (int level, CallbackPtr cb=NULL, void *data=NULL) THROW_
 
void ConfigureEncoder (bool useOMP=true, bool favorSpeedOverSize=false)
 
void ConfigureDecoder (bool useOMP=true, bool skipUserData=false)
 
void ResetStreamPos () THROW_
 
void SetChannel (DataT *channel, int c=0)
 
void SetHeader (const PGFHeader &header, BYTE flags=0, UINT8 *userData=0, UINT32 userDataLength=0) THROW_
 
void SetMaxValue (UINT32 maxValue)
 
void SetProgressMode (ProgressMode pm)
 
void SetRefreshCallback (RefreshCB callback, void *arg)
 
void SetColorTable (UINT32 iFirstColor, UINT32 nColors, const RGBQUAD *prgbColors) THROW_
 
DataTGetChannel (int c=0)
 
void GetColorTable (UINT32 iFirstColor, UINT32 nColors, RGBQUAD *prgbColors) const THROW_
 
const RGBQUAD * GetColorTable () const
 
const PGFHeaderGetHeader () const
 
UINT32 GetMaxValue () const
 
UINT64 GetUserDataPos () const
 
const UINT8 * GetUserData (UINT32 &size) const
 
UINT32 GetEncodedHeaderLength () const
 
UINT32 GetEncodedLevelLength (int level) const
 
UINT32 ReadEncodedHeader (UINT8 *target, UINT32 targetLen) const THROW_
 
UINT32 ReadEncodedData (int level, UINT8 *target, UINT32 targetLen) const THROW_
 
UINT32 ChannelWidth (int c=0) const
 
UINT32 ChannelHeight (int c=0) const
 
BYTE ChannelDepth () const
 
UINT32 Width (int level=0) const
 
UINT32 Height (int level=0) const
 
BYTE Level () const
 
BYTE Levels () const
 
BYTE Quality () const
 
BYTE Channels () const
 
BYTE Mode () const
 
BYTE BPP () const
 
bool ROIisSupported () const
 
BYTE UsedBitsPerChannel () const
 
BYTE Version () const
 

Static Public Member Functions

static bool ImportIsSupported (BYTE mode)
 
static UINT32 LevelWidth (UINT32 width, int level)
 
static UINT32 LevelHeight (UINT32 height, int level)
 
static BYTE CurrentVersion (BYTE version=PGFVersion)
 
static BYTE CurrentChannelDepth (BYTE version=PGFVersion)
 

Protected Attributes

CWaveletTransformm_wtChannel [MaxChannels]
 wavelet transformed color channels More...
 
DataTm_channel [MaxChannels]
 untransformed channels in YUV format More...
 
CDecoderm_decoder
 PGF decoder. More...
 
CEncoderm_encoder
 PGF encoder. More...
 
UINT32 * m_levelLength
 length of each level in bytes; first level starts immediately after this array More...
 
UINT32 m_width [MaxChannels]
 width of each channel at current level More...
 
UINT32 m_height [MaxChannels]
 height of each channel at current level More...
 
PGFPreHeader m_preHeader
 PGF pre-header. More...
 
PGFHeader m_header
 PGF file header. More...
 
PGFPostHeader m_postHeader
 PGF post-header. More...
 
UINT64 m_userDataPos
 stream position of user data More...
 
int m_currentLevel
 transform level of current image More...
 
BYTE m_quant
 quantization parameter More...
 
bool m_downsample
 chrominance channels are downsampled More...
 
bool m_favorSpeedOverSize
 favor encoding speed over compression ratio More...
 
bool m_useOMPinEncoder
 use Open MP in encoder More...
 
bool m_useOMPinDecoder
 use Open MP in decoder More...
 
bool m_skipUserData
 skip user data (metadata) during open More...
 
bool m_streamReinitialized
 stream has been reinitialized More...
 
PGFRect m_roi
 region of interest More...
 

Private Member Functions

void ComputeLevels ()
 
void CompleteHeader ()
 
void RgbToYuv (int pitch, UINT8 *rgbBuff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data) THROW_
 
void Downsample (int nChannel)
 
UINT32 UpdatePostHeaderSize () THROW_
 
void WriteLevel () THROW_
 
void SetROI (PGFRect rect)
 
UINT8 Clamp4 (DataT v) const
 
UINT16 Clamp6 (DataT v) const
 
UINT8 Clamp8 (DataT v) const
 
UINT16 Clamp16 (DataT v) const
 
UINT32 Clamp31 (DataT v) const
 

Private Attributes

RefreshCB m_cb
 pointer to refresh callback procedure More...
 
void * m_cbArg
 refresh callback argument More...
 
double m_percent
 progress [0..1] More...
 
ProgressMode m_progressMode
 progress mode used in Read and Write; PM_Relative is default mode More...
 

Detailed Description

PGF main class.

PGF image class is the main class. You always need a PGF object for encoding or decoding image data. Decoding: pgf.Open(...) pgf.Read(...) pgf.GetBitmap(...) Encoding: pgf.SetHeader(...) pgf.ImportBitmap(...) pgf.Write(...)

Author
C. Stamm, R. Spuler

Definition at line 57 of file PGFimage.h.

Constructor & Destructor Documentation

CPGFImage::CPGFImage ( )

Standard constructor: It is used to create a PGF instance for opening and reading.

Definition at line 55 of file PGFimage.cpp.

56 : m_decoder(0)
57 , m_encoder(0)
58 , m_levelLength(0)
59 , m_quant(0)
60 , m_userDataPos(0)
61 , m_downsample(false)
62 , m_favorSpeedOverSize(false)
63 , m_useOMPinEncoder(true)
64 , m_useOMPinDecoder(true)
65 , m_skipUserData(false)
66 #ifdef __PGFROISUPPORT__
67 , m_streamReinitialized(false)
68 #endif
69 , m_cb(0)
70 , m_cbArg(0)
72 , m_percent(0)
73 {
74 
75  // init preHeader
76  memcpy(m_preHeader.magic, Magic, 3);
78  m_preHeader.hSize = 0;
79 
80  // init postHeader
83 
84  // init channels
85  for (int i=0; i < MaxChannels; i++) {
86  m_channel[i] = 0;
87  m_wtChannel[i] = 0;
88  }
89 
90  // set image width and height
91  m_width[0] = 0;
92  m_height[0] = 0;
93 }
CPGFImage::~CPGFImage ( )
virtual

Destructor: Destroy internal data structures.

Definition at line 97 of file PGFimage.cpp.

97  {
98  Destroy();
99 }

Member Function Documentation

BYTE CPGFImage::BPP ( ) const
inline

Return the number of bits per pixel. Valid values can be 1, 8, 12, 16, 24, 32, 48, 64.

Returns
Number of bits per pixel.

Definition at line 460 of file PGFimage.h.

460 { return m_header.bpp; }
BYTE CPGFImage::ChannelDepth ( ) const
inline

Return bits per channel of the image's encoder.

Returns
Bits per channel

Definition at line 409 of file PGFimage.h.

UINT32 CPGFImage::ChannelHeight ( int  c = 0) const
inline

Return current image height of given channel in pixels. The returned height depends on the levels read so far and on ROI.

Parameters
cA channel index
Returns
Channel height in pixels

Definition at line 404 of file PGFimage.h.

404 { ASSERT(c >= 0 && c < MaxChannels); return m_height[c]; }
BYTE CPGFImage::Channels ( ) const
inline

Return the number of image channels. An image of type RGB contains 3 image channels (B, G, R).

Returns
Number of image channels

Definition at line 447 of file PGFimage.h.

447 { return m_header.channels; }
UINT32 CPGFImage::ChannelWidth ( int  c = 0) const
inline

Return current image width of given channel in pixels. The returned width depends on the levels read so far and on ROI.

Parameters
cA channel index
Returns
Channel width in pixels

Definition at line 397 of file PGFimage.h.

397 { ASSERT(c >= 0 && c < MaxChannels); return m_width[c]; }
UINT16 CPGFImage::Clamp16 ( DataT  v) const
inlineprivate

Definition at line 561 of file PGFimage.h.

561  {
562  if (v & 0xFFFF0000) return (v < 0) ? (UINT16)0: (UINT16)65535; else return (UINT16)v;
563  }
UINT32 CPGFImage::Clamp31 ( DataT  v) const
inlineprivate

Definition at line 564 of file PGFimage.h.

564  {
565  return (v < 0) ? 0 : (UINT32)v;
566  }
UINT8 CPGFImage::Clamp4 ( DataT  v) const
inlineprivate

Definition at line 551 of file PGFimage.h.

551  {
552  if (v & 0xFFFFFFF0) return (v < 0) ? (UINT8)0: (UINT8)15; else return (UINT8)v;
553  }
UINT16 CPGFImage::Clamp6 ( DataT  v) const
inlineprivate

Definition at line 554 of file PGFimage.h.

554  {
555  if (v & 0xFFFFFFC0) return (v < 0) ? (UINT16)0: (UINT16)63; else return (UINT16)v;
556  }
UINT8 CPGFImage::Clamp8 ( DataT  v) const
inlineprivate

Definition at line 557 of file PGFimage.h.

557  {
558  // needs only one test in the normal case
559  if (v & 0xFFFFFF00) return (v < 0) ? (UINT8)0 : (UINT8)255; else return (UINT8)v;
560  }
void CPGFImage::Close ( )
virtual

Close PGF image after opening and reading. Destructor calls this method during destruction.

Definition at line 121 of file PGFimage.cpp.

121  {
122  delete m_decoder; m_decoder = 0;
123 }
void CPGFImage::CompleteHeader ( )
private

Definition at line 207 of file PGFimage.cpp.

207  {
208  if (m_header.mode == ImageModeUnknown) {
209  // undefined mode
210  switch(m_header.bpp) {
211  case 1: m_header.mode = ImageModeBitmap; break;
212  case 8: m_header.mode = ImageModeGrayScale; break;
213  case 12: m_header.mode = ImageModeRGB12; break;
214  case 16: m_header.mode = ImageModeRGB16; break;
215  case 24: m_header.mode = ImageModeRGBColor; break;
216  case 32: m_header.mode = ImageModeRGBA; break;
217  case 48: m_header.mode = ImageModeRGB48; break;
218  default: m_header.mode = ImageModeRGBColor; break;
219  }
220  }
221  if (!m_header.bpp) {
222  // undefined bpp
223  switch(m_header.mode) {
224  case ImageModeBitmap:
225  m_header.bpp = 1;
226  break;
228  case ImageModeGrayScale:
229  m_header.bpp = 8;
230  break;
231  case ImageModeRGB12:
232  m_header.bpp = 12;
233  break;
234  case ImageModeRGB16:
235  case ImageModeGray16:
236  m_header.bpp = 16;
237  break;
238  case ImageModeRGBColor:
239  case ImageModeLabColor:
240  m_header.bpp = 24;
241  break;
242  case ImageModeRGBA:
243  case ImageModeCMYKColor:
244  case ImageModeGray32:
245  m_header.bpp = 32;
246  break;
247  case ImageModeRGB48:
248  case ImageModeLab48:
249  m_header.bpp = 48;
250  break;
251  case ImageModeCMYK64:
252  m_header.bpp = 64;
253  break;
254  default:
255  ASSERT(false);
256  m_header.bpp = 24;
257  }
258  }
259  if (m_header.mode == ImageModeRGBColor && m_header.bpp == 32) {
260  // change mode
262  }
263  ASSERT(m_header.mode != ImageModeBitmap || m_header.bpp == 1);
264  ASSERT(m_header.mode != ImageModeIndexedColor || m_header.bpp == 8);
265  ASSERT(m_header.mode != ImageModeGrayScale || m_header.bpp == 8);
266  ASSERT(m_header.mode != ImageModeGray16 || m_header.bpp == 16);
267  ASSERT(m_header.mode != ImageModeGray32 || m_header.bpp == 32);
268  ASSERT(m_header.mode != ImageModeRGBColor || m_header.bpp == 24);
269  ASSERT(m_header.mode != ImageModeRGBA || m_header.bpp == 32);
270  ASSERT(m_header.mode != ImageModeRGB12 || m_header.bpp == 12);
271  ASSERT(m_header.mode != ImageModeRGB16 || m_header.bpp == 16);
272  ASSERT(m_header.mode != ImageModeRGB48 || m_header.bpp == 48);
273  ASSERT(m_header.mode != ImageModeLabColor || m_header.bpp == 24);
274  ASSERT(m_header.mode != ImageModeLab48 || m_header.bpp == 48);
275  ASSERT(m_header.mode != ImageModeCMYKColor || m_header.bpp == 32);
276  ASSERT(m_header.mode != ImageModeCMYK64 || m_header.bpp == 64);
277 
278  // set number of channels
279  if (!m_header.channels) {
280  switch(m_header.mode) {
281  case ImageModeBitmap:
283  case ImageModeGrayScale:
284  case ImageModeGray16:
285  case ImageModeGray32:
286  m_header.channels = 1;
287  break;
288  case ImageModeRGBColor:
289  case ImageModeRGB12:
290  case ImageModeRGB16:
291  case ImageModeRGB48:
292  case ImageModeLabColor:
293  case ImageModeLab48:
294  m_header.channels = 3;
295  break;
296  case ImageModeRGBA:
297  case ImageModeCMYKColor:
298  case ImageModeCMYK64:
299  m_header.channels = 4;
300  break;
301  default:
302  ASSERT(false);
303  m_header.channels = 3;
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 }
void CPGFImage::ComputeLevels ( )
private

Definition at line 798 of file PGFimage.cpp.

798  {
799  const int maxThumbnailWidth = 20*FilterWidth;
800  const int m = __min(m_header.width, m_header.height);
801  int s = m;
802 
803  if (m_header.nLevels < 1 || m_header.nLevels > MaxLevel) {
804  m_header.nLevels = 1;
805  // compute a good value depending on the size of the image
806  while (s > maxThumbnailWidth) {
807  m_header.nLevels++;
808  s = s/2;
809  }
810  }
811 
812  int levels = m_header.nLevels; // we need a signed value during level reduction
813 
814  // reduce number of levels if the image size is smaller than FilterWidth*2^levels
815  s = FilterWidth*(1 << levels); // must be at least the double filter size because of subsampling
816  while (m < s) {
817  levels--;
818  s = s/2;
819  }
820  if (levels > MaxLevel) m_header.nLevels = MaxLevel;
821  else if (levels < 0) m_header.nLevels = 0;
822  else m_header.nLevels = (UINT8)levels;
823 
824  // used in Write when PM_Absolute
825  m_percent = pow(0.25, m_header.nLevels);
826 
827  ASSERT(0 <= m_header.nLevels && m_header.nLevels <= MaxLevel);
828 }
void CPGFImage::ConfigureDecoder ( bool  useOMP = true,
bool  skipUserData = false 
)
inline

Configures the decoder.

Parameters
useOMPUse parallel threading with Open MP during decoding. Default value: true. Influences the decoding only if the codec has been compiled with OpenMP support.
skipUserDataThe file might contain user data (metadata). User data ist usually read during Open and stored in memory. Set this flag to false when storing in memory is not needed.

Definition at line 266 of file PGFimage.h.

266 { m_useOMPinDecoder = useOMP; m_skipUserData = skipUserData; }
void CPGFImage::ConfigureEncoder ( bool  useOMP = true,
bool  favorSpeedOverSize = false 
)
inline

Configures the encoder.

Parameters
useOMPUse parallel threading with Open MP during encoding. Default value: true. Influences the encoding only if the codec has been compiled with OpenMP support.
favorSpeedOverSizeFavors encoding speed over compression ratio. Default value: false

Definition at line 260 of file PGFimage.h.

260 { m_useOMPinEncoder = useOMP; m_favorSpeedOverSize = favorSpeedOverSize; }
static BYTE CPGFImage::CurrentChannelDepth ( BYTE  version = PGFVersion)
inlinestatic

Compute and return codec version.

Returns
current PGF codec version

Definition at line 508 of file PGFimage.h.

508 { return (version & PGF32) ? 32 : 16; }
BYTE CPGFImage::CurrentVersion ( BYTE  version = PGFVersion)
static

Compute and return codec version.

Returns
current PGF codec version

Return version

Definition at line 714 of file PGFimage.cpp.

714  {
715  if (version & Version6) return 6;
716  if (version & Version5) return 5;
717  if (version & Version2) return 2;
718  return 1;
719 }
void CPGFImage::Destroy ( )
virtual

Destroy internal data structures. Destructor calls this method during destruction.

Definition at line 104 of file PGFimage.cpp.

104  {
105  Close();
106 
107  for (int i=0; i < m_header.channels; i++) {
108  delete m_wtChannel[i]; m_wtChannel[i]=0; // also deletes m_channel
109  m_channel[i] = 0;
110  }
112  delete[] m_levelLength; m_levelLength = 0;
113  delete m_encoder; m_encoder = NULL;
114 
115  m_userDataPos = 0;
116 }
void CPGFImage::Downsample ( int  nChannel)
private

Definition at line 754 of file PGFimage.cpp.

754  {
755  ASSERT(ch > 0);
756 
757  const int w = m_width[0];
758  const int w2 = w/2;
759  const int h2 = m_height[0]/2;
760  const int oddW = w%2; // don't use bool -> problems with MaxSpeed optimization
761  const int oddH = m_height[0]%2; // "
762  int loPos = 0;
763  int hiPos = w;
764  int sampledPos = 0;
765  DataT* buff = m_channel[ch]; ASSERT(buff);
766 
767  for (int i=0; i < h2; i++) {
768  for (int j=0; j < w2; j++) {
769  // compute average of pixel block
770  buff[sampledPos] = (buff[loPos] + buff[loPos + 1] + buff[hiPos] + buff[hiPos + 1]) >> 2;
771  loPos += 2; hiPos += 2;
772  sampledPos++;
773  }
774  if (oddW) {
775  buff[sampledPos] = (buff[loPos] + buff[hiPos]) >> 1;
776  loPos++; hiPos++;
777  sampledPos++;
778  }
779  loPos += w; hiPos += w;
780  }
781  if (oddH) {
782  for (int j=0; j < w2; j++) {
783  buff[sampledPos] = (buff[loPos] + buff[loPos+1]) >> 1;
784  loPos += 2; hiPos += 2;
785  sampledPos++;
786  }
787  if (oddW) {
788  buff[sampledPos] = buff[loPos];
789  }
790  }
791 
792  // downsampled image has half width and half height
793  m_width[ch] = (m_width[ch] + 1)/2;
794  m_height[ch] = (m_height[ch] + 1)/2;
795 }
void CPGFImage::GetBitmap ( int  pitch,
UINT8 *  buff,
BYTE  bpp,
int  channelMap[] = NULL,
CallbackPtr  cb = NULL,
void *  data = NULL 
) const

Get image data in interleaved format: (ordering of RGB data is BGR[A]) Upsampling, YUV to RGB transform and interleaving are done here to reduce the number of passes over the data. The absolute value of pitch is the number of bytes of an image row of the given image buffer. If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row). if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte). 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 provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode. If your provided image buffer expects a channel sequence ARGB, then the channelMap looks like { 3, 2, 1, 0 }. It might throw an IOException.

Parameters
pitchThe number of bytes of a row of the image buffer.
buffAn image buffer.
bppThe number of bits per pixel used in image buffer.
channelMapA integer array containing the mapping of PGF channel ordering to expected channel ordering.
cbA pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding.
dataData Pointer to C++ class container to host callback procedure.

Definition at line 1697 of file PGFimage.cpp.

1697  {
1698  ASSERT(buff);
1699  UINT32 w = m_width[0];
1700  UINT32 h = m_height[0];
1701  UINT8* targetBuff = 0; // used if ROI is used
1702  UINT8* buffStart = 0; // used if ROI is used
1703  int targetPitch = 0; // used if ROI is used
1704 
1705 #ifdef __PGFROISUPPORT__
1706  const PGFRect& roi = (ROIisSupported()) ? m_wtChannel[0]->GetROI(m_currentLevel) : PGFRect(0, 0, w, h); // roi is usually larger than m_roi
1708  ASSERT(w <= roi.Width() && h <= roi.Height());
1709  ASSERT(roi.left <= levelRoi.left && levelRoi.right <= roi.right);
1710  ASSERT(roi.top <= levelRoi.top && levelRoi.bottom <= roi.bottom);
1711 
1712  if (ROIisSupported() && (levelRoi.Width() < w || levelRoi.Height() < h)) {
1713  // ROI is used -> create a temporary image buffer for roi
1714  // compute pitch
1715  targetPitch = pitch;
1716  pitch = AlignWordPos(w*bpp)/8;
1717 
1718  // create temporary output buffer
1719  targetBuff = buff;
1720  buff = buffStart = new(std::nothrow) UINT8[pitch*h];
1721  if (!buff) ReturnWithError(InsufficientMemory);
1722  }
1723 #endif
1724 
1725  const bool wOdd = (1 == w%2);
1726 
1727  const double dP = 1.0/h;
1728  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
1729  if (channelMap == NULL) channelMap = defMap;
1730  int sampledPos = 0, yPos = 0;
1731  DataT uAvg, vAvg;
1732  double percent = 0;
1733  UINT32 i, j;
1734 
1735  switch(m_header.mode) {
1736  case ImageModeBitmap:
1737  {
1738  ASSERT(m_header.channels == 1);
1739  ASSERT(m_header.bpp == 1);
1740  ASSERT(bpp == 1);
1741 
1742  const UINT32 w2 = (w + 7)/8;
1743  DataT* y = m_channel[0]; ASSERT(y);
1744 
1745  for (i=0; i < h; i++) {
1746 
1747  for (j=0; j < w2; j++) {
1748  buff[j] = Clamp8(y[yPos++] + YUVoffset8);
1749  }
1750  yPos += w - w2;
1751 
1752  //UINT32 cnt = w;
1753  //for (j=0; j < w2; j++) {
1754  // buff[j] = 0;
1755  // for (int k=0; k < 8; k++) {
1756  // if (cnt) {
1757  // buff[j] <<= 1;
1758  // buff[j] |= (1 & (y[yPos++] - YUVoffset8));
1759  // cnt--;
1760  // }
1761  // }
1762  //}
1763  buff += pitch;
1764 
1765  if (cb) {
1766  percent += dP;
1767  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1768  }
1769  }
1770  break;
1771  }
1772  case ImageModeIndexedColor:
1773  case ImageModeGrayScale:
1774  case ImageModeHSLColor:
1775  case ImageModeHSBColor:
1776  {
1777  ASSERT(m_header.channels >= 1);
1778  ASSERT(m_header.bpp == m_header.channels*8);
1779  ASSERT(bpp%8 == 0);
1780 
1781  int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
1782 
1783  for (i=0; i < h; i++) {
1784  cnt = 0;
1785  for (j=0; j < w; j++) {
1786  for (int c=0; c < m_header.channels; c++) {
1787  buff[cnt + channelMap[c]] = Clamp8(m_channel[c][yPos] + YUVoffset8);
1788  }
1789  cnt += channels;
1790  yPos++;
1791  }
1792  buff += pitch;
1793 
1794  if (cb) {
1795  percent += dP;
1796  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1797  }
1798  }
1799  break;
1800  }
1801  case ImageModeGray16:
1802  {
1803  ASSERT(m_header.channels >= 1);
1804  ASSERT(m_header.bpp == m_header.channels*16);
1805 
1806  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1807  int cnt, channels;
1808 
1809  if (bpp%16 == 0) {
1810  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1811  UINT16 *buff16 = (UINT16 *)buff;
1812  int pitch16 = pitch/2;
1813  channels = bpp/16; ASSERT(channels >= m_header.channels);
1814 
1815  for (i=0; i < h; i++) {
1816  cnt = 0;
1817  for (j=0; j < w; j++) {
1818  for (int c=0; c < m_header.channels; c++) {
1819  buff16[cnt + channelMap[c]] = Clamp16((m_channel[c][yPos] + yuvOffset16) << shift);
1820  }
1821  cnt += channels;
1822  yPos++;
1823  }
1824  buff16 += pitch16;
1825 
1826  if (cb) {
1827  percent += dP;
1828  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1829  }
1830  }
1831  } else {
1832  ASSERT(bpp%8 == 0);
1833  const int shift = __max(0, UsedBitsPerChannel() - 8);
1834  channels = bpp/8; ASSERT(channels >= m_header.channels);
1835 
1836  for (i=0; i < h; i++) {
1837  cnt = 0;
1838  for (j=0; j < w; j++) {
1839  for (int c=0; c < m_header.channels; c++) {
1840  buff[cnt + channelMap[c]] = Clamp8((m_channel[c][yPos] + yuvOffset16) >> shift);
1841  }
1842  cnt += channels;
1843  yPos++;
1844  }
1845  buff += pitch;
1846 
1847  if (cb) {
1848  percent += dP;
1849  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1850  }
1851  }
1852  }
1853  break;
1854  }
1855  case ImageModeRGBColor:
1856  {
1857  ASSERT(m_header.channels == 3);
1858  ASSERT(m_header.bpp == m_header.channels*8);
1859  ASSERT(bpp%8 == 0);
1860  ASSERT(bpp >= m_header.bpp);
1861 
1862  DataT* y = m_channel[0]; ASSERT(y);
1863  DataT* u = m_channel[1]; ASSERT(u);
1864  DataT* v = m_channel[2]; ASSERT(v);
1865  UINT8 *buffg = &buff[channelMap[1]],
1866  *buffr = &buff[channelMap[2]],
1867  *buffb = &buff[channelMap[0]];
1868  UINT8 g;
1869  int cnt, channels = bpp/8;
1870  if(m_downsample){
1871  for (i=0; i < h; i++) {
1872  if (i%2) sampledPos -= (w + 1)/2;
1873  cnt = 0;
1874  for (j=0; j < w; j++) {
1875  // image was downsampled
1876  uAvg = u[sampledPos];
1877  vAvg = v[sampledPos];
1878  // Yuv
1879  buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
1880  buffr[cnt] = Clamp8(uAvg + g);
1881  buffb[cnt] = Clamp8(vAvg + g);
1882  yPos++;
1883  cnt += channels;
1884  if (j%2) sampledPos++;
1885  }
1886  buffb += pitch;
1887  buffg += pitch;
1888  buffr += pitch;
1889  if (wOdd) sampledPos++;
1890  if (cb) {
1891  percent += dP;
1892  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1893  }
1894  }
1895  }else{
1896  for (i=0; i < h; i++) {
1897  cnt = 0;
1898  for (j = 0; j < w; j++) {
1899  uAvg = u[yPos];
1900  vAvg = v[yPos];
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  }
1908  buffb += pitch;
1909  buffg += pitch;
1910  buffr += pitch;
1911 
1912  if (cb) {
1913  percent += dP;
1914  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1915  }
1916  }
1917  }
1918  break;
1919  }
1920  case ImageModeRGB48:
1921  {
1922  ASSERT(m_header.channels == 3);
1923  ASSERT(m_header.bpp == 48);
1924 
1925  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1926 
1927  DataT* y = m_channel[0]; ASSERT(y);
1928  DataT* u = m_channel[1]; ASSERT(u);
1929  DataT* v = m_channel[2]; ASSERT(v);
1930  int cnt, channels;
1931  DataT g;
1932 
1933  if (bpp >= 48 && bpp%16 == 0) {
1934  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1935  UINT16 *buff16 = (UINT16 *)buff;
1936  int pitch16 = pitch/2;
1937  channels = bpp/16; ASSERT(channels >= m_header.channels);
1938 
1939  for (i=0; i < h; i++) {
1940  if (i%2) sampledPos -= (w + 1)/2;
1941  cnt = 0;
1942  for (j=0; j < w; j++) {
1943  if (m_downsample) {
1944  // image was downsampled
1945  uAvg = u[sampledPos];
1946  vAvg = v[sampledPos];
1947  } else {
1948  uAvg = u[yPos];
1949  vAvg = v[yPos];
1950  }
1951  // Yuv
1952  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
1953  buff16[cnt + channelMap[1]] = Clamp16(g << shift);
1954  buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
1955  buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
1956  yPos++;
1957  cnt += channels;
1958  if (j%2) sampledPos++;
1959  }
1960  buff16 += pitch16;
1961  if (wOdd) sampledPos++;
1962 
1963  if (cb) {
1964  percent += dP;
1965  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1966  }
1967  }
1968  } else {
1969  ASSERT(bpp%8 == 0);
1970  const int shift = __max(0, UsedBitsPerChannel() - 8);
1971  channels = bpp/8; ASSERT(channels >= m_header.channels);
1972 
1973  for (i=0; i < h; i++) {
1974  if (i%2) sampledPos -= (w + 1)/2;
1975  cnt = 0;
1976  for (j=0; j < w; j++) {
1977  if (m_downsample) {
1978  // image was downsampled
1979  uAvg = u[sampledPos];
1980  vAvg = v[sampledPos];
1981  } else {
1982  uAvg = u[yPos];
1983  vAvg = v[yPos];
1984  }
1985  // Yuv
1986  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
1987  buff[cnt + channelMap[1]] = Clamp8(g >> shift);
1988  buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
1989  buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
1990  yPos++;
1991  cnt += channels;
1992  if (j%2) sampledPos++;
1993  }
1994  buff += pitch;
1995  if (wOdd) sampledPos++;
1996 
1997  if (cb) {
1998  percent += dP;
1999  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2000  }
2001  }
2002  }
2003  break;
2004  }
2005  case ImageModeLabColor:
2006  {
2007  ASSERT(m_header.channels == 3);
2008  ASSERT(m_header.bpp == m_header.channels*8);
2009  ASSERT(bpp%8 == 0);
2010 
2011  DataT* l = m_channel[0]; ASSERT(l);
2012  DataT* a = m_channel[1]; ASSERT(a);
2013  DataT* b = m_channel[2]; ASSERT(b);
2014  int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
2015 
2016  for (i=0; i < h; i++) {
2017  if (i%2) sampledPos -= (w + 1)/2;
2018  cnt = 0;
2019  for (j=0; j < w; j++) {
2020  if (m_downsample) {
2021  // image was downsampled
2022  uAvg = a[sampledPos];
2023  vAvg = b[sampledPos];
2024  } else {
2025  uAvg = a[yPos];
2026  vAvg = b[yPos];
2027  }
2028  buff[cnt + channelMap[0]] = Clamp8(l[yPos] + YUVoffset8);
2029  buff[cnt + channelMap[1]] = Clamp8(uAvg + YUVoffset8);
2030  buff[cnt + channelMap[2]] = Clamp8(vAvg + YUVoffset8);
2031  cnt += channels;
2032  yPos++;
2033  if (j%2) sampledPos++;
2034  }
2035  buff += pitch;
2036  if (wOdd) sampledPos++;
2037 
2038  if (cb) {
2039  percent += dP;
2040  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2041  }
2042  }
2043  break;
2044  }
2045  case ImageModeLab48:
2046  {
2047  ASSERT(m_header.channels == 3);
2048  ASSERT(m_header.bpp == m_header.channels*16);
2049 
2050  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2051 
2052  DataT* l = m_channel[0]; ASSERT(l);
2053  DataT* a = m_channel[1]; ASSERT(a);
2054  DataT* b = m_channel[2]; ASSERT(b);
2055  int cnt, channels;
2056 
2057  if (bpp%16 == 0) {
2058  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2059  UINT16 *buff16 = (UINT16 *)buff;
2060  int pitch16 = pitch/2;
2061  channels = bpp/16; ASSERT(channels >= m_header.channels);
2062 
2063  for (i=0; i < h; i++) {
2064  if (i%2) sampledPos -= (w + 1)/2;
2065  cnt = 0;
2066  for (j=0; j < w; j++) {
2067  if (m_downsample) {
2068  // image was downsampled
2069  uAvg = a[sampledPos];
2070  vAvg = b[sampledPos];
2071  } else {
2072  uAvg = a[yPos];
2073  vAvg = b[yPos];
2074  }
2075  buff16[cnt + channelMap[0]] = Clamp16((l[yPos] + yuvOffset16) << shift);
2076  buff16[cnt + channelMap[1]] = Clamp16((uAvg + yuvOffset16) << shift);
2077  buff16[cnt + channelMap[2]] = Clamp16((vAvg + yuvOffset16) << shift);
2078  cnt += channels;
2079  yPos++;
2080  if (j%2) sampledPos++;
2081  }
2082  buff16 += pitch16;
2083  if (wOdd) sampledPos++;
2084 
2085  if (cb) {
2086  percent += dP;
2087  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2088  }
2089  }
2090  } else {
2091  ASSERT(bpp%8 == 0);
2092  const int shift = __max(0, UsedBitsPerChannel() - 8);
2093  channels = bpp/8; ASSERT(channels >= m_header.channels);
2094 
2095  for (i=0; i < h; i++) {
2096  if (i%2) sampledPos -= (w + 1)/2;
2097  cnt = 0;
2098  for (j=0; j < w; j++) {
2099  if (m_downsample) {
2100  // image was downsampled
2101  uAvg = a[sampledPos];
2102  vAvg = b[sampledPos];
2103  } else {
2104  uAvg = a[yPos];
2105  vAvg = b[yPos];
2106  }
2107  buff[cnt + channelMap[0]] = Clamp8((l[yPos] + yuvOffset16) >> shift);
2108  buff[cnt + channelMap[1]] = Clamp8((uAvg + yuvOffset16) >> shift);
2109  buff[cnt + channelMap[2]] = Clamp8((vAvg + yuvOffset16) >> shift);
2110  cnt += channels;
2111  yPos++;
2112  if (j%2) sampledPos++;
2113  }
2114  buff += pitch;
2115  if (wOdd) sampledPos++;
2116 
2117  if (cb) {
2118  percent += dP;
2119  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2120  }
2121  }
2122  }
2123  break;
2124  }
2125  case ImageModeRGBA:
2126  case ImageModeCMYKColor:
2127  {
2128  ASSERT(m_header.channels == 4);
2129  ASSERT(m_header.bpp == m_header.channels*8);
2130  ASSERT(bpp%8 == 0);
2131 
2132  DataT* y = m_channel[0]; ASSERT(y);
2133  DataT* u = m_channel[1]; ASSERT(u);
2134  DataT* v = m_channel[2]; ASSERT(v);
2135  DataT* a = m_channel[3]; ASSERT(a);
2136  UINT8 g, aAvg;
2137  int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
2138 
2139  for (i=0; i < h; i++) {
2140  if (i%2) sampledPos -= (w + 1)/2;
2141  cnt = 0;
2142  for (j=0; j < w; j++) {
2143  if (m_downsample) {
2144  // image was downsampled
2145  uAvg = u[sampledPos];
2146  vAvg = v[sampledPos];
2147  aAvg = Clamp8(a[sampledPos] + YUVoffset8);
2148  } else {
2149  uAvg = u[yPos];
2150  vAvg = v[yPos];
2151  aAvg = Clamp8(a[yPos] + YUVoffset8);
2152  }
2153  // Yuv
2154  buff[cnt + channelMap[1]] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2155  buff[cnt + channelMap[2]] = Clamp8(uAvg + g);
2156  buff[cnt + channelMap[0]] = Clamp8(vAvg + g);
2157  buff[cnt + channelMap[3]] = aAvg;
2158  yPos++;
2159  cnt += channels;
2160  if (j%2) sampledPos++;
2161  }
2162  buff += pitch;
2163  if (wOdd) sampledPos++;
2164 
2165  if (cb) {
2166  percent += dP;
2167  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2168  }
2169  }
2170  break;
2171  }
2172  case ImageModeCMYK64:
2173  {
2174  ASSERT(m_header.channels == 4);
2175  ASSERT(m_header.bpp == 64);
2176 
2177  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2178 
2179  DataT* y = m_channel[0]; ASSERT(y);
2180  DataT* u = m_channel[1]; ASSERT(u);
2181  DataT* v = m_channel[2]; ASSERT(v);
2182  DataT* a = m_channel[3]; ASSERT(a);
2183  DataT g, aAvg;
2184  int cnt, channels;
2185 
2186  if (bpp%16 == 0) {
2187  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2188  UINT16 *buff16 = (UINT16 *)buff;
2189  int pitch16 = pitch/2;
2190  channels = bpp/16; ASSERT(channels >= m_header.channels);
2191 
2192  for (i=0; i < h; i++) {
2193  if (i%2) sampledPos -= (w + 1)/2;
2194  cnt = 0;
2195  for (j=0; j < w; j++) {
2196  if (m_downsample) {
2197  // image was downsampled
2198  uAvg = u[sampledPos];
2199  vAvg = v[sampledPos];
2200  aAvg = a[sampledPos] + yuvOffset16;
2201  } else {
2202  uAvg = u[yPos];
2203  vAvg = v[yPos];
2204  aAvg = a[yPos] + yuvOffset16;
2205  }
2206  // Yuv
2207  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2208  buff16[cnt + channelMap[1]] = Clamp16(g << shift);
2209  buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
2210  buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
2211  buff16[cnt + channelMap[3]] = Clamp16(aAvg << shift);
2212  yPos++;
2213  cnt += channels;
2214  if (j%2) sampledPos++;
2215  }
2216  buff16 += pitch16;
2217  if (wOdd) sampledPos++;
2218 
2219  if (cb) {
2220  percent += dP;
2221  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2222  }
2223  }
2224  } else {
2225  ASSERT(bpp%8 == 0);
2226  const int shift = __max(0, UsedBitsPerChannel() - 8);
2227  channels = bpp/8; ASSERT(channels >= m_header.channels);
2228 
2229  for (i=0; i < h; i++) {
2230  if (i%2) sampledPos -= (w + 1)/2;
2231  cnt = 0;
2232  for (j=0; j < w; j++) {
2233  if (m_downsample) {
2234  // image was downsampled
2235  uAvg = u[sampledPos];
2236  vAvg = v[sampledPos];
2237  aAvg = a[sampledPos] + yuvOffset16;
2238  } else {
2239  uAvg = u[yPos];
2240  vAvg = v[yPos];
2241  aAvg = a[yPos] + yuvOffset16;
2242  }
2243  // Yuv
2244  g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2245  buff[cnt + channelMap[1]] = Clamp8(g >> shift);
2246  buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
2247  buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
2248  buff[cnt + channelMap[3]] = Clamp8(aAvg >> shift);
2249  yPos++;
2250  cnt += channels;
2251  if (j%2) sampledPos++;
2252  }
2253  buff += pitch;
2254  if (wOdd) sampledPos++;
2255 
2256  if (cb) {
2257  percent += dP;
2258  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2259  }
2260  }
2261  }
2262  break;
2263  }
2264 #ifdef __PGF32SUPPORT__
2265  case ImageModeGray32:
2266  {
2267  ASSERT(m_header.channels == 1);
2268  ASSERT(m_header.bpp == 32);
2269 
2270  const int yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
2271 
2272  DataT* y = m_channel[0]; ASSERT(y);
2273 
2274  if (bpp == 32) {
2275  const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2276  UINT32 *buff32 = (UINT32 *)buff;
2277  int pitch32 = pitch/4;
2278 
2279  for (i=0; i < h; i++) {
2280  for (j=0; j < w; j++) {
2281  buff32[j] = Clamp31((y[yPos++] + yuvOffset31) << shift);
2282  }
2283  buff32 += pitch32;
2284 
2285  if (cb) {
2286  percent += dP;
2287  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2288  }
2289  }
2290  } else if (bpp == 16) {
2291  const int usedBits = UsedBitsPerChannel();
2292  UINT16 *buff16 = (UINT16 *)buff;
2293  int pitch16 = pitch/2;
2294 
2295  if (usedBits < 16) {
2296  const int shift = 16 - usedBits;
2297  for (i=0; i < h; i++) {
2298  for (j=0; j < w; j++) {
2299  buff16[j] = Clamp16((y[yPos++] + yuvOffset31) << shift);
2300  }
2301  buff16 += pitch16;
2302 
2303  if (cb) {
2304  percent += dP;
2305  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2306  }
2307  }
2308  } else {
2309  const int shift = __max(0, usedBits - 16);
2310  for (i=0; i < h; i++) {
2311  for (j=0; j < w; j++) {
2312  buff16[j] = Clamp16((y[yPos++] + yuvOffset31) >> shift);
2313  }
2314  buff16 += pitch16;
2315 
2316  if (cb) {
2317  percent += dP;
2318  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2319  }
2320  }
2321  }
2322  } else {
2323  ASSERT(bpp == 8);
2324  const int shift = __max(0, UsedBitsPerChannel() - 8);
2325 
2326  for (i=0; i < h; i++) {
2327  for (j=0; j < w; j++) {
2328  buff[j] = Clamp8((y[yPos++] + yuvOffset31) >> shift);
2329  }
2330  buff += pitch;
2331 
2332  if (cb) {
2333  percent += dP;
2334  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2335  }
2336  }
2337  }
2338  break;
2339  }
2340 #endif
2341  case ImageModeRGB12:
2342  {
2343  ASSERT(m_header.channels == 3);
2344  ASSERT(m_header.bpp == m_header.channels*4);
2345  ASSERT(bpp == m_header.channels*4);
2346  ASSERT(!m_downsample);
2347 
2348  DataT* y = m_channel[0]; ASSERT(y);
2349  DataT* u = m_channel[1]; ASSERT(u);
2350  DataT* v = m_channel[2]; ASSERT(v);
2351  UINT16 yval;
2352  int cnt;
2353 
2354  for (i=0; i < h; i++) {
2355  cnt = 0;
2356  for (j=0; j < w; j++) {
2357  // Yuv
2358  uAvg = u[yPos];
2359  vAvg = v[yPos];
2360  yval = Clamp4(y[yPos++] + YUVoffset4 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2361  if (j%2 == 0) {
2362  buff[cnt] = UINT8(Clamp4(vAvg + yval) | (yval << 4));
2363  cnt++;
2364  buff[cnt] = Clamp4(uAvg + yval);
2365  } else {
2366  buff[cnt] |= Clamp4(vAvg + yval) << 4;
2367  cnt++;
2368  buff[cnt] = UINT8(yval | (Clamp4(uAvg + yval) << 4));
2369  cnt++;
2370  }
2371  }
2372  buff += pitch;
2373 
2374  if (cb) {
2375  percent += dP;
2376  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2377  }
2378  }
2379  break;
2380  }
2381  case ImageModeRGB16:
2382  {
2383  ASSERT(m_header.channels == 3);
2384  ASSERT(m_header.bpp == 16);
2385  ASSERT(bpp == 16);
2386  ASSERT(!m_downsample);
2387 
2388  DataT* y = m_channel[0]; ASSERT(y);
2389  DataT* u = m_channel[1]; ASSERT(u);
2390  DataT* v = m_channel[2]; ASSERT(v);
2391  UINT16 yval;
2392  UINT16 *buff16 = (UINT16 *)buff;
2393  int pitch16 = pitch/2;
2394 
2395  for (i=0; i < h; i++) {
2396  for (j=0; j < w; j++) {
2397  // Yuv
2398  uAvg = u[yPos];
2399  vAvg = v[yPos];
2400  yval = Clamp6(y[yPos++] + YUVoffset6 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2401  buff16[j] = (yval << 5) | ((Clamp6(uAvg + yval) >> 1) << 11) | (Clamp6(vAvg + yval) >> 1);
2402  }
2403  buff16 += pitch16;
2404 
2405  if (cb) {
2406  percent += dP;
2407  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2408  }
2409  }
2410  break;
2411  }
2412  default:
2413  ASSERT(false);
2414  }
2415 
2416 #ifdef __PGFROISUPPORT__
2417  if (targetBuff) {
2418  // copy valid ROI (m_roi) from temporary buffer (roi) to target buffer
2419  if (bpp%8 == 0) {
2420  BYTE bypp = bpp/8;
2421  buff = buffStart + (levelRoi.top - roi.top)*pitch + (levelRoi.left - roi.left)*bypp;
2422  w = levelRoi.Width()*bypp;
2423  h = levelRoi.Height();
2424 
2425  for (i=0; i < h; i++) {
2426  for (j=0; j < w; j++) {
2427  targetBuff[j] = buff[j];
2428  }
2429  targetBuff += targetPitch;
2430  buff += pitch;
2431  }
2432  } else {
2433  // to do
2434  }
2435 
2436  delete[] buffStart;
2437  }
2438 #endif
2439 }
DataT* CPGFImage::GetChannel ( int  c = 0)
inline

Return an internal YUV image channel.

Parameters
cA channel index
Returns
An internal YUV image channel

Definition at line 321 of file PGFimage.h.

321 { ASSERT(c >= 0 && c < MaxChannels); return m_channel[c]; }
void CPGFImage::GetColorTable ( UINT32  iFirstColor,
UINT32  nColors,
RGBQUAD *  prgbColors 
) const

Retrieves red, green, blue (RGB) color values from a range of entries in the palette of the DIB section. It might throw an IOException.

Parameters
iFirstColorThe color table index of the first entry to retrieve.
nColorsThe number of color table entries to retrieve.
prgbColorsA pointer to the array of RGBQUAD structures to retrieve the color table entries.

Definition at line 1269 of file PGFimage.cpp.

1269  {
1270  if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError);
1271 
1272  for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
1273  prgbColors[j] = m_postHeader.clut[i];
1274  }
1275 }
const RGBQUAD* CPGFImage::GetColorTable ( ) const
inline
Returns
Address of color table

Definition at line 334 of file PGFimage.h.

334 { return m_postHeader.clut; }
UINT32 CPGFImage::GetEncodedHeaderLength ( ) const

Return the length of all encoded headers in bytes. Precondition: The PGF image has been opened with a call of Open(...).

Returns
The length of all encoded headers in bytes

Definition at line 607 of file PGFimage.cpp.

607  {
608  ASSERT(m_decoder);
610 }
UINT32 CPGFImage::GetEncodedLevelLength ( int  level) const
inline

Return the length of an encoded PGF level in bytes. Precondition: The PGF image has been opened with a call of Open(...).

Parameters
levelThe image level
Returns
The length of a PGF level in bytes

Definition at line 370 of file PGFimage.h.

370 { ASSERT(level >= 0 && level < m_header.nLevels); return m_levelLength[m_header.nLevels - level - 1]; }
const PGFHeader* CPGFImage::GetHeader ( ) const
inline

Return the PGF header structure.

Returns
A PGF header structure

Definition at line 339 of file PGFimage.h.

339 { return &m_header; }
UINT32 CPGFImage::GetMaxValue ( ) const
inline

Get maximum intensity value for image modes with more than eight bits per channel. Don't call this method before the PGF header has been read.

Returns
The maximum intensity value.

Definition at line 345 of file PGFimage.h.

345 { return (1 << m_header.usedBitsPerChannel) - 1; }
const UINT8 * CPGFImage::GetUserData ( UINT32 &  size) const

Return user data and size of user data. Precondition: The PGF image has been opened with a call of Open(...).

Parameters
size[out] Size of user data in bytes.
Returns
A pointer to user data or NULL if there is no user data.

Definition at line 320 of file PGFimage.cpp.

320  {
321  size = m_postHeader.userDataLen;
322  return m_postHeader.userData;
323 }
UINT64 CPGFImage::GetUserDataPos ( ) const
inline

Return the stream position of the user data or 0. Precondition: The PGF image has been opened with a call of Open(...).

Definition at line 350 of file PGFimage.h.

350 { return m_userDataPos; }
void CPGFImage::GetYUV ( int  pitch,
DataT buff,
BYTE  bpp,
int  channelMap[] = NULL,
CallbackPtr  cb = NULL,
void *  data = NULL 
) const

Get YUV image data in interleaved format: (ordering is YUV[A]) The absolute value of pitch is the number of bytes of an image row of the given image buffer. If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row). if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte). 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 provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode. If your provided image buffer expects a channel sequence VUY, then the channelMap looks like { 2, 1, 0 }. It might throw an IOException.

Parameters
pitchThe number of bytes of a row of the image buffer.
buffAn image buffer.
bppThe number of bits per pixel used in image buffer.
channelMapA integer array containing the mapping of PGF channel ordering to expected channel ordering.
cbA pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding.
dataData Pointer to C++ class container to host callback procedure.

Get YUV image data in interleaved format: (ordering is YUV[A]) The absolute value of pitch is the number of bytes of an image row of the given image buffer. If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row). if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte). 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 provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode. If your provided image buffer expects a channel sequence VUY, then the channelMap looks like { 2, 1, 0 }. It might throw an IOException.

Parameters
pitchThe number of bytes of a row of the image buffer.
buffAn image buffer.
bppThe number of bits per pixel used in image buffer.
channelMapA integer array containing the mapping of PGF channel ordering to expected channel ordering.
cbA pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding.

Definition at line 2455 of file PGFimage.cpp.

2455  {
2456  ASSERT(buff);
2457  const UINT32 w = m_width[0];
2458  const UINT32 h = m_height[0];
2459  const bool wOdd = (1 == w%2);
2460  const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
2461  const int pitch2 = pitch/DataTSize;
2462  const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
2463  const double dP = 1.0/h;
2464 
2465  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
2466  if (channelMap == NULL) channelMap = defMap;
2467  int sampledPos = 0, yPos = 0;
2468  DataT uAvg, vAvg;
2469  double percent = 0;
2470  UINT32 i, j;
2471 
2472  if (m_header.channels == 3) {
2473  ASSERT(bpp%dataBits == 0);
2474 
2475  DataT* y = m_channel[0]; ASSERT(y);
2476  DataT* u = m_channel[1]; ASSERT(u);
2477  DataT* v = m_channel[2]; ASSERT(v);
2478  int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2479 
2480  for (i=0; i < h; i++) {
2481  if (i%2) sampledPos -= (w + 1)/2;
2482  cnt = 0;
2483  for (j=0; j < w; j++) {
2484  if (m_downsample) {
2485  // image was downsampled
2486  uAvg = u[sampledPos];
2487  vAvg = v[sampledPos];
2488  } else {
2489  uAvg = u[yPos];
2490  vAvg = v[yPos];
2491  }
2492  buff[cnt + channelMap[0]] = y[yPos];
2493  buff[cnt + channelMap[1]] = uAvg;
2494  buff[cnt + channelMap[2]] = vAvg;
2495  yPos++;
2496  cnt += channels;
2497  if (j%2) sampledPos++;
2498  }
2499  buff += pitch2;
2500  if (wOdd) sampledPos++;
2501 
2502  if (cb) {
2503  percent += dP;
2504  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2505  }
2506  }
2507  } else if (m_header.channels == 4) {
2508  ASSERT(m_header.bpp == m_header.channels*8);
2509  ASSERT(bpp%dataBits == 0);
2510 
2511  DataT* y = m_channel[0]; ASSERT(y);
2512  DataT* u = m_channel[1]; ASSERT(u);
2513  DataT* v = m_channel[2]; ASSERT(v);
2514  DataT* a = m_channel[3]; ASSERT(a);
2515  UINT8 aAvg;
2516  int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2517 
2518  for (i=0; i < h; i++) {
2519  if (i%2) sampledPos -= (w + 1)/2;
2520  cnt = 0;
2521  for (j=0; j < w; j++) {
2522  if (m_downsample) {
2523  // image was downsampled
2524  uAvg = u[sampledPos];
2525  vAvg = v[sampledPos];
2526  aAvg = Clamp8(a[sampledPos] + yuvOffset);
2527  } else {
2528  uAvg = u[yPos];
2529  vAvg = v[yPos];
2530  aAvg = Clamp8(a[yPos] + yuvOffset);
2531  }
2532  // Yuv
2533  buff[cnt + channelMap[0]] = y[yPos];
2534  buff[cnt + channelMap[1]] = uAvg;
2535  buff[cnt + channelMap[2]] = vAvg;
2536  buff[cnt + channelMap[3]] = aAvg;
2537  yPos++;
2538  cnt += channels;
2539  if (j%2) sampledPos++;
2540  }
2541  buff += pitch2;
2542  if (wOdd) sampledPos++;
2543 
2544  if (cb) {
2545  percent += dP;
2546  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2547  }
2548  }
2549  }
2550 }
UINT32 CPGFImage::Height ( int  level = 0) const
inline

Return image height of channel 0 at given level in pixels. The returned height is independent of any Read-operations and ROI.

Parameters
levelA level
Returns
Image level height in pixels

Definition at line 423 of file PGFimage.h.

423 { ASSERT(level >= 0); return LevelHeight(m_header.height, level); }
void CPGFImage::ImportBitmap ( int  pitch,
UINT8 *  buff,
BYTE  bpp,
int  channelMap[] = NULL,
CallbackPtr  cb = NULL,
void *  data = NULL 
)

Import an image from a specified image buffer. This method is usually called before Write(...) and after SetHeader(...). The absolute value of pitch is the number of bytes of an image row. If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row). If pitch is positive, then buff points to the first row of a top-down image (first byte). 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 provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR. If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1, 0 }. It might throw an IOException.

Parameters
pitchThe number of bytes of a row of the image buffer.
buffAn image buffer.
bppThe number of bits per pixel used in image buffer.
channelMapA integer array containing the mapping of input channel ordering to expected channel ordering.
cbA pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding.
dataData Pointer to C++ class container to host callback procedure.

Definition at line 737 of file PGFimage.cpp.

737  {
738  ASSERT(buff);
739  ASSERT(m_channel[0]);
740 
741  // color transform
742  RgbToYuv(pitch, buff, bpp, channelMap, cb, data);
743 
744  if (m_downsample) {
745  // Subsampling of the chrominance and alpha channels
746  for (int i=1; i < m_header.channels; i++) {
747  Downsample(i);
748  }
749  }
750 }
bool CPGFImage::ImportIsSupported ( BYTE  mode)
static

Check for valid import image mode.

Parameters
modeImage mode
Returns
True if an image of given mode can be imported with ImportBitmap(...)

Definition at line 1224 of file PGFimage.cpp.

1224  {
1225  size_t size = DataTSize;
1226 
1227  if (size >= 2) {
1228  switch(mode) {
1229  case ImageModeBitmap:
1230  case ImageModeIndexedColor:
1231  case ImageModeGrayScale:
1232  case ImageModeRGBColor:
1233  case ImageModeCMYKColor:
1234  case ImageModeHSLColor:
1235  case ImageModeHSBColor:
1236  //case ImageModeDuotone:
1237  case ImageModeLabColor:
1238  case ImageModeRGB12:
1239  case ImageModeRGB16:
1240  case ImageModeRGBA:
1241  return true;
1242  }
1243  }
1244  if (size >= 3) {
1245  switch(mode) {
1246  case ImageModeGray16:
1247  case ImageModeRGB48:
1248  case ImageModeLab48:
1249  case ImageModeCMYK64:
1250  //case ImageModeDuotone16:
1251  return true;
1252  }
1253  }
1254  if (size >=4) {
1255  switch(mode) {
1256  case ImageModeGray32:
1257  return true;
1258  }
1259  }
1260  return false;
1261 }
void CPGFImage::ImportYUV ( int  pitch,
DataT buff,
BYTE  bpp,
int  channelMap[] = NULL,
CallbackPtr  cb = NULL,
void *  data = NULL 
)

Import a YUV image from a specified image buffer. The absolute value of pitch is the number of bytes of an image row. If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row). If pitch is positive, then buff points to the first row of a top-down image (first byte). 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 provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR. If your provided image buffer contains a channel sequence VUY, then the channelMap looks like { 2, 1, 0 }. It might throw an IOException.

Parameters
pitchThe number of bytes of a row of the image buffer.
buffAn image buffer.
bppThe number of bits per pixel used in image buffer.
channelMapA integer array containing the mapping of input channel ordering to expected channel ordering.
cbA pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding.
dataData Pointer to C++ class container to host callback procedure.

Import a YUV image from a specified image buffer. The absolute value of pitch is the number of bytes of an image row. If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row). If pitch is positive, then buff points to the first row of a top-down image (first byte). 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 provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR. If your provided image buffer contains a channel sequence VUY, then the channelMap looks like { 2, 1, 0 }. It might throw an IOException.

Parameters
pitchThe number of bytes of a row of the image buffer.
buffAn image buffer.
bppThe number of bits per pixel used in image buffer.
channelMapA integer array containing the mapping of input channel ordering to expected channel ordering.
cbA pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding.

Definition at line 2566 of file PGFimage.cpp.

2566  {
2567  ASSERT(buff);
2568  const double dP = 1.0/m_header.height;
2569  const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
2570  const int pitch2 = pitch/DataTSize;
2571  const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
2572 
2573  int yPos = 0, cnt = 0;
2574  double percent = 0;
2575  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
2576 
2577  if (channelMap == NULL) channelMap = defMap;
2578 
2579  if (m_header.channels == 3) {
2580  ASSERT(bpp%dataBits == 0);
2581 
2582  DataT* y = m_channel[0]; ASSERT(y);
2583  DataT* u = m_channel[1]; ASSERT(u);
2584  DataT* v = m_channel[2]; ASSERT(v);
2585  const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2586 
2587  for (UINT32 h=0; h < m_header.height; h++) {
2588  if (cb) {
2589  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2590  percent += dP;
2591  }
2592 
2593  cnt = 0;
2594  for (UINT32 w=0; w < m_header.width; w++) {
2595  y[yPos] = buff[cnt + channelMap[0]];
2596  u[yPos] = buff[cnt + channelMap[1]];
2597  v[yPos] = buff[cnt + channelMap[2]];
2598  yPos++;
2599  cnt += channels;
2600  }
2601  buff += pitch2;
2602  }
2603  } else if (m_header.channels == 4) {
2604  ASSERT(bpp%dataBits == 0);
2605 
2606  DataT* y = m_channel[0]; ASSERT(y);
2607  DataT* u = m_channel[1]; ASSERT(u);
2608  DataT* v = m_channel[2]; ASSERT(v);
2609  DataT* a = m_channel[3]; ASSERT(a);
2610  const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2611 
2612  for (UINT32 h=0; h < m_header.height; h++) {
2613  if (cb) {
2614  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2615  percent += dP;
2616  }
2617 
2618  cnt = 0;
2619  for (UINT32 w=0; w < m_header.width; w++) {
2620  y[yPos] = buff[cnt + channelMap[0]];
2621  u[yPos] = buff[cnt + channelMap[1]];
2622  v[yPos] = buff[cnt + channelMap[2]];
2623  a[yPos] = buff[cnt + channelMap[3]] - yuvOffset;
2624  yPos++;
2625  cnt += channels;
2626  }
2627  buff += pitch2;
2628  }
2629  }
2630 
2631  if (m_downsample) {
2632  // Subsampling of the chrominance and alpha channels
2633  for (int i=1; i < m_header.channels; i++) {
2634  Downsample(i);
2635  }
2636  }
2637 }
bool CPGFImage::IsOpen ( ) const
inline

Returns true if the PGF has been opened and not closed.

Definition at line 87 of file PGFimage.h.

87 { return m_decoder != NULL; }
BYTE CPGFImage::Level ( ) const
inline

Return current image level. Since Read(...) can be used to read each image level separately, it is helpful to know the current level. The current level immediately after Open(...) is Levels().

Returns
Current image level

Definition at line 430 of file PGFimage.h.

430 { return (BYTE)m_currentLevel; }
static UINT32 CPGFImage::LevelHeight ( UINT32  height,
int  level 
)
inlinestatic

Compute and return image height at given level.

Parameters
heightOriginal image height (at level 0)
levelAn image level
Returns
Image level height in pixels

Definition at line 498 of file PGFimage.h.

498 { ASSERT(level >= 0); UINT32 h = (height >> level); return ((h << level) == height) ? h : h + 1; }
BYTE CPGFImage::Levels ( ) const
inline

Return the number of image levels.

Returns
Number of image levels

Definition at line 435 of file PGFimage.h.

435 { return m_header.nLevels; }
static UINT32 CPGFImage::LevelWidth ( UINT32  width,
int  level 
)
inlinestatic

Compute and return image width at given level.

Parameters
widthOriginal image width (at level 0)
levelAn image level
Returns
Image level width in pixels

Definition at line 491 of file PGFimage.h.

491 { ASSERT(level >= 0); UINT32 w = (width >> level); return ((w << level) == width) ? w : w + 1; }
BYTE CPGFImage::Mode ( ) const
inline

Return the image mode. An image mode is a predefined constant value (see also PGFtypes.h) compatible with Adobe Photoshop. It represents an image type and format.

Returns
Image mode

Definition at line 454 of file PGFimage.h.

454 { return m_header.mode; }
void CPGFImage::Open ( CPGFStream stream)

Open a PGF image at current stream position: read pre-header, header, and ckeck image type. Precondition: The stream has been opened for reading. It might throw an IOException.

Parameters
streamA PGF stream

Definition at line 130 of file PGFimage.cpp.

130  {
131  ASSERT(stream);
132 
133  // create decoder and read PGFPreHeader PGFHeader PGFPostHeader LevelLengths
136 
137  if (m_header.nLevels > MaxLevel) ReturnWithError(FormatCannotRead);
138 
139  // set current level
141 
142  // set image width and height
143  m_width[0] = m_header.width;
144  m_height[0] = m_header.height;
145 
146  // complete header
147  CompleteHeader();
148 
149  // interpret quant parameter
158  m_downsample = true;
159  m_quant = m_header.quality - 1;
160  } else {
161  m_downsample = false;
163  }
164 
165  // set channel dimensions (chrominance is subsampled by factor 2)
166  if (m_downsample) {
167  for (int i=1; i < m_header.channels; i++) {
168  m_width[i] = (m_width[0] + 1)/2;
169  m_height[i] = (m_height[0] + 1)/2;
170  }
171  } else {
172  for (int i=1; i < m_header.channels; i++) {
173  m_width[i] = m_width[0];
174  m_height[i] = m_height[0];
175  }
176  }
177 
178  if (m_header.nLevels > 0) {
179  // init wavelet subbands
180  for (int i=0; i < m_header.channels; i++) {
182  }
183 
184  // used in Read when PM_Absolute
185  m_percent = pow(0.25, m_header.nLevels);
186 
187  } else {
188  // very small image: we don't use DWT and encoding
189 
190  // read channels
191  for (int c=0; c < m_header.channels; c++) {
192  const UINT32 size = m_width[c]*m_height[c];
193  m_channel[c] = new(std::nothrow) DataT[size];
194  if (!m_channel[c]) ReturnWithError(InsufficientMemory);
195 
196  // read channel data from stream
197  for (UINT32 i=0; i < size; i++) {
198  int count = DataTSize;
199  stream->Read(&count, &m_channel[c][i]);
200  if (count != DataTSize) ReturnWithError(MissingData);
201  }
202  }
203  }
204 }
BYTE CPGFImage::Quality ( ) const
inline

Return the PGF quality. The quality is inbetween 0 and MaxQuality. PGF quality 0 means lossless quality.

Returns
PGF quality

Definition at line 441 of file PGFimage.h.

441 { return m_header.quality; }
void CPGFImage::Read ( int  level = 0,
CallbackPtr  cb = NULL,
void *  data = NULL 
)

Read and decode some levels of a PGF image at current stream position. A PGF image is structered in levels, numbered between 0 and Levels() - 1. Each level can be seen as a single image, containing the same content as all other levels, but in a different size (width, height). The image size at level i is double the size (width, height) of the image at level i+1. The image at level 0 contains the original size. Precondition: The PGF image has been opened with a call of Open(...). It might throw an IOException.

Parameters
level[0, nLevels) The image level of the resulting image in the internal image buffer.
cbA pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding.
dataData Pointer to C++ class container to host callback procedure.

Definition at line 382 of file PGFimage.cpp.

382  {
383  ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
384  ASSERT(m_decoder);
385 
386 #ifdef __PGFROISUPPORT__
387  if (ROIisSupported() && m_header.nLevels > 0) {
388  // new encoding scheme supporting ROI
389  PGFRect rect(0, 0, m_header.width, m_header.height);
390  Read(rect, level, cb, data);
391  return;
392  }
393 #endif
394 
395  if (m_header.nLevels == 0) {
396  if (level == 0) {
397  // the data has already been read during open
398  // now update progress
399  if (cb) {
400  if ((*cb)(1.0, true, data)) ReturnWithError(EscapePressed);
401  }
402  }
403  } else {
404  const int levelDiff = m_currentLevel - level;
405  double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
406 
407  // encoding scheme without ROI
408  while (m_currentLevel > level) {
409  for (int i=0; i < m_header.channels; i++) {
410  ASSERT(m_wtChannel[i]);
411  // decode file and write stream to m_wtChannel
412  if (m_currentLevel == m_header.nLevels) {
413  // last level also has LL band
415  }
416  if (m_preHeader.version & Version5) {
417  // since version 5
420  } else {
421  // until version 4
423  }
425  }
426 
427  volatile OSError error = NoError; // volatile prevents optimizations
428  #pragma omp parallel for default(shared)
429  for (int i=0; i < m_header.channels; i++) {
430  // inverse transform from m_wtChannel to m_channel
431  if (error == NoError) {
432  OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
433  if (err != NoError) error = err;
434  }
435  ASSERT(m_channel[i]);
436  }
437  if (error != NoError) ReturnWithError(error);
438 
439  // set new level: must be done before refresh callback
440  m_currentLevel--;
441 
442  // now we have to refresh the display
443  if (m_cb) m_cb(m_cbArg);
444 
445  // now update progress
446  if (cb) {
447  percent *= 4;
448  if (m_progressMode == PM_Absolute) m_percent = percent;
449  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
450  }
451  }
452  }
453 
454  // automatically closing
455  if (m_currentLevel == 0) Close();
456 }
void CPGFImage::Read ( PGFRect rect,
int  level = 0,
CallbackPtr  cb = NULL,
void *  data = NULL 
)

Read a rectangular region of interest of a PGF image at current stream position. The origin of the coordinate axis is the top-left corner of the image. All coordinates are measured in pixels. It might throw an IOException.

Parameters
rect[inout] Rectangular region of interest (ROI). The rect might be cropped.
level[0, nLevels) The image level of the resulting image in the internal image buffer.
cbA pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding.
dataData Pointer to C++ class container to host callback procedure.
UINT32 CPGFImage::ReadEncodedData ( int  level,
UINT8 *  target,
UINT32  targetLen 
) const

Reads the data of an encoded PGF level and copies it to a target buffer without decoding. Precondition: The PGF image has been opened with a call of Open(...). It might throw an IOException.

Parameters
levelThe image level
targetThe target buffer
targetLenThe length of the target buffer in bytes
Returns
The number of bytes copied to the target buffer

Definition at line 653 of file PGFimage.cpp.

653  {
654  ASSERT(level >= 0 && level < m_header.nLevels);
655  ASSERT(target);
656  ASSERT(targetLen > 0);
657  ASSERT(m_decoder);
658 
659  // reset stream position
661 
662  // position stream
663  UINT64 offset = 0;
664 
665  for (int i=m_header.nLevels - 1; i > level; i--) {
666  offset += m_levelLength[m_header.nLevels - 1 - i];
667  }
668  m_decoder->Skip(offset);
669 
670  // compute number of bytes to read
671  UINT32 len = __min(targetLen, GetEncodedLevelLength(level));
672 
673  // read data
674  len = m_decoder->ReadEncodedData(target, len);
675  ASSERT(len >= 0 && len <= targetLen);
676 
677  return len;
678 }
UINT32 CPGFImage::ReadEncodedHeader ( UINT8 *  target,
UINT32  targetLen 
) const

Reads the encoded PGF headers and copies it to a target buffer. Precondition: The PGF image has been opened with a call of Open(...). It might throw an IOException.

Parameters
targetThe target buffer
targetLenThe length of the target buffer in bytes
Returns
The number of bytes copied to the target buffer

Definition at line 619 of file PGFimage.cpp.

619  {
620  ASSERT(target);
621  ASSERT(targetLen > 0);
622  ASSERT(m_decoder);
623 
624  // reset stream position
626 
627  // compute number of bytes to read
628  UINT32 len = __min(targetLen, GetEncodedHeaderLength());
629 
630  // read data
631  len = m_decoder->ReadEncodedData(target, len);
632  ASSERT(len >= 0 && len <= targetLen);
633 
634  return len;
635 }
void CPGFImage::ReadPreview ( )
inline

Read and decode smallest level of a PGF image at current stream position. For details, please refert to Read(...) Precondition: The PGF image has been opened with a call of Open(...). It might throw an IOException.

Definition at line 121 of file PGFimage.h.

121 { Read(Levels() - 1); }
void CPGFImage::Reconstruct ( int  level = 0)

After you've written a PGF image, you can call this method followed by GetBitmap/GetYUV to get a quick reconstruction (coded -> decoded image). It might throw an IOException.

Parameters
levelThe image level of the resulting image in the internal image buffer.

Definition at line 330 of file PGFimage.cpp.

330  {
331  if (m_header.nLevels == 0) {
332  // image didn't use wavelet transform
333  if (level == 0) {
334  for (int i=0; i < m_header.channels; i++) {
335  ASSERT(m_wtChannel[i]);
336  m_channel[i] = m_wtChannel[i]->GetSubband(0, LL)->GetBuffer();
337  }
338  }
339  } else {
340  int currentLevel = m_header.nLevels;
341 
342  if (ROIisSupported()) {
343  // enable ROI reading
345  }
346 
347  while (currentLevel > level) {
348  for (int i=0; i < m_header.channels; i++) {
349  ASSERT(m_wtChannel[i]);
350  // dequantize subbands
351  if (currentLevel == m_header.nLevels) {
352  // last level also has LL band
353  m_wtChannel[i]->GetSubband(currentLevel, LL)->Dequantize(m_quant);
354  }
355  m_wtChannel[i]->GetSubband(currentLevel, HL)->Dequantize(m_quant);
356  m_wtChannel[i]->GetSubband(currentLevel, LH)->Dequantize(m_quant);
357  m_wtChannel[i]->GetSubband(currentLevel, HH)->Dequantize(m_quant);
358 
359  // inverse transform from m_wtChannel to m_channel
360  OSError err = m_wtChannel[i]->InverseTransform(currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
361  if (err != NoError) ReturnWithError(err);
362  ASSERT(m_channel[i]);
363  }
364 
365  currentLevel--;
366  }
367  }
368 }
void CPGFImage::ResetStreamPos ( )

Reset stream position to start of PGF pre-header

Definition at line 639 of file PGFimage.cpp.

639  {
640  ASSERT(m_decoder);
641  return m_decoder->SetStreamPosToStart();
642 }
void CPGFImage::RgbToYuv ( int  pitch,
UINT8 *  rgbBuff,
BYTE  bpp,
int  channelMap[],
CallbackPtr  cb,
void *  data 
)
private

Definition at line 1308 of file PGFimage.cpp.

1308  {
1309  ASSERT(buff);
1310  int yPos = 0, cnt = 0;
1311  double percent = 0;
1312  const double dP = 1.0/m_header.height;
1313  int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
1314 
1315  if (channelMap == NULL) channelMap = defMap;
1316 
1317  switch(m_header.mode) {
1318  case ImageModeBitmap:
1319  {
1320  ASSERT(m_header.channels == 1);
1321  ASSERT(m_header.bpp == 1);
1322  ASSERT(bpp == 1);
1323 
1324  const UINT32 w = m_header.width;
1325  const UINT32 w2 = (m_header.width + 7)/8;
1326  DataT* y = m_channel[0]; ASSERT(y);
1327 
1328  for (UINT32 h=0; h < m_header.height; h++) {
1329  if (cb) {
1330  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1331  percent += dP;
1332  }
1333 
1334  for (UINT32 j=0; j < w2; j++) {
1335  y[yPos++] = buff[j] - YUVoffset8;
1336  }
1337  for (UINT32 j=w2; j < w; j++) {
1338  y[yPos++] = YUVoffset8;
1339  }
1340 
1341  //UINT cnt = w;
1342  //for (UINT32 j=0; j < w2; j++) {
1343  // for (int k=7; k >= 0; k--) {
1344  // if (cnt) {
1345  // y[yPos++] = YUVoffset8 + (1 & (buff[j] >> k));
1346  // cnt--;
1347  // }
1348  // }
1349  //}
1350  buff += pitch;
1351  }
1352  }
1353  break;
1354  case ImageModeIndexedColor:
1355  case ImageModeGrayScale:
1356  case ImageModeHSLColor:
1357  case ImageModeHSBColor:
1358  case ImageModeLabColor:
1359  {
1360  ASSERT(m_header.channels >= 1);
1361  ASSERT(m_header.bpp == m_header.channels*8);
1362  ASSERT(bpp%8 == 0);
1363  const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1364 
1365  for (UINT32 h=0; h < m_header.height; h++) {
1366  if (cb) {
1367  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1368  percent += dP;
1369  }
1370 
1371  cnt = 0;
1372  for (UINT32 w=0; w < m_header.width; w++) {
1373  for (int c=0; c < m_header.channels; c++) {
1374  m_channel[c][yPos] = buff[cnt + channelMap[c]] - YUVoffset8;
1375  }
1376  cnt += channels;
1377  yPos++;
1378  }
1379  buff += pitch;
1380  }
1381  }
1382  break;
1383  case ImageModeGray16:
1384  case ImageModeLab48:
1385  {
1386  ASSERT(m_header.channels >= 1);
1387  ASSERT(m_header.bpp == m_header.channels*16);
1388  ASSERT(bpp%16 == 0);
1389 
1390  UINT16 *buff16 = (UINT16 *)buff;
1391  const int pitch16 = pitch/2;
1392  const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1393  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1394  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1395 
1396  for (UINT32 h=0; h < m_header.height; h++) {
1397  if (cb) {
1398  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1399  percent += dP;
1400  }
1401 
1402  cnt = 0;
1403  for (UINT32 w=0; w < m_header.width; w++) {
1404  for (int c=0; c < m_header.channels; c++) {
1405  m_channel[c][yPos] = (buff16[cnt + channelMap[c]] >> shift) - yuvOffset16;
1406  }
1407  cnt += channels;
1408  yPos++;
1409  }
1410  buff16 += pitch16;
1411  }
1412  }
1413  break;
1414  case ImageModeRGBColor:
1415  {
1416  ASSERT(m_header.channels == 3);
1417  ASSERT(m_header.bpp == m_header.channels*8);
1418  ASSERT(bpp%8 == 0);
1419 
1420  DataT* y = m_channel[0]; ASSERT(y);
1421  DataT* u = m_channel[1]; ASSERT(u);
1422  DataT* v = m_channel[2]; ASSERT(v);
1423  const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1424  UINT8 b, g, r;
1425 
1426  for (UINT32 h=0; h < m_header.height; h++) {
1427  if (cb) {
1428  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1429  percent += dP;
1430  }
1431 
1432  cnt = 0;
1433  for (UINT32 w=0; w < m_header.width; w++) {
1434  b = buff[cnt + channelMap[0]];
1435  g = buff[cnt + channelMap[1]];
1436  r = buff[cnt + channelMap[2]];
1437  // Yuv
1438  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
1439  u[yPos] = r - g;
1440  v[yPos] = b - g;
1441  yPos++;
1442  cnt += channels;
1443  }
1444  buff += pitch;
1445  }
1446  }
1447  break;
1448  case ImageModeRGB48:
1449  {
1450  ASSERT(m_header.channels == 3);
1451  ASSERT(m_header.bpp == m_header.channels*16);
1452  ASSERT(bpp%16 == 0);
1453 
1454  UINT16 *buff16 = (UINT16 *)buff;
1455  const int pitch16 = pitch/2;
1456  const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1457  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1458  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1459 
1460  DataT* y = m_channel[0]; ASSERT(y);
1461  DataT* u = m_channel[1]; ASSERT(u);
1462  DataT* v = m_channel[2]; ASSERT(v);
1463  UINT16 b, g, r;
1464 
1465  for (UINT32 h=0; h < m_header.height; h++) {
1466  if (cb) {
1467  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1468  percent += dP;
1469  }
1470 
1471  cnt = 0;
1472  for (UINT32 w=0; w < m_header.width; w++) {
1473  b = buff16[cnt + channelMap[0]] >> shift;
1474  g = buff16[cnt + channelMap[1]] >> shift;
1475  r = buff16[cnt + channelMap[2]] >> shift;
1476  // Yuv
1477  y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
1478  u[yPos] = r - g;
1479  v[yPos] = b - g;
1480  yPos++;
1481  cnt += channels;
1482  }
1483  buff16 += pitch16;
1484  }
1485  }
1486  break;
1487  case ImageModeRGBA:
1488  case ImageModeCMYKColor:
1489  {
1490  ASSERT(m_header.channels == 4);
1491  ASSERT(m_header.bpp == m_header.channels*8);
1492  ASSERT(bpp%8 == 0);
1493  const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1494 
1495  DataT* y = m_channel[0]; ASSERT(y);
1496  DataT* u = m_channel[1]; ASSERT(u);
1497  DataT* v = m_channel[2]; ASSERT(v);
1498  DataT* a = m_channel[3]; ASSERT(a);
1499  UINT8 b, g, r;
1500 
1501  for (UINT32 h=0; h < m_header.height; h++) {
1502  if (cb) {
1503  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1504  percent += dP;
1505  }
1506 
1507  cnt = 0;
1508  for (UINT32 w=0; w < m_header.width; w++) {
1509  b = buff[cnt + channelMap[0]];
1510  g = buff[cnt + channelMap[1]];
1511  r = buff[cnt + channelMap[2]];
1512  // Yuv
1513  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
1514  u[yPos] = r - g;
1515  v[yPos] = b - g;
1516  a[yPos++] = buff[cnt + channelMap[3]] - YUVoffset8;
1517  cnt += channels;
1518  }
1519  buff += pitch;
1520  }
1521  }
1522  break;
1523  case ImageModeCMYK64:
1524  {
1525  ASSERT(m_header.channels == 4);
1526  ASSERT(m_header.bpp == m_header.channels*16);
1527  ASSERT(bpp%16 == 0);
1528 
1529  UINT16 *buff16 = (UINT16 *)buff;
1530  const int pitch16 = pitch/2;
1531  const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1532  const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1533  const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1534 
1535  DataT* y = m_channel[0]; ASSERT(y);
1536  DataT* u = m_channel[1]; ASSERT(u);
1537  DataT* v = m_channel[2]; ASSERT(v);
1538  DataT* a = m_channel[3]; ASSERT(a);
1539  UINT16 b, g, r;
1540 
1541  for (UINT32 h=0; h < m_header.height; h++) {
1542  if (cb) {
1543  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1544  percent += dP;
1545  }
1546 
1547  cnt = 0;
1548  for (UINT32 w=0; w < m_header.width; w++) {
1549  b = buff16[cnt + channelMap[0]] >> shift;
1550  g = buff16[cnt + channelMap[1]] >> shift;
1551  r = buff16[cnt + channelMap[2]] >> shift;
1552  // Yuv
1553  y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
1554  u[yPos] = r - g;
1555  v[yPos] = b - g;
1556  a[yPos++] = (buff16[cnt + channelMap[3]] >> shift) - yuvOffset16;
1557  cnt += channels;
1558  }
1559  buff16 += pitch16;
1560  }
1561  }
1562  break;
1563 #ifdef __PGF32SUPPORT__
1564  case ImageModeGray32:
1565  {
1566  ASSERT(m_header.channels == 1);
1567  ASSERT(m_header.bpp == 32);
1568  ASSERT(bpp == 32);
1569  ASSERT(DataTSize == sizeof(UINT32));
1570 
1571  DataT* y = m_channel[0]; ASSERT(y);
1572 
1573  UINT32 *buff32 = (UINT32 *)buff;
1574  const int pitch32 = pitch/4;
1575  const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1576  const DataT yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
1577 
1578  for (UINT32 h=0; h < m_header.height; h++) {
1579  if (cb) {
1580  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1581  percent += dP;
1582  }
1583 
1584  for (UINT32 w=0; w < m_header.width; w++) {
1585  y[yPos++] = (buff32[w] >> shift) - yuvOffset31;
1586  }
1587  buff32 += pitch32;
1588  }
1589  }
1590  break;
1591 #endif
1592  case ImageModeRGB12:
1593  {
1594  ASSERT(m_header.channels == 3);
1595  ASSERT(m_header.bpp == m_header.channels*4);
1596  ASSERT(bpp == m_header.channels*4);
1597 
1598  DataT* y = m_channel[0]; ASSERT(y);
1599  DataT* u = m_channel[1]; ASSERT(u);
1600  DataT* v = m_channel[2]; ASSERT(v);
1601 
1602  UINT8 rgb = 0, b, g, r;
1603 
1604  for (UINT32 h=0; h < m_header.height; h++) {
1605  if (cb) {
1606  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1607  percent += dP;
1608  }
1609 
1610  cnt = 0;
1611  for (UINT32 w=0; w < m_header.width; w++) {
1612  if (w%2 == 0) {
1613  // even pixel position
1614  rgb = buff[cnt];
1615  b = rgb & 0x0F;
1616  g = (rgb & 0xF0) >> 4;
1617  cnt++;
1618  rgb = buff[cnt];
1619  r = rgb & 0x0F;
1620  } else {
1621  // odd pixel position
1622  b = (rgb & 0xF0) >> 4;
1623  cnt++;
1624  rgb = buff[cnt];
1625  g = rgb & 0x0F;
1626  r = (rgb & 0xF0) >> 4;
1627  cnt++;
1628  }
1629 
1630  // Yuv
1631  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset4;
1632  u[yPos] = r - g;
1633  v[yPos] = b - g;
1634  yPos++;
1635  }
1636  buff += pitch;
1637  }
1638  }
1639  break;
1640  case ImageModeRGB16:
1641  {
1642  ASSERT(m_header.channels == 3);
1643  ASSERT(m_header.bpp == 16);
1644  ASSERT(bpp == 16);
1645 
1646  DataT* y = m_channel[0]; ASSERT(y);
1647  DataT* u = m_channel[1]; ASSERT(u);
1648  DataT* v = m_channel[2]; ASSERT(v);
1649 
1650  UINT16 *buff16 = (UINT16 *)buff;
1651  UINT16 rgb, b, g, r;
1652  const int pitch16 = pitch/2;
1653 
1654  for (UINT32 h=0; h < m_header.height; h++) {
1655  if (cb) {
1656  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1657  percent += dP;
1658  }
1659  for (UINT32 w=0; w < m_header.width; w++) {
1660  rgb = buff16[w];
1661  r = (rgb & 0xF800) >> 10; // highest 5 bits
1662  g = (rgb & 0x07E0) >> 5; // middle 6 bits
1663  b = (rgb & 0x001F) << 1; // lowest 5 bits
1664  // Yuv
1665  y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset6;
1666  u[yPos] = r - g;
1667  v[yPos] = b - g;
1668  yPos++;
1669  }
1670 
1671  buff16 += pitch16;
1672  }
1673  }
1674  break;
1675  default:
1676  ASSERT(false);
1677  }
1678 }
bool CPGFImage::ROIisSupported ( ) const
inline

Return true if the pgf image supports Region Of Interest (ROI).

Returns
true if the pgf image supports ROI.

Definition at line 465 of file PGFimage.h.

465 { return (m_preHeader.version & PGFROI) == PGFROI; }
void CPGFImage::SetChannel ( DataT channel,
int  c = 0 
)
inline

Set internal PGF image buffer channel.

Parameters
channelA YUV data channel
cA channel index

Definition at line 276 of file PGFimage.h.

276 { ASSERT(c >= 0 && c < MaxChannels); m_channel[c] = channel; }
void CPGFImage::SetColorTable ( UINT32  iFirstColor,
UINT32  nColors,
const RGBQUAD *  prgbColors 
)

Sets the red, green, blue (RGB) color values for a range of entries in the palette (clut). It might throw an IOException.

Parameters
iFirstColorThe color table index of the first entry to set.
nColorsThe number of color table entries to set.
prgbColorsA pointer to the array of RGBQUAD structures to set the color table entries.

Definition at line 1283 of file PGFimage.cpp.

1283  {
1284  if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError);
1285 
1286  for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
1287  m_postHeader.clut[i] = prgbColors[j];
1288  }
1289 }
void CPGFImage::SetHeader ( const PGFHeader header,
BYTE  flags = 0,
UINT8 *  userData = 0,
UINT32  userDataLength = 0 
)

Set PGF header and user data. Precondition: The PGF image has been closed with Close(...) or never opened with Open(...). It might throw an IOException.

Parameters
headerA valid and already filled in PGF header structure
flagsA combination of additional version flags. In case you use level-wise encoding then set flag = PGFROI.
userDataA user-defined memory block containing any kind of cached metadata.
userDataLengthThe size of user-defined memory block in bytes

Definition at line 838 of file PGFimage.cpp.

838  {
839  ASSERT(!m_decoder); // current image must be closed
840  ASSERT(header.quality <= MaxQuality);
841 
842  // init state
843 #ifdef __PGFROISUPPORT__
844  m_streamReinitialized = false;
845 #endif
846 
847  // init preHeader
848  memcpy(m_preHeader.magic, Magic, 3);
849  m_preHeader.version = PGFVersion | flags;
851 
852  // copy header
853  memcpy(&m_header, &header, HeaderSize);
854 
855  // complete header
856  CompleteHeader();
857 
858  // check and set number of levels
859  ComputeLevels();
860 
861  // check for downsample
869  m_downsample = true;
870  m_quant = m_header.quality - 1;
871  } else {
872  m_downsample = false;
874  }
875 
876  // update header size and copy user data
878  // update header size
880  }
881  if (userDataLength && userData) {
882  m_postHeader.userData = new(std::nothrow) UINT8[userDataLength];
883  if (!m_postHeader.userData) ReturnWithError(InsufficientMemory);
884  m_postHeader.userDataLen = userDataLength;
885  memcpy(m_postHeader.userData, userData, userDataLength);
886  // update header size
887  m_preHeader.hSize += userDataLength;
888  }
889 
890  // allocate channels
891  for (int i=0; i < m_header.channels; i++) {
892  // set current width and height
893  m_width[i] = m_header.width;
894  m_height[i] = m_header.height;
895 
896  // allocate channels
897  ASSERT(!m_channel[i]);
898  m_channel[i] = new(std::nothrow) DataT[m_header.width*m_header.height];
899  if (!m_channel[i]) {
900  if (i) i--;
901  while(i) {
902  delete[] m_channel[i]; m_channel[i] = 0;
903  i--;
904  }
905  ReturnWithError(InsufficientMemory);
906  }
907  }
908 }
void CPGFImage::SetMaxValue ( UINT32  maxValue)

Set maximum intensity value for image modes with more than eight bits per channel. Call this method after SetHeader, but before ImportBitmap.

Parameters
maxValueThe maximum intensity value.

Definition at line 684 of file PGFimage.cpp.

684  {
685  const BYTE bpc = m_header.bpp/m_header.channels;
686  BYTE pot = 0;
687 
688  while(maxValue > 0) {
689  pot++;
690  maxValue >>= 1;
691  }
692  // store bits per channel
693  if (pot > bpc) pot = bpc;
694  if (pot > 31) pot = 31;
696 }
void CPGFImage::SetProgressMode ( ProgressMode  pm)
inline

Set progress mode used in Read and Write. Default mode is PM_Relative. This method must be called before Open() or SetHeader(). PM_Relative: 100% = level difference between current level and target level of Read/Write PM_Absolute: 100% = number of levels

Definition at line 300 of file PGFimage.h.

300 { m_progressMode = pm; }
void CPGFImage::SetRefreshCallback ( RefreshCB  callback,
void *  arg 
)
inline

Set refresh callback procedure and its parameter. The refresh callback is called during Read(...) after each level read.

Parameters
callbackA refresh callback procedure
argA parameter of the refresh callback procedure

Definition at line 307 of file PGFimage.h.

307 { m_cb = callback; m_cbArg = arg; }
void CPGFImage::SetROI ( PGFRect  rect)
private
UINT32 CPGFImage::UpdatePostHeaderSize ( )
private

Definition at line 1044 of file PGFimage.cpp.

1044  {
1045  ASSERT(m_encoder);
1046 
1047  INT64 offset = m_encoder->ComputeOffset(); ASSERT(offset >= 0);
1048 
1049  if (offset > 0) {
1050  // update post-header size and rewrite pre-header
1051  m_preHeader.hSize += (UINT32)offset;
1053  }
1054 
1055  // write dummy levelLength into stream
1057 }
BYTE CPGFImage::UsedBitsPerChannel ( ) const

Returns number of used bits per input/output image channel. Precondition: header must be initialized.

Returns
number of used bits per input/output image channel.

Definition at line 702 of file PGFimage.cpp.

702  {
703  const BYTE bpc = m_header.bpp/m_header.channels;
704 
705  if (bpc > 8) {
707  } else {
708  return bpc;
709  }
710 }
BYTE CPGFImage::Version ( ) const
inline

Returns images' PGF version

Returns
PGF codec version of the image

Definition at line 476 of file PGFimage.h.

UINT32 CPGFImage::Width ( int  level = 0) const
inline

Return image width of channel 0 at given level in pixels. The returned width is independent of any Read-operations and ROI.

Parameters
levelA level
Returns
Image level width in pixels

Definition at line 416 of file PGFimage.h.

416 { ASSERT(level >= 0); return LevelWidth(m_header.width, level); }
void CPGFImage::Write ( CPGFStream stream,
UINT32 *  nWrittenBytes = NULL,
CallbackPtr  cb = NULL,
void *  data = NULL 
)

Encode and write a entire PGF image (header and image) at current stream position. A PGF image is structered in levels, numbered between 0 and Levels() - 1. Each level can be seen as a single image, containing the same content as all other levels, but in a different size (width, height). The image size at level i is double the size (width, height) of the image at level i+1. The image at level 0 contains the original size. Precondition: the PGF image contains a valid header (see also SetHeader(...)). It might throw an IOException.

Parameters
streamA PGF stream
nWrittenBytes[in-out] The number of bytes written into stream are added to the input value.
cbA pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
dataData Pointer to C++ class container to host callback procedure.

Definition at line 1140 of file PGFimage.cpp.

1140  {
1141  ASSERT(stream);
1142  ASSERT(m_preHeader.hSize);
1143 
1144  // create wavelet transform channels and encoder
1145  UINT32 nBytes = WriteHeader(stream);
1146 
1147  // write image
1148  nBytes += WriteImage(stream, cb, data);
1149 
1150  // return written bytes
1151  if (nWrittenBytes) *nWrittenBytes += nBytes;
1152 }
UINT32 CPGFImage::Write ( int  level,
CallbackPtr  cb = NULL,
void *  data = NULL 
)

Encode and write down to given level at current stream position. A PGF image is structered in levels, numbered between 0 and Levels() - 1. Each level can be seen as a single image, containing the same content as all other levels, but in a different size (width, height). The image size at level i is double the size (width, height) of the image at level i+1. The image at level 0 contains the original size. Preconditions: the PGF image contains a valid header (see also SetHeader(...)) and WriteHeader() has been called before. Levels() > 0. The ROI encoding scheme must be used (see also SetHeader(...)). It might throw an IOException.

Parameters
level[0, nLevels) The image level of the resulting image in the internal image buffer.
cbA pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
dataData Pointer to C++ class container to host callback procedure.
Returns
The number of bytes written into stream.
UINT32 CPGFImage::WriteHeader ( CPGFStream stream)

Create wavelet transform channels and encoder. Write header at current stream position. Call this method before your first call of Write(int level) or WriteImage(), but after SetHeader(). This method is called inside of Write(stream, ...). It might throw an IOException.

Parameters
streamA PGF stream
Returns
The number of bytes written into stream.

Definition at line 917 of file PGFimage.cpp.

917  {
918  ASSERT(m_header.nLevels <= MaxLevel);
919  ASSERT(m_header.quality <= MaxQuality); // quality is already initialized
920 
921  if (m_header.nLevels > 0) {
922  volatile OSError error = NoError; // volatile prevents optimizations
923  // create new wt channels
924  #pragma omp parallel for default(shared)
925  for (int i=0; i < m_header.channels; i++) {
926  DataT *temp = NULL;
927  if (error == NoError) {
928  if (m_wtChannel[i]) {
929  ASSERT(m_channel[i]);
930  // copy m_channel to temp
931  int size = m_height[i]*m_width[i];
932  temp = new(std::nothrow) DataT[size];
933  if (temp) {
934  memcpy(temp, m_channel[i], size*DataTSize);
935  delete m_wtChannel[i]; // also deletes m_channel
936  } else {
937  error = InsufficientMemory;
938  }
939  }
940  if (error == NoError) {
941  if (temp) m_channel[i] = temp;
942  m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels, m_channel[i]);
943  #ifdef __PGFROISUPPORT__
944  m_wtChannel[i]->SetROI(PGFRect(0, 0, m_header.width, m_header.height));
945  #endif
946 
947  // wavelet subband decomposition
948  for (int l=0; error == NoError && l < m_header.nLevels; l++) {
949  OSError err = m_wtChannel[i]->ForwardTransform(l, m_quant);
950  if (err != NoError) error = err;
951  }
952  }
953  }
954  }
955  if (error != NoError) ReturnWithError(error);
956 
958 
959  // create encoder and eventually write headers and levelLength
962 
963  #ifdef __PGFROISUPPORT__
964  if (ROIisSupported()) {
965  // new encoding scheme supporting ROI
966  m_encoder->SetROI();
967  }
968  #endif
969 
970  } else {
971  // very small image: we don't use DWT and encoding
972 
973  // create encoder and eventually write headers and levelLength
975  }
976 
977  INT64 nBytes = m_encoder->ComputeHeaderLength();
978  return (nBytes > 0) ? (UINT32)nBytes : 0;
979 }
UINT32 CPGFImage::WriteImage ( CPGFStream stream,
CallbackPtr  cb = NULL,
void *  data = NULL 
)

Encode and write the one and only image at current stream position. Call this method after WriteHeader(). In case you want to write uncached metadata, then do that after WriteHeader() and before WriteImage(). This method is called inside of Write(stream, ...). It might throw an IOException.

Parameters
streamA PGF stream
cbA pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
dataData Pointer to C++ class container to host callback procedure.
Returns
The number of bytes written into stream.

Definition at line 1069 of file PGFimage.cpp.

1069  {
1070  ASSERT(stream);
1071  ASSERT(m_preHeader.hSize);
1072 
1073  int levels = m_header.nLevels;
1074  double percent = pow(0.25, levels);
1075 
1076  // update post-header size, rewrite pre-header, and write dummy levelLength
1077  UINT32 nWrittenBytes = UpdatePostHeaderSize();
1078 
1079  if (levels == 0) {
1080  // write channels
1081  for (int c=0; c < m_header.channels; c++) {
1082  const UINT32 size = m_width[c]*m_height[c];
1083 
1084  // write channel data into stream
1085  for (UINT32 i=0; i < size; i++) {
1086  int count = DataTSize;
1087  stream->Write(&count, &m_channel[c][i]);
1088  }
1089  }
1090 
1091  // now update progress
1092  if (cb) {
1093  if ((*cb)(1, true, data)) ReturnWithError(EscapePressed);
1094  }
1095 
1096  } else {
1097  // encode quantized wavelet coefficients and write to PGF file
1098  // encode subbands, higher levels first
1099  // color channels are interleaved
1100 
1101  // encode all levels
1102  for (m_currentLevel = levels; m_currentLevel > 0; ) {
1103  WriteLevel(); // decrements m_currentLevel
1104 
1105  // now update progress
1106  if (cb) {
1107  percent *= 4;
1108  if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1109  }
1110  }
1111 
1112  // flush encoder and write level lengths
1113  m_encoder->Flush();
1114  }
1115 
1116  // update level lengths
1117  nWrittenBytes = m_encoder->UpdateLevelLength(); // return written image bytes
1118 
1119  // delete encoder
1120  delete m_encoder; m_encoder = NULL;
1121 
1122  ASSERT(!m_encoder);
1123 
1124  return nWrittenBytes;
1125 }
void CPGFImage::WriteLevel ( )
private

Definition at line 989 of file PGFimage.cpp.

989  {
990  ASSERT(m_encoder);
991  ASSERT(m_currentLevel > 0);
992  ASSERT(m_header.nLevels > 0);
993 
994 #ifdef __PGFROISUPPORT__
995  if (ROIisSupported()) {
996  const int lastChannel = m_header.channels - 1;
997 
998  for (int i=0; i < m_header.channels; i++) {
999  // get number of tiles and tile indices
1000  const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel);
1001  const UINT32 lastTile = nTiles - 1;
1002 
1003  if (m_currentLevel == m_header.nLevels) {
1004  // last level also has LL band
1005  ASSERT(nTiles == 1);
1007  m_encoder->EncodeTileBuffer();
1008  }
1009  for (UINT32 tileY=0; tileY < nTiles; tileY++) {
1010  for (UINT32 tileX=0; tileX < nTiles; tileX++) {
1011  m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, true, tileX, tileY);
1012  m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, true, tileX, tileY);
1013  m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, true, tileX, tileY);
1014  if (i == lastChannel && tileY == lastTile && tileX == lastTile) {
1015  // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level.
1017  }
1018  m_encoder->EncodeTileBuffer();
1019  }
1020  }
1021  }
1022  } else
1023 #endif
1024  {
1025  for (int i=0; i < m_header.channels; i++) {
1026  ASSERT(m_wtChannel[i]);
1027  if (m_currentLevel == m_header.nLevels) {
1028  // last level also has LL band
1030  }
1031  //encoder.EncodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); // until version 4
1032  m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder); // since version 5
1033  m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder); // since version 5
1035  }
1036 
1037  // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level.
1039  }
1040 }

Member Data Documentation

RefreshCB CPGFImage::m_cb
private

pointer to refresh callback procedure

Definition at line 535 of file PGFimage.h.

void* CPGFImage::m_cbArg
private

refresh callback argument

Definition at line 536 of file PGFimage.h.

DataT* CPGFImage::m_channel[MaxChannels]
protected

untransformed channels in YUV format

Definition at line 512 of file PGFimage.h.

int CPGFImage::m_currentLevel
protected

transform level of current image

Definition at line 522 of file PGFimage.h.

CDecoder* CPGFImage::m_decoder
protected

PGF decoder.

Definition at line 513 of file PGFimage.h.

bool CPGFImage::m_downsample
protected

chrominance channels are downsampled

Definition at line 524 of file PGFimage.h.

CEncoder* CPGFImage::m_encoder
protected

PGF encoder.

Definition at line 514 of file PGFimage.h.

bool CPGFImage::m_favorSpeedOverSize
protected

favor encoding speed over compression ratio

Definition at line 525 of file PGFimage.h.

PGFHeader CPGFImage::m_header
protected

PGF file header.

Definition at line 519 of file PGFimage.h.

UINT32 CPGFImage::m_height[MaxChannels]
protected

height of each channel at current level

Definition at line 517 of file PGFimage.h.

UINT32* CPGFImage::m_levelLength
protected

length of each level in bytes; first level starts immediately after this array

Definition at line 515 of file PGFimage.h.

double CPGFImage::m_percent
private

progress [0..1]

Definition at line 537 of file PGFimage.h.

PGFPostHeader CPGFImage::m_postHeader
protected

PGF post-header.

Definition at line 520 of file PGFimage.h.

PGFPreHeader CPGFImage::m_preHeader
protected

PGF pre-header.

Definition at line 518 of file PGFimage.h.

ProgressMode CPGFImage::m_progressMode
private

progress mode used in Read and Write; PM_Relative is default mode

Definition at line 538 of file PGFimage.h.

BYTE CPGFImage::m_quant
protected

quantization parameter

Definition at line 523 of file PGFimage.h.

PGFRect CPGFImage::m_roi
protected

region of interest

Definition at line 531 of file PGFimage.h.

bool CPGFImage::m_skipUserData
protected

skip user data (metadata) during open

Definition at line 528 of file PGFimage.h.

bool CPGFImage::m_streamReinitialized
protected

stream has been reinitialized

Definition at line 530 of file PGFimage.h.

bool CPGFImage::m_useOMPinDecoder
protected

use Open MP in decoder

Definition at line 527 of file PGFimage.h.

bool CPGFImage::m_useOMPinEncoder
protected

use Open MP in encoder

Definition at line 526 of file PGFimage.h.

UINT64 CPGFImage::m_userDataPos
protected

stream position of user data

Definition at line 521 of file PGFimage.h.

UINT32 CPGFImage::m_width[MaxChannels]
protected

width of each channel at current level

Definition at line 516 of file PGFimage.h.

CWaveletTransform* CPGFImage::m_wtChannel[MaxChannels]
protected

wavelet transformed color channels

Definition at line 511 of file PGFimage.h.


The documentation for this class was generated from the following files: