CPGFImage(3)

NAME
CPGFImage - PGF main class.

SYNOPSIS

#include <PGFimage.h>

  Public Member Functions
CPGFImage ()
Standard constructor.
virtual ~CPGFImage ()
Destructor.
void Destroy ()
void Open (CPGFStream *stream)
bool IsOpen () const
Returns true if the PGF has been opened for reading.
void Read (int level=0, CallbackPtr cb=nullptr, void *data=nullptr)
void Read (PGFRect &rect, int level=0, CallbackPtr cb=nullptr, void *data=nullptr)
void ReadPreview ()
void Reconstruct (int level=0)
void GetBitmap (int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=nullptr, CallbackPtr cb=nullptr, void *data=nullptr) const
void GetYUV (int pitch, DataT *buff, BYTE bpp, int channelMap[]=nullptr, CallbackPtr cb=nullptr, void *data=nullptr) const
void ImportBitmap (int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=nullptr, CallbackPtr cb=nullptr, void *data=nullptr)
void ImportYUV (int pitch, DataT *buff, BYTE bpp, int channelMap[]=nullptr, CallbackPtr cb=nullptr, void *data=nullptr)
void Write (CPGFStream *stream, UINT32 *nWrittenBytes=nullptr, CallbackPtr cb=nullptr, void *data=nullptr)
UINT32 WriteHeader (CPGFStream *stream)
UINT32 WriteImage (CPGFStream *stream, CallbackPtr cb=nullptr, void *data=nullptr)
UINT32 Write (int level, CallbackPtr cb=nullptr, void *data=nullptr)
void ConfigureEncoder (bool useOMP=true, bool favorSpeedOverSize=false)
void ConfigureDecoder (bool useOMP=true, UserdataPolicy policy=UP_CacheAll, UINT32 prefixSize=0)
void ResetStreamPos (bool startOfData)
void SetChannel (DataT *channel, int c=0)
void SetHeader (const PGFHeader &header, BYTE flags=0, const UINT8 *userData=0, UINT32 userDataLength=0)
void SetMaxValue (UINT32 maxValue)
void SetProgressMode (ProgressMode pm)
void SetRefreshCallback (RefreshCB callback, void *arg)
void SetColorTable (UINT32 iFirstColor, UINT32 nColors, const RGBQUAD *prgbColors)
DataT * GetChannel (int c=0)
void GetColorTable (UINT32 iFirstColor, UINT32 nColors, RGBQUAD *prgbColors) const
const RGBQUAD * GetColorTable () const
const PGFHeader * GetHeader () const
UINT32 GetMaxValue () const
UINT64 GetUserDataPos () const
const UINT8 * GetUserData (UINT32 &cachedSize, UINT32 *pTotalSize=nullptr) const
UINT32 GetEncodedHeaderLength () const
UINT32 GetEncodedLevelLength (int level) const
UINT32 ReadEncodedHeader (UINT8 *target, UINT32 targetLen) const
UINT32 ReadEncodedData (int level, UINT8 *target, UINT32 targetLen) const
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
bool IsFullyRead () const
Return true if all levels have been read.
BYTE Quality () const
BYTE Channels () const
BYTE Mode () const
BYTE BPP () const
bool ROIisSupported () const
PGFRect ComputeLevelROI () const
BYTE UsedBitsPerChannel () const
BYTE Version () const

  Static Public Member Functions
static bool ImportIsSupported (BYTE mode)
static UINT32 LevelSizeL (UINT32 size, int level)
static UINT32 LevelSizeH (UINT32 size, int level)
static BYTE CodecMajorVersion (BYTE version=PGFVersion)
Return major version.
static BYTE MaxChannelDepth (BYTE version=PGFVersion)

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

  Private Member Functions
void Init ()
void ComputeLevels ()
bool CompleteHeader ()
void RgbToYuv (int pitch, UINT8 *rgbBuff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data)
void Downsample (int nChannel)
UINT32 UpdatePostHeaderSize ()
void WriteLevel ()
PGFRect GetAlignedROI (int c=0) const
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
void * m_cbArg
refresh callback argument
double m_percent
progress [0..1]
ProgressMode m_progressMode
progress mode used in Read and Write; PM_Relative is default mode

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: Open() Read() GetBitmap() Encoding: SetHeader() ImportBitmap() Write()

Author
    C. Stamm, R. Spuler

Definition at line 53 of file PGFimage.h.

Constructor & Destructor Documentation

  CPGFImage::CPGFImage ()

Standard constructor.

Definition at line 64 of file PGFimage.cpp.
64                      {
65         Init();
66 }

  CPGFImage::~CPGFImage () [virtual]

Destructor.

