CPGFImage(3) | Library Functions Manual | 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
Definition at line 53 of file PGFimage.h.
Constructor & Destructor Documentation¶
CPGFImage::CPGFImage ()¶
Standard constructor.
Definition at line 64 of file PGFimage.cpp..PP
64 { 65 Init(); 66 }
CPGFImage::~CPGFImage () [virtual]¶
Destructor.
Definition at line 117 of file PGFimage.cpp..PP
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
Definition at line 461 of file PGFimage.h..PP
461 { return m_header.bpp; }
BYTE CPGFImage::ChannelDepth () const [inline]¶
Return bits per channel of the image's encoder.
Returns
Definition at line 406 of file PGFimage.h..PP
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
Returns
Definition at line 401 of file PGFimage.h..PP
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
Definition at line 448 of file PGFimage.h..PP
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
Returns
Definition at line 394 of file PGFimage.h..PP
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..PP
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..PP
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..PP
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..PP
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..PP
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
Returns
Definition at line 768 of file PGFimage.cpp..PP
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..PP
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
void CPGFImage::ComputeLevels () [private]¶
Definition at line 854 of file PGFimage.cpp..PP
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
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..PP
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
favorSpeedOverSize Favors encoding speed over compression ratio. Default value: false
Definition at line 250 of file PGFimage.h..PP
250 { m_useOMPinEncoder = useOMP; m_favorSpeedOverSize = favorSpeedOverSize; }
void CPGFImage::Destroy ()¶
Definition at line 124 of file PGFimage.cpp..PP
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..PP
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]¶
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
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..PP
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
Returns
Definition at line 317 of file PGFimage.h..PP
317 { ASSERT(c >= 0 && c < MaxChannels); return m_channel[c]; }
const RGBQUAD * CPGFImage::GetColorTable () const [inline]¶
Returns
Definition at line 330 of file PGFimage.h..PP
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
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..PP
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
Definition at line 648 of file PGFimage.cpp..PP
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
Returns
Definition at line 367 of file PGFimage.h..PP
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
Definition at line 335 of file PGFimage.h..PP
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
Definition at line 341 of file PGFimage.h..PP
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
pTotalSize [optional out] Pointer to return the size of user data stored in image header in bytes.
Returns
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
pTotalSize [optional out] Pointer to return the size of user data stored in image header in bytes.
Returns
Definition at line 337 of file PGFimage.cpp..PP
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..PP
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
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
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..PP
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
Returns
Definition at line 420 of file PGFimage.h..PP
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
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..PP
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
Returns
Definition at line 1305 of file PGFimage.cpp..PP
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
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
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..PP
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..PP
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..PP
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..PP
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
Definition at line 427 of file PGFimage.h..PP
427 { return (BYTE)m_currentLevel; }
BYTE CPGFImage::Levels () const [inline]¶
Return the number of image levels.
Returns
Definition at line 432 of file PGFimage.h..PP
432 { return m_header.nLevels; }
static UINT32 CPGFImage::LevelSizeH (UINT32 size, int level) [inline], [static]¶
Compute and return image width/height of HH subband at given level.
Parameters
level An image level
Returns
Definition at line 506 of file PGFimage.h..PP
506 { ASSERT(level >= 0); UINT32 d = 1 << (level - 1); return (size + d - 1) >> level; }
static UINT32 CPGFImage::LevelSizeL (UINT32 size, int level) [inline], [static]¶
Compute and return image width/height of LL subband at given level.
Parameters
level An image level
Returns
Definition at line 499 of file PGFimage.h..PP
499 { ASSERT(level >= 0); UINT32 d = 1 << level; return (size + d - 1) >> level; }
static BYTE CPGFImage::MaxChannelDepth (BYTE version = PGFVersion) [inline], [static]¶
Return maximum channel depth.
Parameters
Returns
Definition at line 518 of file PGFimage.h..PP
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
Definition at line 455 of file PGFimage.h..PP
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
Definition at line 141 of file PGFimage.cpp..PP
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
Definition at line 442 of file PGFimage.h..PP
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
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..PP
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
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.
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
target The target buffer
targetLen The length of the target buffer in bytes
Returns
Definition at line 707 of file PGFimage.cpp..PP
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
targetLen The length of the target buffer in bytes
Returns
Definition at line 660 of file PGFimage.cpp..PP
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..PP
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
Definition at line 348 of file PGFimage.cpp..PP
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
Definition at line 682 of file PGFimage.cpp..PP
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..PP
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
Definition at line 466 of file PGFimage.h..PP
466 { return (m_preHeader.version & PGFROI) == PGFROI; }
void CPGFImage::SetChannel (DataT * channel, int c = 0) [inline]¶
Set internal PGF image buffer channel.
Parameters
c A channel index
Definition at line 272 of file PGFimage.h..PP
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
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..PP
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
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..PP
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
Definition at line 738 of file PGFimage.cpp..PP
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..PP
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
arg A parameter of the refresh callback procedure
Definition at line 303 of file PGFimage.h..PP
303 { m_cb = callback; m_cbArg = arg; }
void CPGFImage::SetROI (PGFRect rect) [private]¶
UINT32 CPGFImage::UpdatePostHeaderSize () [private]¶
Definition at line 1124 of file PGFimage.cpp..PP
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
Definition at line 756 of file PGFimage.cpp..PP
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
Definition at line 484 of file PGFimage.h..PP
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
Returns
Definition at line 413 of file PGFimage.h..PP
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
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..PP
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
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
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
Returns
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
Returns
Definition at line 979 of file PGFimage.cpp..PP
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
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
Definition at line 1150 of file PGFimage.cpp..PP
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..PP
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.
Version 7.21.2 | libpgf |