libpgf
6.11.42
PGF - Progressive Graphics File
|
PGF main class. More...
#include <PGFimage.h>
Public Member Functions | |
CPGFImage () | |
virtual | ~CPGFImage () |
virtual void | Close () |
virtual void | Destroy () |
void | Open (CPGFStream *stream) THROW_ |
bool | IsOpen () const |
void | Read (int level=0, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
void | Read (PGFRect &rect, int level=0, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
void | ReadPreview () THROW_ |
void | Reconstruct (int level=0) THROW_ |
void | GetBitmap (int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) const THROW_ |
void | GetYUV (int pitch, DataT *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) const THROW_ |
void | ImportBitmap (int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
void | ImportYUV (int pitch, DataT *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
void | Write (CPGFStream *stream, UINT32 *nWrittenBytes=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
UINT32 | WriteHeader (CPGFStream *stream) THROW_ |
UINT32 | Write (int level, CallbackPtr cb=NULL, void *data=NULL) THROW_ |
void | ConfigureEncoder (bool useOMP=true, bool favorSpeedOverSize=false) |
void | ConfigureDecoder (bool useOMP=true) |
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) |
BYTE | UsedBitsPerChannel () const |
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 |
const UINT8 * | GetUserData (UINT32 &size) const |
UINT32 | GetEncodedHeaderLength () const |
UINT32 | GetEncodedLevelLength (int level) const |
void | ResetStreamPos () THROW_ |
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 | 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. | |
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_levelwise |
write level-wise (only used with WriteNextLevel) | |
bool | m_streamReinitialized |
stream has been reinitialized | |
PGFRect | m_roi |
region of interest | |
Private Member Functions | |
void | ComputeLevels () |
void | CompleteHeader () |
void | RgbToYuv (int pitch, UINT8 *rgbBuff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data) THROW_ |
void | Downsample (int nChannel) |
void | WriteLevel () THROW_ |
void | SetROI (PGFRect rect) |
UINT8 | Clamp4 (DataT v) const |
UINT16 | Clamp6 (DataT v) const |
UINT8 | Clamp8 (DataT v) const |
UINT16 | Clamp16 (DataT v) const |
UINT32 | Clamp31 (DataT v) const |
Private Attributes | |
RefreshCB | m_cb |
pointer to refresh callback procedure | |
void * | m_cbArg |
refresh callback argument |
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 51 of file PGFimage.h.
Standard constructor: It is used to create a PGF instance for opening and reading.
Definition at line 55 of file PGFimage.cpp.
: m_decoder(0) , m_encoder(0) , m_levelLength(0) , m_quant(0) , m_downsample(false) , m_favorSpeedOverSize(false) , m_useOMPinEncoder(true) , m_useOMPinDecoder(true) #ifdef __PGFROISUPPORT__ , m_levelwise(true) , m_streamReinitialized(false) #endif , m_cb(0) , m_cbArg(0) { // init preHeader memcpy(m_preHeader.magic, Magic, 3); m_preHeader.version = PGFVersion; m_preHeader.hSize = 0; // init postHeader m_postHeader.userData = 0; m_postHeader.userDataLen = 0; // init channels for (int i=0; i < MaxChannels; i++) { m_channel[i] = 0; m_wtChannel[i] = 0; } // set image width and height m_width[0] = 0; m_height[0] = 0; }
CPGFImage::~CPGFImage | ( | ) | [virtual] |
Destructor: Destroy internal data structures.
Definition at line 94 of file PGFimage.cpp.
{ Destroy(); }
BYTE CPGFImage::BPP | ( | ) | const [inline] |
Return the number of bits per pixel. Valid values can be 1, 8, 12, 16, 24, 31, 32, 48, 64.
Definition at line 452 of file PGFimage.h.
BYTE CPGFImage::ChannelDepth | ( | ) | const [inline] |
Return bits per channel of the image's encoder.
Definition at line 401 of file PGFimage.h.
{ 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 396 of file PGFimage.h.
{ 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 439 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 389 of file PGFimage.h.
{ ASSERT(c >= 0 && c < MaxChannels); return m_width[c]; }
UINT16 CPGFImage::Clamp16 | ( | DataT | v | ) | const [inline, private] |
Definition at line 543 of file PGFimage.h.
{ if (v & 0xFFFF0000) return (v < 0) ? (UINT16)0: (UINT16)65535; else return (UINT16)v; }
UINT32 CPGFImage::Clamp31 | ( | DataT | v | ) | const [inline, private] |
Definition at line 546 of file PGFimage.h.
{
return (v < 0) ? 0 : (UINT32)v;
}
UINT8 CPGFImage::Clamp4 | ( | DataT | v | ) | const [inline, private] |
Definition at line 533 of file PGFimage.h.
{ if (v & 0xFFFFFFF0) return (v < 0) ? (UINT8)0: (UINT8)15; else return (UINT8)v; }
UINT16 CPGFImage::Clamp6 | ( | DataT | v | ) | const [inline, private] |
Definition at line 536 of file PGFimage.h.
{ if (v & 0xFFFFFFC0) return (v < 0) ? (UINT16)0: (UINT16)63; else return (UINT16)v; }
UINT8 CPGFImage::Clamp8 | ( | DataT | v | ) | const [inline, private] |
Definition at line 539 of file PGFimage.h.
{ // needs only one test in the normal case if (v & 0xFFFFFF00) return (v < 0) ? (UINT8)0 : (UINT8)255; else return (UINT8)v; }
void CPGFImage::Close | ( | ) | [virtual] |
Close PGF image after opening and reading. Destructor calls this method during destruction.
Definition at line 116 of file PGFimage.cpp.
void CPGFImage::CompleteHeader | ( | ) | [private] |
Definition at line 195 of file PGFimage.cpp.
{ if (m_header.mode == ImageModeUnknown) { // undefined mode switch(m_header.bpp) { case 1: m_header.mode = ImageModeBitmap; break; case 8: m_header.mode = ImageModeGrayScale; break; case 12: m_header.mode = ImageModeRGB12; break; case 16: m_header.mode = ImageModeRGB16; break; case 24: m_header.mode = ImageModeRGBColor; break; case 32: m_header.mode = ImageModeRGBA; break; case 48: m_header.mode = ImageModeRGB48; break; default: m_header.mode = ImageModeRGBColor; break; } } if (!m_header.bpp) { // undefined bpp switch(m_header.mode) { case ImageModeBitmap: m_header.bpp = 1; break; case ImageModeIndexedColor: case ImageModeGrayScale: m_header.bpp = 8; break; case ImageModeRGB12: m_header.bpp = 12; break; case ImageModeRGB16: case ImageModeGray16: m_header.bpp = 16; break; case ImageModeRGBColor: case ImageModeLabColor: m_header.bpp = 24; break; case ImageModeRGBA: case ImageModeCMYKColor: #ifdef __PGF32SUPPORT__ case ImageModeGray32: #endif m_header.bpp = 32; break; case ImageModeRGB48: case ImageModeLab48: m_header.bpp = 48; break; case ImageModeCMYK64: m_header.bpp = 64; break; default: ASSERT(false); m_header.bpp = 24; } } if (m_header.mode == ImageModeRGBColor && m_header.bpp == 32) { // change mode m_header.mode = ImageModeRGBA; } ASSERT(m_header.mode != ImageModeBitmap || m_header.bpp == 1); ASSERT(m_header.mode != ImageModeGrayScale || m_header.bpp == 8); ASSERT(m_header.mode != ImageModeGray16 || m_header.bpp == 16); ASSERT(m_header.mode != ImageModeRGBColor || m_header.bpp == 24); ASSERT(m_header.mode != ImageModeRGBA || m_header.bpp == 32); ASSERT(m_header.mode != ImageModeRGB12 || m_header.bpp == 12); ASSERT(m_header.mode != ImageModeRGB16 || m_header.bpp == 16); ASSERT(m_header.mode != ImageModeRGB48 || m_header.bpp == 48); ASSERT(m_header.mode != ImageModeLabColor || m_header.bpp == 24); ASSERT(m_header.mode != ImageModeLab48 || m_header.bpp == 48); ASSERT(m_header.mode != ImageModeCMYKColor || m_header.bpp == 32); ASSERT(m_header.mode != ImageModeCMYK64 || m_header.bpp == 64); // set number of channels if (!m_header.channels) { switch(m_header.mode) { case ImageModeBitmap: case ImageModeIndexedColor: case ImageModeGrayScale: case ImageModeGray16: #ifdef __PGF32SUPPORT__ case ImageModeGray32: #endif m_header.channels = 1; break; case ImageModeRGBColor: case ImageModeRGB12: case ImageModeRGB16: case ImageModeRGB48: case ImageModeLabColor: case ImageModeLab48: m_header.channels = 3; break; case ImageModeRGBA: case ImageModeCMYKColor: case ImageModeCMYK64: m_header.channels = 4; break; default: ASSERT(false); m_header.channels = 3; } } // store used bits per channel UINT8 bpc = m_header.bpp/m_header.channels; if (bpc > 31) bpc = 31; if (!m_header.usedBitsPerChannel || m_header.usedBitsPerChannel > bpc) { m_header.usedBitsPerChannel = bpc; } }
void CPGFImage::ComputeLevels | ( | ) | [private] |
Definition at line 799 of file PGFimage.cpp.
{ const int maxThumbnailWidth = 20*FilterWidth; const int m = __min(m_header.width, m_header.height); int s = m; if (m_header.nLevels < 1 || m_header.nLevels > MaxLevel) { m_header.nLevels = 1; // compute a good value depending on the size of the image while (s > maxThumbnailWidth) { m_header.nLevels++; s = s/2; } } int levels = m_header.nLevels; // we need a signed value during level reduction // reduce number of levels if the image size is smaller than FilterWidth*2^levels s = FilterWidth*(1 << levels); // must be at least the double filter size because of subsampling while (m < s) { levels--; s = s/2; } if (levels > MaxLevel) m_header.nLevels = MaxLevel; else if (levels < 0) m_header.nLevels = 0; else m_header.nLevels = (UINT8)levels; ASSERT(0 <= m_header.nLevels && m_header.nLevels <= MaxLevel); }
void CPGFImage::ConfigureDecoder | ( | bool | useOMP = true | ) | [inline] |
Configures the encoder.
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. |
Definition at line 249 of file PGFimage.h.
{ m_useOMPinDecoder = useOMP; }
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 244 of file PGFimage.h.
{ m_useOMPinEncoder = useOMP; m_favorSpeedOverSize = favorSpeedOverSize; }
static BYTE CPGFImage::CurrentChannelDepth | ( | BYTE | version = PGFVersion | ) | [inline, static] |
Compute and return codec version.
Definition at line 494 of file PGFimage.h.
{ return (version & PGF32) ? 32 : 16; }
BYTE CPGFImage::CurrentVersion | ( | BYTE | version = PGFVersion | ) | [static] |
Compute and return codec version.
Return version
Definition at line 714 of file PGFimage.cpp.
void CPGFImage::Destroy | ( | ) | [virtual] |
Destroy internal data structures. Destructor calls this method during destruction.
Definition at line 101 of file PGFimage.cpp.
{ Close(); for (int i=0; i < m_header.channels; i++) { delete m_wtChannel[i]; m_wtChannel[i]=0; // also deletes m_channel m_channel[i] = 0; } delete[] m_postHeader.userData; m_postHeader.userData = 0; m_postHeader.userDataLen = 0; delete[] m_levelLength; m_levelLength = 0; delete m_encoder; m_encoder = NULL; }
void CPGFImage::Downsample | ( | int | nChannel | ) | [private] |
Definition at line 754 of file PGFimage.cpp.
{ ASSERT(ch > 0); const int w = m_width[0]; const int w2 = w/2; const int h2 = m_height[0]/2; const int oddW = w%2; // don't use bool -> problems with MaxSpeed optimization const int oddH = m_height[0]%2; // " int i, j; int loPos = 0; int hiPos = w; int sampledPos = 0; DataT* buff = m_channel[ch]; ASSERT(buff); for (i=0; i < h2; i++) { for (j=0; j < w2; j++) { // compute average of pixel block buff[sampledPos] = (buff[loPos] + buff[loPos + 1] + buff[hiPos] + buff[hiPos + 1]) >> 2; loPos += 2; hiPos += 2; sampledPos++; } if (oddW) { buff[sampledPos] = (buff[loPos] + buff[hiPos]) >> 1; loPos++; hiPos++; sampledPos++; } loPos += w; hiPos += w; } if (oddH) { for (j=0; j < w2; j++) { buff[sampledPos] = (buff[loPos] + buff[loPos+1]) >> 1; loPos += 2; hiPos += 2; sampledPos++; } if (oddW) { buff[sampledPos] = buff[loPos]; } } // downsampled image has half width and half height m_width[ch] = (m_width[ch] + 1)/2; m_height[ch] = (m_height[ch] + 1)/2; }
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 1668 of file PGFimage.cpp.
{ ASSERT(buff); UINT32 w = m_width[0]; UINT32 h = m_height[0]; UINT8* targetBuff = 0; // used if ROI is used UINT8* buffStart = 0; // used if ROI is used int targetPitch = 0; // used if ROI is used #ifdef __PGFROISUPPORT__ const PGFRect& roi = (ROIisSupported()) ? m_wtChannel[0]->GetROI(m_currentLevel) : PGFRect(0, 0, w, h); // roi is usually larger than m_roi 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)); ASSERT(w == roi.Width() && h == roi.Height()); ASSERT(roi.left <= levelRoi.left && levelRoi.right <= roi.right); ASSERT(roi.top <= levelRoi.top && levelRoi.bottom <= roi.bottom); if (ROIisSupported() && (levelRoi.Width() < w || levelRoi.Height() < h)) { // ROI is used -> create a temporary image buffer for roi // compute pitch targetPitch = pitch; pitch = AlignWordPos(w*bpp)/8; // create temporary output buffer targetBuff = buff; buff = buffStart = new(std::nothrow) UINT8[pitch*h]; if (!buff) ReturnWithError(InsufficientMemory); } #endif const bool wOdd = (1 == w%2); const double dP = 1.0/h; int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels); if (channelMap == NULL) channelMap = defMap; int sampledPos = 0, yPos = 0; DataT uAvg, vAvg; double percent = 0; UINT32 i, j; switch(m_header.mode) { case ImageModeBitmap: { ASSERT(m_header.channels == 1); ASSERT(m_header.bpp == 1); ASSERT(bpp == 1); const UINT32 w2 = (w + 7)/8; DataT* y = m_channel[0]; ASSERT(y); for (i=0; i < h; i++) { for (j=0; j < w2; j++) { buff[j] = Clamp8(y[yPos++] + YUVoffset8); } yPos += w - w2; //UINT32 cnt = w; //for (j=0; j < w2; j++) { // buff[j] = 0; // for (int k=0; k < 8; k++) { // if (cnt) { // buff[j] <<= 1; // buff[j] |= (1 & (y[yPos++] - YUVoffset8)); // cnt--; // } // } //} buff += pitch; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } break; } case ImageModeIndexedColor: case ImageModeGrayScale: case ImageModeHSLColor: case ImageModeHSBColor: { ASSERT(m_header.channels >= 1); ASSERT(m_header.bpp == m_header.channels*8); ASSERT(bpp%8 == 0); int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { cnt = 0; for (j=0; j < w; j++) { for (int c=0; c < m_header.channels; c++) { buff[cnt + channelMap[c]] = Clamp8(m_channel[c][yPos] + YUVoffset8); } cnt += channels; yPos++; } buff += pitch; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } break; } case ImageModeGray16: { ASSERT(m_header.channels >= 1); ASSERT(m_header.bpp == m_header.channels*16); const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); int cnt, channels; if (bpp%16 == 0) { const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); UINT16 *buff16 = (UINT16 *)buff; int pitch16 = pitch/2; channels = bpp/16; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { cnt = 0; for (j=0; j < w; j++) { for (int c=0; c < m_header.channels; c++) { buff16[cnt + channelMap[c]] = Clamp16(m_channel[c][yPos] + yuvOffset16) << shift; } cnt += channels; yPos++; } buff16 += pitch16; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } else { ASSERT(bpp%8 == 0); const int shift = __max(0, UsedBitsPerChannel() - 8); channels = bpp/8; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { cnt = 0; for (j=0; j < w; j++) { for (int c=0; c < m_header.channels; c++) { buff[cnt + channelMap[c]] = UINT8(Clamp16(m_channel[c][yPos] + yuvOffset16) >> shift); } cnt += channels; yPos++; } buff += pitch; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } break; } case ImageModeRGBColor: { ASSERT(m_header.channels == 3); ASSERT(m_header.bpp == m_header.channels*8); ASSERT(bpp%8 == 0); ASSERT(bpp >= m_header.bpp); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); UINT8 *buffg = &buff[channelMap[1]], *buffr = &buff[channelMap[2]], *buffb = &buff[channelMap[0]]; UINT8 g; int cnt, channels = bpp/8; if(m_downsample){ for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { // image was downsampled uAvg = u[sampledPos]; vAvg = v[sampledPos]; // Yuv buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator buffr[cnt] = Clamp8(uAvg + g); buffb[cnt] = Clamp8(vAvg + g); yPos++; cnt += channels; if (j%2) sampledPos++; } buffb += pitch; buffg += pitch; buffr += pitch; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } }else{ for (i=0; i < h; i++) { cnt = 0; for (j = 0; j < w; j++) { uAvg = u[yPos]; vAvg = v[yPos]; // Yuv buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator buffr[cnt] = Clamp8(uAvg + g); buffb[cnt] = Clamp8(vAvg + g); yPos++; cnt += channels; } buffb += pitch; buffg += pitch; buffr += pitch; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } break; } case ImageModeRGB48: { ASSERT(m_header.channels == 3); ASSERT(m_header.bpp == 48); const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); UINT16 g; int cnt, channels; if (bpp >= 48 && bpp%16 == 0) { const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); UINT16 *buff16 = (UINT16 *)buff; int pitch16 = pitch/2; channels = bpp/16; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { if (m_downsample) { // image was downsampled uAvg = u[sampledPos]; vAvg = v[sampledPos]; } else { uAvg = u[yPos]; vAvg = v[yPos]; } // Yuv g = Clamp16(y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator buff16[cnt + channelMap[1]] = g << shift; buff16[cnt + channelMap[2]] = Clamp16(uAvg + g) << shift; buff16[cnt + channelMap[0]] = Clamp16(vAvg + g) << shift; yPos++; cnt += channels; if (j%2) sampledPos++; } buff16 += pitch16; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } else { ASSERT(bpp%8 == 0); const int shift = __max(0, UsedBitsPerChannel() - 8); channels = bpp/8; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { if (m_downsample) { // image was downsampled uAvg = u[sampledPos]; vAvg = v[sampledPos]; } else { uAvg = u[yPos]; vAvg = v[yPos]; } // Yuv g = Clamp16(y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator buff[cnt + channelMap[1]] = UINT8(g >> shift); buff[cnt + channelMap[2]] = UINT8(Clamp16(uAvg + g) >> shift); buff[cnt + channelMap[0]] = UINT8(Clamp16(vAvg + g) >> shift); yPos++; cnt += channels; if (j%2) sampledPos++; } buff += pitch; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } break; } case ImageModeLabColor: { ASSERT(m_header.channels == 3); ASSERT(m_header.bpp == m_header.channels*8); ASSERT(bpp%8 == 0); DataT* l = m_channel[0]; ASSERT(l); DataT* a = m_channel[1]; ASSERT(a); DataT* b = m_channel[2]; ASSERT(b); int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { if (m_downsample) { // image was downsampled uAvg = a[sampledPos]; vAvg = b[sampledPos]; } else { uAvg = a[yPos]; vAvg = b[yPos]; } buff[cnt + channelMap[0]] = Clamp8(l[yPos] + YUVoffset8); buff[cnt + channelMap[1]] = Clamp8(uAvg + YUVoffset8); buff[cnt + channelMap[2]] = Clamp8(vAvg + YUVoffset8); cnt += channels; yPos++; if (j%2) sampledPos++; } buff += pitch; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } break; } case ImageModeLab48: { ASSERT(m_header.channels == 3); ASSERT(m_header.bpp == m_header.channels*16); const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); DataT* l = m_channel[0]; ASSERT(l); DataT* a = m_channel[1]; ASSERT(a); DataT* b = m_channel[2]; ASSERT(b); int cnt, channels; if (bpp%16 == 0) { const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); UINT16 *buff16 = (UINT16 *)buff; int pitch16 = pitch/2; channels = bpp/16; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { if (m_downsample) { // image was downsampled uAvg = a[sampledPos]; vAvg = b[sampledPos]; } else { uAvg = a[yPos]; vAvg = b[yPos]; } buff16[cnt + channelMap[0]] = Clamp16(l[yPos] + yuvOffset16) << shift; buff16[cnt + channelMap[1]] = Clamp16(uAvg + yuvOffset16) << shift; buff16[cnt + channelMap[2]] = Clamp16(vAvg + yuvOffset16) << shift; cnt += channels; yPos++; if (j%2) sampledPos++; } buff16 += pitch16; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } else { ASSERT(bpp%8 == 0); const int shift = __max(0, UsedBitsPerChannel() - 8); channels = bpp/8; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { if (m_downsample) { // image was downsampled uAvg = a[sampledPos]; vAvg = b[sampledPos]; } else { uAvg = a[yPos]; vAvg = b[yPos]; } buff[cnt + channelMap[0]] = UINT8(Clamp16(l[yPos] + yuvOffset16) >> shift); buff[cnt + channelMap[1]] = UINT8(Clamp16(uAvg + yuvOffset16) >> shift); buff[cnt + channelMap[2]] = UINT8(Clamp16(vAvg + yuvOffset16) >> shift); cnt += channels; yPos++; if (j%2) sampledPos++; } buff += pitch; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } break; } case ImageModeRGBA: case ImageModeCMYKColor: { ASSERT(m_header.channels == 4); ASSERT(m_header.bpp == m_header.channels*8); ASSERT(bpp%8 == 0); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); DataT* a = m_channel[3]; ASSERT(a); UINT8 g, aAvg; int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { if (m_downsample) { // image was downsampled uAvg = u[sampledPos]; vAvg = v[sampledPos]; aAvg = Clamp8(a[sampledPos] + YUVoffset8); } else { uAvg = u[yPos]; vAvg = v[yPos]; aAvg = Clamp8(a[yPos] + YUVoffset8); } // Yuv buff[cnt + channelMap[1]] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator buff[cnt + channelMap[2]] = Clamp8(uAvg + g); buff[cnt + channelMap[0]] = Clamp8(vAvg + g); buff[cnt + channelMap[3]] = aAvg; yPos++; cnt += channels; if (j%2) sampledPos++; } buff += pitch; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } break; } case ImageModeCMYK64: { ASSERT(m_header.channels == 4); ASSERT(m_header.bpp == 64); const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); DataT* a = m_channel[3]; ASSERT(a); UINT16 g, aAvg; int cnt, channels; if (bpp%16 == 0) { const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); UINT16 *buff16 = (UINT16 *)buff; int pitch16 = pitch/2; channels = bpp/16; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { if (m_downsample) { // image was downsampled uAvg = u[sampledPos]; vAvg = v[sampledPos]; aAvg = Clamp16(a[sampledPos] + yuvOffset16); } else { uAvg = u[yPos]; vAvg = v[yPos]; aAvg = Clamp16(a[yPos] + yuvOffset16); } // Yuv g = Clamp16(y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator buff16[cnt + channelMap[1]] = g << shift; buff16[cnt + channelMap[2]] = Clamp16(uAvg + g) << shift; buff16[cnt + channelMap[0]] = Clamp16(vAvg + g) << shift; buff16[cnt + channelMap[3]] = aAvg << shift; yPos++; cnt += channels; if (j%2) sampledPos++; } buff16 += pitch16; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } else { ASSERT(bpp%8 == 0); const int shift = __max(0, UsedBitsPerChannel() - 8); channels = bpp/8; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { if (m_downsample) { // image was downsampled uAvg = u[sampledPos]; vAvg = v[sampledPos]; aAvg = Clamp16(a[sampledPos] + yuvOffset16); } else { uAvg = u[yPos]; vAvg = v[yPos]; aAvg = Clamp16(a[yPos] + yuvOffset16); } // Yuv g = Clamp16(y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator buff[cnt + channelMap[1]] = UINT8(g >> shift); buff[cnt + channelMap[2]] = UINT8(Clamp16(uAvg + g) >> shift); buff[cnt + channelMap[0]] = UINT8(Clamp16(vAvg + g) >> shift); buff[cnt + channelMap[3]] = UINT8(aAvg >> shift); yPos++; cnt += channels; if (j%2) sampledPos++; } buff += pitch; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } break; } #ifdef __PGF32SUPPORT__ case ImageModeGray32: { ASSERT(m_header.channels == 1); ASSERT(m_header.bpp == 32); const int yuvOffset32 = 1 << (UsedBitsPerChannel() - 1); DataT* y = m_channel[0]; ASSERT(y); if (bpp == 32) { const int shift = 32 - UsedBitsPerChannel(); ASSERT(shift >= 0); UINT32 *buff32 = (UINT32 *)buff; int pitch32 = pitch/4; for (i=0; i < h; i++) { for (j=0; j < w; j++) { buff32[j] = Clamp31(y[yPos++] + yuvOffset32) << shift; } buff32 += pitch32; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } else if (bpp == 16) { const int usedBits = UsedBitsPerChannel(); UINT16 *buff16 = (UINT16 *)buff; int pitch16 = pitch/2; if (usedBits < 16) { const int shift = 16 - usedBits; for (i=0; i < h; i++) { for (j=0; j < w; j++) { buff16[j] = Clamp16(y[yPos++] + yuvOffset32) << shift; } buff16 += pitch16; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } else { const int shift = __max(0, usedBits - 16); for (i=0; i < h; i++) { for (j=0; j < w; j++) { buff16[j] = UINT16(Clamp31(y[yPos++] + yuvOffset32) >> shift); } buff16 += pitch16; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } } else { ASSERT(bpp == 8); const int shift = __max(0, UsedBitsPerChannel() - 8); for (i=0; i < h; i++) { for (j=0; j < w; j++) { buff[j] = UINT8(Clamp31(y[yPos++] + yuvOffset32) >> shift); } buff += pitch; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } break; } #endif case ImageModeRGB12: { ASSERT(m_header.channels == 3); ASSERT(m_header.bpp == m_header.channels*4); ASSERT(bpp == m_header.channels*4); ASSERT(!m_downsample); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); UINT16 yval; int cnt; for (i=0; i < h; i++) { cnt = 0; for (j=0; j < w; j++) { // Yuv uAvg = u[yPos]; vAvg = v[yPos]; yval = Clamp4(y[yPos++] + YUVoffset4 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator if (j%2 == 0) { buff[cnt] = UINT8(Clamp4(vAvg + yval) | (yval << 4)); cnt++; buff[cnt] = Clamp4(uAvg + yval); } else { buff[cnt] |= Clamp4(vAvg + yval) << 4; cnt++; buff[cnt] = UINT8(yval | (Clamp4(uAvg + yval) << 4)); cnt++; } } buff += pitch; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } break; } case ImageModeRGB16: { ASSERT(m_header.channels == 3); ASSERT(m_header.bpp == 16); ASSERT(bpp == 16); ASSERT(!m_downsample); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); UINT16 yval; UINT16 *buff16 = (UINT16 *)buff; int pitch16 = pitch/2; for (i=0; i < h; i++) { for (j=0; j < w; j++) { // Yuv uAvg = u[yPos]; vAvg = v[yPos]; yval = Clamp6(y[yPos++] + YUVoffset6 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator buff16[j] = (yval << 5) | ((Clamp6(uAvg + yval) >> 1) << 11) | (Clamp6(vAvg + yval) >> 1); } buff16 += pitch16; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } break; } default: ASSERT(false); } #ifdef __PGFROISUPPORT__ if (targetBuff) { // copy valid ROI (m_roi) from temporary buffer (roi) to target buffer if (bpp%8 == 0) { BYTE bypp = bpp/8; buff = buffStart + (levelRoi.top - roi.top)*pitch + (levelRoi.left - roi.left)*bypp; w = levelRoi.Width()*bypp; h = levelRoi.Height(); for (i=0; i < h; i++) { for (j=0; j < w; j++) { targetBuff[j] = buff[j]; } targetBuff += targetPitch; buff += pitch; } } else { // to do } delete[] buffStart; } #endif }
DataT* CPGFImage::GetChannel | ( | int | c = 0 | ) | [inline] |
Return the background color of an RGB image with transparency channel.
c | A channel index |
Definition at line 315 of file PGFimage.h.
{ ASSERT(c >= 0 && c < MaxChannels); return m_channel[c]; }
void CPGFImage::GetColorTable | ( | UINT32 | iFirstColor, |
UINT32 | nColors, | ||
RGBQUAD * | prgbColors | ||
) | const |
Retrieves red, green, blue (RGB) color values from a range of entries in the palette of the DIB section. It might throw an IOException.
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 1240 of file PGFimage.cpp.
{ if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError); for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) { prgbColors[j] = m_postHeader.clut[i]; } }
const RGBQUAD* CPGFImage::GetColorTable | ( | ) | const [inline] |
Definition at line 328 of file PGFimage.h.
{ return m_postHeader.clut; }
UINT32 CPGFImage::GetEncodedHeaderLength | ( | ) | const |
Return the length of all encoded headers in bytes. Precondition: The PGF image has been opened with a call of Open(...).
Definition at line 592 of file PGFimage.cpp.
{ ASSERT(m_decoder); return m_decoder->GetEncodedHeaderLength(); }
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 358 of file PGFimage.h.
{ 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 333 of file PGFimage.h.
{ 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 339 of file PGFimage.h.
{ return (1 << m_header.usedBitsPerChannel) - 1; }
const UINT8 * CPGFImage::GetUserData | ( | UINT32 & | size | ) | const |
Return user data and size of user data.
size | [out] Size of user data in bytes. |
Definition at line 309 of file PGFimage.cpp.
{ size = m_postHeader.userDataLen; return m_postHeader.userData; }
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 2426 of file PGFimage.cpp.
{ ASSERT(buff); const UINT32 w = m_width[0]; const UINT32 h = m_height[0]; const bool wOdd = (1 == w%2); const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32); const int pitch2 = pitch/DataTSize; const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16; const double dP = 1.0/h; int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels); if (channelMap == NULL) channelMap = defMap; int sampledPos = 0, yPos = 0; DataT uAvg, vAvg; double percent = 0; UINT32 i, j; if (m_header.channels == 3) { ASSERT(bpp%dataBits == 0); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { if (m_downsample) { // image was downsampled uAvg = u[sampledPos]; vAvg = v[sampledPos]; } else { uAvg = u[yPos]; vAvg = v[yPos]; } buff[cnt + channelMap[0]] = y[yPos]; buff[cnt + channelMap[1]] = uAvg; buff[cnt + channelMap[2]] = vAvg; yPos++; cnt += channels; if (j%2) sampledPos++; } buff += pitch2; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } else if (m_header.channels == 4) { ASSERT(m_header.bpp == m_header.channels*8); ASSERT(bpp%dataBits == 0); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); DataT* a = m_channel[3]; ASSERT(a); UINT8 aAvg; int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels); for (i=0; i < h; i++) { if (i%2) sampledPos -= (w + 1)/2; cnt = 0; for (j=0; j < w; j++) { if (m_downsample) { // image was downsampled uAvg = u[sampledPos]; vAvg = v[sampledPos]; aAvg = Clamp8(a[sampledPos] + yuvOffset); } else { uAvg = u[yPos]; vAvg = v[yPos]; aAvg = Clamp8(a[yPos] + yuvOffset); } // Yuv buff[cnt + channelMap[0]] = y[yPos]; buff[cnt + channelMap[1]] = uAvg; buff[cnt + channelMap[2]] = vAvg; buff[cnt + channelMap[3]] = aAvg; yPos++; cnt += channels; if (j%2) sampledPos++; } buff += pitch2; if (wOdd) sampledPos++; if (cb) { percent += dP; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } }
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 415 of file PGFimage.h.
{ 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 737 of file PGFimage.cpp.
{ ASSERT(buff); ASSERT(m_channel[0]); // color transform RgbToYuv(pitch, buff, bpp, channelMap, cb, data); if (m_downsample) { // Subsampling of the chrominance and alpha channels for (int i=1; i < m_header.channels; i++) { Downsample(i); } } }
bool CPGFImage::ImportIsSupported | ( | BYTE | mode | ) | [static] |
Check for valid import image mode.
mode | Image mode |
Definition at line 1195 of file PGFimage.cpp.
{ size_t size = DataTSize; if (size >= 2) { switch(mode) { case ImageModeBitmap: case ImageModeIndexedColor: case ImageModeGrayScale: case ImageModeRGBColor: case ImageModeCMYKColor: case ImageModeHSLColor: case ImageModeHSBColor: //case ImageModeDuotone: case ImageModeLabColor: case ImageModeRGB12: case ImageModeRGB16: case ImageModeRGBA: return true; } } if (size >= 3) { switch(mode) { case ImageModeGray16: case ImageModeRGB48: case ImageModeLab48: case ImageModeCMYK64: //case ImageModeDuotone16: return true; } } if (size >=4) { switch(mode) { case ImageModeGray32: return true; } } return false; }
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 2537 of file PGFimage.cpp.
{ ASSERT(buff); const double dP = 1.0/m_header.height; const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32); const int pitch2 = pitch/DataTSize; const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16; int yPos = 0, cnt = 0; double percent = 0; int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels); if (channelMap == NULL) channelMap = defMap; if (m_header.channels == 3) { ASSERT(bpp%dataBits == 0); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels); for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } cnt = 0; for (UINT32 w=0; w < m_header.width; w++) { y[yPos] = buff[cnt + channelMap[0]]; u[yPos] = buff[cnt + channelMap[1]]; v[yPos] = buff[cnt + channelMap[2]]; yPos++; cnt += channels; } buff += pitch2; } } else if (m_header.channels == 4) { ASSERT(bpp%dataBits == 0); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); DataT* a = m_channel[3]; ASSERT(a); const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels); for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } cnt = 0; for (UINT32 w=0; w < m_header.width; w++) { y[yPos] = buff[cnt + channelMap[0]]; u[yPos] = buff[cnt + channelMap[1]]; v[yPos] = buff[cnt + channelMap[2]]; a[yPos] = buff[cnt + channelMap[3]] - yuvOffset; yPos++; cnt += channels; } buff += pitch2; } } if (m_downsample) { // Subsampling of the chrominance and alpha channels for (int i=1; i < m_header.channels; i++) { Downsample(i); } } }
bool CPGFImage::IsOpen | ( | ) | const [inline] |
Returns true if the PGF has been opened and not closed.
Definition at line 81 of file PGFimage.h.
{ 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 422 of file PGFimage.h.
{ 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 484 of file PGFimage.h.
{ ASSERT(level >= 0); UINT32 h = (height >> level); return ((h << level) == height) ? h : h + 1; }
BYTE CPGFImage::Levels | ( | ) | const [inline] |
Return the number of image levels.
Definition at line 427 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 477 of file PGFimage.h.
{ ASSERT(level >= 0); UINT32 w = (width >> level); return ((w << level) == width) ? w : w + 1; }
BYTE CPGFImage::Mode | ( | ) | const [inline] |
Return the image mode. An image mode is a predefined constant value (see also PGFtypes.h) compatible with Adobe Photoshop. It represents an image type and format.
Definition at line 446 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 125 of file PGFimage.cpp.
{ ASSERT(stream); m_decoder = new CDecoder(stream, m_preHeader, m_header, m_postHeader, m_levelLength, m_useOMPinDecoder); if (m_header.nLevels > MaxLevel) ReturnWithError(FormatCannotRead); // set current level m_currentLevel = m_header.nLevels; // set image width and height m_width[0] = m_header.width; m_height[0] = m_header.height; // complete header CompleteHeader(); // interpret quant parameter if (m_header.quality > DownsampleThreshold && (m_header.mode == ImageModeRGBColor || m_header.mode == ImageModeRGBA || m_header.mode == ImageModeRGB48 || m_header.mode == ImageModeCMYKColor || m_header.mode == ImageModeCMYK64 || m_header.mode == ImageModeLabColor || m_header.mode == ImageModeLab48)) { m_downsample = true; m_quant = m_header.quality - 1; } else { m_downsample = false; m_quant = m_header.quality; } // set channel dimensions (chrominance is subsampled by factor 2) if (m_downsample) { for (int i=1; i < m_header.channels; i++) { m_width[i] = (m_width[0] + 1)/2; m_height[i] = (m_height[0] + 1)/2; } } else { for (int i=1; i < m_header.channels; i++) { m_width[i] = m_width[0]; m_height[i] = m_height[0]; } } if (m_header.nLevels > 0) { // init wavelet subbands for (int i=0; i < m_header.channels; i++) { m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels); } } else { // very small image: we don't use DWT and encoding // read channels for (int c=0; c < m_header.channels; c++) { const UINT32 size = m_width[c]*m_height[c]; m_channel[c] = new DataT[size]; // read channel data from stream for (UINT32 i=0; i < size; i++) { int count = DataTSize; stream->Read(&count, &m_channel[c][i]); if (count != DataTSize) ReturnWithError(MissingData); } } } }
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 433 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 370 of file PGFimage.cpp.
{ ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform ASSERT(m_decoder); #ifdef __PGFROISUPPORT__ if (ROIisSupported() && m_header.nLevels > 0) { // new encoding scheme supporting ROI PGFRect rect(0, 0, m_header.width, m_header.height); Read(rect, level, cb, data); return; } #endif if (m_header.nLevels == 0) { if (level == 0) { // the data has already been read during open // now update progress if (cb) { if ((*cb)(1.0, true, data)) ReturnWithError(EscapePressed); } } } else { const int levelDiff = m_currentLevel - level; double percent = pow(0.25, levelDiff); // encoding scheme without ROI while (m_currentLevel > level) { for (int i=0; i < m_header.channels; i++) { ASSERT(m_wtChannel[i]); // decode file and write stream to m_wtChannel if (m_currentLevel == m_header.nLevels) { // last level also has LL band m_wtChannel[i]->GetSubband(m_currentLevel, LL)->PlaceTile(*m_decoder, m_quant); } if (m_preHeader.version & Version5) { // since version 5 m_wtChannel[i]->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant); m_wtChannel[i]->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant); } else { // until version 4 m_decoder->DecodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); } m_wtChannel[i]->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant); } volatile OSError error = NoError; // volatile prevents optimizations #pragma omp parallel for default(shared) for (int i=0; i < m_header.channels; i++) { // inverse transform from m_wtChannel to m_channel if (error == NoError) { OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]); if (err != NoError) error = err; } ASSERT(m_channel[i]); } if (error != NoError) ReturnWithError(error); // set new level: must be done before refresh callback m_currentLevel--; // now we have to refresh the display if (m_cb) m_cb(m_cbArg); // now update progress if (cb) { percent += 3*percent; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } } // automatically closing if (m_currentLevel == 0) Close(); }
void CPGFImage::Read | ( | PGFRect & | rect, |
int | level = 0 , |
||
CallbackPtr | cb = NULL , |
||
void * | data = NULL |
||
) |
Read a rectangular region of interest of a PGF image at current stream position. The origin of the coordinate axis is the top-left corner of the image. All coordinates are measured in pixels. It might throw an IOException.
rect | [inout] Rectangular region of interest (ROI). The rect might be cropped. |
level | [0, nLevels) The image level of the resulting image in the internal image buffer. |
cb | A pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding. |
data | Data Pointer to C++ class container to host callback procedure. |
UINT32 CPGFImage::ReadEncodedData | ( | int | level, |
UINT8 * | target, | ||
UINT32 | targetLen | ||
) | const |
Reads the data of an encoded PGF level and copies it to a target buffer without decoding. Precondition: The PGF image has been opened with a call of Open(...). It might throw an IOException.
level | The image level |
target | The target buffer |
targetLen | The length of the target buffer in bytes |
Definition at line 638 of file PGFimage.cpp.
{ ASSERT(level >= 0 && level < m_header.nLevels); ASSERT(target); ASSERT(targetLen > 0); ASSERT(m_decoder); // reset stream position m_decoder->SetStreamPosToData(); // position stream UINT64 offset = 0; for (int i=m_header.nLevels - 1; i > level; i--) { offset += m_levelLength[m_header.nLevels - 1 - i]; } m_decoder->Skip(offset); // compute number of bytes to read UINT32 len = __min(targetLen, GetEncodedLevelLength(level)); // read data len = m_decoder->ReadEncodedData(target, len); ASSERT(len >= 0 && len <= targetLen); return len; }
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 604 of file PGFimage.cpp.
{ ASSERT(target); ASSERT(targetLen > 0); ASSERT(m_decoder); // reset stream position m_decoder->SetStreamPosToStart(); // compute number of bytes to read UINT32 len = __min(targetLen, GetEncodedHeaderLength()); // read data len = m_decoder->ReadEncodedData(target, len); ASSERT(len >= 0 && len <= targetLen); return len; }
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 115 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 319 of file PGFimage.cpp.
{ if (m_header.nLevels == 0) { // image didn't use wavelet transform if (level == 0) { for (int i=0; i < m_header.channels; i++) { ASSERT(m_wtChannel[i]); m_channel[i] = m_wtChannel[i]->GetSubband(0, LL)->GetBuffer(); } } } else { int currentLevel = m_header.nLevels; if (ROIisSupported()) { // enable ROI reading SetROI(PGFRect(0, 0, m_header.width, m_header.height)); } while (currentLevel > level) { for (int i=0; i < m_header.channels; i++) { ASSERT(m_wtChannel[i]); // dequantize subbands if (currentLevel == m_header.nLevels) { // last level also has LL band m_wtChannel[i]->GetSubband(currentLevel, LL)->Dequantize(m_quant); } m_wtChannel[i]->GetSubband(currentLevel, HL)->Dequantize(m_quant); m_wtChannel[i]->GetSubband(currentLevel, LH)->Dequantize(m_quant); m_wtChannel[i]->GetSubband(currentLevel, HH)->Dequantize(m_quant); // inverse transform from m_wtChannel to m_channel if (!m_wtChannel[i]->InverseTransform(currentLevel, &m_width[i], &m_height[i], &m_channel[i])) ReturnWithError(InsufficientMemory); ASSERT(m_channel[i]); } currentLevel--; } } }
void CPGFImage::ResetStreamPos | ( | ) |
Reset stream position to start of PGF pre-header
Definition at line 624 of file PGFimage.cpp.
{ ASSERT(m_decoder); return m_decoder->SetStreamPosToStart(); }
void CPGFImage::RgbToYuv | ( | int | pitch, |
UINT8 * | rgbBuff, | ||
BYTE | bpp, | ||
int | channelMap[], | ||
CallbackPtr | cb, | ||
void * | data | ||
) | [private] |
Definition at line 1279 of file PGFimage.cpp.
{ ASSERT(buff); int yPos = 0, cnt = 0; double percent = 0; const double dP = 1.0/m_header.height; int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels); if (channelMap == NULL) channelMap = defMap; switch(m_header.mode) { case ImageModeBitmap: { ASSERT(m_header.channels == 1); ASSERT(m_header.bpp == 1); ASSERT(bpp == 1); const UINT32 w = m_header.width; const UINT32 w2 = (m_header.width + 7)/8; DataT* y = m_channel[0]; ASSERT(y); for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } for (UINT32 j=0; j < w2; j++) { y[yPos++] = buff[j] - YUVoffset8; } for (UINT32 j=w2; j < w; j++) { y[yPos++] = YUVoffset8; } //UINT cnt = w; //for (UINT32 j=0; j < w2; j++) { // for (int k=7; k >= 0; k--) { // if (cnt) { // y[yPos++] = YUVoffset8 + (1 & (buff[j] >> k)); // cnt--; // } // } //} buff += pitch; } } break; case ImageModeIndexedColor: case ImageModeGrayScale: case ImageModeHSLColor: case ImageModeHSBColor: case ImageModeLabColor: { ASSERT(m_header.channels >= 1); ASSERT(m_header.bpp == m_header.channels*8); ASSERT(bpp%8 == 0); const int channels = bpp/8; ASSERT(channels >= m_header.channels); for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } cnt = 0; for (UINT32 w=0; w < m_header.width; w++) { for (int c=0; c < m_header.channels; c++) { m_channel[c][yPos] = buff[cnt + channelMap[c]] - YUVoffset8; } cnt += channels; yPos++; } buff += pitch; } } break; case ImageModeGray16: case ImageModeLab48: { ASSERT(m_header.channels >= 1); ASSERT(m_header.bpp == m_header.channels*16); ASSERT(bpp%16 == 0); UINT16 *buff16 = (UINT16 *)buff; const int pitch16 = pitch/2; const int channels = bpp/16; ASSERT(channels >= m_header.channels); const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } cnt = 0; for (UINT32 w=0; w < m_header.width; w++) { for (int c=0; c < m_header.channels; c++) { m_channel[c][yPos] = (buff16[cnt + channelMap[c]] >> shift) - yuvOffset16; } cnt += channels; yPos++; } buff16 += pitch16; } } break; case ImageModeRGBColor: { ASSERT(m_header.channels == 3); ASSERT(m_header.bpp == m_header.channels*8); ASSERT(bpp%8 == 0); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); const int channels = bpp/8; ASSERT(channels >= m_header.channels); UINT8 b, g, r; for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } cnt = 0; for (UINT32 w=0; w < m_header.width; w++) { b = buff[cnt + channelMap[0]]; g = buff[cnt + channelMap[1]]; r = buff[cnt + channelMap[2]]; // Yuv y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8; u[yPos] = r - g; v[yPos] = b - g; yPos++; cnt += channels; } buff += pitch; } } break; case ImageModeRGB48: { ASSERT(m_header.channels == 3); ASSERT(m_header.bpp == m_header.channels*16); ASSERT(bpp%16 == 0); UINT16 *buff16 = (UINT16 *)buff; const int pitch16 = pitch/2; const int channels = bpp/16; ASSERT(channels >= m_header.channels); const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); UINT16 b, g, r; for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } cnt = 0; for (UINT32 w=0; w < m_header.width; w++) { b = buff16[cnt + channelMap[0]] >> shift; g = buff16[cnt + channelMap[1]] >> shift; r = buff16[cnt + channelMap[2]] >> shift; // Yuv y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16; u[yPos] = r - g; v[yPos] = b - g; yPos++; cnt += channels; } buff16 += pitch16; } } break; case ImageModeRGBA: case ImageModeCMYKColor: { ASSERT(m_header.channels == 4); ASSERT(m_header.bpp == m_header.channels*8); ASSERT(bpp%8 == 0); const int channels = bpp/8; ASSERT(channels >= m_header.channels); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); DataT* a = m_channel[3]; ASSERT(a); UINT8 b, g, r; for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } cnt = 0; for (UINT32 w=0; w < m_header.width; w++) { b = buff[cnt + channelMap[0]]; g = buff[cnt + channelMap[1]]; r = buff[cnt + channelMap[2]]; // Yuv y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8; u[yPos] = r - g; v[yPos] = b - g; a[yPos++] = buff[cnt + channelMap[3]] - YUVoffset8; cnt += channels; } buff += pitch; } } break; case ImageModeCMYK64: { ASSERT(m_header.channels == 4); ASSERT(m_header.bpp == m_header.channels*16); ASSERT(bpp%16 == 0); UINT16 *buff16 = (UINT16 *)buff; const int pitch16 = pitch/2; const int channels = bpp/16; ASSERT(channels >= m_header.channels); const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0); const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); DataT* a = m_channel[3]; ASSERT(a); UINT16 b, g, r; for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } cnt = 0; for (UINT32 w=0; w < m_header.width; w++) { b = buff16[cnt + channelMap[0]] >> shift; g = buff16[cnt + channelMap[1]] >> shift; r = buff16[cnt + channelMap[2]] >> shift; // Yuv y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16; u[yPos] = r - g; v[yPos] = b - g; a[yPos++] = (buff16[cnt + channelMap[3]] >> shift) - yuvOffset16; cnt += channels; } buff16 += pitch16; } } break; #ifdef __PGF32SUPPORT__ case ImageModeGray32: { ASSERT(m_header.channels == 1); ASSERT(m_header.bpp == 32); ASSERT(bpp == 32); ASSERT(DataTSize == sizeof(UINT32)); DataT* y = m_channel[0]; ASSERT(y); UINT32 *buff32 = (UINT32 *)buff; const int pitch32 = pitch/4; const int shift = 32 - UsedBitsPerChannel(); ASSERT(shift >= 0); const DataT yuvOffset32 = 1 << (UsedBitsPerChannel() - 1); for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } for (UINT32 w=0; w < m_header.width; w++) { y[yPos++] = (buff32[w] >> shift) - yuvOffset32; } buff32 += pitch32; } } break; #endif case ImageModeRGB12: { ASSERT(m_header.channels == 3); ASSERT(m_header.bpp == m_header.channels*4); ASSERT(bpp == m_header.channels*4); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); UINT8 rgb = 0, b, g, r; for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } cnt = 0; for (UINT32 w=0; w < m_header.width; w++) { if (w%2 == 0) { // even pixel position rgb = buff[cnt]; b = rgb & 0x0F; g = (rgb & 0xF0) >> 4; cnt++; rgb = buff[cnt]; r = rgb & 0x0F; } else { // odd pixel position b = (rgb & 0xF0) >> 4; cnt++; rgb = buff[cnt]; g = rgb & 0x0F; r = (rgb & 0xF0) >> 4; cnt++; } // Yuv y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset4; u[yPos] = r - g; v[yPos] = b - g; yPos++; } buff += pitch; } } break; case ImageModeRGB16: { ASSERT(m_header.channels == 3); ASSERT(m_header.bpp == 16); ASSERT(bpp == 16); DataT* y = m_channel[0]; ASSERT(y); DataT* u = m_channel[1]; ASSERT(u); DataT* v = m_channel[2]; ASSERT(v); UINT16 *buff16 = (UINT16 *)buff; UINT16 rgb, b, g, r; const int pitch16 = pitch/2; for (UINT32 h=0; h < m_header.height; h++) { if (cb) { if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); percent += dP; } for (UINT32 w=0; w < m_header.width; w++) { rgb = buff16[w]; r = (rgb & 0xF800) >> 10; // highest 5 bits g = (rgb & 0x07E0) >> 5; // middle 6 bits b = (rgb & 0x001F) << 1; // lowest 5 bits // Yuv y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset6; u[yPos] = r - g; v[yPos] = b - g; yPos++; } buff16 += pitch16; } } break; default: ASSERT(false); } }
bool CPGFImage::ROIisSupported | ( | ) | const [inline] |
Return true if the pgf image supports Region Of Interest (ROI).
Definition at line 457 of file PGFimage.h.
{ return (m_preHeader.version & PGFROI) == PGFROI; }
void CPGFImage::SetChannel | ( | DataT * | channel, |
int | c = 0 |
||
) | [inline] |
Set background of an RGB image with transparency channel or reset to default background.
bg | A pointer to a background color or NULL (reset to default background) Set background of an RGB image with transparency channel. |
red | A red value (0..255) |
green | A green value (0..255) |
blue | A blue value (0..255) Set internal PGF image buffer channel. |
channel | A YUV data channel |
c | A channel index |
Definition at line 267 of file PGFimage.h.
{ 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 1254 of file PGFimage.cpp.
{ if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError); for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) { m_postHeader.clut[i] = prgbColors[j]; } }
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 |
userData | A user-defined memory block |
userDataLength | The size of user-defined memory block in bytes |
Definition at line 836 of file PGFimage.cpp.
{ ASSERT(!m_decoder); // current image must be closed ASSERT(header.quality <= MaxQuality); // init state #ifdef __PGFROISUPPORT__ m_levelwise = true; m_streamReinitialized = false; #endif // init preHeader memcpy(m_preHeader.magic, Magic, 3); m_preHeader.version = PGFVersion | flags; m_preHeader.hSize = HeaderSize; // copy header memcpy(&m_header, &header, HeaderSize); // complete header CompleteHeader(); // check and set number of levels ComputeLevels(); // check for downsample if (m_header.quality > DownsampleThreshold && (m_header.mode == ImageModeRGBColor || m_header.mode == ImageModeRGBA || m_header.mode == ImageModeRGB48 || m_header.mode == ImageModeCMYKColor || m_header.mode == ImageModeCMYK64 || m_header.mode == ImageModeLabColor || m_header.mode == ImageModeLab48)) { m_downsample = true; m_quant = m_header.quality - 1; } else { m_downsample = false; m_quant = m_header.quality; } // update header size and copy user data if (m_header.mode == ImageModeIndexedColor) { m_preHeader.hSize += ColorTableSize; } if (userDataLength && userData) { m_postHeader.userData = new(std::nothrow) UINT8[userDataLength]; if (!m_postHeader.userData) ReturnWithError(InsufficientMemory); m_postHeader.userDataLen = userDataLength; memcpy(m_postHeader.userData, userData, userDataLength); m_preHeader.hSize += userDataLength; } // allocate channels for (int i=0; i < m_header.channels; i++) { // set current width and height m_width[i] = m_header.width; m_height[i] = m_header.height; // allocate channels ASSERT(!m_channel[i]); m_channel[i] = new(std::nothrow) DataT[m_header.width*m_header.height]; if (!m_channel[i]) { if (i) i--; while(i) { delete[] m_channel[i]; m_channel[i] = 0; i--; } ReturnWithError(InsufficientMemory); } } }
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 684 of file PGFimage.cpp.
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 296 of file PGFimage.h.
void CPGFImage::SetROI | ( | PGFRect | rect | ) | [private] |
BYTE CPGFImage::UsedBitsPerChannel | ( | ) | const |
Returns number of used bits per input/output image channel. Precondition: header must be initialized.
Definition at line 702 of file PGFimage.cpp.
BYTE CPGFImage::Version | ( | ) | const [inline] |
Returns images' PGF version
Definition at line 462 of file PGFimage.h.
{ 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 408 of file PGFimage.h.
{ 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 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 contains a valid header (see also SetHeader(...)). Please note: the earlier parameter nLevels has now to be set with SetHeader. Either specify the number of levels or use the value 0 for automatic setting. 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 1077 of file PGFimage.cpp.
{ ASSERT(stream); ASSERT(m_preHeader.hSize); #ifdef __PGFROISUPPORT__ // don't use level-wise writing m_levelwise = false; #endif // create wavelet transform channels and encoder WriteHeader(stream); int levels = m_header.nLevels; double percent = pow(0.25, levels - 1); if (levels == 0) { // data has been written in WriteHeader // now update progress if (cb) { if ((*cb)(1, true, data)) ReturnWithError(EscapePressed); } } else { // encode quantized wavelet coefficients and write to PGF file // encode subbands, higher levels first // color channels are interleaved // encode all levels for (m_currentLevel = levels; m_currentLevel > 0; ) { WriteLevel(); // decrements m_currentLevel // now update progress if (cb) { percent *= 4; if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed); } } // flush encoder and write level lengths m_encoder->Flush(); UINT32 nBytes = m_encoder->WriteLevelLength(); // inclusive header // delete encoder delete m_encoder; m_encoder = NULL; // return written bytes if (nWrittenBytes) *nWrittenBytes += nBytes; } ASSERT(!m_encoder); }
UINT32 CPGFImage::Write | ( | int | level, |
CallbackPtr | cb = NULL , |
||
void * | data = NULL |
||
) |
Encode and write down to given level at current stream position. A PGF image is structered in levels, numbered between 0 and Levels() - 1. Each level can be seen as a single image, containing the same content as all other levels, but in a different size (width, height). The image size at level i is double the size (width, height) of the image at level i+1. The image at level 0 contains the original size. Precondition: the PGF image contains a valid header (see also SetHeader(...)) and WriteHeader() has been called before Write(). The ROI encoding scheme is used. 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 writing a single level. If cb returns true, then it stops proceeding. |
data | Data Pointer to C++ class container to host callback procedure. |
UINT32 CPGFImage::WriteHeader | ( | CPGFStream * | stream | ) |
Create wavelet transform channels and encoder. Call this method before your first call of Write(int level), but after SetHeader(). Don't use this method when you call Write(). It might throw an IOException.
stream | A PGF stream |
Definition at line 914 of file PGFimage.cpp.
{ ASSERT(m_header.nLevels <= MaxLevel); ASSERT(m_header.quality <= MaxQuality); // quality is already initialized if (m_header.nLevels > 0) { volatile OSError error = NoError; // volatile prevents optimizations // create new wt channels #pragma omp parallel for default(shared) for (int i=0; i < m_header.channels; i++) { DataT *temp = NULL; if (error == NoError) { if (m_wtChannel[i]) { ASSERT(m_channel[i]); // copy m_channel to temp int size = m_height[i]*m_width[i]; temp = new(std::nothrow) DataT[size]; if (temp) { memcpy(temp, m_channel[i], size*DataTSize); delete m_wtChannel[i]; // also deletes m_channel } else { error = InsufficientMemory; } } if (error == NoError) { if (temp) m_channel[i] = temp; m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels, m_channel[i]); // wavelet subband decomposition for (int l=0; error == NoError && l < m_header.nLevels; l++) { OSError err = m_wtChannel[i]->ForwardTransform(l, m_quant); if (err != NoError) error = err; } } } } if (error != NoError) ReturnWithError(error); m_currentLevel = m_header.nLevels; #ifdef __PGFROISUPPORT__ if (m_levelwise) { m_preHeader.version |= PGFROI; } #endif // create encoder and eventually write headers and levelLength m_encoder = new CEncoder(stream, m_preHeader, m_header, m_postHeader, m_levelLength, m_useOMPinEncoder); if (m_favorSpeedOverSize) m_encoder->FavorSpeedOverSize(); #ifdef __PGFROISUPPORT__ if (ROIisSupported()) { // new encoding scheme supporting ROI m_encoder->SetROI(); } #endif // return number of written bytes return m_encoder->ComputeHeaderLength(); } else { // very small image: we don't use DWT and encoding // create encoder and eventually write headers and levelLength m_encoder = new CEncoder(stream, m_preHeader, m_header, m_postHeader, m_levelLength, m_useOMPinEncoder); // write channels for (int c=0; c < m_header.channels; c++) { const UINT32 size = m_width[c]*m_height[c]; // write channel data into stream for (UINT32 i=0; i < size; i++) { int count = DataTSize; stream->Write(&count, &m_channel[c][i]); } } // write level lengths UINT32 nBytes = m_encoder->WriteLevelLength(); // return written bytes inclusive header // delete encoder delete m_encoder; m_encoder = NULL; // return number of written bytes return nBytes; } }
void CPGFImage::WriteLevel | ( | ) | [private] |
Definition at line 1009 of file PGFimage.cpp.
{ ASSERT(m_encoder); ASSERT(m_currentLevel > 0); ASSERT(m_header.nLevels > 0); #ifdef __PGFROISUPPORT__ if (ROIisSupported()) { const int lastChannel = m_header.channels - 1; for (int i=0; i < m_header.channels; i++) { m_wtChannel[i]->SetROI(); // get number of tiles and tile indices const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel); const UINT32 lastTile = nTiles - 1; if (m_currentLevel == m_header.nLevels) { // last level also has LL band ASSERT(nTiles == 1); m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder); m_encoder->EncodeTileBuffer(); } for (UINT32 tileY=0; tileY < nTiles; tileY++) { for (UINT32 tileX=0; tileX < nTiles; tileX++) { m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, true, tileX, tileY); m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, true, tileX, tileY); m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, true, tileX, tileY); if (i == lastChannel && tileY == lastTile && tileX == lastTile) { // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level. m_encoder->SetEncodedLevel(--m_currentLevel); } m_encoder->EncodeTileBuffer(); } } } } else #endif { for (int i=0; i < m_header.channels; i++) { ASSERT(m_wtChannel[i]); if (m_currentLevel == m_header.nLevels) { // last level also has LL band m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder); } //encoder.EncodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); // until version 4 m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder); // since version 5 m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder); // since version 5 m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder); } // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level. m_encoder->SetEncodedLevel(--m_currentLevel); } }
RefreshCB CPGFImage::m_cb [private] |
pointer to refresh callback procedure
Definition at line 520 of file PGFimage.h.
void* CPGFImage::m_cbArg [private] |
refresh callback argument
Definition at line 521 of file PGFimage.h.
DataT* CPGFImage::m_channel[MaxChannels] [protected] |
untransformed channels in YUV format
Definition at line 498 of file PGFimage.h.
int CPGFImage::m_currentLevel [protected] |
transform level of current image
Definition at line 507 of file PGFimage.h.
CDecoder* CPGFImage::m_decoder [protected] |
PGF decoder.
Definition at line 499 of file PGFimage.h.
bool CPGFImage::m_downsample [protected] |
chrominance channels are downsampled
Definition at line 509 of file PGFimage.h.
CEncoder* CPGFImage::m_encoder [protected] |
PGF encoder.
Definition at line 500 of file PGFimage.h.
bool CPGFImage::m_favorSpeedOverSize [protected] |
favor encoding speed over compression ratio
Definition at line 510 of file PGFimage.h.
PGFHeader CPGFImage::m_header [protected] |
PGF file header.
Definition at line 505 of file PGFimage.h.
UINT32 CPGFImage::m_height[MaxChannels] [protected] |
height of each channel at current level
Definition at line 503 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 501 of file PGFimage.h.
bool CPGFImage::m_levelwise [protected] |
write level-wise (only used with WriteNextLevel)
Definition at line 514 of file PGFimage.h.
PGFPostHeader CPGFImage::m_postHeader [protected] |
PGF post header.
Definition at line 506 of file PGFimage.h.
PGFPreHeader CPGFImage::m_preHeader [protected] |
PGF pre header.
Definition at line 504 of file PGFimage.h.
BYTE CPGFImage::m_quant [protected] |
quantization parameter
Definition at line 508 of file PGFimage.h.
PGFRect CPGFImage::m_roi [protected] |
region of interest
Definition at line 516 of file PGFimage.h.
bool CPGFImage::m_streamReinitialized [protected] |
stream has been reinitialized
Definition at line 515 of file PGFimage.h.
bool CPGFImage::m_useOMPinDecoder [protected] |
use Open MP in decoder
Definition at line 512 of file PGFimage.h.
bool CPGFImage::m_useOMPinEncoder [protected] |
use Open MP in encoder
Definition at line 511 of file PGFimage.h.
UINT32 CPGFImage::m_width[MaxChannels] [protected] |
width of each channel at current level
Definition at line 502 of file PGFimage.h.
CWaveletTransform* CPGFImage::m_wtChannel[MaxChannels] [protected] |
wavelet transformed color channels
Definition at line 497 of file PGFimage.h.