Definition at line 117 of file PGFimage.cpp.
117                       {
118         m_currentLevel = -100; // unusual value used as marker in Destroy()
119         Destroy();
120 }

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 461 of file PGFimage.h.
461 { 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 406 of file PGFimage.h.
406 { return MaxChannelDepth(m_preHeader.version); }

  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
    c A channel index

Returns
    Channel height in pixels

Definition at line 401 of file PGFimage.h.
401 { 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 448 of file PGFimage.h.
448 { 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
    c A channel index

Returns
    Channel width in pixels

Definition at line 394 of file PGFimage.h.
394 { ASSERT(c >= 0 && c < MaxChannels); return m_width[c]; }

  UINT16 CPGFImage::Clamp16 (DataT v) const [inline], [private]

Definition at line 573 of file PGFimage.h.
573                                       {
574                 if (v & 0xFFFF0000) return (v < 0) ? (UINT16)0: (UINT16)65535; else return (UINT16)v;
575         }

  UINT32 CPGFImage::Clamp31 (DataT v) const [inline], [private]

Definition at line 576 of file PGFimage.h.
576                                       {
577                 return (v < 0) ? 0 : (UINT32)v;
578         }

  UINT8 CPGFImage::Clamp4 (DataT v) const [inline], [private]

Definition at line 563 of file PGFimage.h.
563                                     {
564                 if (v & 0xFFFFFFF0) return (v < 0) ? (UINT8)0: (UINT8)15; else return (UINT8)v;
565         }

  UINT16 CPGFImage::Clamp6 (DataT v) const [inline], [private]

Definition at line 566 of file PGFimage.h.
566                                      {
567                 if (v & 0xFFFFFFC0) return (v < 0) ? (UINT16)0: (UINT16)63; else return (UINT16)v;
568         }

  UINT8 CPGFImage::Clamp8 (DataT v) const [inline], [private]

Definition at line 569 of file PGFimage.h.
569                                     {
570                 // needs only one test in the normal case
571                 if (v & 0xFFFFFF00) return (v < 0) ? (UINT8)0 : (UINT8)255; else return (UINT8)v;
572         }

  BYTE CPGFImage::CodecMajorVersion (BYTE version = PGFVersion) [static]

Return major version. Return codec major version.

Parameters
    version pgf pre-header version number

Returns
    PGF major of given version

Definition at line 768 of file PGFimage.cpp.
768                                               {
769         if (version & Version7) return 7;
770         if (version & Version6) return 6;
771         if (version & Version5) return 5;
772         if (version & Version2) return 2;
773         return 1;
774 }

  bool CPGFImage::CompleteHeader () [private]

Definition at line 218 of file PGFimage.cpp.
218                                {
219         // set current codec version
220         m_header.version = PGFVersionNumber(PGFMajorNumber, PGFYear, PGFWeek);
221
222         if (m_header.mode == ImageModeUnknown) {
223                 // undefined mode
224                 switch(m_header.bpp) {
225                 case 1: m_header.mode = ImageModeBitmap; break;
226                 case 8: m_header.mode = ImageModeGrayScale; break;
227                 case 12: m_header.mode = ImageModeRGB12; break;
228                 case 16: m_header.mode = ImageModeRGB16; break;
229                 case 24: m_header.mode = ImageModeRGBColor; break;
230                 case 32: m_header.mode = ImageModeRGBA; break;
231                 case 48: m_header.mode = ImageModeRGB48; break;
232                 default: m_header.mode = ImageModeRGBColor; break;
233                 }
234         }
235         if (!m_header.bpp) {
236                 // undefined bpp
237                 switch(m_header.mode) {
238                 case ImageModeBitmap:
239                         m_header.bpp = 1;
240                         break;
241                 case ImageModeIndexedColor:
242                 case ImageModeGrayScale:
243                         m_header.bpp = 8;
244                         break;
245                 case ImageModeRGB12:
246                         m_header.bpp = 12;
247                         break;
248                 case ImageModeRGB16:
249                 case ImageModeGray16:
250                         m_header.bpp = 16;
251                         break;
252                 case ImageModeRGBColor:
253                 case ImageModeLabColor:
254                         m_header.bpp = 24;
255                         break;
256                 case ImageModeRGBA:
257                 case ImageModeCMYKColor:
258                 case ImageModeGray32:
259                         m_header.bpp = 32;
260                         break;
261                 case ImageModeRGB48:
262                 case ImageModeLab48:
263                         m_header.bpp = 48;
264                         break;
265                 case ImageModeCMYK64:
266                         m_header.bpp = 64;
267                         break;
268                 default:
269                         ASSERT(false);
270                         m_header.bpp = 24;
271                 }
272         }
273         if (m_header.mode == ImageModeRGBColor && m_header.bpp == 32) {
274                 // change mode
275                 m_header.mode = ImageModeRGBA;
276         }
277         if (m_header.mode == ImageModeBitmap && m_header.bpp != 1) return false;
278         if (m_header.mode == ImageModeIndexedColor && m_header.bpp != 8) return false;
279         if (m_header.mode == ImageModeGrayScale && m_header.bpp != 8) return false;
280         if (m_header.mode == ImageModeGray16 && m_header.bpp != 16) return false;
281         if (m_header.mode == ImageModeGray32 && m_header.bpp != 32) return false;
282         if (m_header.mode == ImageModeRGBColor && m_header.bpp != 24) return false;
283         if (m_header.mode == ImageModeRGBA && m_header.bpp != 32) return false;
284         if (m_header.mode == ImageModeRGB12 && m_header.bpp != 12) return false;
285         if (m_header.mode == ImageModeRGB16 && m_header.bpp != 16) return false;
286         if (m_header.mode == ImageModeRGB48 && m_header.bpp != 48) return false;
287         if (m_header.mode == ImageModeLabColor && m_header.bpp != 24) return false;
288         if (m_header.mode == ImageModeLab48 && m_header.bpp != 48) return false;
289         if (m_header.mode == ImageModeCMYKColor && m_header.bpp != 32) return false;
290         if (m_header.mode == ImageModeCMYK64 && m_header.bpp != 64) return false;
291
292         // set number of channels
293         if (!m_header.channels) {
294                 switch(m_header.mode) {
295                 case ImageModeBitmap:
296                 case ImageModeIndexedColor:
297                 case ImageModeGrayScale:
298                 case ImageModeGray16:
299                 case ImageModeGray32:
300                         m_header.channels = 1;
301                         break;
302                 case ImageModeRGBColor:
303                 case ImageModeRGB12:
304                 case ImageModeRGB16:
305                 case ImageModeRGB48:
306                 case ImageModeLabColor:
307                 case ImageModeLab48:
308                         m_header.channels = 3;
309                         break;
310                 case ImageModeRGBA:
311                 case ImageModeCMYKColor:
312                 case ImageModeCMYK64:
313                         m_header.channels = 4;
314                         break;
315                 default:
316                         return false;
317                 }
318         }
319
320         // store used bits per channel
321         UINT8 bpc = m_header.bpp/m_header.channels;
322         if (bpc > 31) bpc = 31;
323         if (!m_header.usedBitsPerChannel || m_header.usedBitsPerChannel > bpc) {
324                 m_header.usedBitsPerChannel = bpc;
325         }
326
327         return true;
328 }

  PGFRect CPGFImage::ComputeLevelROI () const
Return ROI of channel 0 at current level in pixels. The returned rect is only valid after reading a ROI.

Returns
    ROI in pixels

Definition at line 583 of file PGFimage.cpp.
583                                          {
584         if (m_currentLevel == 0) {
585                 return m_roi;
586         } else {
587                 const UINT32 rLeft = LevelSizeL(m_roi.left, m_currentLevel);
588                 const UINT32 rRight = LevelSizeL(m_roi.right, m_currentLevel);
589                 const UINT32 rTop = LevelSizeL(m_roi.top, m_currentLevel);
590                 const UINT32 rBottom = LevelSizeL(m_roi.bottom, m_currentLevel);
591                 return PGFRect(rLeft, rTop, rRight - rLeft, rBottom - rTop);
592         }
593 }

  void CPGFImage::ComputeLevels () [private]

Definition at line 854 of file PGFimage.cpp.
854                               {
855         const int maxThumbnailWidth = 20*FilterSize;
856         const int m = __min(m_header.width, m_header.height);
857         int s = m;
858
859         if (m_header.nLevels < 1 || m_header.nLevels > MaxLevel) {
860                 m_header.nLevels = 1;
861                 // compute a good value depending on the size of the image
862                 while (s > maxThumbnailWidth) {
863                         m_header.nLevels++;
864                         s >>= 1;
865                 }
866         }
867
868         int levels = m_header.nLevels; // we need a signed value during level reduction
869
870         // reduce number of levels if the image size is smaller than FilterSize*(2^levels)
871         s = FilterSize*(1 << levels);   // must be at least the double filter size because of subsampling
872         while (m < s) {
873                 levels--;
874                 s >>= 1;
875         }
876         if (levels > MaxLevel) m_header.nLevels = MaxLevel;
877         else if (levels < 0) m_header.nLevels = 0;
878         else m_header.nLevels = (UINT8)levels;
879
880         // used in Write when PM_Absolute
881         m_percent = pow(0.25, m_header.nLevels);
882
883         ASSERT(0 <= m_header.nLevels && m_header.nLevels <= MaxLevel);
884 }

  void CPGFImage::ConfigureDecoder (bool useOMP = true, UserdataPolicy policy = UP_CacheAll, UINT32 prefixSize = 0) [inline]
Configures the decoder.

Parameters
    useOMP Use parallel threading with Open MP during decoding. Default value: true. Influences the decoding only if the codec has been compiled with OpenMP support.
    policy The file might contain user data (e.g. metadata). The policy defines the behaviour during Open(). UP_CacheAll: User data is read and stored completely in a new allocated memory block. It can be accessed by GetUserData(). UP_CachePrefix: Only prefixSize bytes at the beginning of the user data are stored in a new allocated memory block. It can be accessed by GetUserData(). UP_Skip: User data is skipped and nothing is cached.
    prefixSize Is only used in combination with UP_CachePrefix. It defines the number of bytes cached.

Definition at line 260 of file PGFimage.h.
260 { ASSERT(prefixSize <= MaxUserDataSize);  m_useOMPinDecoder = useOMP; m_userDataPolicy = (UP_CachePrefix) ? prefixSize : 0xFFFFFFFF - policy; }

  void CPGFImage::ConfigureEncoder (bool useOMP = true, bool favorSpeedOverSize = false) [inline]
Configures the encoder.

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

Definition at line 250 of file PGFimage.h.
250 { m_useOMPinEncoder = useOMP; m_favorSpeedOverSize = favorSpeedOverSize; }

  void CPGFImage::Destroy ()

Definition at line 124 of file PGFimage.cpp.
124                         {
125         for (int i = 0; i < m_header.channels; i++) {
126                 delete m_wtChannel[i]; // also deletes m_channel
127         }
128         delete[] m_postHeader.userData;
129         delete[] m_levelLength;
130         delete m_decoder;
131         delete m_encoder;
132
133         if (m_currentLevel != -100) Init();
134 }

  void CPGFImage::Downsample (int nChannel) [private]

Definition at line 810 of file PGFimage.cpp.
810                                  {
811         ASSERT(ch > 0);
812
813         const int w = m_width[0];
814         const int w2 = w/2;
815         const int h2 = m_height[0]/2;
816         const int oddW = w%2;                           // don't use bool -> problems with MaxSpeed optimization
817         const int oddH = m_height[0]%2;         // "
818         int loPos = 0;
819         int hiPos = w;
820         int sampledPos = 0;
821         DataT* buff = m_channel[ch]; ASSERT(buff);
822
823         for (int i=0; i < h2; i++) {
824                 for (int j=0; j < w2; j++) {
825                         // compute average of pixel block
826                         buff[sampledPos] = (buff[loPos] + buff[loPos + 1] + buff[hiPos] + buff[hiPos + 1]) >> 2;
827                         loPos += 2; hiPos += 2;
828                         sampledPos++;
829                 }
830                 if (oddW) {
831                         buff[sampledPos] = (buff[loPos] + buff[hiPos]) >> 1;
832                         loPos++; hiPos++;
833                         sampledPos++;
834                 }
835                 loPos += w; hiPos += w;
836         }
837         if (oddH) {
838                 for (int j=0; j < w2; j++) {
839                         buff[sampledPos] = (buff[loPos] + buff[loPos+1]) >> 1;
840                         loPos += 2; hiPos += 2;
841                         sampledPos++;
842                 }
843                 if (oddW) {
844                         buff[sampledPos] = buff[loPos];
845                 }
846         }
847
848         // downsampled image has half width and half height
849         m_width[ch] = (m_width[ch] + 1)/2;
850         m_height[ch] = (m_height[ch] + 1)/2;
851 }

  PGFRect CPGFImage::GetAlignedROI (int c = 0) const [private]
Returns aligned ROI in pixels of current level of channel c

Parameters
    c A channel index

Definition at line 598 of file PGFimage.cpp.
598                                               {
599         PGFRect roi(0, 0, m_width[c], m_height[c]);
600
601         if (ROIisSupported()) {
602                 ASSERT(m_wtChannel[c]);
603
604                 roi = m_wtChannel[c]->GetAlignedROI(m_currentLevel);
605         }
606         ASSERT(roi.Width() == m_width[c]);
607         ASSERT(roi.Height() == m_height[c]);
608         return roi;
609 }

  void CPGFImage::GetBitmap (int pitch, UINT8 * buff, BYTE bpp, int channelMap[] = nullptr, CallbackPtr cb = nullptr, void * data = nullptr) 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
    pitch The number of bytes of a row of the image buffer.
    buff An image buffer.
    bpp The number of bits per pixel used in image buffer.
    channelMap A integer array containing the mapping of PGF channel ordering to expected channel ordering.
    cb A pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding.
    data Data Pointer to C++ class container to host callback procedure.

Definition at line 1789 of file PGFimage.cpp.
1789                                                                                                                     {
1790         ASSERT(buff);
1791         UINT32 w = m_width[0];  // width of decoded image
1792         UINT32 h = m_height[0]; // height of decoded image
1793         UINT32 yw = w;                  // y-channel width
1794         UINT32 uw = m_width[1]; // u-channel width
1795         UINT32 roiOffsetX = 0;
1796         UINT32 roiOffsetY = 0;
1797         UINT32 yOffset = 0;
1798         UINT32 uOffset = 0;
1799
1800 #ifdef __PGFROISUPPORT__
1801         const PGFRect& roi = GetAlignedROI(); // in pixels, roi is usually larger than levelRoi
1802         ASSERT(w == roi.Width() && h == roi.Height());
1803         const PGFRect levelRoi = ComputeLevelROI();
1804         ASSERT(roi.left <= levelRoi.left && levelRoi.right <= roi.right);
1805         ASSERT(roi.top <= levelRoi.top && levelRoi.bottom <= roi.bottom);
1806
1807         if (ROIisSupported() && (levelRoi.Width() < w || levelRoi.Height() < h)) {
1808                 // ROI is used
1809                 w = levelRoi.Width();
1810                 h = levelRoi.Height();
1811                 roiOffsetX = levelRoi.left - roi.left;
1812                 roiOffsetY = levelRoi.top - roi.top;
1813                 yOffset = roiOffsetX + roiOffsetY*yw;
1814
1815                 if (m_downsample) {
1816                         const PGFRect& downsampledRoi = GetAlignedROI(1);
1817                         uOffset = levelRoi.left/2 - downsampledRoi.left + (levelRoi.top/2 - downsampledRoi.top)*m_width[1];
1818                 } else {
1819                         uOffset = yOffset;
1820                 }
1821         }
1822 #endif
1823
1824         const double dP = 1.0/h;
1825         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
1826         if (channelMap == nullptr) channelMap = defMap;
1827         DataT uAvg, vAvg;
1828         double percent = 0;
1829         UINT32 i, j;
1830
1831         switch(m_header.mode) {
1832         case ImageModeBitmap:
1833                 {
1834                         ASSERT(m_header.channels == 1);
1835                         ASSERT(m_header.bpp == 1);
1836                         ASSERT(bpp == 1);
1837
1838                         const UINT32 w2 = (w + 7)/8;
1839                         DataT* y = m_channel[0]; ASSERT(y);
1840
1841                         if (m_preHeader.version & Version7) {
1842                                 // new unpacked version has a little better compression ratio
1843                                 // since version 7
1844                                 for (i = 0; i < h; i++) {
1845                                         UINT32 cnt = 0;
1846                                         for (j = 0; j < w2; j++) {
1847                                                 UINT8 byte = 0;
1848                                                 for (int k = 0; k < 8; k++) {
1849                                                         byte <<= 1;
1850                                                         UINT8 bit = 0;
1851                                                         if (cnt < w) {
1852                                                                 bit = y[yOffset + cnt] & 1;
1853                                                         }
1854                                                         byte |= bit;
1855                                                         cnt++;
1856                                                 }
1857                                                 buff[j] = byte;
1858                                         }
1859                                         yOffset += yw;
1860                                         buff += pitch;
1861
1862                                         if (cb) {
1863                                                 percent += dP;
1864                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1865                                         }
1866                                 }
1867                         } else {
1868                                 // old versions
1869                                 // packed pixels: 8 pixel in 1 byte of channel[0]
1870                                 if (!(m_preHeader.version & Version5)) yw = w2; // not version 5 or 6
1871                                 yOffset = roiOffsetX/8 + roiOffsetY*yw; // 1 byte in y contains 8 pixel values
1872                                 for (i = 0; i < h; i++) {
1873                                         for (j = 0; j < w2; j++) {
1874                                                 buff[j] = Clamp8(y[yOffset + j] + YUVoffset8);
1875                                         }
1876                                         yOffset += yw;
1877                                         buff += pitch;
1878
1879                                         if (cb) {
1880                                                 percent += dP;
1881                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1882                                         }
1883                                 }
1884                         }
1885                         break;
1886                 }
1887         case ImageModeIndexedColor:
1888         case ImageModeGrayScale:
1889         case ImageModeHSLColor:
1890         case ImageModeHSBColor:
1891                 {
1892                         ASSERT(m_header.channels >= 1);
1893                         ASSERT(m_header.bpp == m_header.channels*8);
1894                         ASSERT(bpp%8 == 0);
1895
1896                         UINT32 cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
1897
1898                         for (i=0; i < h; i++) {
1899                                 UINT32 yPos = yOffset;
1900                                 cnt = 0;
1901                                 for (j=0; j < w; j++) {
1902                                         for (UINT32 c=0; c < m_header.channels; c++) {
1903                                                 buff[cnt + channelMap[c]] = Clamp8(m_channel[c][yPos] + YUVoffset8);
1904                                         }
1905                                         cnt += channels;
1906                                         yPos++;
1907                                 }
1908                                 yOffset += yw;
1909                                 buff += pitch;
1910
1911                                 if (cb) {
1912                                         percent += dP;
1913                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1914                                 }
1915                         }
1916                         break;
1917                 }
1918         case ImageModeGray16:
1919                 {
1920                         ASSERT(m_header.channels >= 1);
1921                         ASSERT(m_header.bpp == m_header.channels*16);
1922
1923                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1924                         UINT32 cnt, channels;
1925
1926                         if (bpp%16 == 0) {
1927                                 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1928                                 UINT16 *buff16 = (UINT16 *)buff;
1929                                 int pitch16 = pitch/2;
1930                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
1931
1932                                 for (i=0; i < h; i++) {
1933                                         UINT32 yPos = yOffset;
1934                                         cnt = 0;
1935                                         for (j=0; j < w; j++) {
1936                                                 for (UINT32 c=0; c < m_header.channels; c++) {
1937                                                         buff16[cnt + channelMap[c]] = Clamp16((m_channel[c][yPos] + yuvOffset16) << shift);
1938                                                 }
1939                                                 cnt += channels;
1940                                                 yPos++;
1941                                         }
1942                                         yOffset += yw;
1943                                         buff16 += pitch16;
1944
1945                                         if (cb) {
1946                                                 percent += dP;
1947                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1948                                         }
1949                                 }
1950                         } else {
1951                                 ASSERT(bpp%8 == 0);
1952                                 const int shift = __max(0, UsedBitsPerChannel() - 8);
1953                                 channels = bpp/8; ASSERT(channels >= m_header.channels);
1954
1955                                 for (i=0; i < h; i++) {
1956                                         UINT32 yPos = yOffset;
1957                                         cnt = 0;
1958                                         for (j=0; j < w; j++) {
1959                                                 for (UINT32 c=0; c < m_header.channels; c++) {
1960                                                         buff[cnt + channelMap[c]] = Clamp8((m_channel[c][yPos] + yuvOffset16) >> shift);
1961                                                 }
1962                                                 cnt += channels;
1963                                                 yPos++;
1964                                         }
1965                                         yOffset += yw;
1966                                         buff += pitch;
1967
1968                                         if (cb) {
1969                                                 percent += dP;
1970                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1971                                         }
1972                                 }
1973                         }
1974                         break;
1975                 }
1976         case ImageModeRGBColor:
1977                 {
1978                         ASSERT(m_header.channels == 3);
1979                         ASSERT(m_header.bpp == m_header.channels*8);
1980                         ASSERT(bpp%8 == 0);
1981                         ASSERT(bpp >= m_header.bpp);
1982
1983                         DataT* y = m_channel[0]; ASSERT(y);
1984                         DataT* u = m_channel[1]; ASSERT(u);
1985                         DataT* v = m_channel[2]; ASSERT(v);
1986                         UINT8 *buffg = &buff[channelMap[1]],
1987                                   *buffr = &buff[channelMap[2]],
1988                                   *buffb = &buff[channelMap[0]];
1989                         UINT8 g;
1990                         UINT32 cnt, channels = bpp/8;
1991
1992                         if (m_downsample) {
1993                                 for (i=0; i < h; i++) {
1994                                         UINT32 uPos = uOffset;
1995                                         UINT32 yPos = yOffset;
1996                                         cnt = 0;
1997                                         for (j=0; j < w; j++) {
1998                                                 // u and v are downsampled
1999                                                 uAvg = u[uPos];
2000                                                 vAvg = v[uPos];
2001                                                 // Yuv
2002                                                 buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2003                                                 buffr[cnt] = Clamp8(uAvg + g);
2004                                                 buffb[cnt] = Clamp8(vAvg + g);
2005                                                 cnt += channels;
2006                                                 if (j & 1) uPos++;
2007                                                 yPos++;
2008                                         }
2009                                         if (i & 1) uOffset += uw;
2010                                         yOffset += yw;
2011                                         buffb += pitch;
2012                                         buffg += pitch;
2013                                         buffr += pitch;
2014
2015                                         if (cb) {
2016                                                 percent += dP;
2017                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2018                                         }
2019                                 }
2020
2021                         } else {
2022                                 for (i=0; i < h; i++) {
2023                                         cnt = 0;
2024                                         UINT32 yPos = yOffset;
2025                                         for (j = 0; j < w; j++) {
2026                                                 uAvg = u[yPos];
2027                                                 vAvg = v[yPos];
2028                                                 // Yuv
2029                                                 buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2030                                                 buffr[cnt] = Clamp8(uAvg + g);
2031                                                 buffb[cnt] = Clamp8(vAvg + g);
2032                                                 cnt += channels;
2033                                                 yPos++;
2034                                         }
2035                                         yOffset += yw;
2036                                         buffb += pitch;
2037                                         buffg += pitch;
2038                                         buffr += pitch;
2039
2040                                         if (cb) {
2041                                                 percent += dP;
2042                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2043                                         }
2044                                 }
2045                         }
2046                         break;
2047                 }
2048         case ImageModeRGB48:
2049                 {
2050                         ASSERT(m_header.channels == 3);
2051                         ASSERT(m_header.bpp == 48);
2052
2053                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2054
2055                         DataT* y = m_channel[0]; ASSERT(y);
2056                         DataT* u = m_channel[1]; ASSERT(u);
2057                         DataT* v = m_channel[2]; ASSERT(v);
2058                         UINT32 cnt, channels;
2059                         DataT g;
2060
2061                         if (bpp >= 48 && bpp%16 == 0) {
2062                                 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2063                                 UINT16 *buff16 = (UINT16 *)buff;
2064                                 int pitch16 = pitch/2;
2065                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
2066
2067                                 for (i=0; i < h; i++) {
2068                                         UINT32 uPos = uOffset;
2069                                         UINT32 yPos = yOffset;
2070                                         cnt = 0;
2071                                         for (j=0; j < w; j++) {
2072                                                 uAvg = u[uPos];
2073                                                 vAvg = v[uPos];
2074                                                 // Yuv
2075                                                 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2076                                                 buff16[cnt + channelMap[1]] = Clamp16(g << shift);
2077                                                 buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
2078                                                 buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
2079                                                 cnt += channels;
2080                                                 if (!m_downsample || (j & 1)) uPos++;
2081                                                 yPos++;
2082                                         }
2083                                         if (!m_downsample || (i & 1)) uOffset += uw;
2084                                         yOffset += yw;
2085                                         buff16 += pitch16;
2086
2087                                         if (cb) {
2088                                                 percent += dP;
2089                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2090                                         }
2091                                 }
2092                         } else {
2093                                 ASSERT(bpp%8 == 0);
2094                                 const int shift = __max(0, UsedBitsPerChannel() - 8);
2095                                 channels = bpp/8; ASSERT(channels >= m_header.channels);
2096
2097                                 for (i=0; i < h; i++) {
2098                                         UINT32 uPos = uOffset;
2099                                         UINT32 yPos = yOffset;
2100                                         cnt = 0;
2101                                         for (j=0; j < w; j++) {
2102                                                 uAvg = u[uPos];
2103                                                 vAvg = v[uPos];
2104                                                 // Yuv
2105                                                 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2106                                                 buff[cnt + channelMap[1]] = Clamp8(g >> shift);
2107                                                 buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
2108                                                 buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
2109                                                 cnt += channels;
2110                                                 if (!m_downsample || (j & 1)) uPos++;
2111                                                 yPos++;
2112                                         }
2113                                         if (!m_downsample || (i & 1)) uOffset += uw;
2114                                         yOffset += yw;
2115                                         buff += pitch;
2116
2117                                         if (cb) {
2118                                                 percent += dP;
2119                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2120                                         }
2121                                 }
2122                         }
2123                         break;
2124                 }
2125         case ImageModeLabColor:
2126                 {
2127                         ASSERT(m_header.channels == 3);
2128                         ASSERT(m_header.bpp == m_header.channels*8);
2129                         ASSERT(bpp%8 == 0);
2130
2131                         DataT* l = m_channel[0]; ASSERT(l);
2132                         DataT* a = m_channel[1]; ASSERT(a);
2133                         DataT* b = m_channel[2]; ASSERT(b);
2134                         UINT32 cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
2135
2136                         for (i=0; i < h; i++) {
2137                                 UINT32 uPos = uOffset;
2138                                 UINT32 yPos = yOffset;
2139                                 cnt = 0;
2140                                 for (j=0; j < w; j++) {
2141                                         uAvg = a[uPos];
2142                                         vAvg = b[uPos];
2143                                         buff[cnt + channelMap[0]] = Clamp8(l[yPos] + YUVoffset8);
2144                                         buff[cnt + channelMap[1]] = Clamp8(uAvg + YUVoffset8);
2145                                         buff[cnt + channelMap[2]] = Clamp8(vAvg + YUVoffset8);
2146                                         cnt += channels;
2147                                         if (!m_downsample || (j & 1)) uPos++;
2148                                         yPos++;
2149                                 }
2150                                 if (!m_downsample || (i & 1)) uOffset += uw;
2151                                 yOffset += yw;
2152                                 buff += pitch;
2153
2154                                 if (cb) {
2155                                         percent += dP;
2156                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2157                                 }
2158                         }
2159                         break;
2160                 }
2161         case ImageModeLab48:
2162                 {
2163                         ASSERT(m_header.channels == 3);
2164                         ASSERT(m_header.bpp == m_header.channels*16);
2165
2166                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2167
2168                         DataT* l = m_channel[0]; ASSERT(l);
2169                         DataT* a = m_channel[1]; ASSERT(a);
2170                         DataT* b = m_channel[2]; ASSERT(b);
2171                         UINT32 cnt, channels;
2172
2173                         if (bpp%16 == 0) {
2174                                 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2175                                 UINT16 *buff16 = (UINT16 *)buff;
2176                                 int pitch16 = pitch/2;
2177                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
2178
2179                                 for (i=0; i < h; i++) {
2180                                         UINT32 uPos = uOffset;
2181                                         UINT32 yPos = yOffset;
2182                                         cnt = 0;
2183                                         for (j=0; j < w; j++) {
2184                                                 uAvg = a[uPos];
2185                                                 vAvg = b[uPos];
2186                                                 buff16[cnt + channelMap[0]] = Clamp16((l[yPos] + yuvOffset16) << shift);
2187                                                 buff16[cnt + channelMap[1]] = Clamp16((uAvg + yuvOffset16) << shift);
2188                                                 buff16[cnt + channelMap[2]] = Clamp16((vAvg + yuvOffset16) << shift);
2189                                                 cnt += channels;
2190                                                 if (!m_downsample || (j & 1)) uPos++;
2191                                                 yPos++;
2192                                         }
2193                                         if (!m_downsample || (i & 1)) uOffset += uw;
2194                                         yOffset += yw;
2195                                         buff16 += pitch16;
2196
2197                                         if (cb) {
2198                                                 percent += dP;
2199                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2200                                         }
2201                                 }
2202                         } else {
2203                                 ASSERT(bpp%8 == 0);
2204                                 const int shift = __max(0, UsedBitsPerChannel() - 8);
2205                                 channels = bpp/8; ASSERT(channels >= m_header.channels);
2206
2207                                 for (i=0; i < h; i++) {
2208                                         UINT32 uPos = uOffset;
2209                                         UINT32 yPos = yOffset;
2210                                         cnt = 0;
2211                                         for (j=0; j < w; j++) {
2212                                                 uAvg = a[uPos];
2213                                                 vAvg = b[uPos];
2214                                                 buff[cnt + channelMap[0]] = Clamp8((l[yPos] + yuvOffset16) >> shift);
2215                                                 buff[cnt + channelMap[1]] = Clamp8((uAvg + yuvOffset16) >> shift);
2216                                                 buff[cnt + channelMap[2]] = Clamp8((vAvg + yuvOffset16) >> shift);
2217                                                 cnt += channels;
2218                                                 if (!m_downsample || (j & 1)) uPos++;
2219                                                 yPos++;
2220                                         }
2221                                         if (!m_downsample || (i & 1)) uOffset += uw;
2222                                         yOffset += yw;
2223                                         buff += pitch;
2224
2225                                         if (cb) {
2226                                                 percent += dP;
2227                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2228                                         }
2229                                 }
2230                         }
2231                         break;
2232                 }
2233         case ImageModeRGBA:
2234         case ImageModeCMYKColor:
2235                 {
2236                         ASSERT(m_header.channels == 4);
2237                         ASSERT(m_header.bpp == m_header.channels*8);
2238                         ASSERT(bpp%8 == 0);
2239
2240                         DataT* y = m_channel[0]; ASSERT(y);
2241                         DataT* u = m_channel[1]; ASSERT(u);
2242                         DataT* v = m_channel[2]; ASSERT(v);
2243                         DataT* a = m_channel[3]; ASSERT(a);
2244                         UINT8 g, aAvg;
2245                         UINT32 cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
2246
2247                         for (i=0; i < h; i++) {
2248                                 UINT32 uPos = uOffset;
2249                                 UINT32 yPos = yOffset;
2250                                 cnt = 0;
2251                                 for (j=0; j < w; j++) {
2252                                         uAvg = u[uPos];
2253                                         vAvg = v[uPos];
2254                                         aAvg = Clamp8(a[uPos] + YUVoffset8);
2255                                         // Yuv
2256                                         buff[cnt + channelMap[1]] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2257                                         buff[cnt + channelMap[2]] = Clamp8(uAvg + g);
2258                                         buff[cnt + channelMap[0]] = Clamp8(vAvg + g);
2259                                         buff[cnt + channelMap[3]] = aAvg;
2260                                         cnt += channels;
2261                                         if (!m_downsample || (j & 1)) uPos++;
2262                                         yPos++;
2263                                 }
2264                                 if (!m_downsample || (i & 1)) uOffset += uw;
2265                                 yOffset += yw;
2266                                 buff += pitch;
2267
2268                                 if (cb) {
2269                                         percent += dP;
2270                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2271                                 }
2272                         }
2273                         break;
2274                 }
2275         case ImageModeCMYK64:
2276                 {
2277                         ASSERT(m_header.channels == 4);
2278                         ASSERT(m_header.bpp == 64);
2279
2280                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2281
2282                         DataT* y = m_channel[0]; ASSERT(y);
2283                         DataT* u = m_channel[1]; ASSERT(u);
2284                         DataT* v = m_channel[2]; ASSERT(v);
2285                         DataT* a = m_channel[3]; ASSERT(a);
2286                         DataT g, aAvg;
2287                         UINT32 cnt, channels;
2288
2289                         if (bpp%16 == 0) {
2290                                 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2291                                 UINT16 *buff16 = (UINT16 *)buff;
2292                                 int pitch16 = pitch/2;
2293                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
2294
2295                                 for (i=0; i < h; i++) {
2296                                         UINT32 uPos = uOffset;
2297                                         UINT32 yPos = yOffset;
2298                                         cnt = 0;
2299                                         for (j=0; j < w; j++) {
2300                                                 uAvg = u[uPos];
2301                                                 vAvg = v[uPos];
2302                                                 aAvg = a[uPos] + yuvOffset16;
2303                                                 // Yuv
2304                                                 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2305                                                 buff16[cnt + channelMap[1]] = Clamp16(g << shift);
2306                                                 buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
2307                                                 buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
2308                                                 buff16[cnt + channelMap[3]] = Clamp16(aAvg << shift);
2309                                                 cnt += channels;
2310                                                 if (!m_downsample || (j & 1)) uPos++;
2311                                                 yPos++;
2312                                         }
2313                                         if (!m_downsample || (i & 1)) uOffset += uw;
2314                                         yOffset += yw;
2315                                         buff16 += pitch16;
2316
2317                                         if (cb) {
2318                                                 percent += dP;
2319                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2320                                         }
2321                                 }
2322                         } else {
2323                                 ASSERT(bpp%8 == 0);
2324                                 const int shift = __max(0, UsedBitsPerChannel() - 8);
2325                                 channels = bpp/8; ASSERT(channels >= m_header.channels);
2326
2327                                 for (i=0; i < h; i++) {
2328                                         UINT32 uPos = uOffset;
2329                                         UINT32 yPos = yOffset;
2330                                         cnt = 0;
2331                                         for (j=0; j < w; j++) {
2332                                                 uAvg = u[uPos];
2333                                                 vAvg = v[uPos];
2334                                                 aAvg = a[uPos] + yuvOffset16;
2335                                                 // Yuv
2336                                                 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2337                                                 buff[cnt + channelMap[1]] = Clamp8(g >> shift);
2338                                                 buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
2339                                                 buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
2340                                                 buff[cnt + channelMap[3]] = Clamp8(aAvg >> shift);
2341                                                 cnt += channels;
2342                                                 if (!m_downsample || (j & 1)) uPos++;
2343                                                 yPos++;
2344                                         }
2345                                         if (!m_downsample || (i & 1)) uOffset += uw;
2346                                         yOffset += yw;
2347                                         buff += pitch;
2348
2349                                         if (cb) {
2350                                                 percent += dP;
2351                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2352                                         }
2353                                 }
2354                         }
2355                         break;
2356                 }
2357 #ifdef __PGF32SUPPORT__
2358         case ImageModeGray32:
2359                 {
2360                         ASSERT(m_header.channels == 1);
2361                         ASSERT(m_header.bpp == 32);
2362
2363                         const int yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
2364                         DataT* y = m_channel[0]; ASSERT(y);
2365
2366                         if (bpp == 32) {
2367                                 const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2368                                 UINT32 *buff32 = (UINT32 *)buff;
2369                                 int pitch32 = pitch/4;
2370
2371                                 for (i=0; i < h; i++) {
2372                                         UINT32 yPos = yOffset;
2373                                         for (j = 0; j < w; j++) {
2374                                                 buff32[j] = Clamp31((y[yPos++] + yuvOffset31) << shift);
2375                                         }
2376                                         yOffset += yw;
2377                                         buff32 += pitch32;
2378
2379                                         if (cb) {
2380                                                 percent += dP;
2381                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2382                                         }
2383                                 }
2384                         } else if (bpp == 16) {
2385                                 const int usedBits = UsedBitsPerChannel();
2386                                 UINT16 *buff16 = (UINT16 *)buff;
2387                                 int pitch16 = pitch/2;
2388
2389                                 if (usedBits < 16) {
2390                                         const int shift = 16 - usedBits;
2391                                         for (i=0; i < h; i++) {
2392                                                 UINT32 yPos = yOffset;
2393                                                 for (j = 0; j < w; j++) {
2394                                                         buff16[j] = Clamp16((y[yPos++] + yuvOffset31) << shift);
2395                                                 }
2396                                                 yOffset += yw;
2397                                                 buff16 += pitch16;
2398
2399                                                 if (cb) {
2400                                                         percent += dP;
2401                                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2402                                                 }
2403                                         }
2404                                 } else {
2405                                         const int shift = __max(0, usedBits - 16);
2406                                         for (i=0; i < h; i++) {
2407                                                 UINT32 yPos = yOffset;
2408                                                 for (j = 0; j < w; j++) {
2409                                                         buff16[j] = Clamp16((y[yPos++] + yuvOffset31) >> shift);
2410                                                 }
2411                                                 yOffset += yw;
2412                                                 buff16 += pitch16;
2413
2414                                                 if (cb) {
2415                                                         percent += dP;
2416                                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2417                                                 }
2418                                         }
2419                                 }
2420                         } else {
2421                                 ASSERT(bpp == 8);
2422                                 const int shift = __max(0, UsedBitsPerChannel() - 8);
2423
2424                                 for (i=0; i < h; i++) {
2425                                         UINT32 yPos = yOffset;
2426                                         for (j = 0; j < w; j++) {
2427                                                 buff[j] = Clamp8((y[yPos++] + yuvOffset31) >> shift);
2428                                         }
2429                                         yOffset += yw;
2430                                         buff += pitch;
2431
2432                                         if (cb) {
2433                                                 percent += dP;
2434                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2435                                         }
2436                                 }
2437                         }
2438                         break;
2439                 }
2440 #endif
2441         case ImageModeRGB12:
2442                 {
2443                         ASSERT(m_header.channels == 3);
2444                         ASSERT(m_header.bpp == m_header.channels*4);
2445                         ASSERT(bpp == m_header.channels*4);
2446                         ASSERT(!m_downsample);
2447
2448                         DataT* y = m_channel[0]; ASSERT(y);
2449                         DataT* u = m_channel[1]; ASSERT(u);
2450                         DataT* v = m_channel[2]; ASSERT(v);
2451                         UINT16 yval;
2452                         UINT32 cnt;
2453
2454                         for (i=0; i < h; i++) {
2455                                 UINT32 yPos = yOffset;
2456                                 cnt = 0;
2457                                 for (j=0; j < w; j++) {
2458                                         // Yuv
2459                                         uAvg = u[yPos];
2460                                         vAvg = v[yPos];
2461                                         yval = Clamp4(y[yPos] + YUVoffset4 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2462                                         if (j%2 == 0) {
2463                                                 buff[cnt] = UINT8(Clamp4(vAvg + yval) | (yval << 4));
2464                                                 cnt++;
2465                                                 buff[cnt] = Clamp4(uAvg + yval);
2466                                         } else {
2467                                                 buff[cnt] |= Clamp4(vAvg + yval) << 4;
2468                                                 cnt++;
2469                                                 buff[cnt] = UINT8(yval | (Clamp4(uAvg + yval) << 4));
2470                                                 cnt++;
2471                                         }
2472                                         yPos++;
2473                                 }
2474                                 yOffset += yw;
2475                                 buff += pitch;
2476
2477                                 if (cb) {
2478                                         percent += dP;
2479                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2480                                 }
2481                         }
2482                         break;
2483                 }
2484         case ImageModeRGB16:
2485                 {
2486                         ASSERT(m_header.channels == 3);
2487                         ASSERT(m_header.bpp == 16);
2488                         ASSERT(bpp == 16);
2489                         ASSERT(!m_downsample);
2490
2491                         DataT* y = m_channel[0]; ASSERT(y);
2492                         DataT* u = m_channel[1]; ASSERT(u);
2493                         DataT* v = m_channel[2]; ASSERT(v);
2494                         UINT16 yval;
2495                         UINT16 *buff16 = (UINT16 *)buff;
2496                         int pitch16 = pitch/2;
2497
2498                         for (i=0; i < h; i++) {
2499                                 UINT32 yPos = yOffset;
2500                                 for (j = 0; j < w; j++) {
2501                                         // Yuv
2502                                         uAvg = u[yPos];
2503                                         vAvg = v[yPos];
2504                                         yval = Clamp6(y[yPos++] + YUVoffset6 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2505                                         buff16[j] = (yval << 5) | ((Clamp6(uAvg + yval) >> 1) << 11) | (Clamp6(vAvg + yval) >> 1);
2506                                 }
2507                                 yOffset += yw;
2508                                 buff16 += pitch16;
2509
2510                                 if (cb) {
2511                                         percent += dP;
2512                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2513                                 }
2514                         }
2515                         break;
2516                 }
2517         default:
2518                 ASSERT(false);
2519         }
2520
2521 #ifdef _DEBUG
2522         // display ROI (RGB) in debugger
2523         roiimage.width = w;
2524         roiimage.height = h;
2525         if (pitch > 0) {
2526                 roiimage.pitch = pitch;
2527                 roiimage.data = buff;
2528         } else {
2529                 roiimage.pitch = -pitch;
2530                 roiimage.data = buff + (h - 1)*pitch;
2531         }
2532 #endif
2533
2534 }

  DataT * CPGFImage::GetChannel (int c = 0) [inline]
Return an internal YUV image channel.

Parameters
    c A channel index

Returns
    An internal YUV image channel

Definition at line 317 of file PGFimage.h.
317 { ASSERT(c >= 0 && c < MaxChannels); return m_channel[c]; }

  const RGBQUAD * CPGFImage::GetColorTable () const [inline]

Returns
    Address of color table

Definition at line 330 of file PGFimage.h.
330 { return m_postHeader.clut; }

  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
    iFirstColor The color table index of the first entry to retrieve.
    nColors The number of color table entries to retrieve.
    prgbColors A pointer to the array of RGBQUAD structures to retrieve the color table entries.

Definition at line 1350 of file PGFimage.cpp.
1350                                                                                            {
1351         if (iFirstColor + nColors > ColorTableLen)      ReturnWithError(ColorTableError);
1352
1353         for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
1354                 prgbColors[j] = m_postHeader.clut[i];
1355         }
1356 }

  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 648 of file PGFimage.cpp.
648                                                {
649         ASSERT(m_decoder);
650         return m_decoder->GetEncodedHeaderLength();
651 }

  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
    level The image level

Returns
    The length of a PGF level in bytes

Definition at line 367 of file PGFimage.h.
367 { 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 335 of file PGFimage.h.
335 { 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 341 of file PGFimage.h.
341 { return (1 << m_header.usedBitsPerChannel) - 1; }

  const UINT8 * CPGFImage::GetUserData (UINT32 & cachedSize, UINT32 * pTotalSize = nullptr) const
Return user data and size of user data. Precondition: The PGF image has been opened with a call of Open(...).

Parameters
    cachedSize [out] Size of returned user data in bytes.
    pTotalSize [optional out] Pointer to return the size of user data stored in image header in bytes.

Returns
    A pointer to user data or nullptr if there is no user data available.

Return user data and size of user data. Precondition: The PGF image has been opened with a call of Open(...). In an encoder scenario don't call this method before WriteHeader().

Parameters
    cachedSize [out] Size of returned user data in bytes.
    pTotalSize [optional out] Pointer to return the size of user data stored in image header in bytes.

Returns
    A pointer to user data or nullptr if there is no user data available.

Definition at line 337 of file PGFimage.cpp.
337                                                                                   {
338         cachedSize = m_postHeader.cachedUserDataLen;
339         if (pTotalSize) *pTotalSize = m_postHeader.userDataLen;
340         return m_postHeader.userData;
341 }

  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 346 of file PGFimage.h.
346 { return m_userDataPos; }

  void CPGFImage::GetYUV (int pitch, DataT * buff, BYTE bpp, int channelMap[] = nullptr, CallbackPtr cb = nullptr, void * data = nullptr) 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
    pitch The number of bytes of a row of the image buffer.
    buff An image buffer.
    bpp The number of bits per pixel used in image buffer.
    channelMap A integer array containing the mapping of PGF channel ordering to expected channel ordering.
    cb A pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding.
    data Data 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
    pitch The number of bytes of a row of the image buffer.
    buff An image buffer.
    bpp The number of bits per pixel used in image buffer.
    channelMap A integer array containing the mapping of PGF channel ordering to expected channel ordering.
    cb A 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 2550 of file PGFimage.cpp.
2550                                                                                                                  {
2551         ASSERT(buff);
2552         const UINT32 w = m_width[0];
2553         const UINT32 h = m_height[0];
2554         const bool wOdd = (1 == w%2);
2555         const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
2556         const int pitch2 = pitch/DataTSize;
2557         const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
2558         const double dP = 1.0/h;
2559
2560         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
2561         if (channelMap == nullptr) channelMap = defMap;
2562         int sampledPos = 0, yPos = 0;
2563         DataT uAvg, vAvg;
2564         double percent = 0;
2565         UINT32 i, j;
2566
2567         if (m_header.channels == 3) {
2568                 ASSERT(bpp%dataBits == 0);
2569
2570                 DataT* y = m_channel[0]; ASSERT(y);
2571                 DataT* u = m_channel[1]; ASSERT(u);
2572                 DataT* v = m_channel[2]; ASSERT(v);
2573                 int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2574
2575                 for (i=0; i < h; i++) {
2576                         if (i%2) sampledPos -= (w + 1)/2;
2577                         cnt = 0;
2578                         for (j=0; j < w; j++) {
2579                                 if (m_downsample) {
2580                                         // image was downsampled
2581                                         uAvg = u[sampledPos];
2582                                         vAvg = v[sampledPos];
2583                                 } else {
2584                                         uAvg = u[yPos];
2585                                         vAvg = v[yPos];
2586                                 }
2587                                 buff[cnt + channelMap[0]] = y[yPos];
2588                                 buff[cnt + channelMap[1]] = uAvg;
2589                                 buff[cnt + channelMap[2]] = vAvg;
2590                                 yPos++;
2591                                 cnt += channels;
2592                                 if (j%2) sampledPos++;
2593                         }
2594                         buff += pitch2;
2595                         if (wOdd) sampledPos++;
2596
2597                         if (cb) {
2598                                 percent += dP;
2599                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2600                         }
2601                 }
2602         } else if (m_header.channels == 4) {
2603                 ASSERT(m_header.bpp == m_header.channels*8);
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                 UINT8 aAvg;
2611                 int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2612
2613                 for (i=0; i < h; i++) {
2614                         if (i%2) sampledPos -= (w + 1)/2;
2615                         cnt = 0;
2616                         for (j=0; j < w; j++) {
2617                                 if (m_downsample) {
2618                                         // image was downsampled
2619                                         uAvg = u[sampledPos];
2620                                         vAvg = v[sampledPos];
2621                                         aAvg = Clamp8(a[sampledPos] + yuvOffset);
2622                                 } else {
2623                                         uAvg = u[yPos];
2624                                         vAvg = v[yPos];
2625                                         aAvg = Clamp8(a[yPos] + yuvOffset);
2626                                 }
2627                                 // Yuv
2628                                 buff[cnt + channelMap[0]] = y[yPos];
2629                                 buff[cnt + channelMap[1]] = uAvg;
2630                                 buff[cnt + channelMap[2]] = vAvg;
2631                                 buff[cnt + channelMap[3]] = aAvg;
2632                                 yPos++;
2633                                 cnt += channels;
2634                                 if (j%2) sampledPos++;
2635                         }
2636                         buff += pitch2;
2637                         if (wOdd) sampledPos++;
2638
2639                         if (cb) {
2640                                 percent += dP;
2641                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2642                         }
2643                 }
2644         }
2645 }

  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
    level A level

Returns
    Image level height in pixels

Definition at line 420 of file PGFimage.h.
420 { ASSERT(level >= 0); return LevelSizeL(m_header.height, level); }

  void CPGFImage::ImportBitmap (int pitch, UINT8 * buff, BYTE bpp, int channelMap[] = nullptr, CallbackPtr cb = nullptr, void * data = nullptr)
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
    pitch The number of bytes of a row of the image buffer.
    buff An image buffer.
    bpp The number of bits per pixel used in image buffer.
    channelMap A integer array containing the mapping of input channel ordering to expected channel ordering.
    cb A pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding.
    data Data Pointer to C++ class container to host callback procedure.

Definition at line 792 of file PGFimage.cpp.
792                                                                                                                  {
793         ASSERT(buff);
794         ASSERT(m_channel[0]);
795
796         // color transform
797         RgbToYuv(pitch, buff, bpp, channelMap, cb, data);
798
799         if (m_downsample) {
800                 // Subsampling of the chrominance and alpha channels
801                 for (int i=1; i < m_header.channels; i++) {
802                         Downsample(i);
803                 }
804         }
805 }

  bool CPGFImage::ImportIsSupported (BYTE mode) [static]
Check for valid import image mode.

Parameters
    mode Image mode

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

Definition at line 1305 of file PGFimage.cpp.
1305                                            {
1306         size_t size = DataTSize;
1307
1308         if (size >= 2) {
1309                 switch(mode) {
1310                         case ImageModeBitmap:
1311                         case ImageModeIndexedColor:
1312                         case ImageModeGrayScale:
1313                         case ImageModeRGBColor:
1314                         case ImageModeCMYKColor:
1315                         case ImageModeHSLColor:
1316                         case ImageModeHSBColor:
1317                         //case ImageModeDuotone:
1318                         case ImageModeLabColor:
1319                         case ImageModeRGB12:
1320                         case ImageModeRGB16:
1321                         case ImageModeRGBA:
1322                                 return true;
1323                 }
1324         }
1325         if (size >= 3) {
1326                 switch(mode) {
1327                         case ImageModeGray16:
1328                         case ImageModeRGB48:
1329                         case ImageModeLab48:
1330                         case ImageModeCMYK64:
1331                         //case ImageModeDuotone16:
1332                                 return true;
1333                 }
1334         }
1335         if (size >=4) {
1336                 switch(mode) {
1337                         case ImageModeGray32:
1338                                 return true;
1339                 }
1340         }
1341         return false;
1342 }

  void CPGFImage::ImportYUV (int pitch, DataT * buff, BYTE bpp, int channelMap[] = nullptr, CallbackPtr cb = nullptr, void * data = nullptr)
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
    pitch The number of bytes of a row of the image buffer.
    buff An image buffer.
    bpp The number of bits per pixel used in image buffer.
    channelMap A integer array containing the mapping of input channel ordering to expected channel ordering.
    cb A pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding.
    data Data 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
    pitch The number of bytes of a row of the image buffer.
    buff An image buffer.
    bpp The number of bits per pixel used in image buffer.
    channelMap A integer array containing the mapping of input channel ordering to expected channel ordering.
    cb A 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 2661 of file PGFimage.cpp.
2661                                                                                                               {
2662         ASSERT(buff);
2663         const double dP = 1.0/m_header.height;
2664         const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
2665         const int pitch2 = pitch/DataTSize;
2666         const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
2667
2668         int yPos = 0, cnt = 0;
2669         double percent = 0;
2670         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
2671
2672         if (channelMap == nullptr) channelMap = defMap;
2673
2674         if (m_header.channels == 3)     {
2675                 ASSERT(bpp%dataBits == 0);
2676
2677                 DataT* y = m_channel[0]; ASSERT(y);
2678                 DataT* u = m_channel[1]; ASSERT(u);
2679                 DataT* v = m_channel[2]; ASSERT(v);
2680                 const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2681
2682                 for (UINT32 h=0; h < m_header.height; h++) {
2683                         if (cb) {
2684                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2685                                 percent += dP;
2686                         }
2687
2688                         cnt = 0;
2689                         for (UINT32 w=0; w < m_header.width; w++) {
2690                                 y[yPos] = buff[cnt + channelMap[0]];
2691                                 u[yPos] = buff[cnt + channelMap[1]];
2692                                 v[yPos] = buff[cnt + channelMap[2]];
2693                                 yPos++;
2694                                 cnt += channels;
2695                         }
2696                         buff += pitch2;
2697                 }
2698         } else if (m_header.channels == 4) {
2699                 ASSERT(bpp%dataBits == 0);
2700
2701                 DataT* y = m_channel[0]; ASSERT(y);
2702                 DataT* u = m_channel[1]; ASSERT(u);
2703                 DataT* v = m_channel[2]; ASSERT(v);
2704                 DataT* a = m_channel[3]; ASSERT(a);
2705                 const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2706
2707                 for (UINT32 h=0; h < m_header.height; h++) {
2708                         if (cb) {
2709                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2710                                 percent += dP;
2711                         }
2712
2713                         cnt = 0;
2714                         for (UINT32 w=0; w < m_header.width; w++) {
2715                                 y[yPos] = buff[cnt + channelMap[0]];
2716                                 u[yPos] = buff[cnt + channelMap[1]];
2717                                 v[yPos] = buff[cnt + channelMap[2]];
2718                                 a[yPos] = buff[cnt + channelMap[3]] - yuvOffset;
2719                                 yPos++;
2720                                 cnt += channels;
2721                         }
2722                         buff += pitch2;
2723                 }
2724         }
2725
2726         if (m_downsample) {
2727                 // Subsampling of the chrominance and alpha channels
2728                 for (int i=1; i < m_header.channels; i++) {
2729                         Downsample(i);
2730                 }
2731         }
2732 }

  void CPGFImage::Init () [private]

Definition at line 69 of file PGFimage.cpp.
69                      {
70         // init pointers
71         m_decoder = nullptr;
72         m_encoder = nullptr;
73         m_levelLength = nullptr;
74
75         // init members
76 #ifdef __PGFROISUPPORT__
77         m_streamReinitialized = false;
78 #endif
79         m_currentLevel = 0;
80         m_quant = 0;
81         m_userDataPos = 0;
82         m_downsample = false;
83         m_favorSpeedOverSize = false;
84         m_useOMPinEncoder = true;
85         m_useOMPinDecoder = true;
86         m_cb = nullptr;
87         m_cbArg = nullptr;
88         m_progressMode = PM_Relative;
89         m_percent = 0;
90         m_userDataPolicy = UP_CacheAll;
91
92         // init preHeader
93         memcpy(m_preHeader.magic, PGFMagic, 3);
94         m_preHeader.version = PGFVersion;
95         m_preHeader.hSize = 0;
96
97         // init postHeader
98         m_postHeader.userData = nullptr;
99         m_postHeader.userDataLen = 0;
100         m_postHeader.cachedUserDataLen = 0;
101
102         // init channels
103         for (int i = 0; i < MaxChannels; i++) {
104                 m_channel[i] = nullptr;
105                 m_wtChannel[i] = nullptr;
106         }
107
108         // set image width and height
109         for (int i = 0; i < MaxChannels; i++) {
110                 m_width[0] = 0;
111                 m_height[0] = 0;
112         }
113 }

  bool CPGFImage::IsFullyRead () const [inline]

Return true if all levels have been read.

Definition at line 436 of file PGFimage.h.
436 { return m_currentLevel == 0; }

  bool CPGFImage::IsOpen () const [inline]

Returns true if the PGF has been opened for reading.

Definition at line 77 of file PGFimage.h.
77 { return m_decoder != nullptr; }

  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 427 of file PGFimage.h.
427 { return (BYTE)m_currentLevel; }

  BYTE CPGFImage::Levels () const [inline]
Return the number of image levels.

Returns
    Number of image levels

Definition at line 432 of file PGFimage.h.
432 { return m_header.nLevels; }

  UINT32 CPGFImage::LevelSizeH (UINT32 size, int level) [inline], [static]
Compute and return image width/height of HH subband at given level.

Parameters
    size Original image size (e.g. width or height at level 0)
    level An image level

Returns
    high pass size at given level in pixels

Definition at line 506 of file PGFimage.h.
506 { ASSERT(level >= 0); UINT32 d = 1 << (level - 1); return (size + d - 1) >> level; }

  UINT32 CPGFImage::LevelSizeL (UINT32 size, int level) [inline], [static]
Compute and return image width/height of LL subband at given level.

Parameters
    size Original image size (e.g. width or height at level 0)
    level An image level

Returns
    Image width/height at given level in pixels

Definition at line 499 of file PGFimage.h.
499 { ASSERT(level >= 0); UINT32 d = 1 << level; return (size + d - 1) >> level; }

  BYTE CPGFImage::MaxChannelDepth (BYTE version = PGFVersion) [inline], [static]
Return maximum channel depth.

Parameters
    version pgf pre-header version number

Returns
    maximum channel depth in bit of given version (16 or 32 bit)

Definition at line 518 of file PGFimage.h.
518 { return (version & PGF32) ? 32 : 16; }

  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 455 of file PGFimage.h.
455 { 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
    stream A PGF stream

Definition at line 141 of file PGFimage.cpp.
141                                        {
142         ASSERT(stream);
143
144         // create decoder and read PGFPreHeader PGFHeader PGFPostHeader LevelLengths
145         m_decoder = new CDecoder(stream, m_preHeader, m_header, m_postHeader, m_levelLength,
146                 m_userDataPos, m_useOMPinDecoder, m_userDataPolicy);
147
148         if (m_header.nLevels > MaxLevel) ReturnWithError(FormatCannotRead);
149
150         // set current level
151         m_currentLevel = m_header.nLevels;
152
153         // set image width and height
154         m_width[0] = m_header.width;
155         m_height[0] = m_header.height;
156
157         // complete header
158         if (!CompleteHeader()) ReturnWithError(FormatCannotRead);
159
160         // interpret quant parameter
161         if (m_header.quality > DownsampleThreshold &&
162                 (m_header.mode == ImageModeRGBColor ||
163                  m_header.mode == ImageModeRGBA ||
164                  m_header.mode == ImageModeRGB48 ||
165                  m_header.mode == ImageModeCMYKColor ||
166                  m_header.mode == ImageModeCMYK64 ||
167                  m_header.mode == ImageModeLabColor ||
168                  m_header.mode == ImageModeLab48)) {
169                 m_downsample = true;
170                 m_quant = m_header.quality - 1;
171         } else {
172                 m_downsample = false;
173                 m_quant = m_header.quality;
174         }
175
176         // set channel dimensions (chrominance is subsampled by factor 2)
177         if (m_downsample) {
178                 for (int i=1; i < m_header.channels; i++) {
179                         m_width[i] = (m_width[0] + 1) >> 1;
180                         m_height[i] = (m_height[0] + 1) >> 1;
181                 }
182         } else {
183                 for (int i=1; i < m_header.channels; i++) {
184                         m_width[i] = m_width[0];
185                         m_height[i] = m_height[0];
186                 }
187         }
188
189         if (m_header.nLevels > 0) {
190                 // init wavelet subbands
191                 for (int i=0; i < m_header.channels; i++) {
192                         m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels);
193                 }
194
195                 // used in Read when PM_Absolute
196                 m_percent = pow(0.25, m_header.nLevels);
197
198         } else {
199                 // very small image: we don't use DWT and encoding
200
201                 // read channels
202                 for (int c=0; c < m_header.channels; c++) {
203                         const UINT32 size = m_width[c]*m_height[c];
204                         m_channel[c] = new(std::nothrow) DataT[size];
205                         if (!m_channel[c]) ReturnWithError(InsufficientMemory);
206
207                         // read channel data from stream
208                         for (UINT32 i=0; i < size; i++) {
209                                 int count = DataTSize;
210                                 stream->Read(&count, &m_channel[c][i]);
211                                 if (count != DataTSize) ReturnWithError(MissingData);
212                         }
213                 }
214         }
215 }

  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 442 of file PGFimage.h.
442 { return m_header.quality; }

  void CPGFImage::Read (int level = 0, CallbackPtr cb = nullptr, void * data = nullptr)
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.
    cb A pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding.
    data Data Pointer to C++ class container to host callback procedure.

Definition at line 402 of file PGFimage.cpp.
402                                                                 {
403         ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
404         ASSERT(m_decoder);
405
406 #ifdef __PGFROISUPPORT__
407         if (ROIisSupported() && m_header.nLevels > 0) {
408                 // new encoding scheme supporting ROI
409                 PGFRect rect(0, 0, m_header.width, m_header.height);
410                 Read(rect, level, cb, data);
411                 return;
412         }
413 #endif
414
415         if (m_header.nLevels == 0) {
416                 if (level == 0) {
417                         // the data has already been read during open
418                         // now update progress
419                         if (cb) {
420                                 if ((*cb)(1.0, true, data)) ReturnWithError(EscapePressed);
421                         }
422                 }
423         } else {
424                 const int levelDiff = m_currentLevel - level;
425                 double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
426
427                 // encoding scheme without ROI
428                 while (m_currentLevel > level) {
429                         for (int i=0; i < m_header.channels; i++) {
430                                 CWaveletTransform* wtChannel = m_wtChannel[i];
431                                 ASSERT(wtChannel);
432
433                                 // decode file and write stream to m_wtChannel
434                                 if (m_currentLevel == m_header.nLevels) {
435                                         // last level also has LL band
436                                         wtChannel->GetSubband(m_currentLevel, LL)->PlaceTile(*m_decoder, m_quant);
437                                 }
438                                 if (m_preHeader.version & Version5) {
439                                         // since version 5
440                                         wtChannel->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant);
441                                         wtChannel->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant);
442                                 } else {
443                                         // until version 4
444                                         m_decoder->DecodeInterleaved(wtChannel, m_currentLevel, m_quant);
445                                 }
446                                 wtChannel->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant);
447                         }
448
449                         volatile OSError error = NoError; // volatile prevents optimizations
450 #ifdef LIBPGF_USE_OPENMP
451                         #pragma omp parallel for default(shared)
452 #endif
453                         for (int i=0; i < m_header.channels; i++) {
454                                 // inverse transform from m_wtChannel to m_channel
455                                 if (error == NoError) {
456                                         OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
457                                         if (err != NoError) error = err;
458                                 }
459                                 ASSERT(m_channel[i]);
460                         }
461                         if (error != NoError) ReturnWithError(error);
462
463                         // set new level: must be done before refresh callback
464                         m_currentLevel--;
465
466                         // now we have to refresh the display
467                         if (m_cb) m_cb(m_cbArg);
468
469                         // now update progress
470                         if (cb) {
471                                 percent *= 4;
472                                 if (m_progressMode == PM_Absolute) m_percent = percent;
473                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
474                         }
475                 }
476         }
477 }

  void CPGFImage::Read (PGFRect & rect, int level = 0, CallbackPtr cb = nullptr, void * data = nullptr)
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) at level 0. The rect might be cropped.
    level [0, nLevels) The image level of the resulting image in the internal image buffer.
    cb A pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding.
    data Data Pointer to C++ class container to host callback procedure.

Read and decode rectangular region of interest (ROI) 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) at level 0. The rect might be cropped.
    level The image level of the resulting image in the internal image buffer.
    cb A pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding.
    data Data Pointer to C++ class container to host callback procedure.

Definition at line 489 of file PGFimage.cpp.
489                                                                                {
490         ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
491         ASSERT(m_decoder);
492
493         if (m_header.nLevels == 0 || !ROIisSupported()) {
494                 rect.left = rect.top = 0;
495                 rect.right = m_header.width; rect.bottom = m_header.height;
496                 Read(level, cb, data);
497         } else {
498                 ASSERT(ROIisSupported());
499                 // new encoding scheme supporting ROI
500                 ASSERT(rect.left < m_header.width && rect.top < m_header.height);
501
502                 // check rectangle
503                 if (rect.right == 0 || rect.right > m_header.width) rect.right = m_header.width;
504                 if (rect.bottom == 0 || rect.bottom > m_header.height) rect.bottom = m_header.height;
505
506                 const int levelDiff = m_currentLevel - level;
507                 double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
508
509                 // check level difference
510                 if (levelDiff <= 0) {
511                         // it is a new read call, probably with a new ROI
512                         m_currentLevel = m_header.nLevels;
513                         m_decoder->SetStreamPosToData();
514                 }
515
516                 // enable ROI decoding and reading
517                 SetROI(rect);
518
519                 while (m_currentLevel > level) {
520                         for (int i=0; i < m_header.channels; i++) {
521                                 CWaveletTransform* wtChannel = m_wtChannel[i];
522                                 ASSERT(wtChannel);
523
524                                 // get number of tiles and tile indices
525                                 const UINT32 nTiles = wtChannel->GetNofTiles(m_currentLevel); // independent of ROI
526
527                                 // decode file and write stream to m_wtChannel
528                                 if (m_currentLevel == m_header.nLevels) { // last level also has LL band
529                                         ASSERT(nTiles == 1);
530                                         m_decoder->GetNextMacroBlock();
531                                         wtChannel->GetSubband(m_currentLevel, LL)->PlaceTile(*m_decoder, m_quant);
532                                 }
533                                 for (UINT32 tileY=0; tileY < nTiles; tileY++) {
534                                         for (UINT32 tileX=0; tileX < nTiles; tileX++) {
535                                                 // check relevance of tile
536                                                 if (wtChannel->TileIsRelevant(m_currentLevel, tileX, tileY)) {
537                                                         m_decoder->GetNextMacroBlock();
538                                                         wtChannel->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
539                                                         wtChannel->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
540                                                         wtChannel->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
541                                                 } else {
542                                                         // skip tile
543                                                         m_decoder->SkipTileBuffer();
544                                                 }
545                                         }
546                                 }
547                         }
548
549                         volatile OSError error = NoError; // volatile prevents optimizations
550 #ifdef LIBPGF_USE_OPENMP
551                         #pragma omp parallel for default(shared)
552 #endif
553                         for (int i=0; i < m_header.channels; i++) {
554                                 // inverse transform from m_wtChannel to m_channel
555                                 if (error == NoError) {
556                                         OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
557                                         if (err != NoError) error = err;
558                                 }
559                                 ASSERT(m_channel[i]);
560                         }
561                         if (error != NoError) ReturnWithError(error);
562
563                         // set new level: must be done before refresh callback
564                         m_currentLevel--;
565
566                         // now we have to refresh the display
567                         if (m_cb) m_cb(m_cbArg);
568
569                         // now update progress
570                         if (cb) {
571                                 percent *= 4;
572                                 if (m_progressMode == PM_Absolute) m_percent = percent;
573                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
574                         }
575                 }
576         }
577 }

  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
    level The image level
    target The target buffer
    targetLen The length of the target buffer in bytes

Returns
    The number of bytes copied to the target buffer

Definition at line 707 of file PGFimage.cpp.
707                                                                                   {
708         ASSERT(level >= 0 && level < m_header.nLevels);
709         ASSERT(target);
710         ASSERT(targetLen > 0);
711         ASSERT(m_decoder);
712
713         // reset stream position
714         m_decoder->SetStreamPosToData();
715
716         // position stream
717         UINT64 offset = 0;
718
719         for (int i=m_header.nLevels - 1; i > level; i--) {
720                 offset += m_levelLength[m_header.nLevels - 1 - i];
721         }
722         m_decoder->Skip(offset);
723
724         // compute number of bytes to read
725         UINT32 len = __min(targetLen, GetEncodedLevelLength(level));
726
727         // read data
728         len = m_decoder->ReadEncodedData(target, len);
729         ASSERT(len >= 0 && len <= targetLen);
730
731         return len;
732 }

  UINT32 CPGFImage::ReadEncodedHeader (UINT8 * target, UINT32 targetLen) const
Reads the encoded PGF header 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
    target The target buffer
    targetLen The length of the target buffer in bytes

Returns
    The number of bytes copied to the target buffer

Definition at line 660 of file PGFimage.cpp.
660                                                                          {
661         ASSERT(target);
662         ASSERT(targetLen > 0);
663         ASSERT(m_decoder);
664
665         // reset stream position
666         m_decoder->SetStreamPosToStart();
667
668         // compute number of bytes to read
669         UINT32 len = __min(targetLen, GetEncodedHeaderLength());
670
671         // read data
672         len = m_decoder->ReadEncodedData(target, len);
673         ASSERT(len >= 0 && len <= targetLen);
674
675         return len;
676 }

  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 111 of file PGFimage.h.
111 { 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
    level The image level of the resulting image in the internal image buffer.

Definition at line 348 of file PGFimage.cpp.
348                                        {
349         if (m_header.nLevels == 0) {
350                 // image didn't use wavelet transform
351                 if (level == 0) {
352                         for (int i=0; i < m_header.channels; i++) {
353                                 ASSERT(m_wtChannel[i]);
354                                 m_channel[i] = m_wtChannel[i]->GetSubband(0, LL)->GetBuffer();
355                         }
356                 }
357         } else {
358                 int currentLevel = m_header.nLevels;
359
360         #ifdef __PGFROISUPPORT__
361                 if (ROIisSupported()) {
362                         // enable ROI reading
363                         SetROI(PGFRect(0, 0, m_header.width, m_header.height));
364                 }
365         #endif
366
367                 while (currentLevel > level) {
368                         for (int i=0; i < m_header.channels; i++) {
369                                 ASSERT(m_wtChannel[i]);
370                                 // dequantize subbands
371                                 if (currentLevel == m_header.nLevels) {
372                                         // last level also has LL band
373                                         m_wtChannel[i]->GetSubband(currentLevel, LL)->Dequantize(m_quant);
374                                 }
375                                 m_wtChannel[i]->GetSubband(currentLevel, HL)->Dequantize(m_quant);
376                                 m_wtChannel[i]->GetSubband(currentLevel, LH)->Dequantize(m_quant);
377                                 m_wtChannel[i]->GetSubband(currentLevel, HH)->Dequantize(m_quant);
378
379                                 // inverse transform from m_wtChannel to m_channel
380                                 OSError err = m_wtChannel[i]->InverseTransform(currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
381                                 if (err != NoError) ReturnWithError(err);
382                                 ASSERT(m_channel[i]);
383                         }
384
385                         currentLevel--;
386                 }
387         }
388 }

  void CPGFImage::ResetStreamPos (bool startOfData)
Reset stream position to start of PGF pre-header or start of data. Must not be called before Open() or before Write(). Use this method after Read() if you want to read the same image several times, e.g. reading different ROIs.

Parameters
    startOfData true: you want to read the same image several times. false: resets stream position to the initial position

Definition at line 682 of file PGFimage.cpp.
682                                                {
683         m_currentLevel = 0;
684         if (startOfData) {
685                 ASSERT(m_decoder);
686                 m_decoder->SetStreamPosToData();
687         } else {
688                 if (m_decoder) {
689                         m_decoder->SetStreamPosToStart();
690                 } else if (m_encoder) {
691                         m_encoder->SetStreamPosToStart();
692                 } else {
693                         ASSERT(false);
694                 }
695         }
696 }

  void CPGFImage::RgbToYuv (int pitch, UINT8 * rgbBuff, BYTE bpp, int channelMap[], CallbackPtr cb, void * data) [private]

Definition at line 1389 of file PGFimage.cpp.
1389                                                                                                          {
1390         ASSERT(buff);
1391         UINT32 yPos = 0, cnt = 0;
1392         double percent = 0;
1393         const double dP = 1.0/m_header.height;
1394         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
1395
1396         if (channelMap == nullptr) channelMap = defMap;
1397
1398         switch(m_header.mode) {
1399         case ImageModeBitmap:
1400                 {
1401                         ASSERT(m_header.channels == 1);
1402                         ASSERT(m_header.bpp == 1);
1403                         ASSERT(bpp == 1);
1404
1405                         const UINT32 w = m_header.width;
1406                         const UINT32 w2 = (m_header.width + 7)/8;
1407                         DataT* y = m_channel[0]; ASSERT(y);
1408
1409                         // new unpacked version since version 7
1410                         for (UINT32 h = 0; h < m_header.height; h++) {
1411                                 if (cb) {
1412                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1413                                         percent += dP;
1414                                 }
1415                                 cnt = 0;
1416                                 for (UINT32 j = 0; j < w2; j++) {
1417                                         UINT8 byte = buff[j];
1418                                         for (int k = 0; k < 8; k++) {
1419                                                 UINT8 bit = (byte & 0x80) >> 7;
1420                                                 if (cnt < w) y[yPos++] = bit;
1421                                                 byte <<= 1;
1422                                                 cnt++;
1423                                         }
1424                                 }
1425                                 buff += pitch;
1426                         }
1427                         /* old version: packed values: 8 pixels in 1 byte
1428                         for (UINT32 h = 0; h < m_header.height; h++) {
1429                                 if (cb) {
1430                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1431                                         percent += dP;
1432                                 }
1433
1434                                 for (UINT32 j = 0; j < w2; j++) {
1435                                         y[yPos++] = buff[j] - YUVoffset8;
1436                                 }
1437                                 // version 5 and 6
1438                                 // for (UINT32 j = w2; j < w; j++) {
1439                                 //      y[yPos++] = YUVoffset8;
1440                                 //}
1441                                 buff += pitch;
1442                         }
1443                         */
1444                 }
1445                 break;
1446         case ImageModeIndexedColor:
1447         case ImageModeGrayScale:
1448         case ImageModeHSLColor:
1449         case ImageModeHSBColor:
1450         case ImageModeLabColor:
1451                 {
1452                         ASSERT(m_header.channels >= 1);
1453                         ASSERT(m_header.bpp == m_header.channels*8);
1454                         ASSERT(bpp%8 == 0);
1455                         const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1456
1457                         for (UINT32 h=0; h < m_header.height; h++) {
1458                                 if (cb) {
1459                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1460                                         percent += dP;
1461                                 }
1462
1463                                 cnt = 0;
1464                                 for (UINT32 w=0; w < m_header.width; w++) {
1465                                         for (int c=0; c < m_header.channels; c++) {
1466                                                 m_channel[c][yPos] = buff[cnt + channelMap[c]] - YUVoffset8;
1467                                         }
1468                                         cnt += channels;
1469                                         yPos++;
1470                                 }
1471                                 buff += pitch;
1472                         }
1473                 }
1474                 break;
1475         case ImageModeGray16:
1476         case ImageModeLab48:
1477                 {
1478                         ASSERT(m_header.channels >= 1);
1479                         ASSERT(m_header.bpp == m_header.channels*16);
1480                         ASSERT(bpp%16 == 0);
1481
1482                         UINT16 *buff16 = (UINT16 *)buff;
1483                         const int pitch16 = pitch/2;
1484                         const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1485                         const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1486                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1487
1488                         for (UINT32 h=0; h < m_header.height; h++) {
1489                                 if (cb) {
1490                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1491                                         percent += dP;
1492                                 }
1493
1494                                 cnt = 0;
1495                                 for (UINT32 w=0; w < m_header.width; w++) {
1496                                         for (int c=0; c < m_header.channels; c++) {
1497                                                 m_channel[c][yPos] = (buff16[cnt + channelMap[c]] >> shift) - yuvOffset16;
1498                                         }
1499                                         cnt += channels;
1500                                         yPos++;
1501                                 }
1502                                 buff16 += pitch16;
1503                         }
1504                 }
1505                 break;
1506         case ImageModeRGBColor:
1507                 {
1508                         ASSERT(m_header.channels == 3);
1509                         ASSERT(m_header.bpp == m_header.channels*8);
1510                         ASSERT(bpp%8 == 0);
1511
1512                         DataT* y = m_channel[0]; ASSERT(y);
1513                         DataT* u = m_channel[1]; ASSERT(u);
1514                         DataT* v = m_channel[2]; ASSERT(v);
1515                         const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1516                         UINT8 b, g, r;
1517
1518                         for (UINT32 h=0; h < m_header.height; h++) {
1519                                 if (cb) {
1520                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1521                                         percent += dP;
1522                                 }
1523
1524                                 cnt = 0;
1525                                 for (UINT32 w=0; w < m_header.width; w++) {
1526                                         b = buff[cnt + channelMap[0]];
1527                                         g = buff[cnt + channelMap[1]];
1528                                         r = buff[cnt + channelMap[2]];
1529                                         // Yuv
1530                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
1531                                         u[yPos] = r - g;
1532                                         v[yPos] = b - g;
1533                                         yPos++;
1534                                         cnt += channels;
1535                                 }
1536                                 buff += pitch;
1537                         }
1538                 }
1539                 break;
1540         case ImageModeRGB48:
1541                 {
1542                         ASSERT(m_header.channels == 3);
1543                         ASSERT(m_header.bpp == m_header.channels*16);
1544                         ASSERT(bpp%16 == 0);
1545
1546                         UINT16 *buff16 = (UINT16 *)buff;
1547                         const int pitch16 = pitch/2;
1548                         const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1549                         const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1550                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1551
1552                         DataT* y = m_channel[0]; ASSERT(y);
1553                         DataT* u = m_channel[1]; ASSERT(u);
1554                         DataT* v = m_channel[2]; ASSERT(v);
1555                         UINT16 b, g, r;
1556
1557                         for (UINT32 h=0; h < m_header.height; h++) {
1558                                 if (cb) {
1559                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1560                                         percent += dP;
1561                                 }
1562
1563                                 cnt = 0;
1564                                 for (UINT32 w=0; w < m_header.width; w++) {
1565                                         b = buff16[cnt + channelMap[0]] >> shift;
1566                                         g = buff16[cnt + channelMap[1]] >> shift;
1567                                         r = buff16[cnt + channelMap[2]] >> shift;
1568                                         // Yuv
1569                                         y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
1570                                         u[yPos] = r - g;
1571                                         v[yPos] = b - g;
1572                                         yPos++;
1573                                         cnt += channels;
1574                                 }
1575                                 buff16 += pitch16;
1576                         }
1577                 }
1578                 break;
1579         case ImageModeRGBA:
1580         case ImageModeCMYKColor:
1581                 {
1582                         ASSERT(m_header.channels == 4);
1583                         ASSERT(m_header.bpp == m_header.channels*8);
1584                         ASSERT(bpp%8 == 0);
1585                         const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1586
1587                         DataT* y = m_channel[0]; ASSERT(y);
1588                         DataT* u = m_channel[1]; ASSERT(u);
1589                         DataT* v = m_channel[2]; ASSERT(v);
1590                         DataT* a = m_channel[3]; ASSERT(a);
1591                         UINT8 b, g, r;
1592
1593                         for (UINT32 h=0; h < m_header.height; h++) {
1594                                 if (cb) {
1595                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1596                                         percent += dP;
1597                                 }
1598
1599                                 cnt = 0;
1600                                 for (UINT32 w=0; w < m_header.width; w++) {
1601                                         b = buff[cnt + channelMap[0]];
1602                                         g = buff[cnt + channelMap[1]];
1603                                         r = buff[cnt + channelMap[2]];
1604                                         // Yuv
1605                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
1606                                         u[yPos] = r - g;
1607                                         v[yPos] = b - g;
1608                                         a[yPos++] = buff[cnt + channelMap[3]] - YUVoffset8;
1609                                         cnt += channels;
1610                                 }
1611                                 buff += pitch;
1612                         }
1613                 }
1614                 break;
1615         case ImageModeCMYK64:
1616                 {
1617                         ASSERT(m_header.channels == 4);
1618                         ASSERT(m_header.bpp == m_header.channels*16);
1619                         ASSERT(bpp%16 == 0);
1620
1621                         UINT16 *buff16 = (UINT16 *)buff;
1622                         const int pitch16 = pitch/2;
1623                         const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1624                         const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1625                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1626
1627                         DataT* y = m_channel[0]; ASSERT(y);
1628                         DataT* u = m_channel[1]; ASSERT(u);
1629                         DataT* v = m_channel[2]; ASSERT(v);
1630                         DataT* a = m_channel[3]; ASSERT(a);
1631                         UINT16 b, g, r;
1632
1633                         for (UINT32 h=0; h < m_header.height; h++) {
1634                                 if (cb) {
1635                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1636                                         percent += dP;
1637                                 }
1638
1639                                 cnt = 0;
1640                                 for (UINT32 w=0; w < m_header.width; w++) {
1641                                         b = buff16[cnt + channelMap[0]] >> shift;
1642                                         g = buff16[cnt + channelMap[1]] >> shift;
1643                                         r = buff16[cnt + channelMap[2]] >> shift;
1644                                         // Yuv
1645                                         y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
1646                                         u[yPos] = r - g;
1647                                         v[yPos] = b - g;
1648                                         a[yPos++] = (buff16[cnt + channelMap[3]] >> shift) - yuvOffset16;
1649                                         cnt += channels;
1650                                 }
1651                                 buff16 += pitch16;
1652                         }
1653                 }
1654                 break;
1655 #ifdef __PGF32SUPPORT__
1656         case ImageModeGray32:
1657                 {
1658                         ASSERT(m_header.channels == 1);
1659                         ASSERT(m_header.bpp == 32);
1660                         ASSERT(bpp == 32);
1661                         ASSERT(DataTSize == sizeof(UINT32));
1662
1663                         DataT* y = m_channel[0]; ASSERT(y);
1664
1665                         UINT32 *buff32 = (UINT32 *)buff;
1666                         const int pitch32 = pitch/4;
1667                         const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1668                         const DataT yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
1669
1670                         for (UINT32 h=0; h < m_header.height; h++) {
1671                                 if (cb) {
1672                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1673                                         percent += dP;
1674                                 }
1675
1676                                 for (UINT32 w=0; w < m_header.width; w++) {
1677                                         y[yPos++] = (buff32[w] >> shift) - yuvOffset31;
1678                                 }
1679                                 buff32 += pitch32;
1680                         }
1681                 }
1682                 break;
1683 #endif
1684         case ImageModeRGB12:
1685                 {
1686                         ASSERT(m_header.channels == 3);
1687                         ASSERT(m_header.bpp == m_header.channels*4);
1688                         ASSERT(bpp == m_header.channels*4);
1689
1690                         DataT* y = m_channel[0]; ASSERT(y);
1691                         DataT* u = m_channel[1]; ASSERT(u);
1692                         DataT* v = m_channel[2]; ASSERT(v);
1693
1694                         UINT8 rgb = 0, b, g, r;
1695
1696                         for (UINT32 h=0; h < m_header.height; h++) {
1697                                 if (cb) {
1698                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1699                                         percent += dP;
1700                                 }
1701
1702                                 cnt = 0;
1703                                 for (UINT32 w=0; w < m_header.width; w++) {
1704                                         if (w%2 == 0) {
1705                                                 // even pixel position
1706                                                 rgb = buff[cnt];
1707                                                 b = rgb & 0x0F;
1708                                                 g = (rgb & 0xF0) >> 4;
1709                                                 cnt++;
1710                                                 rgb = buff[cnt];
1711                                                 r = rgb & 0x0F;
1712                                         } else {
1713                                                 // odd pixel position
1714                                                 b = (rgb & 0xF0) >> 4;
1715                                                 cnt++;
1716                                                 rgb = buff[cnt];
1717                                                 g = rgb & 0x0F;
1718                                                 r = (rgb & 0xF0) >> 4;
1719                                                 cnt++;
1720                                         }
1721
1722                                         // Yuv
1723                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset4;
1724                                         u[yPos] = r - g;
1725                                         v[yPos] = b - g;
1726                                         yPos++;
1727                                 }
1728                                 buff += pitch;
1729                         }
1730                 }
1731                 break;
1732         case ImageModeRGB16:
1733                 {
1734                         ASSERT(m_header.channels == 3);
1735                         ASSERT(m_header.bpp == 16);
1736                         ASSERT(bpp == 16);
1737
1738                         DataT* y = m_channel[0]; ASSERT(y);
1739                         DataT* u = m_channel[1]; ASSERT(u);
1740                         DataT* v = m_channel[2]; ASSERT(v);
1741
1742                         UINT16 *buff16 = (UINT16 *)buff;
1743                         UINT16 rgb, b, g, r;
1744                         const int pitch16 = pitch/2;
1745
1746                         for (UINT32 h=0; h < m_header.height; h++) {
1747                                 if (cb) {
1748                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1749                                         percent += dP;
1750                                 }
1751                                 for (UINT32 w=0; w < m_header.width; w++) {
1752                                         rgb = buff16[w];
1753                                         r = (rgb & 0xF800) >> 10;       // highest 5 bits
1754                                         g = (rgb & 0x07E0) >> 5;        // middle 6 bits
1755                                         b = (rgb & 0x001F) << 1;        // lowest 5 bits
1756                                         // Yuv
1757                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset6;
1758                                         u[yPos] = r - g;
1759                                         v[yPos] = b - g;
1760                                         yPos++;
1761                                 }
1762
1763                                 buff16 += pitch16;
1764                         }
1765                 }
1766                 break;
1767         default:
1768                 ASSERT(false);
1769         }
1770 }

  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 466 of file PGFimage.h.
466 { return (m_preHeader.version & PGFROI) == PGFROI; }

  void CPGFImage::SetChannel (DataT * channel, int c = 0) [inline]
Set internal PGF image buffer channel.

Parameters
    channel A YUV data channel
    c A channel index

Definition at line 272 of file PGFimage.h.
272 { 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
    iFirstColor The color table index of the first entry to set.
    nColors The number of color table entries to set.
    prgbColors A pointer to the array of RGBQUAD structures to set the color table entries.

Definition at line 1364 of file PGFimage.cpp.
1364                                                                                            {
1365         if (iFirstColor + nColors > ColorTableLen)      ReturnWithError(ColorTableError);
1366
1367         for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
1368                 m_postHeader.clut[i] = prgbColors[j];
1369         }
1370 }

  void CPGFImage::SetHeader (const PGFHeader & header, BYTE flags = 0, const UINT8 * userData = 0, UINT32 userDataLength = 0)
Set PGF header and user data. Precondition: The PGF image has been never opened with Open(...). It might throw an IOException.

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

Definition at line 894 of file PGFimage.cpp.
894                                                                                                                  {
895         ASSERT(!m_decoder);     // current image must be closed
896         ASSERT(header.quality <= MaxQuality);
897         ASSERT(userDataLength <= MaxUserDataSize);
898
899         // init state
900 #ifdef __PGFROISUPPORT__
901         m_streamReinitialized = false;
902 #endif
903
904         // init preHeader
905         memcpy(m_preHeader.magic, PGFMagic, 3);
906         m_preHeader.version = PGFVersion | flags;
907         m_preHeader.hSize = HeaderSize;
908
909         // copy header
910         memcpy(&m_header, &header, HeaderSize);
911
912         // check quality
913         if (m_header.quality > MaxQuality) m_header.quality = MaxQuality;
914
915         // complete header
916         CompleteHeader();
917
918         // check and set number of levels
919         ComputeLevels();
920
921         // check for downsample
922         if (m_header.quality > DownsampleThreshold &&  (m_header.mode == ImageModeRGBColor ||
923                                                                                                         m_header.mode == ImageModeRGBA ||
924                                                                                                         m_header.mode == ImageModeRGB48 ||
925                                                                                                         m_header.mode == ImageModeCMYKColor ||
926                                                                                                         m_header.mode == ImageModeCMYK64 ||
927                                                                                                         m_header.mode == ImageModeLabColor ||
928                                                                                                         m_header.mode == ImageModeLab48)) {
929                 m_downsample = true;
930                 m_quant = m_header.quality - 1;
931         } else {
932                 m_downsample = false;
933                 m_quant = m_header.quality;
934         }
935
936         // update header size and copy user data
937         if (m_header.mode == ImageModeIndexedColor) {
938                 // update header size
939                 m_preHeader.hSize += ColorTableSize;
940         }
941         if (userDataLength && userData) {
942                 if (userDataLength > MaxUserDataSize) userDataLength = MaxUserDataSize;
943                 m_postHeader.userData = new(std::nothrow) UINT8[userDataLength];
944                 if (!m_postHeader.userData) ReturnWithError(InsufficientMemory);
945                 m_postHeader.userDataLen = m_postHeader.cachedUserDataLen = userDataLength;
946                 memcpy(m_postHeader.userData, userData, userDataLength);
947                 // update header size
948                 m_preHeader.hSize += userDataLength;
949         }
950
951         // allocate channels
952         for (int i=0; i < m_header.channels; i++) {
953                 // set current width and height
954                 m_width[i] = m_header.width;
955                 m_height[i] = m_header.height;
956
957                 // allocate channels
958                 ASSERT(!m_channel[i]);
959                 m_channel[i] = new(std::nothrow) DataT[m_header.width*m_header.height];
960                 if (!m_channel[i]) {
961                         if (i) i--;
962                         while(i) {
963                                 delete[] m_channel[i]; m_channel[i] = 0;
964                                 i--;
965                         }
966                         ReturnWithError(InsufficientMemory);
967                 }
968         }
969 }

  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
    maxValue The maximum intensity value.

Definition at line 738 of file PGFimage.cpp.
738                                            {
739         const BYTE bpc = m_header.bpp/m_header.channels;
740         BYTE pot = 0;
741
742         while(maxValue > 0) {
743                 pot++;
744                 maxValue >>= 1;
745         }
746         // store bits per channel
747         if (pot > bpc) pot = bpc;
748         if (pot > 31) pot = 31;
749         m_header.usedBitsPerChannel = pot;
750 }

  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 296 of file PGFimage.h.
296 { 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
    callback A refresh callback procedure
    arg A parameter of the refresh callback procedure

Definition at line 303 of file PGFimage.h.
303 { m_cb = callback; m_cbArg = arg; }

  void CPGFImage::SetROI (PGFRect rect) [private]
Compute ROIs for each channel and each level <= current level Called inside of Read(rect, ...).

Parameters
    rect rectangular region of interest (ROI) at level 0

Definition at line 615 of file PGFimage.cpp.
615                                    {
616         ASSERT(m_decoder);
617         ASSERT(ROIisSupported());
618         ASSERT(m_wtChannel[0]);
619
620         // store ROI for a later call of GetBitmap
621         m_roi = rect;
622
623         // enable ROI decoding
624         m_decoder->SetROI();
625
626         // prepare wavelet channels for using ROI
627         m_wtChannel[0]->SetROI(rect);
628
629         if (m_downsample && m_header.channels > 1) {
630                 // all further channels are downsampled, therefore downsample ROI
631                 rect.left >>= 1;
632                 rect.top >>= 1;
633                 rect.right = (rect.right + 1) >> 1;
634                 rect.bottom = (rect.bottom + 1) >> 1;
635         }
636         for (int i=1; i < m_header.channels; i++) {
637                 ASSERT(m_wtChannel[i]);
638                 m_wtChannel[i]->SetROI(rect);
639         }
640 }

  UINT32 CPGFImage::UpdatePostHeaderSize () [private]

Definition at line 1124 of file PGFimage.cpp.
1124                                        {
1125         ASSERT(m_encoder);
1126
1127         INT64 offset = m_encoder->ComputeOffset(); ASSERT(offset >= 0);
1128
1129         if (offset > 0) {
1130                 // update post-header size and rewrite pre-header
1131                 m_preHeader.hSize += (UINT32)offset;
1132                 m_encoder->UpdatePostHeaderSize(m_preHeader);
1133         }
1134
1135         // write dummy levelLength into stream
1136         return m_encoder->WriteLevelLength(m_levelLength);
1137 }

  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 756 of file PGFimage.cpp.
756                                          {
757         const BYTE bpc = m_header.bpp/m_header.channels;
758
759         if (bpc > 8) {
760                 return m_header.usedBitsPerChannel;
761         } else {
762                 return bpc;
763         }
764 }

  BYTE CPGFImage::Version () const [inline]
Returns the used codec major version of a pgf image

Returns
    PGF codec major version of this image

Definition at line 484 of file PGFimage.h.
484 { BYTE ver = CodecMajorVersion(m_preHeader.version); return (ver <= 7) ? ver : (BYTE)m_header.version.major; }

  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
    level A level

Returns
    Image level width in pixels

Definition at line 413 of file PGFimage.h.
413 { ASSERT(level >= 0); return LevelSizeL(m_header.width, level); }

  void CPGFImage::Write (CPGFStream * stream, UINT32 * nWrittenBytes = nullptr, CallbackPtr cb = nullptr, void * data = nullptr)
Encode and write an 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
    stream A PGF stream
    nWrittenBytes [in-out] The number of bytes written into stream are added to the input value.
    cb A pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
    data Data Pointer to C++ class container to host callback procedure.

Definition at line 1221 of file PGFimage.cpp.
1221                                                                                                  {
1222         ASSERT(stream);
1223         ASSERT(m_preHeader.hSize);
1224
1225         // create wavelet transform channels and encoder
1226         UINT32 nBytes = WriteHeader(stream);
1227
1228         // write image
1229         nBytes += WriteImage(stream, cb, data);
1230
1231         // return written bytes
1232         if (nWrittenBytes) *nWrittenBytes += nBytes;
1233 }

  UINT32 CPGFImage::Write (int level, CallbackPtr cb = nullptr, void * data = nullptr)
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.
    cb A pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
    data Data Pointer to C++ class container to host callback procedure.

Returns
    The number of bytes written into stream.

Definition at line 1250 of file PGFimage.cpp.
1250                                                                  {
1251         ASSERT(m_header.nLevels > 0);
1252         ASSERT(0 <= level && level < m_header.nLevels);
1253         ASSERT(m_encoder);
1254         ASSERT(ROIisSupported());
1255
1256         const int levelDiff = m_currentLevel - level;
1257         double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
1258         UINT32 nWrittenBytes = 0;
1259
1260         if (m_currentLevel == m_header.nLevels) {
1261                 // update post-header size, rewrite pre-header, and write dummy levelLength
1262                 nWrittenBytes = UpdatePostHeaderSize();
1263         } else {
1264                 // prepare for next level: save current file position, because the stream might have been reinitialized
1265                 if (m_encoder->ComputeBufferLength()) {
1266                         m_streamReinitialized = true;
1267                 }
1268         }
1269
1270         // encoding scheme with ROI
1271         while (m_currentLevel > level) {
1272                 WriteLevel();   // decrements m_currentLevel
1273
1274                 if (m_levelLength) {
1275                         nWrittenBytes += m_levelLength[m_header.nLevels - m_currentLevel - 1];
1276                 }
1277
1278                 // now update progress
1279                 if (cb) {
1280                         percent *= 4;
1281                         if (m_progressMode == PM_Absolute) m_percent = percent;
1282                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1283                 }
1284         }
1285
1286         // automatically closing
1287         if (m_currentLevel == 0) {
1288                 if (!m_streamReinitialized) {
1289                         // don't write level lengths, if the stream position changed inbetween two Write operations
1290                         m_encoder->UpdateLevelLength();
1291                 }
1292                 // delete encoder
1293                 delete m_encoder; m_encoder = nullptr;
1294         }
1295
1296         return nWrittenBytes;
1297 }

  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
    stream A PGF stream

Returns
    The number of bytes written into stream.

Create wavelet transform channels and encoder. Write header at current stream position. Performs forward FWT. 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
    stream A PGF stream

Returns
    The number of bytes written into stream.

Definition at line 979 of file PGFimage.cpp.
979                                                 {
980         ASSERT(m_header.nLevels <= MaxLevel);
981         ASSERT(m_header.quality <= MaxQuality); // quality is already initialized
982
983         if (m_header.nLevels > 0) {
984                 volatile OSError error = NoError; // volatile prevents optimizations
985                 // create new wt channels
986 #ifdef LIBPGF_USE_OPENMP
987                 #pragma omp parallel for default(shared)
988 #endif
989                 for (int i=0; i < m_header.channels; i++) {
990                         DataT *temp = nullptr;
991                         if (error == NoError) {
992                                 if (m_wtChannel[i]) {
993                                         ASSERT(m_channel[i]);
994                                         // copy m_channel to temp
995                                         int size = m_height[i]*m_width[i];
996                                         temp = new(std::nothrow) DataT[size];
997                                         if (temp) {
998                                                 memcpy(temp, m_channel[i], size*DataTSize);
999                                                 delete m_wtChannel[i];  // also deletes m_channel
1000                                                 m_channel[i] = nullptr;
1001                                         } else {
1002                                                 error = InsufficientMemory;
1003                                         }
1004                                 }
1005                                 if (error == NoError) {
1006                                         if (temp) {
1007                                                 ASSERT(!m_channel[i]);
1008                                                 m_channel[i] = temp;
1009                                         }
1010                                         m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels, m_channel[i]);
1011                                         if (m_wtChannel[i]) {
1012                                         #ifdef __PGFROISUPPORT__
1013                                                 m_wtChannel[i]->SetROI(PGFRect(0, 0, m_width[i], m_height[i]));
1014                                         #endif
1015
1016                                                 // wavelet subband decomposition
1017                                                 for (int l=0; error == NoError && l < m_header.nLevels; l++) {
1018                                                         OSError err = m_wtChannel[i]->ForwardTransform(l, m_quant);
1019                                                         if (err != NoError) error = err;
1020                                                 }
1021                                         } else {
1022                                                 delete[] m_channel[i];
1023                                                 error = InsufficientMemory;
1024                                         }
1025                                 }
1026                         }
1027                 }
1028                 if (error != NoError) {
1029                         // free already allocated memory
1030                         for (int i=0; i < m_header.channels; i++) {
1031                                 delete m_wtChannel[i];
1032                         }
1033                         ReturnWithError(error);
1034                 }
1035
1036                 m_currentLevel = m_header.nLevels;
1037
1038                 // create encoder, write headers and user data, but not level-length area
1039                 m_encoder = new CEncoder(stream, m_preHeader, m_header, m_postHeader, m_userDataPos, m_useOMPinEncoder);
1040                 if (m_favorSpeedOverSize) m_encoder->FavorSpeedOverSize();
1041
1042         #ifdef __PGFROISUPPORT__
1043                 if (ROIisSupported()) {
1044                         // new encoding scheme supporting ROI
1045                         m_encoder->SetROI();
1046                 }
1047         #endif
1048
1049         } else {
1050                 // very small image: we don't use DWT and encoding
1051
1052                 // create encoder, write headers and user data, but not level-length area
1053                 m_encoder = new CEncoder(stream, m_preHeader, m_header, m_postHeader, m_userDataPos, m_useOMPinEncoder);
1054         }
1055
1056         INT64 nBytes = m_encoder->ComputeHeaderLength();
1057         return (nBytes > 0) ? (UINT32)nBytes : 0;
1058 }

  UINT32 CPGFImage::WriteImage (CPGFStream * stream, CallbackPtr cb = nullptr, void * data = nullptr)
Encode and write an 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
    stream A PGF stream
    cb A pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
    data Data Pointer to C++ class container to host callback procedure.

Returns
    The number of bytes written into stream.

Definition at line 1150 of file PGFimage.cpp.
1150                                                                                {
1151         ASSERT(stream);
1152         ASSERT(m_preHeader.hSize);
1153
1154         int levels = m_header.nLevels;
1155         double percent = pow(0.25, levels);
1156
1157         // update post-header size, rewrite pre-header, and write dummy levelLength
1158         UINT32 nWrittenBytes = UpdatePostHeaderSize();
1159
1160         if (levels == 0) {
1161                 // for very small images: write channels uncoded
1162                 for (int c=0; c < m_header.channels; c++) {
1163                         const UINT32 size = m_width[c]*m_height[c];
1164
1165                         // write channel data into stream
1166                         for (UINT32 i=0; i < size; i++) {
1167                                 int count = DataTSize;
1168                                 stream->Write(&count, &m_channel[c][i]);
1169                         }
1170                 }
1171
1172                 // now update progress
1173                 if (cb) {
1174                         if ((*cb)(1, true, data)) ReturnWithError(EscapePressed);
1175                 }
1176
1177         } else {
1178                 // encode quantized wavelet coefficients and write to PGF file
1179                 // encode subbands, higher levels first
1180                 // color channels are interleaved
1181
1182                 // encode all levels
1183                 for (m_currentLevel = levels; m_currentLevel > 0; ) {
1184                         WriteLevel(); // decrements m_currentLevel
1185
1186                         // now update progress
1187                         if (cb) {
1188                                 percent *= 4;
1189                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1190                         }
1191                 }
1192
1193                 // flush encoder and write level lengths
1194                 m_encoder->Flush();
1195         }
1196
1197         // update level lengths
1198         nWrittenBytes += m_encoder->UpdateLevelLength(); // return written image bytes
1199
1200         // delete encoder
1201         delete m_encoder; m_encoder = nullptr;
1202
1203         ASSERT(!m_encoder);
1204
1205         return nWrittenBytes;
1206 }

  void CPGFImage::WriteLevel () [private]

Definition at line 1068 of file PGFimage.cpp.
1068                            {
1069         ASSERT(m_encoder);
1070         ASSERT(m_currentLevel > 0);
1071         ASSERT(m_header.nLevels > 0);
1072
1073 #ifdef __PGFROISUPPORT__
1074         if (ROIisSupported()) {
1075                 const int lastChannel = m_header.channels - 1;
1076
1077                 for (int i=0; i < m_header.channels; i++) {
1078                         // get number of tiles and tile indices
1079                         const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel);
1080                         const UINT32 lastTile = nTiles - 1;
1081
1082                         if (m_currentLevel == m_header.nLevels) {
1083                                 // last level also has LL band
1084                                 ASSERT(nTiles == 1);
1085                                 m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder);
1086                                 m_encoder->EncodeTileBuffer(); // encode macro block with tile-end = true
1087                         }
1088                         for (UINT32 tileY=0; tileY < nTiles; tileY++) {
1089                                 for (UINT32 tileX=0; tileX < nTiles; tileX++) {
1090                                         // extract tile to macro block and encode already filled macro blocks with tile-end = false
1091                                         m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, true, tileX, tileY);
1092                                         m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, true, tileX, tileY);
1093                                         m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, true, tileX, tileY);
1094                                         if (i == lastChannel && tileY == lastTile && tileX == lastTile) {
1095                                                 // all necessary data are buffered. next call of EncodeTileBuffer will write the last piece of data of the current level.
1096                                                 m_encoder->SetEncodedLevel(--m_currentLevel);
1097                                         }
1098                                         m_encoder->EncodeTileBuffer(); // encode last macro block with tile-end = true
1099                                 }
1100                         }
1101                 }
1102         } else
1103 #endif
1104         {
1105                 for (int i=0; i < m_header.channels; i++) {
1106                         ASSERT(m_wtChannel[i]);
1107                         if (m_currentLevel == m_header.nLevels) {
1108                                 // last level also has LL band
1109                                 m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder);
1110                         }
1111                         //encoder.EncodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); // until version 4
1112                         m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder); // since version 5
1113                         m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder); // since version 5
1114                         m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder);
1115                 }
1116
1117                 // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level.
1118                 m_encoder->SetEncodedLevel(--m_currentLevel);
1119         }
1120 }

