PGF main class. More...
#include <PGFimage.h>
Public Member Functions | |
CPGFImage () | |
virtual | ~CPGFImage () |
virtual void | Close () |
virtual void | Destroy () |
void | Open (CPGFStream *stream) THROW_ |
bool | IsOpen () const |
void | Read (int level=0, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
void | ReadPreview () THROW_ |
void | Reconstruct (int level=0) THROW_ |
void | GetBitmap (int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) const THROW_ |
void | GetYUV (int pitch, DataT *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) const THROW_ |
void | ImportBitmap (int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
void | ImportYUV (int pitch, DataT *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
void | Write (CPGFStream *stream, UINT32 *nWrittenBytes=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
UINT32 | WriteHeader (CPGFStream *stream) THROW_ |
UINT32 | WriteImage (CPGFStream *stream, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
void | ConfigureEncoder (bool useOMP=true, bool favorSpeedOverSize=false) |
void | ConfigureDecoder (bool useOMP=true, bool skipUserData=false) |
void | ResetStreamPos () THROW_ |
void | SetChannel (DataT *channel, int c=0) |
void | SetHeader (const PGFHeader &header, BYTE flags=0, UINT8 *userData=0, UINT32 userDataLength=0) THROW_ |
void | SetMaxValue (UINT32 maxValue) |
void | SetProgressMode (ProgressMode pm) |
void | SetRefreshCallback (RefreshCB callback, void *arg) |
void | SetColorTable (UINT32 iFirstColor, UINT32 nColors, const RGBQUAD *prgbColors) THROW_ |
DataT * | GetChannel (int c=0) |
void | GetColorTable (UINT32 iFirstColor, UINT32 nColors, RGBQUAD *prgbColors) const THROW_ |
const RGBQUAD * | GetColorTable () const |
const PGFHeader * | GetHeader () const |
UINT32 | GetMaxValue () const |
UINT64 | GetUserDataPos () const |
const UINT8 * | GetUserData (UINT32 &size) const |
UINT32 | GetEncodedHeaderLength () const |
UINT32 | GetEncodedLevelLength (int level) const |
UINT32 | ReadEncodedHeader (UINT8 *target, UINT32 targetLen) const THROW_ |
UINT32 | ReadEncodedData (int level, UINT8 *target, UINT32 targetLen) const THROW_ |
UINT32 | ChannelWidth (int c=0) const |
UINT32 | ChannelHeight (int c=0) const |
BYTE | ChannelDepth () const |
UINT32 | Width (int level=0) const |
UINT32 | Height (int level=0) const |
BYTE | Level () const |
BYTE | Levels () const |
BYTE | Quality () const |
BYTE | Channels () const |
BYTE | Mode () const |
BYTE | BPP () const |
bool | ROIisSupported () const |
BYTE | UsedBitsPerChannel () const |
BYTE | Version () const |
Static Public Member Functions | |
static bool | ImportIsSupported (BYTE mode) |
static UINT32 | LevelWidth (UINT32 width, int level) |
static UINT32 | LevelHeight (UINT32 height, int level) |
static BYTE | CurrentVersion (BYTE version=PGFVersion) |
static BYTE | CurrentChannelDepth (BYTE version=PGFVersion) |
Protected Attributes | |
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 | |
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_skipUserData |
skip user data (metadata) during open | |
Private Member Functions | |
void | ComputeLevels () |
bool | CompleteHeader () |
void | RgbToYuv (int pitch, UINT8 *rgbBuff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data) THROW_ |
void | Downsample (int nChannel) |
UINT32 | UpdatePostHeaderSize () THROW_ |
void | WriteLevel () THROW_ |
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 |
PGF main class.
PGF image class is the main class. You always need a PGF object for encoding or decoding image data. Decoding: pgf.Open(...) pgf.Read(...) pgf.GetBitmap(...) Encoding: pgf.SetHeader(...) pgf.ImportBitmap(...) pgf.Write(...)
Definition at line 57 of file PGFimage.h.
CPGFImage::CPGFImage | ( | ) |
Standard constructor: It is used to create a PGF instance for opening and reading.
Definition at line 55 of file PGFimage.cpp.
00056 : m_decoder(0) 00057 , m_encoder(0) 00058 , m_levelLength(0) 00059 , m_currentLevel(0) 00060 , m_quant(0) 00061 , m_userDataPos(0) 00062 , m_downsample(false) 00063 , m_favorSpeedOverSize(false) 00064 , m_useOMPinEncoder(true) 00065 , m_useOMPinDecoder(true) 00066 , m_skipUserData(false) 00067 #ifdef __PGFROISUPPORT__ 00068 , m_streamReinitialized(false) 00069 #endif 00070 , m_cb(0) 00071 , m_cbArg(0) 00072 , m_progressMode(PM_Relative) 00073 , m_percent(0) 00074 { 00075 00076 // init preHeader 00077 memcpy(m_preHeader.magic, PGFMagic, 3); 00078 m_preHeader.version = PGFVersion; 00079 m_preHeader.hSize = 0; 00080 00081 // init postHeader 00082 m_postHeader.userData = 0; 00083 m_postHeader.userDataLen = 0; 00084 00085 // init channels 00086 for (int i=0; i < MaxChannels; i++) { 00087 m_channel[i] = 0; 00088 m_wtChannel[i] = 0; 00089 } 00090 00091 // set image width and height 00092 m_width[0] = 0; 00093 m_height[0] = 0; 00094 }
CPGFImage::~CPGFImage | ( | ) | [virtual] |
Destructor: Destroy internal data structures.
Definition at line 98 of file PGFimage.cpp.
00098 { 00099 Destroy(); 00100 }
BYTE CPGFImage::BPP | ( | ) | const [inline] |
Return the number of bits per pixel. Valid values can be 1, 8, 12, 16, 24, 32, 48, 64.
Definition at line 460 of file PGFimage.h.
BYTE CPGFImage::ChannelDepth | ( | ) | const [inline] |
Return bits per channel of the image's encoder.
Definition at line 409 of file PGFimage.h.
00409 { return CurrentChannelDepth(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.
c | A channel index |
Definition at line 404 of file PGFimage.h.
00404 { 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).
Definition at line 447 of file PGFimage.h.
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.
c | A channel index |
Definition at line 397 of file PGFimage.h.
00397 { ASSERT(c >= 0 && c < MaxChannels); return m_width[c]; }
UINT16 CPGFImage::Clamp16 | ( | DataT | v | ) | const [inline, private] |
Definition at line 561 of file PGFimage.h.
UINT32 CPGFImage::Clamp31 | ( | DataT | v | ) | const [inline, private] |
Definition at line 564 of file PGFimage.h.
UINT8 CPGFImage::Clamp4 | ( | DataT | v | ) | const [inline, private] |
Definition at line 551 of file PGFimage.h.
UINT16 CPGFImage::Clamp6 | ( | DataT | v | ) | const [inline, private] |
Definition at line 554 of file PGFimage.h.
UINT8 CPGFImage::Clamp8 | ( | DataT | v | ) | const [inline, private] |
Definition at line 557 of file PGFimage.h.
void CPGFImage::Close | ( | ) | [virtual] |
Close PGF image after opening and reading. Destructor calls this method during destruction.
Definition at line 122 of file PGFimage.cpp.
bool CPGFImage::CompleteHeader | ( | ) | [private] |
Definition at line 208 of file PGFimage.cpp.
00208 { 00209 if (m_header.mode == ImageModeUnknown) { 00210 // undefined mode 00211 switch(m_header.bpp) { 00212 case 1: m_header.mode = ImageModeBitmap; break; 00213 case 8: m_header.mode = ImageModeGrayScale; break; 00214 case 12: m_header.mode = ImageModeRGB12; break; 00215 case 16: m_header.mode = ImageModeRGB16; break; 00216 case 24: m_header.mode = ImageModeRGBColor; break; 00217 case 32: m_header.mode = ImageModeRGBA; break; 00218 case 48: m_header.mode = ImageModeRGB48; break; 00219 default: m_header.mode = ImageModeRGBColor; break; 00220 } 00221 } 00222 if (!m_header.bpp) { 00223 // undefined bpp 00224 switch(m_header.mode) { 00225 case ImageModeBitmap: 00226 m_header.bpp = 1; 00227 break; 00228 case ImageModeIndexedColor: 00229 case ImageModeGrayScale: 00230 m_header.bpp = 8; 00231 break; 00232 case ImageModeRGB12: 00233 m_header.bpp = 12; 00234 break; 00235 case ImageModeRGB16: 00236 case ImageModeGray16: 00237 m_header.bpp = 16; 00238 break; 00239 case ImageModeRGBColor: 00240 case ImageModeLabColor: 00241 m_header.bpp = 24; 00242 break; 00243 case ImageModeRGBA: 00244 case ImageModeCMYKColor: 00245 case ImageModeGray32: 00246 m_header.bpp = 32; 00247 break; 00248 case ImageModeRGB48: 00249 case ImageModeLab48: 00250 m_header.bpp = 48; 00251 break; 00252 case ImageModeCMYK64: 00253 m_header.bpp = 64; 00254 break; 00255 default: 00256 ASSERT(false); 00257 m_header.bpp = 24; 00258 } 00259 } 00260 if (m_header.mode == ImageModeRGBColor && m_header.bpp == 32) { 00261 // change mode 00262 m_header.mode = ImageModeRGBA; 00263 } 00264 if (m_header.mode == ImageModeBitmap && m_header.bpp != 1) return false; 00265 if (m_header.mode == ImageModeIndexedColor && m_header.bpp != 8) return false; 00266 if (m_header.mode == ImageModeGrayScale && m_header.bpp != 8) return false; 00267 if (m_header.mode == ImageModeGray16 && m_header.bpp != 16) return false; 00268 if (m_header.mode == ImageModeGray32 && m_header.bpp != 32) return false; 00269 if (m_header.mode == ImageModeRGBColor && m_header.bpp != 24) return false; 00270 if (m_header.mode == ImageModeRGBA && m_header.bpp != 32) return false; 00271 if (m_header.mode == ImageModeRGB12 && m_header.bpp != 12) return false; 00272 if (m_header.mode == ImageModeRGB16 && m_header.bpp != 16) return false; 00273 if (m_header.mode == ImageModeRGB48 && m_header.bpp != 48) return false; 00274 if (m_header.mode == ImageModeLabColor && m_header.bpp != 24) return false; 00275 if (m_header.mode == ImageModeLab48 && m_header.bpp != 48) return false; 00276 if (m_header.mode == ImageModeCMYKColor && m_header.bpp != 32) return false; 00277 if (m_header.mode == ImageModeCMYK64 && m_header.bpp != 64) return false; 00278 00279 // set number of channels 00280 if (!m_header.channels) { 00281 switch(m_header.mode) { 00282 case ImageModeBitmap: 00283 case ImageModeIndexedColor: 00284 case ImageModeGrayScale: 00285 case ImageModeGray16: 00286 case ImageModeGray32: 00287 m_header.channels = 1; 00288 break; 00289 case ImageModeRGBColor: 00290 case ImageModeRGB12: 00291 case ImageModeRGB16: 00292 case ImageModeRGB48: 00293 case ImageModeLabColor: 00294 case ImageModeLab48: 00295 m_header.channels = 3; 00296 break; 00297 case ImageModeRGBA: 00298 case ImageModeCMYKColor: 00299 case ImageModeCMYK64: 00300 m_header.channels = 4; 00301 break; 00302 default: 00303 return false; 00304 } 00305 } 00306 00307 // store used bits per channel 00308 UINT8 bpc = m_header.bpp/m_header.channels; 00309 if (bpc > 31) bpc = 31; 00310 if (!m_header.usedBitsPerChannel || m_header.usedBitsPerChannel > bpc) { 00311 m_header.usedBitsPerChannel = bpc; 00312 } 00313 00314 return true; 00315 }
void CPGFImage::ComputeLevels | ( | ) | [private] |
Definition at line 804 of file PGFimage.cpp.
00804 { 00805 const int maxThumbnailWidth = 20*FilterWidth; 00806 const int m = __min(m_header.width, m_header.height); 00807 int s = m; 00808 00809 if (m_header.nLevels < 1 || m_header.nLevels > MaxLevel) { 00810 m_header.nLevels = 1; 00811 // compute a good value depending on the size of the image 00812 while (s > maxThumbnailWidth) { 00813 m_header.nLevels++; 00814 s = s/2; 00815 } 00816 } 00817 00818 int levels = m_header.nLevels; // we need a signed value during level reduction 00819 00820 // reduce number of levels if the image size is smaller than FilterWidth*2^levels 00821 s = FilterWidth*(1 << levels); // must be at least the double filter size because of subsampling 00822 while (m < s) { 00823 levels--; 00824 s = s/2; 00825 } 00826 if (levels > MaxLevel) m_header.nLevels = MaxLevel; 00827 else if (levels < 0) m_header.nLevels = 0; 00828 else m_header.nLevels = (UINT8)levels; 00829 00830 // used in Write when PM_Absolute 00831 m_percent = pow(0.25, m_header.nLevels); 00832 00833 ASSERT(0 <= m_header.nLevels && m_header.nLevels <= MaxLevel); 00834 }
void CPGFImage::ConfigureDecoder | ( | bool | useOMP = true , |
|
bool | skipUserData = false | |||
) | [inline] |
Configures the decoder.
useOMP | Use parallel threading with Open MP during decoding. Default value: true. Influences the decoding only if the codec has been compiled with OpenMP support. | |
skipUserData | The file might contain user data (metadata). User data ist usually read during Open and stored in memory. Set this flag to false when storing in memory is not needed. |
Definition at line 266 of file PGFimage.h.
00266 { m_useOMPinDecoder = useOMP; m_skipUserData = skipUserData; }
void CPGFImage::ConfigureEncoder | ( | bool | useOMP = true , |
|
bool | favorSpeedOverSize = false | |||
) | [inline] |
Configures the encoder.
useOMP | Use parallel threading with Open MP during encoding. Default value: true. Influences the encoding only if the codec has been compiled with OpenMP support. | |
favorSpeedOverSize | Favors encoding speed over compression ratio. Default value: false |
Definition at line 260 of file PGFimage.h.
00260 { m_useOMPinEncoder = useOMP; m_favorSpeedOverSize = favorSpeedOverSize; }
static BYTE CPGFImage::CurrentChannelDepth | ( | BYTE | version = PGFVersion |
) | [inline, static] |
Compute and return codec version.
Definition at line 508 of file PGFimage.h.
00508 { return (version & PGF32) ? 32 : 16; }
BYTE CPGFImage::CurrentVersion | ( | BYTE | version = PGFVersion |
) | [static] |
Compute and return codec version.
Return version
Definition at line 720 of file PGFimage.cpp.
void CPGFImage::Destroy | ( | ) | [virtual] |
Destroy internal data structures. Destructor calls this method during destruction.
Definition at line 105 of file PGFimage.cpp.
00105 { 00106 Close(); 00107 00108 for (int i=0; i < m_header.channels; i++) { 00109 delete m_wtChannel[i]; m_wtChannel[i]=0; // also deletes m_channel 00110 m_channel[i] = 0; 00111 } 00112 delete[] m_postHeader.userData; m_postHeader.userData = 0; m_postHeader.userDataLen = 0; 00113 delete[] m_levelLength; m_levelLength = 0; 00114 delete m_encoder; m_encoder = NULL; 00115 00116 m_userDataPos = 0; 00117 }
void CPGFImage::Downsample | ( | int | nChannel | ) | [private] |
Definition at line 760 of file PGFimage.cpp.
00760 { 00761 ASSERT(ch > 0); 00762 00763 const int w = m_width[0]; 00764 const int w2 = w/2; 00765 const int h2 = m_height[0]/2; 00766 const int oddW = w%2; // don't use bool -> problems with MaxSpeed optimization 00767 const int oddH = m_height[0]%2; // " 00768 int loPos = 0; 00769 int hiPos = w; 00770 int sampledPos = 0; 00771 DataT* buff = m_channel[ch]; ASSERT(buff); 00772 00773 for (int i=0; i < h2; i++) { 00774 for (int j=0; j < w2; j++) { 00775 // compute average of pixel block 00776 buff[sampledPos] = (buff[loPos] + buff[loPos + 1] + buff[hiPos] + buff[hiPos + 1]) >> 2; 00777 loPos += 2; hiPos += 2; 00778 sampledPos++; 00779 } 00780 if (oddW) { 00781 buff[sampledPos] = (buff[loPos] + buff[hiPos]) >> 1; 00782 loPos++; hiPos++; 00783 sampledPos++; 00784 } 00785 loPos += w; hiPos += w; 00786 } 00787 if (oddH) { 00788 for (int j=0; j < w2; j++) { 00789 buff[sampledPos] = (buff[loPos] + buff[loPos+1]) >> 1; 00790 loPos += 2; hiPos += 2; 00791 sampledPos++; 00792 } 00793 if (oddW) { 00794 buff[sampledPos] = buff[loPos]; 00795 } 00796 } 00797 00798 // downsampled image has half width and half height 00799 m_width[ch] = (m_width[ch] + 1)/2; 00800 m_height[ch] = (m_height[ch] + 1)/2; 00801 }
void CPGFImage::GetBitmap | ( | int | pitch, | |
UINT8 * | buff, | |||
BYTE | bpp, | |||
int | channelMap[] = NULL , |
|||
CallbackPtr | cb = NULL , |
|||
void * | data = NULL | |||
) | const |
Get image data in interleaved format: (ordering of RGB data is BGR[A]) Upsampling, YUV to RGB transform and interleaving are done here to reduce the number of passes over the data. The absolute value of pitch is the number of bytes of an image row of the given image buffer. If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row). if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte). The sequence of output channels in the output image buffer does not need to be the same as provided by PGF. In case of different sequences you have to provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode. If your provided image buffer expects a channel sequence ARGB, then the channelMap looks like { 3, 2, 1, 0 }. It might throw an IOException.
pitch | The number of bytes of a row of the image buffer. | |
buff | An image buffer. | |
bpp | The number of bits per pixel used in image buffer. | |
channelMap | A integer array containing the mapping of PGF channel ordering to expected channel ordering. | |
cb | A pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding. | |
data | Data Pointer to C++ class container to host callback procedure. |
Definition at line 1720 of file PGFimage.cpp.
01720 { 01721 ASSERT(buff); 01722 UINT32 w = m_width[0]; 01723 UINT32 h = m_height[0]; 01724 UINT8* targetBuff = 0; // used if ROI is used 01725 UINT8* buffStart = 0; // used if ROI is used 01726 int targetPitch = 0; // used if ROI is used 01727 01728 #ifdef __PGFROISUPPORT__ 01729 const PGFRect& roi = (ROIisSupported()) ? m_wtChannel[0]->GetROI(m_currentLevel) : PGFRect(0, 0, w, h); // roi is usually larger than m_roi 01730 const PGFRect levelRoi(LevelWidth(m_roi.left, m_currentLevel), LevelHeight(m_roi.top, m_currentLevel), LevelWidth(m_roi.Width(), m_currentLevel), LevelHeight(m_roi.Height(), m_currentLevel)); 01731 ASSERT(w <= roi.Width() && h <= roi.Height()); 01732 ASSERT(roi.left <= levelRoi.left && levelRoi.right <= roi.right); 01733 ASSERT(roi.top <= levelRoi.top && levelRoi.bottom <= roi.bottom); 01734 01735 if (ROIisSupported() && (levelRoi.Width() < w || levelRoi.Height() < h)) { 01736 // ROI is used -> create a temporary image buffer for roi 01737 // compute pitch 01738 targetPitch = pitch; 01739 pitch = AlignWordPos(w*bpp)/8; 01740 01741 // create temporary output buffer 01742 targetBuff = buff; 01743 buff = buffStart = new(std::nothrow) UINT8[pitch*h]; 01744 if (!buff) ReturnWithError(InsufficientMemory); 01745 } 01746 #endif 01747 01748 const bool wOdd = (1 == w%2); 01749 01750 const double dP = 1.0/h; 01751 int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels); 01752 if (channelMap == NULL) channelMap = defMap; 01753 int sampledPos = 0, yPos = 0; 01754 DataT uAvg, vAvg; 01755 double percent = 0; 01756 UINT32 i, j; 01757 01758 switch(m_header.mode) { 01759 case ImageModeBitmap: 01760 { 01761 ASSERT(m_header.channels == 1); 01762 ASSERT(m_header.bpp == 1); 01763 ASSERT(bpp == 1); 01764 01765 const UINT32 w2 = (w + 7)/8; 01766 DataT* y = m_channel[0]; ASSERT(y); 01767 01768 for (i=0; i < h; i++) { 01769 01770 for (j=0; j < w2; j++) { 01771 buff[j] = Clamp8(y[yPos++] + YUVoffset8); 01772 } 01773 yPos += w - w2; 01774 01775 //UINT32 cnt = w; 01776 //for (j=0; j < w2; j++) { 01777 // buff[j] = 0; 01778 // for (int k=0; k < 8; k++) { 01779 // if (cnt) { 01780 // buff[j] <<= 1; 01781 // buff[j] |= (1 & (y[yPos++] - YUVoffset8)); 01782 // cnt--; 01783 // } 01784 // } 01785 //} 01786 buff += pitch; 01787 01788 if (cb) { 01789 percent += dP; 01790 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01791 } 01792 } 01793 break; 01794 } 01795 case ImageModeIndexedColor: 01796 case ImageModeGrayScale: 01797 case ImageModeHSLColor: 01798 case ImageModeHSBColor: 01799 { 01800 ASSERT(m_header.channels >= 1); 01801 ASSERT(m_header.bpp == m_header.channels*8); 01802 ASSERT(bpp%8 == 0); 01803 01804 int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels); 01805 01806 for (i=0; i < h; i++) { 01807 cnt = 0; 01808 for (j=0; j < w; j++) { 01809 for (int c=0; c < m_header.channels; c++) { 01810 buff[cnt + channelMap[c]] = Clamp8(m_channel[c][yPos] + YUVoffset8); 01811 } 01812 cnt += channels; 01813 yPos++; 01814 } 01815 buff += pitch; 01816 01817 if (cb) { 01818 percent += dP; 01819 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01820 } 01821 } 01822 break; 01823 } 01824 case ImageModeGray16: 01825 { 01826 ASSERT(m_header.channels >= 1); 01827 ASSERT(m_header.bpp == m_header.channels*16); 01828 01829 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); 01830 int cnt, channels; 01831 01832 if (bpp%16 == 0) { 01833 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); 01834 UINT16 *buff16 = (UINT16 *)buff; 01835 int pitch16 = pitch/2; 01836 channels = bpp/16; ASSERT(channels >= m_header.channels); 01837 01838 for (i=0; i < h; i++) { 01839 cnt = 0; 01840 for (j=0; j < w; j++) { 01841 for (int c=0; c < m_header.channels; c++) { 01842 buff16[cnt + channelMap[c]] = Clamp16((m_channel[c][yPos] + yuvOffset16) << shift); 01843 } 01844 cnt += channels; 01845 yPos++; 01846 } 01847 buff16 += pitch16; 01848 01849 if (cb) { 01850 percent += dP; 01851 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01852 } 01853 } 01854 } else { 01855 ASSERT(bpp%8 == 0); 01856 const int shift = __max(0, UsedBitsPerChannel() - 8); 01857 channels = bpp/8; ASSERT(channels >= m_header.channels); 01858 01859 for (i=0; i < h; i++) { 01860 cnt = 0; 01861 for (j=0; j < w; j++) { 01862 for (int c=0; c < m_header.channels; c++) { 01863 buff[cnt + channelMap[c]] = Clamp8((m_channel[c][yPos] + yuvOffset16) >> shift); 01864 } 01865 cnt += channels; 01866 yPos++; 01867 } 01868 buff += pitch; 01869 01870 if (cb) { 01871 percent += dP; 01872 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01873 } 01874 } 01875 } 01876 break; 01877 } 01878 case ImageModeRGBColor: 01879 { 01880 ASSERT(m_header.channels == 3); 01881 ASSERT(m_header.bpp == m_header.channels*8); 01882 ASSERT(bpp%8 == 0); 01883 ASSERT(bpp >= m_header.bpp); 01884 01885 DataT* y = m_channel[0]; ASSERT(y); 01886 DataT* u = m_channel[1]; ASSERT(u); 01887 DataT* v = m_channel[2]; ASSERT(v); 01888 UINT8 *buffg = &buff[channelMap[1]], 01889 *buffr = &buff[channelMap[2]], 01890 *buffb = &buff[channelMap[0]]; 01891 UINT8 g; 01892 int cnt, channels = bpp/8; 01893 if(m_downsample){ 01894 for (i=0; i < h; i++) { 01895 if (i%2) sampledPos -= (w + 1)/2; 01896 cnt = 0; 01897 for (j=0; j < w; j++) { 01898 // image was downsampled 01899 uAvg = u[sampledPos]; 01900 vAvg = v[sampledPos]; 01901 // Yuv 01902 buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator 01903 buffr[cnt] = Clamp8(uAvg + g); 01904 buffb[cnt] = Clamp8(vAvg + g); 01905 yPos++; 01906 cnt += channels; 01907 if (j%2) sampledPos++; 01908 } 01909 buffb += pitch; 01910 buffg += pitch; 01911 buffr += pitch; 01912 if (wOdd) sampledPos++; 01913 if (cb) { 01914 percent += dP; 01915 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01916 } 01917 } 01918 }else{ 01919 for (i=0; i < h; i++) { 01920 cnt = 0; 01921 for (j = 0; j < w; j++) { 01922 uAvg = u[yPos]; 01923 vAvg = v[yPos]; 01924 // Yuv 01925 buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator 01926 buffr[cnt] = Clamp8(uAvg + g); 01927 buffb[cnt] = Clamp8(vAvg + g); 01928 yPos++; 01929 cnt += channels; 01930 } 01931 buffb += pitch; 01932 buffg += pitch; 01933 buffr += pitch; 01934 01935 if (cb) { 01936 percent += dP; 01937 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01938 } 01939 } 01940 } 01941 break; 01942 } 01943 case ImageModeRGB48: 01944 { 01945 ASSERT(m_header.channels == 3); 01946 ASSERT(m_header.bpp == 48); 01947 01948 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); 01949 01950 DataT* y = m_channel[0]; ASSERT(y); 01951 DataT* u = m_channel[1]; ASSERT(u); 01952 DataT* v = m_channel[2]; ASSERT(v); 01953 int cnt, channels; 01954 DataT g; 01955 01956 if (bpp >= 48 && bpp%16 == 0) { 01957 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); 01958 UINT16 *buff16 = (UINT16 *)buff; 01959 int pitch16 = pitch/2; 01960 channels = bpp/16; ASSERT(channels >= m_header.channels); 01961 01962 for (i=0; i < h; i++) { 01963 if (i%2) sampledPos -= (w + 1)/2; 01964 cnt = 0; 01965 for (j=0; j < w; j++) { 01966 if (m_downsample) { 01967 // image was downsampled 01968 uAvg = u[sampledPos]; 01969 vAvg = v[sampledPos]; 01970 } else { 01971 uAvg = u[yPos]; 01972 vAvg = v[yPos]; 01973 } 01974 // Yuv 01975 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator 01976 buff16[cnt + channelMap[1]] = Clamp16(g << shift); 01977 buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift); 01978 buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift); 01979 yPos++; 01980 cnt += channels; 01981 if (j%2) sampledPos++; 01982 } 01983 buff16 += pitch16; 01984 if (wOdd) sampledPos++; 01985 01986 if (cb) { 01987 percent += dP; 01988 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01989 } 01990 } 01991 } else { 01992 ASSERT(bpp%8 == 0); 01993 const int shift = __max(0, UsedBitsPerChannel() - 8); 01994 channels = bpp/8; ASSERT(channels >= m_header.channels); 01995 01996 for (i=0; i < h; i++) { 01997 if (i%2) sampledPos -= (w + 1)/2; 01998 cnt = 0; 01999 for (j=0; j < w; j++) { 02000 if (m_downsample) { 02001 // image was downsampled 02002 uAvg = u[sampledPos]; 02003 vAvg = v[sampledPos]; 02004 } else { 02005 uAvg = u[yPos]; 02006 vAvg = v[yPos]; 02007 } 02008 // Yuv 02009 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator 02010 buff[cnt + channelMap[1]] = Clamp8(g >> shift); 02011 buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift); 02012 buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift); 02013 yPos++; 02014 cnt += channels; 02015 if (j%2) sampledPos++; 02016 } 02017 buff += pitch; 02018 if (wOdd) sampledPos++; 02019 02020 if (cb) { 02021 percent += dP; 02022 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02023 } 02024 } 02025 } 02026 break; 02027 } 02028 case ImageModeLabColor: 02029 { 02030 ASSERT(m_header.channels == 3); 02031 ASSERT(m_header.bpp == m_header.channels*8); 02032 ASSERT(bpp%8 == 0); 02033 02034 DataT* l = m_channel[0]; ASSERT(l); 02035 DataT* a = m_channel[1]; ASSERT(a); 02036 DataT* b = m_channel[2]; ASSERT(b); 02037 int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels); 02038 02039 for (i=0; i < h; i++) { 02040 if (i%2) sampledPos -= (w + 1)/2; 02041 cnt = 0; 02042 for (j=0; j < w; j++) { 02043 if (m_downsample) { 02044 // image was downsampled 02045 uAvg = a[sampledPos]; 02046 vAvg = b[sampledPos]; 02047 } else { 02048 uAvg = a[yPos]; 02049 vAvg = b[yPos]; 02050 } 02051 buff[cnt + channelMap[0]] = Clamp8(l[yPos] + YUVoffset8); 02052 buff[cnt + channelMap[1]] = Clamp8(uAvg + YUVoffset8); 02053 buff[cnt + channelMap[2]] = Clamp8(vAvg + YUVoffset8); 02054 cnt += channels; 02055 yPos++; 02056 if (j%2) sampledPos++; 02057 } 02058 buff += pitch; 02059 if (wOdd) sampledPos++; 02060 02061 if (cb) { 02062 percent += dP; 02063 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02064 } 02065 } 02066 break; 02067 } 02068 case ImageModeLab48: 02069 { 02070 ASSERT(m_header.channels == 3); 02071 ASSERT(m_header.bpp == m_header.channels*16); 02072 02073 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); 02074 02075 DataT* l = m_channel[0]; ASSERT(l); 02076 DataT* a = m_channel[1]; ASSERT(a); 02077 DataT* b = m_channel[2]; ASSERT(b); 02078 int cnt, channels; 02079 02080 if (bpp%16 == 0) { 02081 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); 02082 UINT16 *buff16 = (UINT16 *)buff; 02083 int pitch16 = pitch/2; 02084 channels = bpp/16; ASSERT(channels >= m_header.channels); 02085 02086 for (i=0; i < h; i++) { 02087 if (i%2) sampledPos -= (w + 1)/2; 02088 cnt = 0; 02089 for (j=0; j < w; j++) { 02090 if (m_downsample) { 02091 // image was downsampled 02092 uAvg = a[sampledPos]; 02093 vAvg = b[sampledPos]; 02094 } else { 02095 uAvg = a[yPos]; 02096 vAvg = b[yPos]; 02097 } 02098 buff16[cnt + channelMap[0]] = Clamp16((l[yPos] + yuvOffset16) << shift); 02099 buff16[cnt + channelMap[1]] = Clamp16((uAvg + yuvOffset16) << shift); 02100 buff16[cnt + channelMap[2]] = Clamp16((vAvg + yuvOffset16) << shift); 02101 cnt += channels; 02102 yPos++; 02103 if (j%2) sampledPos++; 02104 } 02105 buff16 += pitch16; 02106 if (wOdd) sampledPos++; 02107 02108 if (cb) { 02109 percent += dP; 02110 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02111 } 02112 } 02113 } else { 02114 ASSERT(bpp%8 == 0); 02115 const int shift = __max(0, UsedBitsPerChannel() - 8); 02116 channels = bpp/8; ASSERT(channels >= m_header.channels); 02117 02118 for (i=0; i < h; i++) { 02119 if (i%2) sampledPos -= (w + 1)/2; 02120 cnt = 0; 02121 for (j=0; j < w; j++) { 02122 if (m_downsample) { 02123 // image was downsampled 02124 uAvg = a[sampledPos]; 02125 vAvg = b[sampledPos]; 02126 } else { 02127 uAvg = a[yPos]; 02128 vAvg = b[yPos]; 02129 } 02130 buff[cnt + channelMap[0]] = Clamp8((l[yPos] + yuvOffset16) >> shift); 02131 buff[cnt + channelMap[1]] = Clamp8((uAvg + yuvOffset16) >> shift); 02132 buff[cnt + channelMap[2]] = Clamp8((vAvg + yuvOffset16) >> shift); 02133 cnt += channels; 02134 yPos++; 02135 if (j%2) sampledPos++; 02136 } 02137 buff += pitch; 02138 if (wOdd) sampledPos++; 02139 02140 if (cb) { 02141 percent += dP; 02142 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02143 } 02144 } 02145 } 02146 break; 02147 } 02148 case ImageModeRGBA: 02149 case ImageModeCMYKColor: 02150 { 02151 ASSERT(m_header.channels == 4); 02152 ASSERT(m_header.bpp == m_header.channels*8); 02153 ASSERT(bpp%8 == 0); 02154 02155 DataT* y = m_channel[0]; ASSERT(y); 02156 DataT* u = m_channel[1]; ASSERT(u); 02157 DataT* v = m_channel[2]; ASSERT(v); 02158 DataT* a = m_channel[3]; ASSERT(a); 02159 UINT8 g, aAvg; 02160 int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels); 02161 02162 for (i=0; i < h; i++) { 02163 if (i%2) sampledPos -= (w + 1)/2; 02164 cnt = 0; 02165 for (j=0; j < w; j++) { 02166 if (m_downsample) { 02167 // image was downsampled 02168 uAvg = u[sampledPos]; 02169 vAvg = v[sampledPos]; 02170 aAvg = Clamp8(a[sampledPos] + YUVoffset8); 02171 } else { 02172 uAvg = u[yPos]; 02173 vAvg = v[yPos]; 02174 aAvg = Clamp8(a[yPos] + YUVoffset8); 02175 } 02176 // Yuv 02177 buff[cnt + channelMap[1]] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator 02178 buff[cnt + channelMap[2]] = Clamp8(uAvg + g); 02179 buff[cnt + channelMap[0]] = Clamp8(vAvg + g); 02180 buff[cnt + channelMap[3]] = aAvg; 02181 yPos++; 02182 cnt += channels; 02183 if (j%2) sampledPos++; 02184 } 02185 buff += pitch; 02186 if (wOdd) sampledPos++; 02187 02188 if (cb) { 02189 percent += dP; 02190 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02191 } 02192 } 02193 break; 02194 } 02195 case ImageModeCMYK64: 02196 { 02197 ASSERT(m_header.channels == 4); 02198 ASSERT(m_header.bpp == 64); 02199 02200 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); 02201 02202 DataT* y = m_channel[0]; ASSERT(y); 02203 DataT* u = m_channel[1]; ASSERT(u); 02204 DataT* v = m_channel[2]; ASSERT(v); 02205 DataT* a = m_channel[3]; ASSERT(a); 02206 DataT g, aAvg; 02207 int cnt, channels; 02208 02209 if (bpp%16 == 0) { 02210 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); 02211 UINT16 *buff16 = (UINT16 *)buff; 02212 int pitch16 = pitch/2; 02213 channels = bpp/16; ASSERT(channels >= m_header.channels); 02214 02215 for (i=0; i < h; i++) { 02216 if (i%2) sampledPos -= (w + 1)/2; 02217 cnt = 0; 02218 for (j=0; j < w; j++) { 02219 if (m_downsample) { 02220 // image was downsampled 02221 uAvg = u[sampledPos]; 02222 vAvg = v[sampledPos]; 02223 aAvg = a[sampledPos] + yuvOffset16; 02224 } else { 02225 uAvg = u[yPos]; 02226 vAvg = v[yPos]; 02227 aAvg = a[yPos] + yuvOffset16; 02228 } 02229 // Yuv 02230 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator 02231 buff16[cnt + channelMap[1]] = Clamp16(g << shift); 02232 buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift); 02233 buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift); 02234 buff16[cnt + channelMap[3]] = Clamp16(aAvg << shift); 02235 yPos++; 02236 cnt += channels; 02237 if (j%2) sampledPos++; 02238 } 02239 buff16 += pitch16; 02240 if (wOdd) sampledPos++; 02241 02242 if (cb) { 02243 percent += dP; 02244 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02245 } 02246 } 02247 } else { 02248 ASSERT(bpp%8 == 0); 02249 const int shift = __max(0, UsedBitsPerChannel() - 8); 02250 channels = bpp/8; ASSERT(channels >= m_header.channels); 02251 02252 for (i=0; i < h; i++) { 02253 if (i%2) sampledPos -= (w + 1)/2; 02254 cnt = 0; 02255 for (j=0; j < w; j++) { 02256 if (m_downsample) { 02257 // image was downsampled 02258 uAvg = u[sampledPos]; 02259 vAvg = v[sampledPos]; 02260 aAvg = a[sampledPos] + yuvOffset16; 02261 } else { 02262 uAvg = u[yPos]; 02263 vAvg = v[yPos]; 02264 aAvg = a[yPos] + yuvOffset16; 02265 } 02266 // Yuv 02267 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator 02268 buff[cnt + channelMap[1]] = Clamp8(g >> shift); 02269 buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift); 02270 buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift); 02271 buff[cnt + channelMap[3]] = Clamp8(aAvg >> shift); 02272 yPos++; 02273 cnt += channels; 02274 if (j%2) sampledPos++; 02275 } 02276 buff += pitch; 02277 if (wOdd) sampledPos++; 02278 02279 if (cb) { 02280 percent += dP; 02281 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02282 } 02283 } 02284 } 02285 break; 02286 } 02287 #ifdef __PGF32SUPPORT__ 02288 case ImageModeGray32: 02289 { 02290 ASSERT(m_header.channels == 1); 02291 ASSERT(m_header.bpp == 32); 02292 02293 const int yuvOffset31 = 1 << (UsedBitsPerChannel() - 1); 02294 02295 DataT* y = m_channel[0]; ASSERT(y); 02296 02297 if (bpp == 32) { 02298 const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0); 02299 UINT32 *buff32 = (UINT32 *)buff; 02300 int pitch32 = pitch/4; 02301 02302 for (i=0; i < h; i++) { 02303 for (j=0; j < w; j++) { 02304 buff32[j] = Clamp31((y[yPos++] + yuvOffset31) << shift); 02305 } 02306 buff32 += pitch32; 02307 02308 if (cb) { 02309 percent += dP; 02310 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02311 } 02312 } 02313 } else if (bpp == 16) { 02314 const int usedBits = UsedBitsPerChannel(); 02315 UINT16 *buff16 = (UINT16 *)buff; 02316 int pitch16 = pitch/2; 02317 02318 if (usedBits < 16) { 02319 const int shift = 16 - usedBits; 02320 for (i=0; i < h; i++) { 02321 for (j=0; j < w; j++) { 02322 buff16[j] = Clamp16((y[yPos++] + yuvOffset31) << shift); 02323 } 02324 buff16 += pitch16; 02325 02326 if (cb) { 02327 percent += dP; 02328 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02329 } 02330 } 02331 } else { 02332 const int shift = __max(0, usedBits - 16); 02333 for (i=0; i < h; i++) { 02334 for (j=0; j < w; j++) { 02335 buff16[j] = Clamp16((y[yPos++] + yuvOffset31) >> shift); 02336 } 02337 buff16 += pitch16; 02338 02339 if (cb) { 02340 percent += dP; 02341 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02342 } 02343 } 02344 } 02345 } else { 02346 ASSERT(bpp == 8); 02347 const int shift = __max(0, UsedBitsPerChannel() - 8); 02348 02349 for (i=0; i < h; i++) { 02350 for (j=0; j < w; j++) { 02351 buff[j] = Clamp8((y[yPos++] + yuvOffset31) >> shift); 02352 } 02353 buff += pitch; 02354 02355 if (cb) { 02356 percent += dP; 02357 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02358 } 02359 } 02360 } 02361 break; 02362 } 02363 #endif 02364 case ImageModeRGB12: 02365 { 02366 ASSERT(m_header.channels == 3); 02367 ASSERT(m_header.bpp == m_header.channels*4); 02368 ASSERT(bpp == m_header.channels*4); 02369 ASSERT(!m_downsample); 02370 02371 DataT* y = m_channel[0]; ASSERT(y); 02372 DataT* u = m_channel[1]; ASSERT(u); 02373 DataT* v = m_channel[2]; ASSERT(v); 02374 UINT16 yval; 02375 int cnt; 02376 02377 for (i=0; i < h; i++) { 02378 cnt = 0; 02379 for (j=0; j < w; j++) { 02380 // Yuv 02381 uAvg = u[yPos]; 02382 vAvg = v[yPos]; 02383 yval = Clamp4(y[yPos++] + YUVoffset4 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator 02384 if (j%2 == 0) { 02385 buff[cnt] = UINT8(Clamp4(vAvg + yval) | (yval << 4)); 02386 cnt++; 02387 buff[cnt] = Clamp4(uAvg + yval); 02388 } else { 02389 buff[cnt] |= Clamp4(vAvg + yval) << 4; 02390 cnt++; 02391 buff[cnt] = UINT8(yval | (Clamp4(uAvg + yval) << 4)); 02392 cnt++; 02393 } 02394 } 02395 buff += pitch; 02396 02397 if (cb) { 02398 percent += dP; 02399 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02400 } 02401 } 02402 break; 02403 } 02404 case ImageModeRGB16: 02405 { 02406 ASSERT(m_header.channels == 3); 02407 ASSERT(m_header.bpp == 16); 02408 ASSERT(bpp == 16); 02409 ASSERT(!m_downsample); 02410 02411 DataT* y = m_channel[0]; ASSERT(y); 02412 DataT* u = m_channel[1]; ASSERT(u); 02413 DataT* v = m_channel[2]; ASSERT(v); 02414 UINT16 yval; 02415 UINT16 *buff16 = (UINT16 *)buff; 02416 int pitch16 = pitch/2; 02417 02418 for (i=0; i < h; i++) { 02419 for (j=0; j < w; j++) { 02420 // Yuv 02421 uAvg = u[yPos]; 02422 vAvg = v[yPos]; 02423 yval = Clamp6(y[yPos++] + YUVoffset6 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator 02424 buff16[j] = (yval << 5) | ((Clamp6(uAvg + yval) >> 1) << 11) | (Clamp6(vAvg + yval) >> 1); 02425 } 02426 buff16 += pitch16; 02427 02428 if (cb) { 02429 percent += dP; 02430 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02431 } 02432 } 02433 break; 02434 } 02435 default: 02436 ASSERT(false); 02437 } 02438 02439 #ifdef __PGFROISUPPORT__ 02440 if (targetBuff) { 02441 // copy valid ROI (m_roi) from temporary buffer (roi) to target buffer 02442 if (bpp%8 == 0) { 02443 BYTE bypp = bpp/8; 02444 buff = buffStart + (levelRoi.top - roi.top)*pitch + (levelRoi.left - roi.left)*bypp; 02445 w = levelRoi.Width()*bypp; 02446 h = levelRoi.Height(); 02447 02448 for (i=0; i < h; i++) { 02449 for (j=0; j < w; j++) { 02450 targetBuff[j] = buff[j]; 02451 } 02452 targetBuff += targetPitch; 02453 buff += pitch; 02454 } 02455 } else { 02456 // to do 02457 } 02458 02459 delete[] buffStart; buffStart = 0; 02460 } 02461 #endif 02462 }
DataT* CPGFImage::GetChannel | ( | int | c = 0 |
) | [inline] |
Return an internal YUV image channel.
c | A channel index |
Definition at line 321 of file PGFimage.h.
00321 { ASSERT(c >= 0 && c < MaxChannels); return m_channel[c]; }
const RGBQUAD* CPGFImage::GetColorTable | ( | ) | const [inline] |
Definition at line 334 of file PGFimage.h.
00334 { 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.
iFirstColor | The color table index of the first entry to retrieve. | |
nColors | The number of color table entries to retrieve. | |
prgbColors | A pointer to the array of RGBQUAD structures to retrieve the color table entries. |
Definition at line 1292 of file PGFimage.cpp.
01292 { 01293 if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError); 01294 01295 for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) { 01296 prgbColors[j] = m_postHeader.clut[i]; 01297 } 01298 }
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(...).
Definition at line 613 of file PGFimage.cpp.
00613 { 00614 ASSERT(m_decoder); 00615 return m_decoder->GetEncodedHeaderLength(); 00616 }
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(...).
level | The image level |
Definition at line 370 of file PGFimage.h.
00370 { 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.
Definition at line 339 of file PGFimage.h.
00339 { 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.
Definition at line 345 of file PGFimage.h.
00345 { return (1 << m_header.usedBitsPerChannel) - 1; }
const UINT8 * CPGFImage::GetUserData | ( | UINT32 & | size | ) | const |
Return user data and size of user data. Precondition: The PGF image has been opened with a call of Open(...).
size | [out] Size of user data in bytes. |
Definition at line 322 of file PGFimage.cpp.
00322 { 00323 size = m_postHeader.userDataLen; 00324 return m_postHeader.userData; 00325 }
UINT64 CPGFImage::GetUserDataPos | ( | ) | const [inline] |
Return the stream position of the user data or 0. Precondition: The PGF image has been opened with a call of Open(...).
Definition at line 350 of file PGFimage.h.
00350 { return m_userDataPos; }
void CPGFImage::GetYUV | ( | int | pitch, | |
DataT * | buff, | |||
BYTE | bpp, | |||
int | channelMap[] = NULL , |
|||
CallbackPtr | cb = NULL , |
|||
void * | data = NULL | |||
) | const |
Get YUV image data in interleaved format: (ordering is YUV[A]) The absolute value of pitch is the number of bytes of an image row of the given image buffer. If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row). if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte). The sequence of output channels in the output image buffer does not need to be the same as provided by PGF. In case of different sequences you have to provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode. If your provided image buffer expects a channel sequence VUY, then the channelMap looks like { 2, 1, 0 }. It might throw an IOException.
pitch | The number of bytes of a row of the image buffer. | |
buff | An image buffer. | |
bpp | The number of bits per pixel used in image buffer. | |
channelMap | A integer array containing the mapping of PGF channel ordering to expected channel ordering. | |
cb | A pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding. | |
data | Data Pointer to C++ class container to host callback procedure. |
Get YUV image data in interleaved format: (ordering is YUV[A]) The absolute value of pitch is the number of bytes of an image row of the given image buffer. If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row). if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte). The sequence of output channels in the output image buffer does not need to be the same as provided by PGF. In case of different sequences you have to provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode. If your provided image buffer expects a channel sequence VUY, then the channelMap looks like { 2, 1, 0 }. It might throw an IOException.
pitch | The number of bytes of a row of the image buffer. | |
buff | An image buffer. | |
bpp | The number of bits per pixel used in image buffer. | |
channelMap | A integer array containing the mapping of PGF channel ordering to expected channel ordering. | |
cb | A pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding. |
Definition at line 2478 of file PGFimage.cpp.
02478 { 02479 ASSERT(buff); 02480 const UINT32 w = m_width[0]; 02481 const UINT32 h = m_height[0]; 02482 const bool wOdd = (1 == w%2); 02483 const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32); 02484 const int pitch2 = pitch/DataTSize; 02485 const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16; 02486 const double dP = 1.0/h; 02487 02488 int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels); 02489 if (channelMap == NULL) channelMap = defMap; 02490 int sampledPos = 0, yPos = 0; 02491 DataT uAvg, vAvg; 02492 double percent = 0; 02493 UINT32 i, j; 02494 02495 if (m_header.channels == 3) { 02496 ASSERT(bpp%dataBits == 0); 02497 02498 DataT* y = m_channel[0]; ASSERT(y); 02499 DataT* u = m_channel[1]; ASSERT(u); 02500 DataT* v = m_channel[2]; ASSERT(v); 02501 int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels); 02502 02503 for (i=0; i < h; i++) { 02504 if (i%2) sampledPos -= (w + 1)/2; 02505 cnt = 0; 02506 for (j=0; j < w; j++) { 02507 if (m_downsample) { 02508 // image was downsampled 02509 uAvg = u[sampledPos]; 02510 vAvg = v[sampledPos]; 02511 } else { 02512 uAvg = u[yPos]; 02513 vAvg = v[yPos]; 02514 } 02515 buff[cnt + channelMap[0]] = y[yPos]; 02516 buff[cnt + channelMap[1]] = uAvg; 02517 buff[cnt + channelMap[2]] = vAvg; 02518 yPos++; 02519 cnt += channels; 02520 if (j%2) sampledPos++; 02521 } 02522 buff += pitch2; 02523 if (wOdd) sampledPos++; 02524 02525 if (cb) { 02526 percent += dP; 02527 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02528 } 02529 } 02530 } else if (m_header.channels == 4) { 02531 ASSERT(m_header.bpp == m_header.channels*8); 02532 ASSERT(bpp%dataBits == 0); 02533 02534 DataT* y = m_channel[0]; ASSERT(y); 02535 DataT* u = m_channel[1]; ASSERT(u); 02536 DataT* v = m_channel[2]; ASSERT(v); 02537 DataT* a = m_channel[3]; ASSERT(a); 02538 UINT8 aAvg; 02539 int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels); 02540 02541 for (i=0; i < h; i++) { 02542 if (i%2) sampledPos -= (w + 1)/2; 02543 cnt = 0; 02544 for (j=0; j < w; j++) { 02545 if (m_downsample) { 02546 // image was downsampled 02547 uAvg = u[sampledPos]; 02548 vAvg = v[sampledPos]; 02549 aAvg = Clamp8(a[sampledPos] + yuvOffset); 02550 } else { 02551 uAvg = u[yPos]; 02552 vAvg = v[yPos]; 02553 aAvg = Clamp8(a[yPos] + yuvOffset); 02554 } 02555 // Yuv 02556 buff[cnt + channelMap[0]] = y[yPos]; 02557 buff[cnt + channelMap[1]] = uAvg; 02558 buff[cnt + channelMap[2]] = vAvg; 02559 buff[cnt + channelMap[3]] = aAvg; 02560 yPos++; 02561 cnt += channels; 02562 if (j%2) sampledPos++; 02563 } 02564 buff += pitch2; 02565 if (wOdd) sampledPos++; 02566 02567 if (cb) { 02568 percent += dP; 02569 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02570 } 02571 } 02572 } 02573 }
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.
level | A level |
Definition at line 423 of file PGFimage.h.
00423 { ASSERT(level >= 0); return LevelHeight(m_header.height, level); }
void CPGFImage::ImportBitmap | ( | int | pitch, | |
UINT8 * | buff, | |||
BYTE | bpp, | |||
int | channelMap[] = NULL , |
|||
CallbackPtr | cb = NULL , |
|||
void * | data = NULL | |||
) |
Import an image from a specified image buffer. This method is usually called before Write(...) and after SetHeader(...). The absolute value of pitch is the number of bytes of an image row. If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row). If pitch is positive, then buff points to the first row of a top-down image (first byte). The sequence of input channels in the input image buffer does not need to be the same as expected from PGF. In case of different sequences you have to provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR. If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1, 0 }. It might throw an IOException.
pitch | The number of bytes of a row of the image buffer. | |
buff | An image buffer. | |
bpp | The number of bits per pixel used in image buffer. | |
channelMap | A integer array containing the mapping of input channel ordering to expected channel ordering. | |
cb | A pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding. | |
data | Data Pointer to C++ class container to host callback procedure. |
Definition at line 743 of file PGFimage.cpp.
00743 { 00744 ASSERT(buff); 00745 ASSERT(m_channel[0]); 00746 00747 // color transform 00748 RgbToYuv(pitch, buff, bpp, channelMap, cb, data); 00749 00750 if (m_downsample) { 00751 // Subsampling of the chrominance and alpha channels 00752 for (int i=1; i < m_header.channels; i++) { 00753 Downsample(i); 00754 } 00755 } 00756 }
bool CPGFImage::ImportIsSupported | ( | BYTE | mode | ) | [static] |
Check for valid import image mode.
mode | Image mode |
Definition at line 1247 of file PGFimage.cpp.
01247 { 01248 size_t size = DataTSize; 01249 01250 if (size >= 2) { 01251 switch(mode) { 01252 case ImageModeBitmap: 01253 case ImageModeIndexedColor: 01254 case ImageModeGrayScale: 01255 case ImageModeRGBColor: 01256 case ImageModeCMYKColor: 01257 case ImageModeHSLColor: 01258 case ImageModeHSBColor: 01259 //case ImageModeDuotone: 01260 case ImageModeLabColor: 01261 case ImageModeRGB12: 01262 case ImageModeRGB16: 01263 case ImageModeRGBA: 01264 return true; 01265 } 01266 } 01267 if (size >= 3) { 01268 switch(mode) { 01269 case ImageModeGray16: 01270 case ImageModeRGB48: 01271 case ImageModeLab48: 01272 case ImageModeCMYK64: 01273 //case ImageModeDuotone16: 01274 return true; 01275 } 01276 } 01277 if (size >=4) { 01278 switch(mode) { 01279 case ImageModeGray32: 01280 return true; 01281 } 01282 } 01283 return false; 01284 }
void CPGFImage::ImportYUV | ( | int | pitch, | |
DataT * | buff, | |||
BYTE | bpp, | |||
int | channelMap[] = NULL , |
|||
CallbackPtr | cb = NULL , |
|||
void * | data = NULL | |||
) |
Import a YUV image from a specified image buffer. The absolute value of pitch is the number of bytes of an image row. If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row). If pitch is positive, then buff points to the first row of a top-down image (first byte). The sequence of input channels in the input image buffer does not need to be the same as expected from PGF. In case of different sequences you have to provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR. If your provided image buffer contains a channel sequence VUY, then the channelMap looks like { 2, 1, 0 }. It might throw an IOException.
pitch | The number of bytes of a row of the image buffer. | |
buff | An image buffer. | |
bpp | The number of bits per pixel used in image buffer. | |
channelMap | A integer array containing the mapping of input channel ordering to expected channel ordering. | |
cb | A pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding. | |
data | Data Pointer to C++ class container to host callback procedure. |
Import a YUV image from a specified image buffer. The absolute value of pitch is the number of bytes of an image row. If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row). If pitch is positive, then buff points to the first row of a top-down image (first byte). The sequence of input channels in the input image buffer does not need to be the same as expected from PGF. In case of different sequences you have to provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR. If your provided image buffer contains a channel sequence VUY, then the channelMap looks like { 2, 1, 0 }. It might throw an IOException.
pitch | The number of bytes of a row of the image buffer. | |
buff | An image buffer. | |
bpp | The number of bits per pixel used in image buffer. | |
channelMap | A integer array containing the mapping of input channel ordering to expected channel ordering. | |
cb | A pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding. |
Definition at line 2589 of file PGFimage.cpp.
02589 { 02590 ASSERT(buff); 02591 const double dP = 1.0/m_header.height; 02592 const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32); 02593 const int pitch2 = pitch/DataTSize; 02594 const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16; 02595 02596 int yPos = 0, cnt = 0; 02597 double percent = 0; 02598 int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels); 02599 02600 if (channelMap == NULL) channelMap = defMap; 02601 02602 if (m_header.channels == 3) { 02603 ASSERT(bpp%dataBits == 0); 02604 02605 DataT* y = m_channel[0]; ASSERT(y); 02606 DataT* u = m_channel[1]; ASSERT(u); 02607 DataT* v = m_channel[2]; ASSERT(v); 02608 const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels); 02609 02610 for (UINT32 h=0; h < m_header.height; h++) { 02611 if (cb) { 02612 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02613 percent += dP; 02614 } 02615 02616 cnt = 0; 02617 for (UINT32 w=0; w < m_header.width; w++) { 02618 y[yPos] = buff[cnt + channelMap[0]]; 02619 u[yPos] = buff[cnt + channelMap[1]]; 02620 v[yPos] = buff[cnt + channelMap[2]]; 02621 yPos++; 02622 cnt += channels; 02623 } 02624 buff += pitch2; 02625 } 02626 } else if (m_header.channels == 4) { 02627 ASSERT(bpp%dataBits == 0); 02628 02629 DataT* y = m_channel[0]; ASSERT(y); 02630 DataT* u = m_channel[1]; ASSERT(u); 02631 DataT* v = m_channel[2]; ASSERT(v); 02632 DataT* a = m_channel[3]; ASSERT(a); 02633 const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels); 02634 02635 for (UINT32 h=0; h < m_header.height; h++) { 02636 if (cb) { 02637 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 02638 percent += dP; 02639 } 02640 02641 cnt = 0; 02642 for (UINT32 w=0; w < m_header.width; w++) { 02643 y[yPos] = buff[cnt + channelMap[0]]; 02644 u[yPos] = buff[cnt + channelMap[1]]; 02645 v[yPos] = buff[cnt + channelMap[2]]; 02646 a[yPos] = buff[cnt + channelMap[3]] - yuvOffset; 02647 yPos++; 02648 cnt += channels; 02649 } 02650 buff += pitch2; 02651 } 02652 } 02653 02654 if (m_downsample) { 02655 // Subsampling of the chrominance and alpha channels 02656 for (int i=1; i < m_header.channels; i++) { 02657 Downsample(i); 02658 } 02659 } 02660 }
bool CPGFImage::IsOpen | ( | ) | const [inline] |
Returns true if the PGF has been opened and not closed.
Definition at line 87 of file PGFimage.h.
00087 { return m_decoder != NULL; }
BYTE CPGFImage::Level | ( | ) | const [inline] |
Return current image level. Since Read(...) can be used to read each image level separately, it is helpful to know the current level. The current level immediately after Open(...) is Levels().
Definition at line 430 of file PGFimage.h.
00430 { return (BYTE)m_currentLevel; }
static UINT32 CPGFImage::LevelHeight | ( | UINT32 | height, | |
int | level | |||
) | [inline, static] |
Compute and return image height at given level.
height | Original image height (at level 0) | |
level | An image level |
Definition at line 498 of file PGFimage.h.
BYTE CPGFImage::Levels | ( | ) | const [inline] |
Return the number of image levels.
Definition at line 435 of file PGFimage.h.
static UINT32 CPGFImage::LevelWidth | ( | UINT32 | width, | |
int | level | |||
) | [inline, static] |
Compute and return image width at given level.
width | Original image width (at level 0) | |
level | An image level |
Definition at line 491 of file PGFimage.h.
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.
Definition at line 454 of file PGFimage.h.
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.
stream | A PGF stream |
Definition at line 131 of file PGFimage.cpp.
00131 { 00132 ASSERT(stream); 00133 00134 // create decoder and read PGFPreHeader PGFHeader PGFPostHeader LevelLengths 00135 m_decoder = new CDecoder(stream, m_preHeader, m_header, m_postHeader, m_levelLength, 00136 m_userDataPos, m_useOMPinDecoder, m_skipUserData); 00137 00138 if (m_header.nLevels > MaxLevel) ReturnWithError(FormatCannotRead); 00139 00140 // set current level 00141 m_currentLevel = m_header.nLevels; 00142 00143 // set image width and height 00144 m_width[0] = m_header.width; 00145 m_height[0] = m_header.height; 00146 00147 // complete header 00148 if (!CompleteHeader()) ReturnWithError(FormatCannotRead); 00149 00150 // interpret quant parameter 00151 if (m_header.quality > DownsampleThreshold && 00152 (m_header.mode == ImageModeRGBColor || 00153 m_header.mode == ImageModeRGBA || 00154 m_header.mode == ImageModeRGB48 || 00155 m_header.mode == ImageModeCMYKColor || 00156 m_header.mode == ImageModeCMYK64 || 00157 m_header.mode == ImageModeLabColor || 00158 m_header.mode == ImageModeLab48)) { 00159 m_downsample = true; 00160 m_quant = m_header.quality - 1; 00161 } else { 00162 m_downsample = false; 00163 m_quant = m_header.quality; 00164 } 00165 00166 // set channel dimensions (chrominance is subsampled by factor 2) 00167 if (m_downsample) { 00168 for (int i=1; i < m_header.channels; i++) { 00169 m_width[i] = (m_width[0] + 1)/2; 00170 m_height[i] = (m_height[0] + 1)/2; 00171 } 00172 } else { 00173 for (int i=1; i < m_header.channels; i++) { 00174 m_width[i] = m_width[0]; 00175 m_height[i] = m_height[0]; 00176 } 00177 } 00178 00179 if (m_header.nLevels > 0) { 00180 // init wavelet subbands 00181 for (int i=0; i < m_header.channels; i++) { 00182 m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels); 00183 } 00184 00185 // used in Read when PM_Absolute 00186 m_percent = pow(0.25, m_header.nLevels); 00187 00188 } else { 00189 // very small image: we don't use DWT and encoding 00190 00191 // read channels 00192 for (int c=0; c < m_header.channels; c++) { 00193 const UINT32 size = m_width[c]*m_height[c]; 00194 m_channel[c] = new(std::nothrow) DataT[size]; 00195 if (!m_channel[c]) ReturnWithError(InsufficientMemory); 00196 00197 // read channel data from stream 00198 for (UINT32 i=0; i < size; i++) { 00199 int count = DataTSize; 00200 stream->Read(&count, &m_channel[c][i]); 00201 if (count != DataTSize) ReturnWithError(MissingData); 00202 } 00203 } 00204 } 00205 }
BYTE CPGFImage::Quality | ( | ) | const [inline] |
Return the PGF quality. The quality is inbetween 0 and MaxQuality. PGF quality 0 means lossless quality.
Definition at line 441 of file PGFimage.h.
void CPGFImage::Read | ( | int | level = 0 , |
|
CallbackPtr | cb = NULL , |
|||
void * | data = NULL | |||
) |
Read and decode some levels of a PGF image at current stream position. A PGF image is structered in levels, numbered between 0 and Levels() - 1. Each level can be seen as a single image, containing the same content as all other levels, but in a different size (width, height). The image size at level i is double the size (width, height) of the image at level i+1. The image at level 0 contains the original size. Precondition: The PGF image has been opened with a call of Open(...). It might throw an IOException.
level | [0, nLevels) The image level of the resulting image in the internal image buffer. | |
cb | A pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding. | |
data | Data Pointer to C++ class container to host callback procedure. |
Definition at line 384 of file PGFimage.cpp.
00384 { 00385 ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform 00386 ASSERT(m_decoder); 00387 00388 #ifdef __PGFROISUPPORT__ 00389 if (ROIisSupported() && m_header.nLevels > 0) { 00390 // new encoding scheme supporting ROI 00391 PGFRect rect(0, 0, m_header.width, m_header.height); 00392 Read(rect, level, cb, data); 00393 return; 00394 } 00395 #endif 00396 00397 if (m_header.nLevels == 0) { 00398 if (level == 0) { 00399 // the data has already been read during open 00400 // now update progress 00401 if (cb) { 00402 if ((*cb)(1.0, true, data)) ReturnWithError(EscapePressed); 00403 } 00404 } 00405 } else { 00406 const int levelDiff = m_currentLevel - level; 00407 double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent; 00408 00409 // encoding scheme without ROI 00410 while (m_currentLevel > level) { 00411 for (int i=0; i < m_header.channels; i++) { 00412 ASSERT(m_wtChannel[i]); 00413 // decode file and write stream to m_wtChannel 00414 if (m_currentLevel == m_header.nLevels) { 00415 // last level also has LL band 00416 m_wtChannel[i]->GetSubband(m_currentLevel, LL)->PlaceTile(*m_decoder, m_quant); 00417 } 00418 if (m_preHeader.version & Version5) { 00419 // since version 5 00420 m_wtChannel[i]->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant); 00421 m_wtChannel[i]->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant); 00422 } else { 00423 // until version 4 00424 m_decoder->DecodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); 00425 } 00426 m_wtChannel[i]->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant); 00427 } 00428 00429 volatile OSError error = NoError; // volatile prevents optimizations 00430 #ifdef LIBPGF_USE_OPENMP 00431 #pragma omp parallel for default(shared) 00432 #endif 00433 for (int i=0; i < m_header.channels; i++) { 00434 // inverse transform from m_wtChannel to m_channel 00435 if (error == NoError) { 00436 OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]); 00437 if (err != NoError) error = err; 00438 } 00439 ASSERT(m_channel[i]); 00440 } 00441 if (error != NoError) ReturnWithError(error); 00442 00443 // set new level: must be done before refresh callback 00444 m_currentLevel--; 00445 00446 // now we have to refresh the display 00447 if (m_cb) m_cb(m_cbArg); 00448 00449 // now update progress 00450 if (cb) { 00451 percent *= 4; 00452 if (m_progressMode == PM_Absolute) m_percent = percent; 00453 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 00454 } 00455 } 00456 } 00457 00458 // automatically closing 00459 if (m_currentLevel == 0) Close(); 00460 }
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.
level | The image level | |
target | The target buffer | |
targetLen | The length of the target buffer in bytes |
Definition at line 659 of file PGFimage.cpp.
00659 { 00660 ASSERT(level >= 0 && level < m_header.nLevels); 00661 ASSERT(target); 00662 ASSERT(targetLen > 0); 00663 ASSERT(m_decoder); 00664 00665 // reset stream position 00666 m_decoder->SetStreamPosToData(); 00667 00668 // position stream 00669 UINT64 offset = 0; 00670 00671 for (int i=m_header.nLevels - 1; i > level; i--) { 00672 offset += m_levelLength[m_header.nLevels - 1 - i]; 00673 } 00674 m_decoder->Skip(offset); 00675 00676 // compute number of bytes to read 00677 UINT32 len = __min(targetLen, GetEncodedLevelLength(level)); 00678 00679 // read data 00680 len = m_decoder->ReadEncodedData(target, len); 00681 ASSERT(len >= 0 && len <= targetLen); 00682 00683 return len; 00684 }
UINT32 CPGFImage::ReadEncodedHeader | ( | UINT8 * | target, | |
UINT32 | targetLen | |||
) | const |
Reads the encoded PGF headers and copies it to a target buffer. Precondition: The PGF image has been opened with a call of Open(...). It might throw an IOException.
target | The target buffer | |
targetLen | The length of the target buffer in bytes |
Definition at line 625 of file PGFimage.cpp.
00625 { 00626 ASSERT(target); 00627 ASSERT(targetLen > 0); 00628 ASSERT(m_decoder); 00629 00630 // reset stream position 00631 m_decoder->SetStreamPosToStart(); 00632 00633 // compute number of bytes to read 00634 UINT32 len = __min(targetLen, GetEncodedHeaderLength()); 00635 00636 // read data 00637 len = m_decoder->ReadEncodedData(target, len); 00638 ASSERT(len >= 0 && len <= targetLen); 00639 00640 return len; 00641 }
void CPGFImage::ReadPreview | ( | ) | [inline] |
Read and decode smallest level of a PGF image at current stream position. For details, please refert to Read(...) Precondition: The PGF image has been opened with a call of Open(...). It might throw an IOException.
Definition at line 121 of file PGFimage.h.
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.
level | The image level of the resulting image in the internal image buffer. |
Definition at line 332 of file PGFimage.cpp.
00332 { 00333 if (m_header.nLevels == 0) { 00334 // image didn't use wavelet transform 00335 if (level == 0) { 00336 for (int i=0; i < m_header.channels; i++) { 00337 ASSERT(m_wtChannel[i]); 00338 m_channel[i] = m_wtChannel[i]->GetSubband(0, LL)->GetBuffer(); 00339 } 00340 } 00341 } else { 00342 int currentLevel = m_header.nLevels; 00343 00344 if (ROIisSupported()) { 00345 // enable ROI reading 00346 SetROI(PGFRect(0, 0, m_header.width, m_header.height)); 00347 } 00348 00349 while (currentLevel > level) { 00350 for (int i=0; i < m_header.channels; i++) { 00351 ASSERT(m_wtChannel[i]); 00352 // dequantize subbands 00353 if (currentLevel == m_header.nLevels) { 00354 // last level also has LL band 00355 m_wtChannel[i]->GetSubband(currentLevel, LL)->Dequantize(m_quant); 00356 } 00357 m_wtChannel[i]->GetSubband(currentLevel, HL)->Dequantize(m_quant); 00358 m_wtChannel[i]->GetSubband(currentLevel, LH)->Dequantize(m_quant); 00359 m_wtChannel[i]->GetSubband(currentLevel, HH)->Dequantize(m_quant); 00360 00361 // inverse transform from m_wtChannel to m_channel 00362 OSError err = m_wtChannel[i]->InverseTransform(currentLevel, &m_width[i], &m_height[i], &m_channel[i]); 00363 if (err != NoError) ReturnWithError(err); 00364 ASSERT(m_channel[i]); 00365 } 00366 00367 currentLevel--; 00368 } 00369 } 00370 }
void CPGFImage::ResetStreamPos | ( | ) |
Reset stream position to start of PGF pre-header
Definition at line 645 of file PGFimage.cpp.
00645 { 00646 ASSERT(m_decoder); 00647 return m_decoder->SetStreamPosToStart(); 00648 }
void CPGFImage::RgbToYuv | ( | int | pitch, | |
UINT8 * | rgbBuff, | |||
BYTE | bpp, | |||
int | channelMap[], | |||
CallbackPtr | cb, | |||
void * | data | |||
) | [private] |
Definition at line 1331 of file PGFimage.cpp.
01331 { 01332 ASSERT(buff); 01333 int yPos = 0, cnt = 0; 01334 double percent = 0; 01335 const double dP = 1.0/m_header.height; 01336 int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels); 01337 01338 if (channelMap == NULL) channelMap = defMap; 01339 01340 switch(m_header.mode) { 01341 case ImageModeBitmap: 01342 { 01343 ASSERT(m_header.channels == 1); 01344 ASSERT(m_header.bpp == 1); 01345 ASSERT(bpp == 1); 01346 01347 const UINT32 w = m_header.width; 01348 const UINT32 w2 = (m_header.width + 7)/8; 01349 DataT* y = m_channel[0]; ASSERT(y); 01350 01351 for (UINT32 h=0; h < m_header.height; h++) { 01352 if (cb) { 01353 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01354 percent += dP; 01355 } 01356 01357 for (UINT32 j=0; j < w2; j++) { 01358 y[yPos++] = buff[j] - YUVoffset8; 01359 } 01360 for (UINT32 j=w2; j < w; j++) { 01361 y[yPos++] = YUVoffset8; 01362 } 01363 01364 //UINT cnt = w; 01365 //for (UINT32 j=0; j < w2; j++) { 01366 // for (int k=7; k >= 0; k--) { 01367 // if (cnt) { 01368 // y[yPos++] = YUVoffset8 + (1 & (buff[j] >> k)); 01369 // cnt--; 01370 // } 01371 // } 01372 //} 01373 buff += pitch; 01374 } 01375 } 01376 break; 01377 case ImageModeIndexedColor: 01378 case ImageModeGrayScale: 01379 case ImageModeHSLColor: 01380 case ImageModeHSBColor: 01381 case ImageModeLabColor: 01382 { 01383 ASSERT(m_header.channels >= 1); 01384 ASSERT(m_header.bpp == m_header.channels*8); 01385 ASSERT(bpp%8 == 0); 01386 const int channels = bpp/8; ASSERT(channels >= m_header.channels); 01387 01388 for (UINT32 h=0; h < m_header.height; h++) { 01389 if (cb) { 01390 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01391 percent += dP; 01392 } 01393 01394 cnt = 0; 01395 for (UINT32 w=0; w < m_header.width; w++) { 01396 for (int c=0; c < m_header.channels; c++) { 01397 m_channel[c][yPos] = buff[cnt + channelMap[c]] - YUVoffset8; 01398 } 01399 cnt += channels; 01400 yPos++; 01401 } 01402 buff += pitch; 01403 } 01404 } 01405 break; 01406 case ImageModeGray16: 01407 case ImageModeLab48: 01408 { 01409 ASSERT(m_header.channels >= 1); 01410 ASSERT(m_header.bpp == m_header.channels*16); 01411 ASSERT(bpp%16 == 0); 01412 01413 UINT16 *buff16 = (UINT16 *)buff; 01414 const int pitch16 = pitch/2; 01415 const int channels = bpp/16; ASSERT(channels >= m_header.channels); 01416 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); 01417 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); 01418 01419 for (UINT32 h=0; h < m_header.height; h++) { 01420 if (cb) { 01421 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01422 percent += dP; 01423 } 01424 01425 cnt = 0; 01426 for (UINT32 w=0; w < m_header.width; w++) { 01427 for (int c=0; c < m_header.channels; c++) { 01428 m_channel[c][yPos] = (buff16[cnt + channelMap[c]] >> shift) - yuvOffset16; 01429 } 01430 cnt += channels; 01431 yPos++; 01432 } 01433 buff16 += pitch16; 01434 } 01435 } 01436 break; 01437 case ImageModeRGBColor: 01438 { 01439 ASSERT(m_header.channels == 3); 01440 ASSERT(m_header.bpp == m_header.channels*8); 01441 ASSERT(bpp%8 == 0); 01442 01443 DataT* y = m_channel[0]; ASSERT(y); 01444 DataT* u = m_channel[1]; ASSERT(u); 01445 DataT* v = m_channel[2]; ASSERT(v); 01446 const int channels = bpp/8; ASSERT(channels >= m_header.channels); 01447 UINT8 b, g, r; 01448 01449 for (UINT32 h=0; h < m_header.height; h++) { 01450 if (cb) { 01451 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01452 percent += dP; 01453 } 01454 01455 cnt = 0; 01456 for (UINT32 w=0; w < m_header.width; w++) { 01457 b = buff[cnt + channelMap[0]]; 01458 g = buff[cnt + channelMap[1]]; 01459 r = buff[cnt + channelMap[2]]; 01460 // Yuv 01461 y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8; 01462 u[yPos] = r - g; 01463 v[yPos] = b - g; 01464 yPos++; 01465 cnt += channels; 01466 } 01467 buff += pitch; 01468 } 01469 } 01470 break; 01471 case ImageModeRGB48: 01472 { 01473 ASSERT(m_header.channels == 3); 01474 ASSERT(m_header.bpp == m_header.channels*16); 01475 ASSERT(bpp%16 == 0); 01476 01477 UINT16 *buff16 = (UINT16 *)buff; 01478 const int pitch16 = pitch/2; 01479 const int channels = bpp/16; ASSERT(channels >= m_header.channels); 01480 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); 01481 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); 01482 01483 DataT* y = m_channel[0]; ASSERT(y); 01484 DataT* u = m_channel[1]; ASSERT(u); 01485 DataT* v = m_channel[2]; ASSERT(v); 01486 UINT16 b, g, r; 01487 01488 for (UINT32 h=0; h < m_header.height; h++) { 01489 if (cb) { 01490 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01491 percent += dP; 01492 } 01493 01494 cnt = 0; 01495 for (UINT32 w=0; w < m_header.width; w++) { 01496 b = buff16[cnt + channelMap[0]] >> shift; 01497 g = buff16[cnt + channelMap[1]] >> shift; 01498 r = buff16[cnt + channelMap[2]] >> shift; 01499 // Yuv 01500 y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16; 01501 u[yPos] = r - g; 01502 v[yPos] = b - g; 01503 yPos++; 01504 cnt += channels; 01505 } 01506 buff16 += pitch16; 01507 } 01508 } 01509 break; 01510 case ImageModeRGBA: 01511 case ImageModeCMYKColor: 01512 { 01513 ASSERT(m_header.channels == 4); 01514 ASSERT(m_header.bpp == m_header.channels*8); 01515 ASSERT(bpp%8 == 0); 01516 const int channels = bpp/8; ASSERT(channels >= m_header.channels); 01517 01518 DataT* y = m_channel[0]; ASSERT(y); 01519 DataT* u = m_channel[1]; ASSERT(u); 01520 DataT* v = m_channel[2]; ASSERT(v); 01521 DataT* a = m_channel[3]; ASSERT(a); 01522 UINT8 b, g, r; 01523 01524 for (UINT32 h=0; h < m_header.height; h++) { 01525 if (cb) { 01526 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01527 percent += dP; 01528 } 01529 01530 cnt = 0; 01531 for (UINT32 w=0; w < m_header.width; w++) { 01532 b = buff[cnt + channelMap[0]]; 01533 g = buff[cnt + channelMap[1]]; 01534 r = buff[cnt + channelMap[2]]; 01535 // Yuv 01536 y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8; 01537 u[yPos] = r - g; 01538 v[yPos] = b - g; 01539 a[yPos++] = buff[cnt + channelMap[3]] - YUVoffset8; 01540 cnt += channels; 01541 } 01542 buff += pitch; 01543 } 01544 } 01545 break; 01546 case ImageModeCMYK64: 01547 { 01548 ASSERT(m_header.channels == 4); 01549 ASSERT(m_header.bpp == m_header.channels*16); 01550 ASSERT(bpp%16 == 0); 01551 01552 UINT16 *buff16 = (UINT16 *)buff; 01553 const int pitch16 = pitch/2; 01554 const int channels = bpp/16; ASSERT(channels >= m_header.channels); 01555 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); 01556 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); 01557 01558 DataT* y = m_channel[0]; ASSERT(y); 01559 DataT* u = m_channel[1]; ASSERT(u); 01560 DataT* v = m_channel[2]; ASSERT(v); 01561 DataT* a = m_channel[3]; ASSERT(a); 01562 UINT16 b, g, r; 01563 01564 for (UINT32 h=0; h < m_header.height; h++) { 01565 if (cb) { 01566 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01567 percent += dP; 01568 } 01569 01570 cnt = 0; 01571 for (UINT32 w=0; w < m_header.width; w++) { 01572 b = buff16[cnt + channelMap[0]] >> shift; 01573 g = buff16[cnt + channelMap[1]] >> shift; 01574 r = buff16[cnt + channelMap[2]] >> shift; 01575 // Yuv 01576 y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16; 01577 u[yPos] = r - g; 01578 v[yPos] = b - g; 01579 a[yPos++] = (buff16[cnt + channelMap[3]] >> shift) - yuvOffset16; 01580 cnt += channels; 01581 } 01582 buff16 += pitch16; 01583 } 01584 } 01585 break; 01586 #ifdef __PGF32SUPPORT__ 01587 case ImageModeGray32: 01588 { 01589 ASSERT(m_header.channels == 1); 01590 ASSERT(m_header.bpp == 32); 01591 ASSERT(bpp == 32); 01592 ASSERT(DataTSize == sizeof(UINT32)); 01593 01594 DataT* y = m_channel[0]; ASSERT(y); 01595 01596 UINT32 *buff32 = (UINT32 *)buff; 01597 const int pitch32 = pitch/4; 01598 const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0); 01599 const DataT yuvOffset31 = 1 << (UsedBitsPerChannel() - 1); 01600 01601 for (UINT32 h=0; h < m_header.height; h++) { 01602 if (cb) { 01603 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01604 percent += dP; 01605 } 01606 01607 for (UINT32 w=0; w < m_header.width; w++) { 01608 y[yPos++] = (buff32[w] >> shift) - yuvOffset31; 01609 } 01610 buff32 += pitch32; 01611 } 01612 } 01613 break; 01614 #endif 01615 case ImageModeRGB12: 01616 { 01617 ASSERT(m_header.channels == 3); 01618 ASSERT(m_header.bpp == m_header.channels*4); 01619 ASSERT(bpp == m_header.channels*4); 01620 01621 DataT* y = m_channel[0]; ASSERT(y); 01622 DataT* u = m_channel[1]; ASSERT(u); 01623 DataT* v = m_channel[2]; ASSERT(v); 01624 01625 UINT8 rgb = 0, b, g, r; 01626 01627 for (UINT32 h=0; h < m_header.height; h++) { 01628 if (cb) { 01629 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01630 percent += dP; 01631 } 01632 01633 cnt = 0; 01634 for (UINT32 w=0; w < m_header.width; w++) { 01635 if (w%2 == 0) { 01636 // even pixel position 01637 rgb = buff[cnt]; 01638 b = rgb & 0x0F; 01639 g = (rgb & 0xF0) >> 4; 01640 cnt++; 01641 rgb = buff[cnt]; 01642 r = rgb & 0x0F; 01643 } else { 01644 // odd pixel position 01645 b = (rgb & 0xF0) >> 4; 01646 cnt++; 01647 rgb = buff[cnt]; 01648 g = rgb & 0x0F; 01649 r = (rgb & 0xF0) >> 4; 01650 cnt++; 01651 } 01652 01653 // Yuv 01654 y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset4; 01655 u[yPos] = r - g; 01656 v[yPos] = b - g; 01657 yPos++; 01658 } 01659 buff += pitch; 01660 } 01661 } 01662 break; 01663 case ImageModeRGB16: 01664 { 01665 ASSERT(m_header.channels == 3); 01666 ASSERT(m_header.bpp == 16); 01667 ASSERT(bpp == 16); 01668 01669 DataT* y = m_channel[0]; ASSERT(y); 01670 DataT* u = m_channel[1]; ASSERT(u); 01671 DataT* v = m_channel[2]; ASSERT(v); 01672 01673 UINT16 *buff16 = (UINT16 *)buff; 01674 UINT16 rgb, b, g, r; 01675 const int pitch16 = pitch/2; 01676 01677 for (UINT32 h=0; h < m_header.height; h++) { 01678 if (cb) { 01679 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01680 percent += dP; 01681 } 01682 for (UINT32 w=0; w < m_header.width; w++) { 01683 rgb = buff16[w]; 01684 r = (rgb & 0xF800) >> 10; // highest 5 bits 01685 g = (rgb & 0x07E0) >> 5; // middle 6 bits 01686 b = (rgb & 0x001F) << 1; // lowest 5 bits 01687 // Yuv 01688 y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset6; 01689 u[yPos] = r - g; 01690 v[yPos] = b - g; 01691 yPos++; 01692 } 01693 01694 buff16 += pitch16; 01695 } 01696 } 01697 break; 01698 default: 01699 ASSERT(false); 01700 } 01701 }
bool CPGFImage::ROIisSupported | ( | ) | const [inline] |
Return true if the pgf image supports Region Of Interest (ROI).
Definition at line 465 of file PGFimage.h.
00465 { return (m_preHeader.version & PGFROI) == PGFROI; }
void CPGFImage::SetChannel | ( | DataT * | channel, | |
int | c = 0 | |||
) | [inline] |
Set internal PGF image buffer channel.
channel | A YUV data channel | |
c | A channel index |
Definition at line 276 of file PGFimage.h.
00276 { 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.
iFirstColor | The color table index of the first entry to set. | |
nColors | The number of color table entries to set. | |
prgbColors | A pointer to the array of RGBQUAD structures to set the color table entries. |
Definition at line 1306 of file PGFimage.cpp.
01306 { 01307 if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError); 01308 01309 for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) { 01310 m_postHeader.clut[i] = prgbColors[j]; 01311 } 01312 }
void CPGFImage::SetHeader | ( | const PGFHeader & | header, | |
BYTE | flags = 0 , |
|||
UINT8 * | userData = 0 , |
|||
UINT32 | userDataLength = 0 | |||
) |
Set PGF header and user data. Precondition: The PGF image has been closed with Close(...) or never opened with Open(...). It might throw an IOException.
header | A valid and already filled in PGF header structure | |
flags | A combination of additional version flags. In case you use level-wise encoding then set flag = PGFROI. | |
userData | A user-defined memory block containing any kind of cached metadata. | |
userDataLength | The size of user-defined memory block in bytes |
Definition at line 844 of file PGFimage.cpp.
00844 { 00845 ASSERT(!m_decoder); // current image must be closed 00846 ASSERT(header.quality <= MaxQuality); 00847 00848 // init state 00849 #ifdef __PGFROISUPPORT__ 00850 m_streamReinitialized = false; 00851 #endif 00852 00853 // init preHeader 00854 memcpy(m_preHeader.magic, PGFMagic, 3); 00855 m_preHeader.version = PGFVersion | flags; 00856 m_preHeader.hSize = HeaderSize; 00857 00858 // copy header 00859 memcpy(&m_header, &header, HeaderSize); 00860 00861 // complete header 00862 CompleteHeader(); 00863 00864 // check and set number of levels 00865 ComputeLevels(); 00866 00867 // check for downsample 00868 if (m_header.quality > DownsampleThreshold && (m_header.mode == ImageModeRGBColor || 00869 m_header.mode == ImageModeRGBA || 00870 m_header.mode == ImageModeRGB48 || 00871 m_header.mode == ImageModeCMYKColor || 00872 m_header.mode == ImageModeCMYK64 || 00873 m_header.mode == ImageModeLabColor || 00874 m_header.mode == ImageModeLab48)) { 00875 m_downsample = true; 00876 m_quant = m_header.quality - 1; 00877 } else { 00878 m_downsample = false; 00879 m_quant = m_header.quality; 00880 } 00881 00882 // update header size and copy user data 00883 if (m_header.mode == ImageModeIndexedColor) { 00884 // update header size 00885 m_preHeader.hSize += ColorTableSize; 00886 } 00887 if (userDataLength && userData) { 00888 m_postHeader.userData = new(std::nothrow) UINT8[userDataLength]; 00889 if (!m_postHeader.userData) ReturnWithError(InsufficientMemory); 00890 m_postHeader.userDataLen = userDataLength; 00891 memcpy(m_postHeader.userData, userData, userDataLength); 00892 // update header size 00893 m_preHeader.hSize += userDataLength; 00894 } 00895 00896 // allocate channels 00897 for (int i=0; i < m_header.channels; i++) { 00898 // set current width and height 00899 m_width[i] = m_header.width; 00900 m_height[i] = m_header.height; 00901 00902 // allocate channels 00903 ASSERT(!m_channel[i]); 00904 m_channel[i] = new(std::nothrow) DataT[m_header.width*m_header.height]; 00905 if (!m_channel[i]) { 00906 if (i) i--; 00907 while(i) { 00908 delete[] m_channel[i]; m_channel[i] = 0; 00909 i--; 00910 } 00911 ReturnWithError(InsufficientMemory); 00912 } 00913 } 00914 }
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.
maxValue | The maximum intensity value. |
Definition at line 690 of file PGFimage.cpp.
00690 { 00691 const BYTE bpc = m_header.bpp/m_header.channels; 00692 BYTE pot = 0; 00693 00694 while(maxValue > 0) { 00695 pot++; 00696 maxValue >>= 1; 00697 } 00698 // store bits per channel 00699 if (pot > bpc) pot = bpc; 00700 if (pot > 31) pot = 31; 00701 m_header.usedBitsPerChannel = pot; 00702 }
void CPGFImage::SetProgressMode | ( | ProgressMode | pm | ) | [inline] |
Set progress mode used in Read and Write. Default mode is PM_Relative. This method must be called before Open() or SetHeader(). PM_Relative: 100% = level difference between current level and target level of Read/Write PM_Absolute: 100% = number of levels
Definition at line 300 of file PGFimage.h.
00300 { 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.
callback | A refresh callback procedure | |
arg | A parameter of the refresh callback procedure |
Definition at line 307 of file PGFimage.h.
UINT32 CPGFImage::UpdatePostHeaderSize | ( | ) | [private] |
Definition at line 1067 of file PGFimage.cpp.
01067 { 01068 ASSERT(m_encoder); 01069 01070 INT64 offset = m_encoder->ComputeOffset(); ASSERT(offset >= 0); 01071 01072 if (offset > 0) { 01073 // update post-header size and rewrite pre-header 01074 m_preHeader.hSize += (UINT32)offset; 01075 m_encoder->UpdatePostHeaderSize(m_preHeader); 01076 } 01077 01078 // write dummy levelLength into stream 01079 return m_encoder->WriteLevelLength(m_levelLength); 01080 }
BYTE CPGFImage::UsedBitsPerChannel | ( | ) | const |
Returns number of used bits per input/output image channel. Precondition: header must be initialized.
Definition at line 708 of file PGFimage.cpp.
BYTE CPGFImage::Version | ( | ) | const [inline] |
Returns images' PGF version
Definition at line 476 of file PGFimage.h.
00476 { return CurrentVersion(m_preHeader.version); }
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.
level | A level |
Definition at line 416 of file PGFimage.h.
00416 { ASSERT(level >= 0); return LevelWidth(m_header.width, level); }
void CPGFImage::Write | ( | CPGFStream * | stream, | |
UINT32 * | nWrittenBytes = NULL , |
|||
CallbackPtr | cb = NULL , |
|||
void * | data = NULL | |||
) |
Encode and write a entire PGF image (header and image) at current stream position. A PGF image is structered in levels, numbered between 0 and Levels() - 1. Each level can be seen as a single image, containing the same content as all other levels, but in a different size (width, height). The image size at level i is double the size (width, height) of the image at level i+1. The image at level 0 contains the original size. Precondition: the PGF image contains a valid header (see also SetHeader(...)). It might throw an IOException.
stream | A PGF stream | |
nWrittenBytes | [in-out] The number of bytes written into stream are added to the input value. | |
cb | A pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding. | |
data | Data Pointer to C++ class container to host callback procedure. |
Definition at line 1163 of file PGFimage.cpp.
01163 { 01164 ASSERT(stream); 01165 ASSERT(m_preHeader.hSize); 01166 01167 // create wavelet transform channels and encoder 01168 UINT32 nBytes = WriteHeader(stream); 01169 01170 // write image 01171 nBytes += WriteImage(stream, cb, data); 01172 01173 // return written bytes 01174 if (nWrittenBytes) *nWrittenBytes += nBytes; 01175 }
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.
stream | A PGF stream |
Definition at line 923 of file PGFimage.cpp.
00923 { 00924 ASSERT(m_header.nLevels <= MaxLevel); 00925 ASSERT(m_header.quality <= MaxQuality); // quality is already initialized 00926 00927 if (m_header.nLevels > 0) { 00928 volatile OSError error = NoError; // volatile prevents optimizations 00929 // create new wt channels 00930 #ifdef LIBPGF_USE_OPENMP 00931 #pragma omp parallel for default(shared) 00932 #endif 00933 for (int i=0; i < m_header.channels; i++) { 00934 DataT *temp = NULL; 00935 if (error == NoError) { 00936 if (m_wtChannel[i]) { 00937 ASSERT(m_channel[i]); 00938 // copy m_channel to temp 00939 int size = m_height[i]*m_width[i]; 00940 temp = new(std::nothrow) DataT[size]; 00941 if (temp) { 00942 memcpy(temp, m_channel[i], size*DataTSize); 00943 delete m_wtChannel[i]; // also deletes m_channel 00944 m_channel[i] = NULL; 00945 } else { 00946 error = InsufficientMemory; 00947 } 00948 } 00949 if (error == NoError) { 00950 if (temp) { 00951 ASSERT(!m_channel[i]); 00952 m_channel[i] = temp; 00953 } 00954 m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels, m_channel[i]); 00955 if (m_wtChannel[i]) { 00956 #ifdef __PGFROISUPPORT__ 00957 m_wtChannel[i]->SetROI(PGFRect(0, 0, m_width[i], m_height[i])); 00958 #endif 00959 00960 // wavelet subband decomposition 00961 for (int l=0; error == NoError && l < m_header.nLevels; l++) { 00962 OSError err = m_wtChannel[i]->ForwardTransform(l, m_quant); 00963 if (err != NoError) error = err; 00964 } 00965 } else { 00966 delete[] m_channel[i]; 00967 error = InsufficientMemory; 00968 } 00969 } 00970 } 00971 } 00972 if (error != NoError) { 00973 // free already allocated memory 00974 for (int i=0; i < m_header.channels; i++) { 00975 delete m_wtChannel[i]; 00976 } 00977 ReturnWithError(error); 00978 } 00979 00980 m_currentLevel = m_header.nLevels; 00981 00982 // create encoder and eventually write headers and levelLength 00983 m_encoder = new CEncoder(stream, m_preHeader, m_header, m_postHeader, m_userDataPos, m_useOMPinEncoder); 00984 if (m_favorSpeedOverSize) m_encoder->FavorSpeedOverSize(); 00985 00986 #ifdef __PGFROISUPPORT__ 00987 if (ROIisSupported()) { 00988 // new encoding scheme supporting ROI 00989 m_encoder->SetROI(); 00990 } 00991 #endif 00992 00993 } else { 00994 // very small image: we don't use DWT and encoding 00995 00996 // create encoder and eventually write headers and levelLength 00997 m_encoder = new CEncoder(stream, m_preHeader, m_header, m_postHeader, m_userDataPos, m_useOMPinEncoder); 00998 } 00999 01000 INT64 nBytes = m_encoder->ComputeHeaderLength(); 01001 return (nBytes > 0) ? (UINT32)nBytes : 0; 01002 }
UINT32 CPGFImage::WriteImage | ( | CPGFStream * | stream, | |
CallbackPtr | cb = NULL , |
|||
void * | data = NULL | |||
) |
Encode and write the one and only image at current stream position. Call this method after WriteHeader(). In case you want to write uncached metadata, then do that after WriteHeader() and before WriteImage(). This method is called inside of Write(stream, ...). It might throw an IOException.
stream | A PGF stream | |
cb | A pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding. | |
data | Data Pointer to C++ class container to host callback procedure. |
Definition at line 1092 of file PGFimage.cpp.
01092 { 01093 ASSERT(stream); 01094 ASSERT(m_preHeader.hSize); 01095 01096 int levels = m_header.nLevels; 01097 double percent = pow(0.25, levels); 01098 01099 // update post-header size, rewrite pre-header, and write dummy levelLength 01100 UINT32 nWrittenBytes = UpdatePostHeaderSize(); 01101 01102 if (levels == 0) { 01103 // write channels 01104 for (int c=0; c < m_header.channels; c++) { 01105 const UINT32 size = m_width[c]*m_height[c]; 01106 01107 // write channel data into stream 01108 for (UINT32 i=0; i < size; i++) { 01109 int count = DataTSize; 01110 stream->Write(&count, &m_channel[c][i]); 01111 } 01112 } 01113 01114 // now update progress 01115 if (cb) { 01116 if ((*cb)(1, true, data)) ReturnWithError(EscapePressed); 01117 } 01118 01119 } else { 01120 // encode quantized wavelet coefficients and write to PGF file 01121 // encode subbands, higher levels first 01122 // color channels are interleaved 01123 01124 // encode all levels 01125 for (m_currentLevel = levels; m_currentLevel > 0; ) { 01126 WriteLevel(); // decrements m_currentLevel 01127 01128 // now update progress 01129 if (cb) { 01130 percent *= 4; 01131 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); 01132 } 01133 } 01134 01135 // flush encoder and write level lengths 01136 m_encoder->Flush(); 01137 } 01138 01139 // update level lengths 01140 nWrittenBytes += m_encoder->UpdateLevelLength(); // return written image bytes 01141 01142 // delete encoder 01143 delete m_encoder; m_encoder = NULL; 01144 01145 ASSERT(!m_encoder); 01146 01147 return nWrittenBytes; 01148 }
void CPGFImage::WriteLevel | ( | ) | [private] |
Definition at line 1012 of file PGFimage.cpp.
01012 { 01013 ASSERT(m_encoder); 01014 ASSERT(m_currentLevel > 0); 01015 ASSERT(m_header.nLevels > 0); 01016 01017 #ifdef __PGFROISUPPORT__ 01018 if (ROIisSupported()) { 01019 const int lastChannel = m_header.channels - 1; 01020 01021 for (int i=0; i < m_header.channels; i++) { 01022 // get number of tiles and tile indices 01023 const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel); 01024 const UINT32 lastTile = nTiles - 1; 01025 01026 if (m_currentLevel == m_header.nLevels) { 01027 // last level also has LL band 01028 ASSERT(nTiles == 1); 01029 m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder); 01030 m_encoder->EncodeTileBuffer(); 01031 } 01032 for (UINT32 tileY=0; tileY < nTiles; tileY++) { 01033 for (UINT32 tileX=0; tileX < nTiles; tileX++) { 01034 m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, true, tileX, tileY); 01035 m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, true, tileX, tileY); 01036 m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, true, tileX, tileY); 01037 if (i == lastChannel && tileY == lastTile && tileX == lastTile) { 01038 // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level. 01039 m_encoder->SetEncodedLevel(--m_currentLevel); 01040 } 01041 m_encoder->EncodeTileBuffer(); 01042 } 01043 } 01044 } 01045 } else 01046 #endif 01047 { 01048 for (int i=0; i < m_header.channels; i++) { 01049 ASSERT(m_wtChannel[i]); 01050 if (m_currentLevel == m_header.nLevels) { 01051 // last level also has LL band 01052 m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder); 01053 } 01054 //encoder.EncodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); // until version 4 01055 m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder); // since version 5 01056 m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder); // since version 5 01057 m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder); 01058 } 01059 01060 // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level. 01061 m_encoder->SetEncodedLevel(--m_currentLevel); 01062 } 01063 }
RefreshCB CPGFImage::m_cb [private] |
pointer to refresh callback procedure
Definition at line 535 of file PGFimage.h.
void* CPGFImage::m_cbArg [private] |
refresh callback argument
Definition at line 536 of file PGFimage.h.
DataT* CPGFImage::m_channel[MaxChannels] [protected] |
untransformed channels in YUV format
Definition at line 512 of file PGFimage.h.
int CPGFImage::m_currentLevel [protected] |
transform level of current image
Definition at line 522 of file PGFimage.h.
CDecoder* CPGFImage::m_decoder [protected] |
PGF decoder.
Definition at line 513 of file PGFimage.h.
bool CPGFImage::m_downsample [protected] |
chrominance channels are downsampled
Definition at line 524 of file PGFimage.h.
CEncoder* CPGFImage::m_encoder [protected] |
PGF encoder.
Definition at line 514 of file PGFimage.h.
bool CPGFImage::m_favorSpeedOverSize [protected] |
favor encoding speed over compression ratio
Definition at line 525 of file PGFimage.h.
PGFHeader CPGFImage::m_header [protected] |
PGF file header.
Definition at line 519 of file PGFimage.h.
UINT32 CPGFImage::m_height[MaxChannels] [protected] |
height of each channel at current level
Definition at line 517 of file PGFimage.h.
UINT32* CPGFImage::m_levelLength [protected] |
length of each level in bytes; first level starts immediately after this array
Definition at line 515 of file PGFimage.h.
double CPGFImage::m_percent [private] |
progress [0..1]
Definition at line 537 of file PGFimage.h.
PGFPostHeader CPGFImage::m_postHeader [protected] |
PGF post-header.
Definition at line 520 of file PGFimage.h.
PGFPreHeader CPGFImage::m_preHeader [protected] |
PGF pre-header.
Definition at line 518 of file PGFimage.h.
ProgressMode CPGFImage::m_progressMode [private] |
progress mode used in Read and Write; PM_Relative is default mode
Definition at line 538 of file PGFimage.h.
BYTE CPGFImage::m_quant [protected] |
quantization parameter
Definition at line 523 of file PGFimage.h.
bool CPGFImage::m_skipUserData [protected] |
skip user data (metadata) during open
Definition at line 528 of file PGFimage.h.
bool CPGFImage::m_useOMPinDecoder [protected] |
use Open MP in decoder
Definition at line 527 of file PGFimage.h.
bool CPGFImage::m_useOMPinEncoder [protected] |
use Open MP in encoder
Definition at line 526 of file PGFimage.h.
UINT64 CPGFImage::m_userDataPos [protected] |
stream position of user data
Definition at line 521 of file PGFimage.h.
UINT32 CPGFImage::m_width[MaxChannels] [protected] |
width of each channel at current level
Definition at line 516 of file PGFimage.h.
CWaveletTransform* CPGFImage::m_wtChannel[MaxChannels] [protected] |
wavelet transformed color channels
Definition at line 511 of file PGFimage.h.