Member Data Documentation

  RefreshCB CPGFImage::m_cb [private]

pointer to refresh callback procedure

Definition at line 545 of file PGFimage.h.

  void* CPGFImage::m_cbArg [private]

refresh callback argument

Definition at line 546 of file PGFimage.h.

  DataT* CPGFImage::m_channel[MaxChannels] [protected]

untransformed channels in YUV format

Definition at line 522 of file PGFimage.h.

  int CPGFImage::m_currentLevel [protected]

transform level of current image

Definition at line 532 of file PGFimage.h.

  CDecoder* CPGFImage::m_decoder [protected]

PGF decoder.

Definition at line 523 of file PGFimage.h.

  bool CPGFImage::m_downsample [protected]

chrominance channels are downsampled

Definition at line 535 of file PGFimage.h.

  CEncoder* CPGFImage::m_encoder [protected]

PGF encoder.

Definition at line 524 of file PGFimage.h.

  bool CPGFImage::m_favorSpeedOverSize [protected]

favor encoding speed over compression ratio

Definition at line 536 of file PGFimage.h.

  PGFHeader CPGFImage::m_header [protected]

PGF file header.

Definition at line 529 of file PGFimage.h.

  UINT32 CPGFImage::m_height[MaxChannels] [protected]

height of each channel at current level

Definition at line 527 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 525 of file PGFimage.h.

  double CPGFImage::m_percent [private]

progress [0..1]

Definition at line 547 of file PGFimage.h.

  PGFPostHeader CPGFImage::m_postHeader [protected]

PGF post-header.

Definition at line 530 of file PGFimage.h.

  PGFPreHeader CPGFImage::m_preHeader [protected]

PGF pre-header.

Definition at line 528 of file PGFimage.h.

  ProgressMode CPGFImage::m_progressMode [private]

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

Definition at line 548 of file PGFimage.h.

  BYTE CPGFImage::m_quant [protected]

quantization parameter

Definition at line 534 of file PGFimage.h.

  PGFRect CPGFImage::m_roi [protected]

region of interest

Definition at line 541 of file PGFimage.h.

  bool CPGFImage::m_streamReinitialized [protected]

stream has been reinitialized

Definition at line 540 of file PGFimage.h.

  bool CPGFImage::m_useOMPinDecoder [protected]

use Open MP in decoder

Definition at line 538 of file PGFimage.h.

  bool CPGFImage::m_useOMPinEncoder [protected]

use Open MP in encoder

Definition at line 537 of file PGFimage.h.

  UINT32 CPGFImage::m_userDataPolicy [protected]

user data (metadata) policy during open

Definition at line 533 of file PGFimage.h.

  UINT64 CPGFImage::m_userDataPos [protected]

stream position of user data

Definition at line 531 of file PGFimage.h.

  UINT32 CPGFImage::m_width[MaxChannels] [protected]

width of each channel at current level

Definition at line 526 of file PGFimage.h.

  CWaveletTransform* CPGFImage::m_wtChannel[MaxChannels] [protected]

wavelet transformed color channels

Definition at line 521 of file PGFimage.h.

Author

Generated automatically by Doxygen for libpgf from the source code.