libpgf  6.12.24
PGF - Progressive Graphics File
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
PGFimage.cpp
Go to the documentation of this file.
00001 /*
00002  * The Progressive Graphics File; http://www.libpgf.org
00003  * 
00004  * $Date: 2007-02-03 13:04:21 +0100 (Sa, 03 Feb 2007) $
00005  * $Revision: 280 $
00006  * 
00007  * This file Copyright (C) 2006 xeraina GmbH, Switzerland
00008  * 
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
00011  * as published by the Free Software Foundation; either version 2.1
00012  * of the License, or (at your option) any later version.
00013  * 
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022  */
00023 
00028 
00029 #include "PGFimage.h"
00030 #include "Decoder.h"
00031 #include "Encoder.h"
00032 #include <cmath>
00033 #include <cstring>
00034 
00035 #define YUVoffset4              8                               // 2^3
00036 #define YUVoffset6              32                              // 2^5
00037 #define YUVoffset8              128                             // 2^7
00038 #define YUVoffset16             32768                   // 2^15
00039 //#define YUVoffset31           1073741824              // 2^30
00040 
00042 // global methods and variables
00043 #ifdef NEXCEPTIONS
00044         OSError _PGF_Error_;
00045 
00046         OSError GetLastPGFError() {
00047                 OSError tmp = _PGF_Error_;
00048                 _PGF_Error_ = NoError;
00049                 return tmp;
00050         }
00051 #endif
00052 
00054 // Standard constructor: It is used to create a PGF instance for opening and reading.
00055 CPGFImage::CPGFImage() 
00056 : m_decoder(0)
00057 , m_encoder(0)
00058 , m_levelLength(0)
00059 , m_quant(0)
00060 , m_userDataPos(0)
00061 , m_downsample(false)
00062 , m_favorSpeedOverSize(false)
00063 , m_useOMPinEncoder(true)
00064 , m_useOMPinDecoder(true)
00065 , m_skipUserData(false)
00066 #ifdef __PGFROISUPPORT__
00067 , m_streamReinitialized(false)
00068 #endif
00069 , m_cb(0)
00070 , m_cbArg(0)
00071 , m_progressMode(PM_Relative)
00072 , m_percent(0)
00073 {
00074 
00075         // init preHeader
00076         memcpy(m_preHeader.magic, Magic, 3);
00077         m_preHeader.version = PGFVersion;
00078         m_preHeader.hSize = 0;
00079 
00080         // init postHeader
00081         m_postHeader.userData = 0;
00082         m_postHeader.userDataLen = 0;
00083 
00084         // init channels
00085         for (int i=0; i < MaxChannels; i++) {
00086                 m_channel[i] = 0;
00087                 m_wtChannel[i] = 0;
00088         }
00089 
00090         // set image width and height
00091         m_width[0] = 0;
00092         m_height[0] = 0;
00093 }
00094 
00096 // Destructor: Destroy internal data structures.
00097 CPGFImage::~CPGFImage() {
00098         Destroy();
00099 }
00100 
00102 // Destroy internal data structures.
00103 // Destructor calls this method during destruction.
00104 void CPGFImage::Destroy() {
00105         Close();
00106 
00107         for (int i=0; i < m_header.channels; i++) {
00108                 delete m_wtChannel[i]; m_wtChannel[i]=0; // also deletes m_channel
00109                 m_channel[i] = 0;
00110         }
00111         delete[] m_postHeader.userData; m_postHeader.userData = 0; m_postHeader.userDataLen = 0;
00112         delete[] m_levelLength; m_levelLength = 0;
00113         delete m_encoder; m_encoder = NULL;
00114         
00115         m_userDataPos = 0;
00116 }
00117 
00119 // Close PGF image after opening and reading.
00120 // Destructor calls this method during destruction.
00121 void CPGFImage::Close() {
00122         delete m_decoder; m_decoder = 0;
00123 }
00124 
00126 // Open a PGF image at current stream position: read pre-header, header, levelLength, and ckeck image type.
00127 // Precondition: The stream has been opened for reading.
00128 // It might throw an IOException.
00129 // @param stream A PGF stream
00130 void CPGFImage::Open(CPGFStream *stream) THROW_ {
00131         ASSERT(stream);
00132 
00133         // create decoder and read PGFPreHeader PGFHeader PGFPostHeader LevelLengths
00134         m_decoder = new CDecoder(stream, m_preHeader, m_header, m_postHeader, m_levelLength, 
00135                 m_userDataPos, m_useOMPinDecoder, m_skipUserData);
00136 
00137         if (m_header.nLevels > MaxLevel) ReturnWithError(FormatCannotRead);
00138 
00139         // set current level
00140         m_currentLevel = m_header.nLevels;
00141 
00142         // set image width and height
00143         m_width[0] = m_header.width;
00144         m_height[0] = m_header.height;
00145 
00146         // complete header
00147         CompleteHeader();
00148 
00149         // interpret quant parameter
00150         if (m_header.quality > DownsampleThreshold && 
00151                 (m_header.mode == ImageModeRGBColor || 
00152                  m_header.mode == ImageModeRGBA || 
00153                  m_header.mode == ImageModeRGB48 || 
00154                  m_header.mode == ImageModeCMYKColor || 
00155                  m_header.mode == ImageModeCMYK64 || 
00156                  m_header.mode == ImageModeLabColor || 
00157                  m_header.mode == ImageModeLab48)) {
00158                 m_downsample = true;
00159                 m_quant = m_header.quality - 1;
00160         } else {
00161                 m_downsample = false;
00162                 m_quant = m_header.quality;
00163         }
00164 
00165         // set channel dimensions (chrominance is subsampled by factor 2)
00166         if (m_downsample) {
00167                 for (int i=1; i < m_header.channels; i++) {
00168                         m_width[i] = (m_width[0] + 1)/2;
00169                         m_height[i] = (m_height[0] + 1)/2;
00170                 }
00171         } else {
00172                 for (int i=1; i < m_header.channels; i++) {
00173                         m_width[i] = m_width[0];
00174                         m_height[i] = m_height[0];
00175                 }
00176         }
00177 
00178         if (m_header.nLevels > 0) {
00179                 // init wavelet subbands
00180                 for (int i=0; i < m_header.channels; i++) {
00181                         m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels);
00182                 }
00183 
00184                 // used in Read when PM_Absolute
00185                 m_percent = pow(0.25, m_header.nLevels);
00186 
00187         } else {
00188                 // very small image: we don't use DWT and encoding
00189 
00190                 // read channels
00191                 for (int c=0; c < m_header.channels; c++) {
00192                         const UINT32 size = m_width[c]*m_height[c];
00193                         m_channel[c] = new(std::nothrow) DataT[size];
00194                         if (!m_channel[c]) ReturnWithError(InsufficientMemory);
00195 
00196                         // read channel data from stream
00197                         for (UINT32 i=0; i < size; i++) {
00198                                 int count = DataTSize;
00199                                 stream->Read(&count, &m_channel[c][i]);
00200                                 if (count != DataTSize) ReturnWithError(MissingData);
00201                         }
00202                 }
00203         }
00204 }
00205 
00207 void CPGFImage::CompleteHeader() {
00208         if (m_header.mode == ImageModeUnknown) {
00209                 // undefined mode
00210                 switch(m_header.bpp) {
00211                 case 1: m_header.mode = ImageModeBitmap; break;
00212                 case 8: m_header.mode = ImageModeGrayScale; break;
00213                 case 12: m_header.mode = ImageModeRGB12; break;
00214                 case 16: m_header.mode = ImageModeRGB16; break;
00215                 case 24: m_header.mode = ImageModeRGBColor; break;
00216                 case 32: m_header.mode = ImageModeRGBA; break;
00217                 case 48: m_header.mode = ImageModeRGB48; break;
00218                 default: m_header.mode = ImageModeRGBColor; break;
00219                 }
00220         }
00221         if (!m_header.bpp) {
00222                 // undefined bpp
00223                 switch(m_header.mode) {
00224                 case ImageModeBitmap: 
00225                         m_header.bpp = 1;
00226                         break;
00227                 case ImageModeIndexedColor:
00228                 case ImageModeGrayScale:
00229                         m_header.bpp = 8;
00230                         break;
00231                 case ImageModeRGB12:
00232                         m_header.bpp = 12;
00233                         break;
00234                 case ImageModeRGB16:
00235                 case ImageModeGray16:
00236                         m_header.bpp = 16;
00237                         break;
00238                 case ImageModeRGBColor:
00239                 case ImageModeLabColor:
00240                         m_header.bpp = 24;
00241                         break;
00242                 case ImageModeRGBA:
00243                 case ImageModeCMYKColor:
00244                 case ImageModeGray32:
00245                         m_header.bpp = 32;
00246                         break;
00247                 case ImageModeRGB48:
00248                 case ImageModeLab48:
00249                         m_header.bpp = 48;
00250                         break;
00251                 case ImageModeCMYK64:
00252                         m_header.bpp = 64;
00253                         break;
00254                 default:
00255                         ASSERT(false);
00256                         m_header.bpp = 24;
00257                 }
00258         } 
00259         if (m_header.mode == ImageModeRGBColor && m_header.bpp == 32) {
00260                 // change mode
00261                 m_header.mode = ImageModeRGBA;
00262         }
00263         ASSERT(m_header.mode != ImageModeBitmap || m_header.bpp == 1);
00264         ASSERT(m_header.mode != ImageModeIndexedColor || m_header.bpp == 8);
00265         ASSERT(m_header.mode != ImageModeGrayScale || m_header.bpp == 8);
00266         ASSERT(m_header.mode != ImageModeGray16 || m_header.bpp == 16);
00267         ASSERT(m_header.mode != ImageModeGray32 || m_header.bpp == 32);
00268         ASSERT(m_header.mode != ImageModeRGBColor || m_header.bpp == 24);
00269         ASSERT(m_header.mode != ImageModeRGBA || m_header.bpp == 32);
00270         ASSERT(m_header.mode != ImageModeRGB12 || m_header.bpp == 12);
00271         ASSERT(m_header.mode != ImageModeRGB16 || m_header.bpp == 16);
00272         ASSERT(m_header.mode != ImageModeRGB48 || m_header.bpp == 48);
00273         ASSERT(m_header.mode != ImageModeLabColor || m_header.bpp == 24);
00274         ASSERT(m_header.mode != ImageModeLab48 || m_header.bpp == 48);
00275         ASSERT(m_header.mode != ImageModeCMYKColor || m_header.bpp == 32);
00276         ASSERT(m_header.mode != ImageModeCMYK64 || m_header.bpp == 64);
00277 
00278         // set number of channels
00279         if (!m_header.channels) {
00280                 switch(m_header.mode) {
00281                 case ImageModeBitmap: 
00282                 case ImageModeIndexedColor:
00283                 case ImageModeGrayScale:
00284                 case ImageModeGray16:
00285                 case ImageModeGray32:
00286                         m_header.channels = 1; 
00287                         break;
00288                 case ImageModeRGBColor:
00289                 case ImageModeRGB12:
00290                 case ImageModeRGB16:
00291                 case ImageModeRGB48:
00292                 case ImageModeLabColor:
00293                 case ImageModeLab48:
00294                         m_header.channels = 3;
00295                         break;
00296                 case ImageModeRGBA:
00297                 case ImageModeCMYKColor:
00298                 case ImageModeCMYK64:
00299                         m_header.channels = 4;
00300                         break;
00301                 default:
00302                         ASSERT(false);
00303                         m_header.channels = 3;
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 
00320 const UINT8* CPGFImage::GetUserData(UINT32& size) const {
00321         size = m_postHeader.userDataLen;
00322         return m_postHeader.userData;
00323 }
00324 
00330 void CPGFImage::Reconstruct(int level /*= 0*/) THROW_ {
00331         if (m_header.nLevels == 0) {
00332                 // image didn't use wavelet transform
00333                 if (level == 0) {
00334                         for (int i=0; i < m_header.channels; i++) {
00335                                 ASSERT(m_wtChannel[i]);
00336                                 m_channel[i] = m_wtChannel[i]->GetSubband(0, LL)->GetBuffer();
00337                         }
00338                 }
00339         } else {
00340                 int currentLevel = m_header.nLevels;
00341 
00342                 if (ROIisSupported()) {
00343                         // enable ROI reading
00344                         SetROI(PGFRect(0, 0, m_header.width, m_header.height));
00345                 }
00346 
00347                 while (currentLevel > level) {
00348                         for (int i=0; i < m_header.channels; i++) {
00349                                 ASSERT(m_wtChannel[i]);
00350                                 // dequantize subbands
00351                                 if (currentLevel == m_header.nLevels) { 
00352                                         // last level also has LL band
00353                                         m_wtChannel[i]->GetSubband(currentLevel, LL)->Dequantize(m_quant);
00354                                 }
00355                                 m_wtChannel[i]->GetSubband(currentLevel, HL)->Dequantize(m_quant);
00356                                 m_wtChannel[i]->GetSubband(currentLevel, LH)->Dequantize(m_quant);
00357                                 m_wtChannel[i]->GetSubband(currentLevel, HH)->Dequantize(m_quant);
00358 
00359                                 // inverse transform from m_wtChannel to m_channel
00360                                 OSError err = m_wtChannel[i]->InverseTransform(currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
00361                                 if (err != NoError) ReturnWithError(err);
00362                                 ASSERT(m_channel[i]);
00363                         }
00364 
00365                         currentLevel--;
00366                 }
00367         }
00368 }
00369 
00371 // Read and decode some levels of a PGF image at current stream position.
00372 // A PGF image is structered in levels, numbered between 0 and Levels() - 1.
00373 // Each level can be seen as a single image, containing the same content
00374 // as all other levels, but in a different size (width, height).
00375 // The image size at level i is double the size (width, height) of the image at level i+1.
00376 // The image at level 0 contains the original size.
00377 // Precondition: The PGF image has been opened with a call of Open(...).
00378 // It might throw an IOException.
00379 // @param level The image level of the resulting image in the internal image buffer.
00380 // @param cb A pointer to a callback procedure. The procedure is called after reading a single level. If cb returns true, then it stops proceeding.
00381 // @param data Data Pointer to C++ class container to host callback procedure.
00382 void CPGFImage::Read(int level /*= 0*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
00383         ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
00384         ASSERT(m_decoder);
00385 
00386 #ifdef __PGFROISUPPORT__
00387         if (ROIisSupported() && m_header.nLevels > 0) {
00388                 // new encoding scheme supporting ROI
00389                 PGFRect rect(0, 0, m_header.width, m_header.height);
00390                 Read(rect, level, cb, data);
00391                 return;
00392         }
00393 #endif
00394 
00395         if (m_header.nLevels == 0) {
00396                 if (level == 0) {
00397                         // the data has already been read during open
00398                         // now update progress
00399                         if (cb) {
00400                                 if ((*cb)(1.0, true, data)) ReturnWithError(EscapePressed);
00401                         }
00402                 }
00403         } else {
00404                 const int levelDiff = m_currentLevel - level;
00405                 double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
00406 
00407                 // encoding scheme without ROI
00408                 while (m_currentLevel > level) {
00409                         for (int i=0; i < m_header.channels; i++) {
00410                                 ASSERT(m_wtChannel[i]);
00411                                 // decode file and write stream to m_wtChannel
00412                                 if (m_currentLevel == m_header.nLevels) { 
00413                                         // last level also has LL band
00414                                         m_wtChannel[i]->GetSubband(m_currentLevel, LL)->PlaceTile(*m_decoder, m_quant);
00415                                 }
00416                                 if (m_preHeader.version & Version5) {
00417                                         // since version 5
00418                                         m_wtChannel[i]->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant);
00419                                         m_wtChannel[i]->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant);
00420                                 } else {
00421                                         // until version 4
00422                                         m_decoder->DecodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant);
00423                                 }
00424                                 m_wtChannel[i]->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant);
00425                         }
00426 
00427                         volatile OSError error = NoError; // volatile prevents optimizations
00428                         #pragma omp parallel for default(shared) 
00429                         for (int i=0; i < m_header.channels; i++) {
00430                                 // inverse transform from m_wtChannel to m_channel
00431                                 if (error == NoError) {
00432                                         OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);       
00433                                         if (err != NoError) error = err;
00434                                 }
00435                                 ASSERT(m_channel[i]);
00436                         }
00437                         if (error != NoError) ReturnWithError(error);
00438 
00439                         // set new level: must be done before refresh callback
00440                         m_currentLevel--;
00441 
00442                         // now we have to refresh the display
00443                         if (m_cb) m_cb(m_cbArg);
00444 
00445                         // now update progress
00446                         if (cb) {
00447                                 percent *= 4;
00448                                 if (m_progressMode == PM_Absolute) m_percent = percent;
00449                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
00450                         }
00451                 }
00452         }
00453 
00454         // automatically closing
00455         if (m_currentLevel == 0) Close();
00456 }
00457 
00458 #ifdef __PGFROISUPPORT__
00459 
00460 
00461 
00462 
00463 
00464 
00465 
00466 
00467 
00468 void CPGFImage::Read(PGFRect& rect, int level /*= 0*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
00469         ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
00470         ASSERT(m_decoder);
00471 
00472         if (m_header.nLevels == 0 || !ROIisSupported()) {
00473                 rect.left = rect.top = 0;
00474                 rect.right = m_header.width; rect.bottom = m_header.height;
00475                 Read(level, cb, data);
00476         } else {
00477                 ASSERT(ROIisSupported());
00478                 // new encoding scheme supporting ROI
00479                 ASSERT(rect.left < m_header.width && rect.top < m_header.height);
00480 
00481                 const int levelDiff = m_currentLevel - level;
00482                 double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
00483                 
00484                 // check level difference
00485                 if (levelDiff <= 0) {
00486                         // it is a new read call, probably with a new ROI
00487                         m_currentLevel = m_header.nLevels;
00488                         m_decoder->SetStreamPosToData();
00489                 }
00490 
00491                 // check rectangle
00492                 if (rect.right == 0 || rect.right > m_header.width) rect.right = m_header.width;
00493                 if (rect.bottom == 0 || rect.bottom > m_header.height) rect.bottom = m_header.height;
00494                 
00495                 // enable ROI decoding and reading
00496                 SetROI(rect);
00497 
00498                 while (m_currentLevel > level) {
00499                         for (int i=0; i < m_header.channels; i++) {
00500                                 ASSERT(m_wtChannel[i]);
00501 
00502                                 // get number of tiles and tile indices
00503                                 const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel);
00504                                 const PGFRect& tileIndices = m_wtChannel[i]->GetTileIndices(m_currentLevel);
00505 
00506                                 // decode file and write stream to m_wtChannel
00507                                 if (m_currentLevel == m_header.nLevels) { // last level also has LL band
00508                                         ASSERT(nTiles == 1);
00509                                         m_decoder->DecodeTileBuffer();
00510                                         m_wtChannel[i]->GetSubband(m_currentLevel, LL)->PlaceTile(*m_decoder, m_quant);
00511                                 }
00512                                 for (UINT32 tileY=0; tileY < nTiles; tileY++) {
00513                                         for (UINT32 tileX=0; tileX < nTiles; tileX++) {
00514                                                 // check relevance of tile
00515                                                 if (tileIndices.IsInside(tileX, tileY)) {
00516                                                         m_decoder->DecodeTileBuffer();
00517                                                         m_wtChannel[i]->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
00518                                                         m_wtChannel[i]->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
00519                                                         m_wtChannel[i]->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
00520                                                 } else {
00521                                                         // skip tile
00522                                                         m_decoder->SkipTileBuffer();
00523                                                 }
00524                                         }
00525                                 }
00526                         }
00527 
00528                         volatile OSError error = NoError; // volatile prevents optimizations
00529                         #pragma omp parallel for default(shared) 
00530                         for (int i=0; i < m_header.channels; i++) {
00531                                 // inverse transform from m_wtChannel to m_channel
00532                                 if (error == NoError) {
00533                                         OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
00534                                         if (err != NoError) error = err;
00535                                 }
00536                                 ASSERT(m_channel[i]);
00537                         }
00538                         if (error != NoError) ReturnWithError(error);
00539 
00540                         // set new level: must be done before refresh callback
00541                         m_currentLevel--;
00542 
00543                         // now we have to refresh the display
00544                         if (m_cb) m_cb(m_cbArg);
00545 
00546                         // now update progress
00547                         if (cb) {
00548                                 percent *= 4;
00549                                 if (m_progressMode == PM_Absolute) m_percent = percent;
00550                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
00551                         }
00552                 }
00553         }
00554 
00555         // automatically closing
00556         if (m_currentLevel == 0) Close();
00557 }
00558 
00562 void CPGFImage::SetROI(PGFRect rect) {
00563         ASSERT(m_decoder);
00564         ASSERT(ROIisSupported());
00565 
00566         // store ROI for a later call of GetBitmap
00567         m_roi = rect;
00568 
00569         // enable ROI decoding
00570         m_decoder->SetROI();
00571 
00572         // enlarge ROI because of border artefacts
00573         const UINT32 dx = FilterWidth/2*(1 << m_currentLevel);
00574         const UINT32 dy = FilterHeight/2*(1 << m_currentLevel);
00575 
00576         if (rect.left < dx) rect.left = 0;
00577         else rect.left -= dx;
00578         if (rect.top < dy) rect.top = 0;
00579         else rect.top -= dy;
00580         rect.right += dx;
00581         if (rect.right > m_header.width) rect.right = m_header.width;
00582         rect.bottom += dy;
00583         if (rect.bottom > m_header.height) rect.bottom = m_header.height;
00584 
00585         // prepare wavelet channels for using ROI
00586         ASSERT(m_wtChannel[0]);
00587         m_wtChannel[0]->SetROI(rect);
00588         if (m_downsample && m_header.channels > 1) {
00589                 // all further channels are downsampled, therefore downsample ROI
00590                 rect.left >>= 1;
00591                 rect.top >>= 1;
00592                 rect.right >>= 1;
00593                 rect.bottom >>= 1;
00594         }
00595         for (int i=1; i < m_header.channels; i++) {
00596                 ASSERT(m_wtChannel[i]);
00597                 m_wtChannel[i]->SetROI(rect);
00598         }
00599 }
00600 
00601 #endif // __PGFROISUPPORT__
00602 
00607 UINT32 CPGFImage::GetEncodedHeaderLength() const { 
00608         ASSERT(m_decoder); 
00609         return m_decoder->GetEncodedHeaderLength(); 
00610 }
00611 
00619 UINT32 CPGFImage::ReadEncodedHeader(UINT8* target, UINT32 targetLen) const THROW_ {
00620         ASSERT(target);
00621         ASSERT(targetLen > 0);
00622         ASSERT(m_decoder);
00623 
00624         // reset stream position
00625         m_decoder->SetStreamPosToStart();
00626 
00627         // compute number of bytes to read
00628         UINT32 len = __min(targetLen, GetEncodedHeaderLength());
00629 
00630         // read data
00631         len = m_decoder->ReadEncodedData(target, len);
00632         ASSERT(len >= 0 && len <= targetLen);
00633 
00634         return len;
00635 }
00636 
00639 void CPGFImage::ResetStreamPos() THROW_ {
00640         ASSERT(m_decoder);
00641         return m_decoder->SetStreamPosToStart(); 
00642 }
00643 
00653 UINT32 CPGFImage::ReadEncodedData(int level, UINT8* target, UINT32 targetLen) const THROW_ {
00654         ASSERT(level >= 0 && level < m_header.nLevels);
00655         ASSERT(target);
00656         ASSERT(targetLen > 0);
00657         ASSERT(m_decoder);
00658 
00659         // reset stream position
00660         m_decoder->SetStreamPosToData();
00661 
00662         // position stream
00663         UINT64 offset = 0;
00664 
00665         for (int i=m_header.nLevels - 1; i > level; i--) {
00666                 offset += m_levelLength[m_header.nLevels - 1 - i];
00667         }
00668         m_decoder->Skip(offset);
00669 
00670         // compute number of bytes to read
00671         UINT32 len = __min(targetLen, GetEncodedLevelLength(level));
00672 
00673         // read data
00674         len = m_decoder->ReadEncodedData(target, len);
00675         ASSERT(len >= 0 && len <= targetLen);
00676 
00677         return len;
00678 }
00679 
00684 void CPGFImage::SetMaxValue(UINT32 maxValue) {
00685         const BYTE bpc = m_header.bpp/m_header.channels;
00686         BYTE pot = 0;
00687 
00688         while(maxValue > 0) {
00689                 pot++;
00690                 maxValue >>= 1;
00691         }
00692         // store bits per channel
00693         if (pot > bpc) pot = bpc;
00694         if (pot > 31) pot = 31;
00695         m_header.usedBitsPerChannel = pot;
00696 }
00697 
00702 BYTE CPGFImage::UsedBitsPerChannel() const {
00703         const BYTE bpc = m_header.bpp/m_header.channels;
00704 
00705         if (bpc > 8) {
00706                 return m_header.usedBitsPerChannel;
00707         } else {
00708                 return bpc;
00709         }
00710 }
00711 
00714 BYTE CPGFImage::CurrentVersion(BYTE version) {
00715         if (version & Version6) return 6;
00716         if (version & Version5) return 5;
00717         if (version & Version2) return 2;
00718         return 1;
00719 }
00720 
00722 // Import an image from a specified image buffer.
00723 // This method is usually called before Write(...) and after SetHeader(...).
00724 // It might throw an IOException.
00725 // The absolute value of pitch is the number of bytes of an image row.
00726 // If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row).
00727 // If pitch is positive, then buff points to the first row of a top-down image (first byte).
00728 // 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
00729 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
00730 // If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
00731 // @param pitch The number of bytes of a row of the image buffer.
00732 // @param buff An image buffer.
00733 // @param bpp The number of bits per pixel used in image buffer.
00734 // @param channelMap A integer array containing the mapping of input channel ordering to expected channel ordering.
00735 // @param cb A pointer to a callback procedure. The procedure is called after each imported buffer row. If cb returns true, then it stops proceeding.
00736 // @param data Data Pointer to C++ class container to host callback procedure.
00737 void CPGFImage::ImportBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[] /*= NULL */, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
00738         ASSERT(buff);
00739         ASSERT(m_channel[0]);
00740 
00741         // color transform
00742         RgbToYuv(pitch, buff, bpp, channelMap, cb, data);
00743 
00744         if (m_downsample) {
00745                 // Subsampling of the chrominance and alpha channels
00746                 for (int i=1; i < m_header.channels; i++) {
00747                         Downsample(i);
00748                 }
00749         }
00750 }
00751 
00753 // Bilinerar Subsampling of channel ch by a factor 2
00754 void CPGFImage::Downsample(int ch) {
00755         ASSERT(ch > 0);
00756 
00757         const int w = m_width[0];
00758         const int w2 = w/2;
00759         const int h2 = m_height[0]/2;
00760         const int oddW = w%2;                           // don't use bool -> problems with MaxSpeed optimization
00761         const int oddH = m_height[0]%2;         // "
00762         int loPos = 0;
00763         int hiPos = w;
00764         int sampledPos = 0;
00765         DataT* buff = m_channel[ch]; ASSERT(buff);
00766 
00767         for (int i=0; i < h2; i++) {
00768                 for (int j=0; j < w2; j++) {
00769                         // compute average of pixel block
00770                         buff[sampledPos] = (buff[loPos] + buff[loPos + 1] + buff[hiPos] + buff[hiPos + 1]) >> 2;
00771                         loPos += 2; hiPos += 2;
00772                         sampledPos++;
00773                 }
00774                 if (oddW) { 
00775                         buff[sampledPos] = (buff[loPos] + buff[hiPos]) >> 1;
00776                         loPos++; hiPos++;
00777                         sampledPos++;
00778                 }
00779                 loPos += w; hiPos += w;
00780         }
00781         if (oddH) {
00782                 for (int j=0; j < w2; j++) {
00783                         buff[sampledPos] = (buff[loPos] + buff[loPos+1]) >> 1;
00784                         loPos += 2; hiPos += 2;
00785                         sampledPos++;
00786                 }
00787                 if (oddW) {
00788                         buff[sampledPos] = buff[loPos];
00789                 }
00790         }
00791 
00792         // downsampled image has half width and half height
00793         m_width[ch] = (m_width[ch] + 1)/2;
00794         m_height[ch] = (m_height[ch] + 1)/2;
00795 }
00796 
00798 void CPGFImage::ComputeLevels() {
00799         const int maxThumbnailWidth = 20*FilterWidth;
00800         const int m = __min(m_header.width, m_header.height);
00801         int s = m;
00802 
00803         if (m_header.nLevels < 1 || m_header.nLevels > MaxLevel) {
00804                 m_header.nLevels = 1;
00805                 // compute a good value depending on the size of the image
00806                 while (s > maxThumbnailWidth) {
00807                         m_header.nLevels++;
00808                         s = s/2;
00809                 }
00810         }
00811 
00812         int levels = m_header.nLevels; // we need a signed value during level reduction
00813 
00814         // reduce number of levels if the image size is smaller than FilterWidth*2^levels
00815         s = FilterWidth*(1 << levels);  // must be at least the double filter size because of subsampling
00816         while (m < s) {
00817                 levels--;
00818                 s = s/2;
00819         }
00820         if (levels > MaxLevel) m_header.nLevels = MaxLevel;
00821         else if (levels < 0) m_header.nLevels = 0;
00822         else m_header.nLevels = (UINT8)levels;
00823 
00824         // used in Write when PM_Absolute
00825         m_percent = pow(0.25, m_header.nLevels);
00826 
00827         ASSERT(0 <= m_header.nLevels && m_header.nLevels <= MaxLevel);
00828 }
00829 
00838 void CPGFImage::SetHeader(const PGFHeader& header, BYTE flags /*=0*/, UINT8* userData /*= 0*/, UINT32 userDataLength /*= 0*/) THROW_ {
00839         ASSERT(!m_decoder);     // current image must be closed
00840         ASSERT(header.quality <= MaxQuality);
00841 
00842         // init state
00843 #ifdef __PGFROISUPPORT__
00844         m_streamReinitialized = false;
00845 #endif
00846 
00847         // init preHeader
00848         memcpy(m_preHeader.magic, Magic, 3);
00849         m_preHeader.version = PGFVersion | flags;
00850         m_preHeader.hSize = HeaderSize;
00851 
00852         // copy header
00853         memcpy(&m_header, &header, HeaderSize);
00854 
00855         // complete header
00856         CompleteHeader();
00857 
00858         // check and set number of levels
00859         ComputeLevels();
00860 
00861         // check for downsample
00862         if (m_header.quality > DownsampleThreshold &&  (m_header.mode == ImageModeRGBColor || 
00863                                                                                                         m_header.mode == ImageModeRGBA || 
00864                                                                                                         m_header.mode == ImageModeRGB48 || 
00865                                                                                                         m_header.mode == ImageModeCMYKColor || 
00866                                                                                                         m_header.mode == ImageModeCMYK64 || 
00867                                                                                                         m_header.mode == ImageModeLabColor || 
00868                                                                                                         m_header.mode == ImageModeLab48)) {
00869                 m_downsample = true;
00870                 m_quant = m_header.quality - 1;
00871         } else {
00872                 m_downsample = false;
00873                 m_quant = m_header.quality;
00874         }
00875 
00876         // update header size and copy user data
00877         if (m_header.mode == ImageModeIndexedColor) {
00878                 // update header size
00879                 m_preHeader.hSize += ColorTableSize;
00880         }
00881         if (userDataLength && userData) {
00882                 m_postHeader.userData = new(std::nothrow) UINT8[userDataLength];
00883                 if (!m_postHeader.userData) ReturnWithError(InsufficientMemory);
00884                 m_postHeader.userDataLen = userDataLength;
00885                 memcpy(m_postHeader.userData, userData, userDataLength);
00886                 // update header size
00887                 m_preHeader.hSize += userDataLength;
00888         }
00889 
00890         // allocate channels
00891         for (int i=0; i < m_header.channels; i++) {
00892                 // set current width and height
00893                 m_width[i] = m_header.width;
00894                 m_height[i] = m_header.height;
00895 
00896                 // allocate channels
00897                 ASSERT(!m_channel[i]);
00898                 m_channel[i] = new(std::nothrow) DataT[m_header.width*m_header.height];
00899                 if (!m_channel[i]) {
00900                         if (i) i--;
00901                         while(i) {
00902                                 delete[] m_channel[i]; m_channel[i] = 0;
00903                                 i--;
00904                         }
00905                         ReturnWithError(InsufficientMemory);
00906                 }
00907         }
00908 }
00909 
00917 UINT32 CPGFImage::WriteHeader(CPGFStream* stream) THROW_ {
00918         ASSERT(m_header.nLevels <= MaxLevel);
00919         ASSERT(m_header.quality <= MaxQuality); // quality is already initialized
00920 
00921         if (m_header.nLevels > 0) {
00922                 volatile OSError error = NoError; // volatile prevents optimizations
00923                 // create new wt channels
00924                 #pragma omp parallel for default(shared)
00925                 for (int i=0; i < m_header.channels; i++) {
00926                         DataT *temp = NULL;
00927                         if (error == NoError) {
00928                                 if (m_wtChannel[i]) {
00929                                         ASSERT(m_channel[i]);
00930                                         // copy m_channel to temp
00931                                         int size = m_height[i]*m_width[i];
00932                                         temp = new(std::nothrow) DataT[size];
00933                                         if (temp) {
00934                                                 memcpy(temp, m_channel[i], size*DataTSize);
00935                                                 delete m_wtChannel[i];  // also deletes m_channel
00936                                         } else {
00937                                                 error = InsufficientMemory;
00938                                         }
00939                                 }
00940                                 if (error == NoError) {
00941                                         if (temp) m_channel[i] = temp;
00942                                         m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels, m_channel[i]);
00943                                 #ifdef __PGFROISUPPORT__
00944                                         m_wtChannel[i]->SetROI(PGFRect(0, 0, m_header.width, m_header.height));
00945                                 #endif
00946                                         
00947                                         // wavelet subband decomposition 
00948                                         for (int l=0; error == NoError && l < m_header.nLevels; l++) {
00949                                                 OSError err = m_wtChannel[i]->ForwardTransform(l, m_quant);
00950                                                 if (err != NoError) error = err;
00951                                         }
00952                                 }
00953                         }
00954                 }
00955                 if (error != NoError) ReturnWithError(error);
00956 
00957                 m_currentLevel = m_header.nLevels;
00958 
00959                 // create encoder and eventually write headers and levelLength
00960                 m_encoder = new CEncoder(stream, m_preHeader, m_header, m_postHeader, m_userDataPos, m_useOMPinEncoder);
00961                 if (m_favorSpeedOverSize) m_encoder->FavorSpeedOverSize();
00962 
00963         #ifdef __PGFROISUPPORT__
00964                 if (ROIisSupported()) {
00965                         // new encoding scheme supporting ROI
00966                         m_encoder->SetROI();
00967                 }
00968         #endif
00969 
00970         } else {
00971                 // very small image: we don't use DWT and encoding
00972 
00973                 // create encoder and eventually write headers and levelLength
00974                 m_encoder = new CEncoder(stream, m_preHeader, m_header, m_postHeader, m_userDataPos, m_useOMPinEncoder);
00975         }
00976 
00977         INT64 nBytes = m_encoder->ComputeHeaderLength();
00978         return (nBytes > 0) ? (UINT32)nBytes : 0;
00979 }
00980 
00982 // Encode and write next level of a PGF image at current stream position.
00983 // A PGF image is structered in levels, numbered between 0 and Levels() - 1.
00984 // Each level can be seen as a single image, containing the same content
00985 // as all other levels, but in a different size (width, height).
00986 // The image size at level i is double the size (width, height) of the image at level i+1.
00987 // The image at level 0 contains the original size.
00988 // It might throw an IOException.
00989 void CPGFImage::WriteLevel() THROW_ {
00990         ASSERT(m_encoder);
00991         ASSERT(m_currentLevel > 0);
00992         ASSERT(m_header.nLevels > 0);
00993 
00994 #ifdef __PGFROISUPPORT__
00995         if (ROIisSupported()) {
00996                 const int lastChannel = m_header.channels - 1;
00997 
00998                 for (int i=0; i < m_header.channels; i++) {
00999                         // get number of tiles and tile indices
01000                         const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel);
01001                         const UINT32 lastTile = nTiles - 1;
01002 
01003                         if (m_currentLevel == m_header.nLevels) {
01004                                 // last level also has LL band
01005                                 ASSERT(nTiles == 1);
01006                                 m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder);
01007                                 m_encoder->EncodeTileBuffer();
01008                         }
01009                         for (UINT32 tileY=0; tileY < nTiles; tileY++) {
01010                                 for (UINT32 tileX=0; tileX < nTiles; tileX++) {
01011                                         m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, true, tileX, tileY);
01012                                         m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, true, tileX, tileY);
01013                                         m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, true, tileX, tileY);
01014                                         if (i == lastChannel && tileY == lastTile && tileX == lastTile) {
01015                                                 // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level.
01016                                                 m_encoder->SetEncodedLevel(--m_currentLevel);
01017                                         }
01018                                         m_encoder->EncodeTileBuffer();
01019                                 }
01020                         }
01021                 }
01022         } else 
01023 #endif
01024         {
01025                 for (int i=0; i < m_header.channels; i++) {
01026                         ASSERT(m_wtChannel[i]);
01027                         if (m_currentLevel == m_header.nLevels) { 
01028                                 // last level also has LL band
01029                                 m_wtChannel[i]->GetSubband(m_currentLevel, LL)->ExtractTile(*m_encoder);
01030                         }
01031                         //encoder.EncodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); // until version 4
01032                         m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder); // since version 5
01033                         m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder); // since version 5
01034                         m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder);
01035                 }
01036 
01037                 // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level.
01038                 m_encoder->SetEncodedLevel(--m_currentLevel);
01039         }
01040 }
01041 
01043 // Return written levelLength bytes
01044 UINT32 CPGFImage::UpdatePostHeaderSize() THROW_ {
01045         ASSERT(m_encoder);
01046 
01047         INT64 offset = m_encoder->ComputeOffset(); ASSERT(offset >= 0);
01048 
01049         if (offset > 0) {
01050                 // update post-header size and rewrite pre-header
01051                 m_preHeader.hSize += (UINT32)offset;
01052                 m_encoder->UpdatePostHeaderSize(m_preHeader);
01053         }
01054 
01055         // write dummy levelLength into stream
01056         return m_encoder->WriteLevelLength(m_levelLength);
01057 }
01058 
01069 UINT32 CPGFImage::WriteImage(CPGFStream* stream, CallbackPtr cb /*= NULL*/, void *data /*= NULL*/) THROW_ {
01070         ASSERT(stream);
01071         ASSERT(m_preHeader.hSize);
01072 
01073         int levels = m_header.nLevels;
01074         double percent = pow(0.25, levels);
01075 
01076         // update post-header size, rewrite pre-header, and write dummy levelLength
01077         UINT32 nWrittenBytes = UpdatePostHeaderSize();
01078 
01079         if (levels == 0) {
01080                 // write channels
01081                 for (int c=0; c < m_header.channels; c++) {
01082                         const UINT32 size = m_width[c]*m_height[c];
01083 
01084                         // write channel data into stream
01085                         for (UINT32 i=0; i < size; i++) {
01086                                 int count = DataTSize;
01087                                 stream->Write(&count, &m_channel[c][i]);
01088                         }
01089                 }
01090 
01091                 // now update progress
01092                 if (cb) {
01093                         if ((*cb)(1, true, data)) ReturnWithError(EscapePressed);
01094                 }
01095 
01096         } else {
01097                 // encode quantized wavelet coefficients and write to PGF file
01098                 // encode subbands, higher levels first
01099                 // color channels are interleaved
01100 
01101                 // encode all levels
01102                 for (m_currentLevel = levels; m_currentLevel > 0; ) {
01103                         WriteLevel(); // decrements m_currentLevel
01104 
01105                         // now update progress
01106                         if (cb) {
01107                                 percent *= 4;
01108                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01109                         }
01110                 }
01111 
01112                 // flush encoder and write level lengths
01113                 m_encoder->Flush();
01114         }
01115 
01116         // update level lengths
01117         nWrittenBytes = m_encoder->UpdateLevelLength(); // return written image bytes 
01118 
01119         // delete encoder
01120         delete m_encoder; m_encoder = NULL;
01121 
01122         ASSERT(!m_encoder);
01123 
01124         return nWrittenBytes;
01125 }
01126 
01140 void CPGFImage::Write(CPGFStream* stream, UINT32* nWrittenBytes /*= NULL*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
01141         ASSERT(stream);
01142         ASSERT(m_preHeader.hSize);
01143 
01144         // create wavelet transform channels and encoder
01145         UINT32 nBytes = WriteHeader(stream);
01146 
01147         // write image
01148         nBytes += WriteImage(stream, cb, data);
01149 
01150         // return written bytes
01151         if (nWrittenBytes) *nWrittenBytes += nBytes;
01152 }
01153 
01154 #ifdef __PGFROISUPPORT__
01155 
01156 // Encode and write down to given level at current stream position.
01157 // A PGF image is structered in levels, numbered between 0 and Levels() - 1.
01158 // Each level can be seen as a single image, containing the same content
01159 // as all other levels, but in a different size (width, height).
01160 // The image size at level i is double the size (width, height) of the image at level i+1.
01161 // The image at level 0 contains the original size.
01162 // Precondition: the PGF image contains a valid header (see also SetHeader(...)) and WriteHeader() has been called before Write().
01163 // The ROI encoding scheme is used.
01164 // It might throw an IOException.
01165 // @param level The image level of the resulting image in the internal image buffer.
01166 // @param cb A pointer to a callback procedure. The procedure is called after writing a single level. If cb returns true, then it stops proceeding.
01167 // @param data Data Pointer to C++ class container to host callback procedure.
01168 // @return The number of bytes written into stream.
01169 UINT32 CPGFImage::Write(int level, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
01170         ASSERT(m_header.nLevels > 0);
01171         ASSERT(0 <= level && level < m_header.nLevels);
01172         ASSERT(m_encoder);
01173         ASSERT(ROIisSupported());
01174 
01175         const int levelDiff = m_currentLevel - level;
01176         double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
01177         UINT32 nWrittenBytes = 0;
01178 
01179         if (m_currentLevel == m_header.nLevels) {
01180                 // update post-header size, rewrite pre-header, and write dummy levelLength
01181                 nWrittenBytes = UpdatePostHeaderSize();
01182         } else {
01183                 // prepare for next level: save current file position, because the stream might have been reinitialized
01184                 if (m_encoder->ComputeBufferLength()) {
01185                         m_streamReinitialized = true;
01186                 }
01187         }
01188 
01189         // encoding scheme with ROI
01190         while (m_currentLevel > level) {
01191                 WriteLevel();   // decrements m_currentLevel
01192 
01193                 if (m_levelLength) {
01194                         nWrittenBytes += m_levelLength[m_header.nLevels - m_currentLevel - 1];
01195                 }
01196 
01197                 // now update progress
01198                 if (cb) {
01199                         percent *= 4;
01200                         if (m_progressMode == PM_Absolute) m_percent = percent;
01201                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01202                 }
01203         }
01204 
01205         // automatically closing
01206         if (m_currentLevel == 0) {
01207                 if (!m_streamReinitialized) {
01208                         // don't write level lengths, if the stream position changed inbetween two Write operations
01209                         m_encoder->UpdateLevelLength();
01210                 }
01211                 // delete encoder
01212                 delete m_encoder; m_encoder = NULL;
01213         }
01214 
01215         return nWrittenBytes;
01216 }
01217 #endif // __PGFROISUPPORT__
01218 
01219 
01221 // Check for valid import image mode.
01222 // @param mode Image mode
01223 // @return True if an image of given mode can be imported with ImportBitmap(...)
01224 bool CPGFImage::ImportIsSupported(BYTE mode) {
01225         size_t size = DataTSize;
01226 
01227         if (size >= 2) {
01228                 switch(mode) {
01229                         case ImageModeBitmap:
01230                         case ImageModeIndexedColor:
01231                         case ImageModeGrayScale:
01232                         case ImageModeRGBColor:
01233                         case ImageModeCMYKColor:
01234                         case ImageModeHSLColor:
01235                         case ImageModeHSBColor:
01236                         //case ImageModeDuotone:
01237                         case ImageModeLabColor:
01238                         case ImageModeRGB12:
01239                         case ImageModeRGB16:
01240                         case ImageModeRGBA:
01241                                 return true;
01242                 }
01243         }
01244         if (size >= 3) {
01245                 switch(mode) {
01246                         case ImageModeGray16:
01247                         case ImageModeRGB48:
01248                         case ImageModeLab48:
01249                         case ImageModeCMYK64:
01250                         //case ImageModeDuotone16:
01251                                 return true;
01252                 }
01253         }
01254         if (size >=4) {
01255                 switch(mode) {
01256                         case ImageModeGray32:
01257                                 return true;
01258                 }
01259         }
01260         return false;
01261 }
01262 
01269 void CPGFImage::GetColorTable(UINT32 iFirstColor, UINT32 nColors, RGBQUAD* prgbColors) const THROW_ {
01270         if (iFirstColor + nColors > ColorTableLen)      ReturnWithError(ColorTableError);
01271 
01272         for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
01273                 prgbColors[j] = m_postHeader.clut[i];
01274         }
01275 }
01276 
01283 void CPGFImage::SetColorTable(UINT32 iFirstColor, UINT32 nColors, const RGBQUAD* prgbColors) THROW_ {
01284         if (iFirstColor + nColors > ColorTableLen)      ReturnWithError(ColorTableError);
01285 
01286         for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
01287                 m_postHeader.clut[i] = prgbColors[j];
01288         }
01289 }
01290 
01292 // Buffer transform from interleaved to channel seperated format
01293 // the absolute value of pitch is the number of bytes of an image row
01294 // if pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row)
01295 // if pitch is positive, then buff points to the first row of a top-down image (first byte)
01296 // bpp is the number of bits per pixel used in image buffer buff
01297 //
01298 // RGB is transformed into YUV format (ordering of buffer data is BGR[A])
01299 // Y = (R + 2*G + B)/4 -128
01300 // U = R - G
01301 // V = B - G
01302 //
01303 // Since PGF Codec version 2.0 images are stored in top-down direction
01304 //
01305 // 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
01306 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
01307 // If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
01308 void CPGFImage::RgbToYuv(int pitch, UINT8* buff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data /*=NULL*/) THROW_ {
01309         ASSERT(buff);
01310         int yPos = 0, cnt = 0;
01311         double percent = 0;
01312         const double dP = 1.0/m_header.height;
01313         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
01314 
01315         if (channelMap == NULL) channelMap = defMap;
01316 
01317         switch(m_header.mode) {
01318         case ImageModeBitmap:
01319                 {
01320                         ASSERT(m_header.channels == 1);
01321                         ASSERT(m_header.bpp == 1);
01322                         ASSERT(bpp == 1);
01323                         
01324                         const UINT32 w = m_header.width;
01325                         const UINT32 w2 = (m_header.width + 7)/8;
01326                         DataT* y = m_channel[0]; ASSERT(y);
01327 
01328                         for (UINT32 h=0; h < m_header.height; h++) {
01329                                 if (cb) {
01330                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01331                                         percent += dP;
01332                                 }
01333                                 
01334                                 for (UINT32 j=0; j < w2; j++) {
01335                                         y[yPos++] = buff[j] - YUVoffset8;
01336                                 }
01337                                 for (UINT32 j=w2; j < w; j++) {
01338                                         y[yPos++] = YUVoffset8;
01339                                 }
01340                                 
01341                                 //UINT cnt = w;
01342                                 //for (UINT32 j=0; j < w2; j++) {
01343                                 //      for (int k=7; k >= 0; k--) {
01344                                 //              if (cnt) { 
01345                                 //                      y[yPos++] = YUVoffset8 + (1 & (buff[j] >> k));
01346                                 //                      cnt--;
01347                                 //              }
01348                                 //      }
01349                                 //}
01350                                 buff += pitch;  
01351                         }
01352                 }
01353                 break;
01354         case ImageModeIndexedColor:
01355         case ImageModeGrayScale:
01356         case ImageModeHSLColor:
01357         case ImageModeHSBColor:
01358         case ImageModeLabColor:
01359                 {
01360                         ASSERT(m_header.channels >= 1);
01361                         ASSERT(m_header.bpp == m_header.channels*8);
01362                         ASSERT(bpp%8 == 0);
01363                         const int channels = bpp/8; ASSERT(channels >= m_header.channels);
01364 
01365                         for (UINT32 h=0; h < m_header.height; h++) {
01366                                 if (cb) {
01367                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01368                                         percent += dP;
01369                                 }
01370 
01371                                 cnt = 0;
01372                                 for (UINT32 w=0; w < m_header.width; w++) {
01373                                         for (int c=0; c < m_header.channels; c++) {
01374                                                 m_channel[c][yPos] = buff[cnt + channelMap[c]] - YUVoffset8;
01375                                         }
01376                                         cnt += channels;
01377                                         yPos++;
01378                                 }
01379                                 buff += pitch;  
01380                         }
01381                 }
01382                 break;
01383         case ImageModeGray16:
01384         case ImageModeLab48:
01385                 {
01386                         ASSERT(m_header.channels >= 1);
01387                         ASSERT(m_header.bpp == m_header.channels*16);
01388                         ASSERT(bpp%16 == 0);
01389 
01390                         UINT16 *buff16 = (UINT16 *)buff;
01391                         const int pitch16 = pitch/2;
01392                         const int channels = bpp/16; ASSERT(channels >= m_header.channels);
01393                         const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
01394                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01395 
01396                         for (UINT32 h=0; h < m_header.height; h++) {
01397                                 if (cb) {
01398                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01399                                         percent += dP;
01400                                 }
01401 
01402                                 cnt = 0;
01403                                 for (UINT32 w=0; w < m_header.width; w++) {
01404                                         for (int c=0; c < m_header.channels; c++) {
01405                                                 m_channel[c][yPos] = (buff16[cnt + channelMap[c]] >> shift) - yuvOffset16;
01406                                         }
01407                                         cnt += channels;
01408                                         yPos++;
01409                                 }
01410                                 buff16 += pitch16;
01411                         }
01412                 }
01413                 break;
01414         case ImageModeRGBColor:
01415                 {
01416                         ASSERT(m_header.channels == 3);
01417                         ASSERT(m_header.bpp == m_header.channels*8);
01418                         ASSERT(bpp%8 == 0);
01419 
01420                         DataT* y = m_channel[0]; ASSERT(y);
01421                         DataT* u = m_channel[1]; ASSERT(u);
01422                         DataT* v = m_channel[2]; ASSERT(v);
01423                         const int channels = bpp/8; ASSERT(channels >= m_header.channels);
01424                         UINT8 b, g, r;
01425 
01426                         for (UINT32 h=0; h < m_header.height; h++) {
01427                                 if (cb) {
01428                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01429                                         percent += dP;
01430                                 }
01431 
01432                                 cnt = 0;
01433                                 for (UINT32 w=0; w < m_header.width; w++) {
01434                                         b = buff[cnt + channelMap[0]];
01435                                         g = buff[cnt + channelMap[1]];
01436                                         r = buff[cnt + channelMap[2]];
01437                                         // Yuv
01438                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
01439                                         u[yPos] = r - g;
01440                                         v[yPos] = b - g;
01441                                         yPos++;
01442                                         cnt += channels;
01443                                 }
01444                                 buff += pitch;
01445                         }       
01446                 }
01447                 break;
01448         case ImageModeRGB48:
01449                 {
01450                         ASSERT(m_header.channels == 3);
01451                         ASSERT(m_header.bpp == m_header.channels*16);
01452                         ASSERT(bpp%16 == 0);
01453 
01454                         UINT16 *buff16 = (UINT16 *)buff;
01455                         const int pitch16 = pitch/2;
01456                         const int channels = bpp/16; ASSERT(channels >= m_header.channels);
01457                         const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
01458                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01459 
01460                         DataT* y = m_channel[0]; ASSERT(y);
01461                         DataT* u = m_channel[1]; ASSERT(u);
01462                         DataT* v = m_channel[2]; ASSERT(v);
01463                         UINT16 b, g, r;
01464 
01465                         for (UINT32 h=0; h < m_header.height; h++) {
01466                                 if (cb) {
01467                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01468                                         percent += dP;
01469                                 }
01470 
01471                                 cnt = 0;
01472                                 for (UINT32 w=0; w < m_header.width; w++) {
01473                                         b = buff16[cnt + channelMap[0]] >> shift;
01474                                         g = buff16[cnt + channelMap[1]] >> shift;
01475                                         r = buff16[cnt + channelMap[2]] >> shift;
01476                                         // Yuv
01477                                         y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
01478                                         u[yPos] = r - g;
01479                                         v[yPos] = b - g;
01480                                         yPos++;
01481                                         cnt += channels;
01482                                 }
01483                                 buff16 += pitch16;
01484                         }       
01485                 }
01486                 break;
01487         case ImageModeRGBA:
01488         case ImageModeCMYKColor:
01489                 {
01490                         ASSERT(m_header.channels == 4);
01491                         ASSERT(m_header.bpp == m_header.channels*8);
01492                         ASSERT(bpp%8 == 0);
01493                         const int channels = bpp/8; ASSERT(channels >= m_header.channels);
01494 
01495                         DataT* y = m_channel[0]; ASSERT(y);
01496                         DataT* u = m_channel[1]; ASSERT(u);
01497                         DataT* v = m_channel[2]; ASSERT(v);
01498                         DataT* a = m_channel[3]; ASSERT(a);
01499                         UINT8 b, g, r;
01500 
01501                         for (UINT32 h=0; h < m_header.height; h++) {
01502                                 if (cb) {
01503                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01504                                         percent += dP;
01505                                 }
01506 
01507                                 cnt = 0;
01508                                 for (UINT32 w=0; w < m_header.width; w++) {
01509                                         b = buff[cnt + channelMap[0]];
01510                                         g = buff[cnt + channelMap[1]];
01511                                         r = buff[cnt + channelMap[2]];
01512                                         // Yuv
01513                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
01514                                         u[yPos] = r - g;
01515                                         v[yPos] = b - g;
01516                                         a[yPos++] = buff[cnt + channelMap[3]] - YUVoffset8;
01517                                         cnt += channels;
01518                                 }
01519                                 buff += pitch;
01520                         }       
01521                 }
01522                 break;
01523         case ImageModeCMYK64:
01524                 {
01525                         ASSERT(m_header.channels == 4);
01526                         ASSERT(m_header.bpp == m_header.channels*16);
01527                         ASSERT(bpp%16 == 0);
01528 
01529                         UINT16 *buff16 = (UINT16 *)buff;
01530                         const int pitch16 = pitch/2;
01531                         const int channels = bpp/16; ASSERT(channels >= m_header.channels);
01532                         const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
01533                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01534                         
01535                         DataT* y = m_channel[0]; ASSERT(y);
01536                         DataT* u = m_channel[1]; ASSERT(u);
01537                         DataT* v = m_channel[2]; ASSERT(v);
01538                         DataT* a = m_channel[3]; ASSERT(a);
01539                         UINT16 b, g, r;
01540 
01541                         for (UINT32 h=0; h < m_header.height; h++) {
01542                                 if (cb) {
01543                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01544                                         percent += dP;
01545                                 }
01546 
01547                                 cnt = 0;
01548                                 for (UINT32 w=0; w < m_header.width; w++) {
01549                                         b = buff16[cnt + channelMap[0]] >> shift;
01550                                         g = buff16[cnt + channelMap[1]] >> shift;
01551                                         r = buff16[cnt + channelMap[2]] >> shift;
01552                                         // Yuv
01553                                         y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
01554                                         u[yPos] = r - g;
01555                                         v[yPos] = b - g;
01556                                         a[yPos++] = (buff16[cnt + channelMap[3]] >> shift) - yuvOffset16;
01557                                         cnt += channels;
01558                                 }
01559                                 buff16 += pitch16;
01560                         }       
01561                 }
01562                 break;
01563 #ifdef __PGF32SUPPORT__
01564         case ImageModeGray32:
01565                 {
01566                         ASSERT(m_header.channels == 1);
01567                         ASSERT(m_header.bpp == 32);
01568                         ASSERT(bpp == 32);
01569                         ASSERT(DataTSize == sizeof(UINT32));
01570 
01571                         DataT* y = m_channel[0]; ASSERT(y);
01572 
01573                         UINT32 *buff32 = (UINT32 *)buff;
01574                         const int pitch32 = pitch/4;
01575                         const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
01576                         const DataT yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
01577 
01578                         for (UINT32 h=0; h < m_header.height; h++) {
01579                                 if (cb) {
01580                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01581                                         percent += dP;
01582                                 }
01583 
01584                                 for (UINT32 w=0; w < m_header.width; w++) {
01585                                         y[yPos++] = (buff32[w] >> shift) - yuvOffset31;
01586                                 }
01587                                 buff32 += pitch32;
01588                         }
01589                 }
01590                 break;
01591 #endif
01592         case ImageModeRGB12:
01593                 {
01594                         ASSERT(m_header.channels == 3);
01595                         ASSERT(m_header.bpp == m_header.channels*4);
01596                         ASSERT(bpp == m_header.channels*4);
01597 
01598                         DataT* y = m_channel[0]; ASSERT(y);
01599                         DataT* u = m_channel[1]; ASSERT(u);
01600                         DataT* v = m_channel[2]; ASSERT(v);
01601 
01602                         UINT8 rgb = 0, b, g, r;
01603 
01604                         for (UINT32 h=0; h < m_header.height; h++) {
01605                                 if (cb) {
01606                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01607                                         percent += dP;
01608                                 }
01609 
01610                                 cnt = 0;
01611                                 for (UINT32 w=0; w < m_header.width; w++) {
01612                                         if (w%2 == 0) {
01613                                                 // even pixel position
01614                                                 rgb = buff[cnt];
01615                                                 b = rgb & 0x0F;
01616                                                 g = (rgb & 0xF0) >> 4;
01617                                                 cnt++;
01618                                                 rgb = buff[cnt];
01619                                                 r = rgb & 0x0F;
01620                                         } else {
01621                                                 // odd pixel position
01622                                                 b = (rgb & 0xF0) >> 4;
01623                                                 cnt++;
01624                                                 rgb = buff[cnt];
01625                                                 g = rgb & 0x0F;
01626                                                 r = (rgb & 0xF0) >> 4;
01627                                                 cnt++;
01628                                         }
01629 
01630                                         // Yuv
01631                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset4;
01632                                         u[yPos] = r - g;
01633                                         v[yPos] = b - g;
01634                                         yPos++;
01635                                 }
01636                                 buff += pitch;
01637                         }       
01638                 }
01639                 break;
01640         case ImageModeRGB16:
01641                 {
01642                         ASSERT(m_header.channels == 3);
01643                         ASSERT(m_header.bpp == 16);
01644                         ASSERT(bpp == 16);
01645                         
01646                         DataT* y = m_channel[0]; ASSERT(y);
01647                         DataT* u = m_channel[1]; ASSERT(u);
01648                         DataT* v = m_channel[2]; ASSERT(v);
01649 
01650                         UINT16 *buff16 = (UINT16 *)buff;
01651                         UINT16 rgb, b, g, r;
01652                         const int pitch16 = pitch/2;
01653 
01654                         for (UINT32 h=0; h < m_header.height; h++) {
01655                                 if (cb) {
01656                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01657                                         percent += dP;
01658                                 }
01659                                 for (UINT32 w=0; w < m_header.width; w++) {
01660                                         rgb = buff16[w]; 
01661                                         r = (rgb & 0xF800) >> 10;       // highest 5 bits
01662                                         g = (rgb & 0x07E0) >> 5;        // middle 6 bits
01663                                         b = (rgb & 0x001F) << 1;        // lowest 5 bits
01664                                         // Yuv
01665                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset6;
01666                                         u[yPos] = r - g;
01667                                         v[yPos] = b - g;
01668                                         yPos++;
01669                                 }
01670 
01671                                 buff16 += pitch16;
01672                         }       
01673                 }
01674                 break;
01675         default:
01676                 ASSERT(false);
01677         }
01678 }
01679 
01681 // Get image data in interleaved format: (ordering of RGB data is BGR[A])
01682 // Upsampling, YUV to RGB transform and interleaving are done here to reduce the number 
01683 // of passes over the data.
01684 // The absolute value of pitch is the number of bytes of an image row of the given image buffer.
01685 // If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row).
01686 // if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte).
01687 // 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
01688 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode.
01689 // If your provided image buffer expects a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
01690 // It might throw an IOException.
01691 // @param pitch The number of bytes of a row of the image buffer.
01692 // @param buff An image buffer.
01693 // @param bpp The number of bits per pixel used in image buffer.
01694 // @param channelMap A integer array containing the mapping of PGF channel ordering to expected channel ordering.
01695 // @param cb A pointer to a callback procedure. The procedure is called after each copied buffer row. If cb returns true, then it stops proceeding.
01696 // @param data Data Pointer to C++ class container to host callback procedure.
01697 void CPGFImage::GetBitmap(int pitch, UINT8* buff, BYTE bpp, int channelMap[] /*= NULL */, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) const THROW_ {
01698         ASSERT(buff);
01699         UINT32 w = m_width[0];
01700         UINT32 h = m_height[0];
01701         UINT8* targetBuff = 0;  // used if ROI is used
01702         UINT8* buffStart = 0;   // used if ROI is used
01703         int targetPitch = 0;    // used if ROI is used
01704 
01705 #ifdef __PGFROISUPPORT__
01706         const PGFRect& roi = (ROIisSupported()) ? m_wtChannel[0]->GetROI(m_currentLevel) : PGFRect(0, 0, w, h); // roi is usually larger than m_roi
01707         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));
01708         ASSERT(w <= roi.Width() && h <= roi.Height()); 
01709         ASSERT(roi.left <= levelRoi.left && levelRoi.right <= roi.right); 
01710         ASSERT(roi.top <= levelRoi.top && levelRoi.bottom <= roi.bottom); 
01711 
01712         if (ROIisSupported() && (levelRoi.Width() < w || levelRoi.Height() < h)) {
01713                 // ROI is used -> create a temporary image buffer for roi
01714                 // compute pitch
01715                 targetPitch = pitch;
01716                 pitch = AlignWordPos(w*bpp)/8;
01717 
01718                 // create temporary output buffer
01719                 targetBuff = buff;
01720                 buff = buffStart = new(std::nothrow) UINT8[pitch*h];
01721                 if (!buff) ReturnWithError(InsufficientMemory);
01722         }
01723 #endif
01724 
01725         const bool wOdd = (1 == w%2);
01726 
01727         const double dP = 1.0/h;
01728         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
01729         if (channelMap == NULL) channelMap = defMap;
01730         int sampledPos = 0, yPos = 0;
01731         DataT uAvg, vAvg;
01732         double percent = 0;
01733         UINT32 i, j;
01734 
01735         switch(m_header.mode) {
01736         case ImageModeBitmap:
01737                 {
01738                         ASSERT(m_header.channels == 1);
01739                         ASSERT(m_header.bpp == 1);
01740                         ASSERT(bpp == 1);
01741 
01742                         const UINT32 w2 = (w + 7)/8;
01743                         DataT* y = m_channel[0]; ASSERT(y);
01744 
01745                         for (i=0; i < h; i++) {
01746                                 
01747                                 for (j=0; j < w2; j++) {
01748                                         buff[j] = Clamp8(y[yPos++] + YUVoffset8);
01749                                 }
01750                                 yPos += w - w2;
01751                                 
01752                                 //UINT32 cnt = w;
01753                                 //for (j=0; j < w2; j++) {
01754                                 //      buff[j] = 0;
01755                                 //      for (int k=0; k < 8; k++) {
01756                                 //              if (cnt) {
01757                                 //                      buff[j] <<= 1;
01758                                 //                      buff[j] |= (1 & (y[yPos++] - YUVoffset8)); 
01759                                 //                      cnt--;
01760                                 //              }
01761                                 //      }
01762                                 //}
01763                                 buff += pitch;
01764 
01765                                 if (cb) {
01766                                         percent += dP;
01767                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01768                                 }
01769                         }
01770                         break;
01771                 }
01772         case ImageModeIndexedColor:
01773         case ImageModeGrayScale:
01774         case ImageModeHSLColor:
01775         case ImageModeHSBColor:
01776                 {
01777                         ASSERT(m_header.channels >= 1);
01778                         ASSERT(m_header.bpp == m_header.channels*8);
01779                         ASSERT(bpp%8 == 0);
01780 
01781                         int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
01782 
01783                         for (i=0; i < h; i++) {
01784                                 cnt = 0;
01785                                 for (j=0; j < w; j++) {
01786                                         for (int c=0; c < m_header.channels; c++) {
01787                                                 buff[cnt + channelMap[c]] = Clamp8(m_channel[c][yPos] + YUVoffset8);
01788                                         }
01789                                         cnt += channels;
01790                                         yPos++;
01791                                 }
01792                                 buff += pitch;
01793 
01794                                 if (cb) {
01795                                         percent += dP;
01796                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01797                                 }
01798                         }
01799                         break;
01800                 }
01801         case ImageModeGray16:
01802                 {
01803                         ASSERT(m_header.channels >= 1);
01804                         ASSERT(m_header.bpp == m_header.channels*16);
01805 
01806                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01807                         int cnt, channels;
01808 
01809                         if (bpp%16 == 0) {
01810                                 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
01811                                 UINT16 *buff16 = (UINT16 *)buff;
01812                                 int pitch16 = pitch/2;
01813                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
01814 
01815                                 for (i=0; i < h; i++) {
01816                                         cnt = 0;
01817                                         for (j=0; j < w; j++) {
01818                                                 for (int c=0; c < m_header.channels; c++) {
01819                                                         buff16[cnt + channelMap[c]] = Clamp16((m_channel[c][yPos] + yuvOffset16) << shift);
01820                                                 }
01821                                                 cnt += channels;
01822                                                 yPos++;
01823                                         }
01824                                         buff16 += pitch16;
01825 
01826                                         if (cb) {
01827                                                 percent += dP;
01828                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01829                                         }
01830                                 }
01831                         } else {
01832                                 ASSERT(bpp%8 == 0);
01833                                 const int shift = __max(0, UsedBitsPerChannel() - 8);
01834                                 channels = bpp/8; ASSERT(channels >= m_header.channels);
01835                                 
01836                                 for (i=0; i < h; i++) {
01837                                         cnt = 0;
01838                                         for (j=0; j < w; j++) {
01839                                                 for (int c=0; c < m_header.channels; c++) {
01840                                                         buff[cnt + channelMap[c]] = Clamp8((m_channel[c][yPos] + yuvOffset16) >> shift);
01841                                                 }
01842                                                 cnt += channels;
01843                                                 yPos++;
01844                                         }
01845                                         buff += pitch;
01846 
01847                                         if (cb) {
01848                                                 percent += dP;
01849                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01850                                         }
01851                                 }
01852                         }
01853                         break;
01854                 }
01855         case ImageModeRGBColor:
01856                 {
01857                         ASSERT(m_header.channels == 3);
01858                         ASSERT(m_header.bpp == m_header.channels*8);
01859                         ASSERT(bpp%8 == 0);
01860                         ASSERT(bpp >= m_header.bpp);
01861 
01862                         DataT* y = m_channel[0]; ASSERT(y);
01863                         DataT* u = m_channel[1]; ASSERT(u);
01864                         DataT* v = m_channel[2]; ASSERT(v);
01865                         UINT8 *buffg = &buff[channelMap[1]],
01866                                   *buffr = &buff[channelMap[2]],
01867                                   *buffb = &buff[channelMap[0]];
01868                         UINT8 g;
01869                         int cnt, channels = bpp/8;
01870                         if(m_downsample){
01871                                 for (i=0; i < h; i++) {
01872                                         if (i%2) sampledPos -= (w + 1)/2;
01873                                         cnt = 0;
01874                                         for (j=0; j < w; j++) {
01875                                                 // image was downsampled
01876                                                 uAvg = u[sampledPos];
01877                                                 vAvg = v[sampledPos];
01878                                                 // Yuv
01879                                                 buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
01880                                                 buffr[cnt] = Clamp8(uAvg + g);
01881                                                 buffb[cnt] = Clamp8(vAvg + g);
01882                                                 yPos++;
01883                                                 cnt += channels;
01884                                                 if (j%2) sampledPos++;
01885                                         }
01886                                         buffb += pitch;
01887                                         buffg += pitch;
01888                                         buffr += pitch;
01889                                         if (wOdd) sampledPos++;
01890                                         if (cb) {
01891                                                 percent += dP;
01892                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01893                                         }
01894                                 }
01895                         }else{
01896                                 for (i=0; i < h; i++) {
01897                                         cnt = 0;
01898                                         for (j = 0; j < w; j++) {
01899                                                 uAvg = u[yPos];
01900                                                 vAvg = v[yPos];
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                                         }
01908                                         buffb += pitch;
01909                                         buffg += pitch;
01910                                         buffr += pitch;
01911 
01912                                         if (cb) {
01913                                                 percent += dP;
01914                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01915                                         }
01916                                 }
01917                         }
01918                         break;
01919                 }
01920         case ImageModeRGB48:
01921                 {
01922                         ASSERT(m_header.channels == 3);
01923                         ASSERT(m_header.bpp == 48);
01924 
01925                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01926 
01927                         DataT* y = m_channel[0]; ASSERT(y);
01928                         DataT* u = m_channel[1]; ASSERT(u);
01929                         DataT* v = m_channel[2]; ASSERT(v);
01930                         int cnt, channels;
01931                         DataT g;
01932 
01933                         if (bpp >= 48 && bpp%16 == 0) {
01934                                 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
01935                                 UINT16 *buff16 = (UINT16 *)buff;
01936                                 int pitch16 = pitch/2;
01937                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
01938 
01939                                 for (i=0; i < h; i++) {
01940                                         if (i%2) sampledPos -= (w + 1)/2;
01941                                         cnt = 0;
01942                                         for (j=0; j < w; j++) {
01943                                                 if (m_downsample) {
01944                                                         // image was downsampled
01945                                                         uAvg = u[sampledPos];
01946                                                         vAvg = v[sampledPos];
01947                                                 } else {
01948                                                         uAvg = u[yPos];
01949                                                         vAvg = v[yPos];
01950                                                 }
01951                                                 // Yuv
01952                                                 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
01953                                                 buff16[cnt + channelMap[1]] = Clamp16(g << shift);
01954                                                 buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
01955                                                 buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
01956                                                 yPos++; 
01957                                                 cnt += channels;
01958                                                 if (j%2) sampledPos++;
01959                                         }
01960                                         buff16 += pitch16;
01961                                         if (wOdd) sampledPos++;
01962 
01963                                         if (cb) {
01964                                                 percent += dP;
01965                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01966                                         }
01967                                 }
01968                         } else {
01969                                 ASSERT(bpp%8 == 0);
01970                                 const int shift = __max(0, UsedBitsPerChannel() - 8);
01971                                 channels = bpp/8; ASSERT(channels >= m_header.channels);
01972 
01973                                 for (i=0; i < h; i++) {
01974                                         if (i%2) sampledPos -= (w + 1)/2;
01975                                         cnt = 0;
01976                                         for (j=0; j < w; j++) {
01977                                                 if (m_downsample) {
01978                                                         // image was downsampled
01979                                                         uAvg = u[sampledPos];
01980                                                         vAvg = v[sampledPos];
01981                                                 } else {
01982                                                         uAvg = u[yPos];
01983                                                         vAvg = v[yPos];
01984                                                 }
01985                                                 // Yuv
01986                                                 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
01987                                                 buff[cnt + channelMap[1]] = Clamp8(g >> shift); 
01988                                                 buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
01989                                                 buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
01990                                                 yPos++; 
01991                                                 cnt += channels;
01992                                                 if (j%2) sampledPos++;
01993                                         }
01994                                         buff += pitch;
01995                                         if (wOdd) sampledPos++;
01996 
01997                                         if (cb) {
01998                                                 percent += dP;
01999                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02000                                         }
02001                                 }
02002                         }
02003                         break;
02004                 }
02005         case ImageModeLabColor:
02006                 {
02007                         ASSERT(m_header.channels == 3);
02008                         ASSERT(m_header.bpp == m_header.channels*8);
02009                         ASSERT(bpp%8 == 0);
02010 
02011                         DataT* l = m_channel[0]; ASSERT(l);
02012                         DataT* a = m_channel[1]; ASSERT(a);
02013                         DataT* b = m_channel[2]; ASSERT(b);
02014                         int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
02015 
02016                         for (i=0; i < h; i++) {
02017                                 if (i%2) sampledPos -= (w + 1)/2;
02018                                 cnt = 0;
02019                                 for (j=0; j < w; j++) {
02020                                         if (m_downsample) {
02021                                                 // image was downsampled
02022                                                 uAvg = a[sampledPos];
02023                                                 vAvg = b[sampledPos];
02024                                         } else {
02025                                                 uAvg = a[yPos];
02026                                                 vAvg = b[yPos];
02027                                         }
02028                                         buff[cnt + channelMap[0]] = Clamp8(l[yPos] + YUVoffset8);
02029                                         buff[cnt + channelMap[1]] = Clamp8(uAvg + YUVoffset8); 
02030                                         buff[cnt + channelMap[2]] = Clamp8(vAvg + YUVoffset8);
02031                                         cnt += channels;
02032                                         yPos++;
02033                                         if (j%2) sampledPos++;
02034                                 }
02035                                 buff += pitch;
02036                                 if (wOdd) sampledPos++;
02037 
02038                                 if (cb) {
02039                                         percent += dP;
02040                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02041                                 }
02042                         }
02043                         break;
02044                 }
02045         case ImageModeLab48:
02046                 {
02047                         ASSERT(m_header.channels == 3);
02048                         ASSERT(m_header.bpp == m_header.channels*16);
02049 
02050                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
02051 
02052                         DataT* l = m_channel[0]; ASSERT(l);
02053                         DataT* a = m_channel[1]; ASSERT(a);
02054                         DataT* b = m_channel[2]; ASSERT(b);
02055                         int cnt, channels;
02056 
02057                         if (bpp%16 == 0) {
02058                                 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
02059                                 UINT16 *buff16 = (UINT16 *)buff;
02060                                 int pitch16 = pitch/2;
02061                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
02062 
02063                                 for (i=0; i < h; i++) {
02064                                         if (i%2) sampledPos -= (w + 1)/2;
02065                                         cnt = 0;
02066                                         for (j=0; j < w; j++) {
02067                                                 if (m_downsample) {
02068                                                         // image was downsampled
02069                                                         uAvg = a[sampledPos];
02070                                                         vAvg = b[sampledPos];
02071                                                 } else {
02072                                                         uAvg = a[yPos];
02073                                                         vAvg = b[yPos];
02074                                                 }
02075                                                 buff16[cnt + channelMap[0]] = Clamp16((l[yPos] + yuvOffset16) << shift);
02076                                                 buff16[cnt + channelMap[1]] = Clamp16((uAvg + yuvOffset16) << shift);
02077                                                 buff16[cnt + channelMap[2]] = Clamp16((vAvg + yuvOffset16) << shift);
02078                                                 cnt += channels;
02079                                                 yPos++;
02080                                                 if (j%2) sampledPos++;
02081                                         }
02082                                         buff16 += pitch16;
02083                                         if (wOdd) sampledPos++;
02084 
02085                                         if (cb) {
02086                                                 percent += dP;
02087                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02088                                         }
02089                                 }
02090                         } else {
02091                                 ASSERT(bpp%8 == 0);
02092                                 const int shift = __max(0, UsedBitsPerChannel() - 8);
02093                                 channels = bpp/8; ASSERT(channels >= m_header.channels);
02094 
02095                                 for (i=0; i < h; i++) {
02096                                         if (i%2) sampledPos -= (w + 1)/2;
02097                                         cnt = 0;
02098                                         for (j=0; j < w; j++) {
02099                                                 if (m_downsample) {
02100                                                         // image was downsampled
02101                                                         uAvg = a[sampledPos];
02102                                                         vAvg = b[sampledPos];
02103                                                 } else {
02104                                                         uAvg = a[yPos];
02105                                                         vAvg = b[yPos];
02106                                                 }
02107                                                 buff[cnt + channelMap[0]] = Clamp8((l[yPos] + yuvOffset16) >> shift);
02108                                                 buff[cnt + channelMap[1]] = Clamp8((uAvg + yuvOffset16) >> shift);
02109                                                 buff[cnt + channelMap[2]] = Clamp8((vAvg + yuvOffset16) >> shift);
02110                                                 cnt += channels;
02111                                                 yPos++;
02112                                                 if (j%2) sampledPos++;
02113                                         }
02114                                         buff += pitch;
02115                                         if (wOdd) sampledPos++;
02116 
02117                                         if (cb) {
02118                                                 percent += dP;
02119                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02120                                         }
02121                                 }
02122                         }
02123                         break;
02124                 }
02125         case ImageModeRGBA:
02126         case ImageModeCMYKColor:
02127                 {
02128                         ASSERT(m_header.channels == 4);
02129                         ASSERT(m_header.bpp == m_header.channels*8);
02130                         ASSERT(bpp%8 == 0);
02131 
02132                         DataT* y = m_channel[0]; ASSERT(y);
02133                         DataT* u = m_channel[1]; ASSERT(u);
02134                         DataT* v = m_channel[2]; ASSERT(v);
02135                         DataT* a = m_channel[3]; ASSERT(a);
02136                         UINT8 g, aAvg;
02137                         int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
02138 
02139                         for (i=0; i < h; i++) {
02140                                 if (i%2) sampledPos -= (w + 1)/2;
02141                                 cnt = 0;
02142                                 for (j=0; j < w; j++) {
02143                                         if (m_downsample) {
02144                                                 // image was downsampled
02145                                                 uAvg = u[sampledPos];
02146                                                 vAvg = v[sampledPos];
02147                                                 aAvg = Clamp8(a[sampledPos] + YUVoffset8);
02148                                         } else {
02149                                                 uAvg = u[yPos];
02150                                                 vAvg = v[yPos];
02151                                                 aAvg = Clamp8(a[yPos] + YUVoffset8);
02152                                         }
02153                                         // Yuv
02154                                         buff[cnt + channelMap[1]] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
02155                                         buff[cnt + channelMap[2]] = Clamp8(uAvg + g);
02156                                         buff[cnt + channelMap[0]] = Clamp8(vAvg + g);
02157                                         buff[cnt + channelMap[3]] = aAvg;
02158                                         yPos++; 
02159                                         cnt += channels;
02160                                         if (j%2) sampledPos++;
02161                                 }
02162                                 buff += pitch;
02163                                 if (wOdd) sampledPos++;
02164 
02165                                 if (cb) {
02166                                         percent += dP;
02167                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02168                                 }
02169                         }
02170                         break;
02171                 }
02172         case ImageModeCMYK64: 
02173                 {
02174                         ASSERT(m_header.channels == 4);
02175                         ASSERT(m_header.bpp == 64);
02176 
02177                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
02178 
02179                         DataT* y = m_channel[0]; ASSERT(y);
02180                         DataT* u = m_channel[1]; ASSERT(u);
02181                         DataT* v = m_channel[2]; ASSERT(v);
02182                         DataT* a = m_channel[3]; ASSERT(a);
02183                         DataT g, aAvg;
02184                         int cnt, channels;
02185 
02186                         if (bpp%16 == 0) {
02187                                 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
02188                                 UINT16 *buff16 = (UINT16 *)buff;
02189                                 int pitch16 = pitch/2;
02190                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
02191 
02192                                 for (i=0; i < h; i++) {
02193                                         if (i%2) sampledPos -= (w + 1)/2;
02194                                         cnt = 0;
02195                                         for (j=0; j < w; j++) {
02196                                                 if (m_downsample) {
02197                                                         // image was downsampled
02198                                                         uAvg = u[sampledPos];
02199                                                         vAvg = v[sampledPos];
02200                                                         aAvg = a[sampledPos] + yuvOffset16;
02201                                                 } else {
02202                                                         uAvg = u[yPos];
02203                                                         vAvg = v[yPos];
02204                                                         aAvg = a[yPos] + yuvOffset16;
02205                                                 }
02206                                                 // Yuv
02207                                                 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
02208                                                 buff16[cnt + channelMap[1]] = Clamp16(g << shift);
02209                                                 buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
02210                                                 buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
02211                                                 buff16[cnt + channelMap[3]] = Clamp16(aAvg << shift);
02212                                                 yPos++; 
02213                                                 cnt += channels;
02214                                                 if (j%2) sampledPos++;
02215                                         }
02216                                         buff16 += pitch16;
02217                                         if (wOdd) sampledPos++;
02218 
02219                                         if (cb) {
02220                                                 percent += dP;
02221                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02222                                         }
02223                                 }
02224                         } else {
02225                                 ASSERT(bpp%8 == 0);
02226                                 const int shift = __max(0, UsedBitsPerChannel() - 8);
02227                                 channels = bpp/8; ASSERT(channels >= m_header.channels);
02228 
02229                                 for (i=0; i < h; i++) {
02230                                         if (i%2) sampledPos -= (w + 1)/2;
02231                                         cnt = 0;
02232                                         for (j=0; j < w; j++) {
02233                                                 if (m_downsample) {
02234                                                         // image was downsampled
02235                                                         uAvg = u[sampledPos];
02236                                                         vAvg = v[sampledPos];
02237                                                         aAvg = a[sampledPos] + yuvOffset16;
02238                                                 } else {
02239                                                         uAvg = u[yPos];
02240                                                         vAvg = v[yPos];
02241                                                         aAvg = a[yPos] + yuvOffset16;
02242                                                 }
02243                                                 // Yuv
02244                                                 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
02245                                                 buff[cnt + channelMap[1]] = Clamp8(g >> shift); 
02246                                                 buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
02247                                                 buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
02248                                                 buff[cnt + channelMap[3]] = Clamp8(aAvg >> shift);
02249                                                 yPos++; 
02250                                                 cnt += channels;
02251                                                 if (j%2) sampledPos++;
02252                                         }
02253                                         buff += pitch;
02254                                         if (wOdd) sampledPos++;
02255 
02256                                         if (cb) {
02257                                                 percent += dP;
02258                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02259                                         }
02260                                 }
02261                         }
02262                         break;
02263                 }
02264 #ifdef __PGF32SUPPORT__
02265         case ImageModeGray32:
02266                 {
02267                         ASSERT(m_header.channels == 1);
02268                         ASSERT(m_header.bpp == 32);
02269 
02270                         const int yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
02271 
02272                         DataT* y = m_channel[0]; ASSERT(y);
02273 
02274                         if (bpp == 32) {
02275                                 const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
02276                                 UINT32 *buff32 = (UINT32 *)buff;
02277                                 int pitch32 = pitch/4;
02278 
02279                                 for (i=0; i < h; i++) {
02280                                         for (j=0; j < w; j++) {
02281                                                 buff32[j] = Clamp31((y[yPos++] + yuvOffset31) << shift);
02282                                         }
02283                                         buff32 += pitch32;
02284 
02285                                         if (cb) {
02286                                                 percent += dP;
02287                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02288                                         }
02289                                 }
02290                         } else if (bpp == 16) {
02291                                 const int usedBits = UsedBitsPerChannel();
02292                                 UINT16 *buff16 = (UINT16 *)buff;
02293                                 int pitch16 = pitch/2;
02294 
02295                                 if (usedBits < 16) {
02296                                         const int shift = 16 - usedBits;
02297                                         for (i=0; i < h; i++) {
02298                                                 for (j=0; j < w; j++) {
02299                                                         buff16[j] = Clamp16((y[yPos++] + yuvOffset31) << shift);
02300                                                 }
02301                                                 buff16 += pitch16;
02302 
02303                                                 if (cb) {
02304                                                         percent += dP;
02305                                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02306                                                 }
02307                                         }
02308                                 } else {
02309                                         const int shift = __max(0, usedBits - 16);
02310                                         for (i=0; i < h; i++) {
02311                                                 for (j=0; j < w; j++) {
02312                                                         buff16[j] = Clamp16((y[yPos++] + yuvOffset31) >> shift);
02313                                                 }
02314                                                 buff16 += pitch16;
02315 
02316                                                 if (cb) {
02317                                                         percent += dP;
02318                                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02319                                                 }
02320                                         }
02321                                 }
02322                         } else {
02323                                 ASSERT(bpp == 8);
02324                                 const int shift = __max(0, UsedBitsPerChannel() - 8);
02325                                 
02326                                 for (i=0; i < h; i++) {
02327                                         for (j=0; j < w; j++) {
02328                                                 buff[j] = Clamp8((y[yPos++] + yuvOffset31) >> shift);
02329                                         }
02330                                         buff += pitch;
02331 
02332                                         if (cb) {
02333                                                 percent += dP;
02334                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02335                                         }
02336                                 }
02337                         }
02338                         break;  
02339                 }
02340 #endif
02341         case ImageModeRGB12: 
02342                 {
02343                         ASSERT(m_header.channels == 3);
02344                         ASSERT(m_header.bpp == m_header.channels*4);
02345                         ASSERT(bpp == m_header.channels*4);
02346                         ASSERT(!m_downsample);
02347 
02348                         DataT* y = m_channel[0]; ASSERT(y);
02349                         DataT* u = m_channel[1]; ASSERT(u);
02350                         DataT* v = m_channel[2]; ASSERT(v);
02351                         UINT16 yval;
02352                         int cnt;
02353 
02354                         for (i=0; i < h; i++) {
02355                                 cnt = 0;
02356                                 for (j=0; j < w; j++) {
02357                                         // Yuv
02358                                         uAvg = u[yPos];
02359                                         vAvg = v[yPos];
02360                                         yval = Clamp4(y[yPos++] + YUVoffset4 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
02361                                         if (j%2 == 0) {
02362                                                 buff[cnt] = UINT8(Clamp4(vAvg + yval) | (yval << 4));
02363                                                 cnt++;
02364                                                 buff[cnt] = Clamp4(uAvg + yval);
02365                                         } else {
02366                                                 buff[cnt] |= Clamp4(vAvg + yval) << 4;
02367                                                 cnt++;
02368                                                 buff[cnt] = UINT8(yval | (Clamp4(uAvg + yval) << 4));
02369                                                 cnt++;
02370                                         }
02371                                 }
02372                                 buff += pitch;
02373 
02374                                 if (cb) {
02375                                         percent += dP;
02376                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02377                                 }
02378                         }
02379                         break;
02380                 }
02381         case ImageModeRGB16: 
02382                 {
02383                         ASSERT(m_header.channels == 3);
02384                         ASSERT(m_header.bpp == 16);
02385                         ASSERT(bpp == 16);
02386                         ASSERT(!m_downsample);
02387 
02388                         DataT* y = m_channel[0]; ASSERT(y);
02389                         DataT* u = m_channel[1]; ASSERT(u);
02390                         DataT* v = m_channel[2]; ASSERT(v);
02391                         UINT16 yval;
02392                         UINT16 *buff16 = (UINT16 *)buff;
02393                         int pitch16 = pitch/2;
02394 
02395                         for (i=0; i < h; i++) {
02396                                 for (j=0; j < w; j++) {
02397                                         // Yuv
02398                                         uAvg = u[yPos];
02399                                         vAvg = v[yPos];
02400                                         yval = Clamp6(y[yPos++] + YUVoffset6 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
02401                                         buff16[j] = (yval << 5) | ((Clamp6(uAvg + yval) >> 1) << 11) | (Clamp6(vAvg + yval) >> 1);
02402                                 }
02403                                 buff16 += pitch16;
02404 
02405                                 if (cb) {
02406                                         percent += dP;
02407                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02408                                 }
02409                         }
02410                         break;
02411                 }
02412         default:
02413                 ASSERT(false);
02414         }
02415 
02416 #ifdef __PGFROISUPPORT__
02417         if (targetBuff) {
02418                 // copy valid ROI (m_roi) from temporary buffer (roi) to target buffer
02419                 if (bpp%8 == 0) {
02420                         BYTE bypp = bpp/8;
02421                         buff = buffStart + (levelRoi.top - roi.top)*pitch + (levelRoi.left - roi.left)*bypp;
02422                         w = levelRoi.Width()*bypp;
02423                         h = levelRoi.Height();
02424 
02425                         for (i=0; i < h; i++) {
02426                                 for (j=0; j < w; j++) {
02427                                         targetBuff[j] = buff[j];
02428                                 }
02429                                 targetBuff += targetPitch;
02430                                 buff += pitch;
02431                         }
02432                 } else {
02433                         // to do
02434                 }
02435 
02436                 delete[] buffStart;
02437         }
02438 #endif
02439 }                       
02440 
02455 void CPGFImage::GetYUV(int pitch, DataT* buff, BYTE bpp, int channelMap[] /*= NULL*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) const THROW_ {
02456         ASSERT(buff);
02457         const UINT32 w = m_width[0];
02458         const UINT32 h = m_height[0];
02459         const bool wOdd = (1 == w%2);
02460         const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
02461         const int pitch2 = pitch/DataTSize;
02462         const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
02463         const double dP = 1.0/h;
02464 
02465         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
02466         if (channelMap == NULL) channelMap = defMap;
02467         int sampledPos = 0, yPos = 0;
02468         DataT uAvg, vAvg;
02469         double percent = 0;
02470         UINT32 i, j;
02471 
02472         if (m_header.channels == 3) { 
02473                 ASSERT(bpp%dataBits == 0);
02474 
02475                 DataT* y = m_channel[0]; ASSERT(y);
02476                 DataT* u = m_channel[1]; ASSERT(u);
02477                 DataT* v = m_channel[2]; ASSERT(v);
02478                 int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
02479 
02480                 for (i=0; i < h; i++) {
02481                         if (i%2) sampledPos -= (w + 1)/2;
02482                         cnt = 0;
02483                         for (j=0; j < w; j++) {
02484                                 if (m_downsample) {
02485                                         // image was downsampled
02486                                         uAvg = u[sampledPos];
02487                                         vAvg = v[sampledPos];
02488                                 } else {
02489                                         uAvg = u[yPos];
02490                                         vAvg = v[yPos];
02491                                 }
02492                                 buff[cnt + channelMap[0]] = y[yPos];
02493                                 buff[cnt + channelMap[1]] = uAvg;
02494                                 buff[cnt + channelMap[2]] = vAvg;
02495                                 yPos++; 
02496                                 cnt += channels;
02497                                 if (j%2) sampledPos++;
02498                         }
02499                         buff += pitch2;
02500                         if (wOdd) sampledPos++;
02501 
02502                         if (cb) {
02503                                 percent += dP;
02504                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02505                         }
02506                 }
02507         } else if (m_header.channels == 4) {
02508                 ASSERT(m_header.bpp == m_header.channels*8);
02509                 ASSERT(bpp%dataBits == 0);
02510 
02511                 DataT* y = m_channel[0]; ASSERT(y);
02512                 DataT* u = m_channel[1]; ASSERT(u);
02513                 DataT* v = m_channel[2]; ASSERT(v);
02514                 DataT* a = m_channel[3]; ASSERT(a);
02515                 UINT8 aAvg;
02516                 int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
02517 
02518                 for (i=0; i < h; i++) {
02519                         if (i%2) sampledPos -= (w + 1)/2;
02520                         cnt = 0;
02521                         for (j=0; j < w; j++) {
02522                                 if (m_downsample) {
02523                                         // image was downsampled
02524                                         uAvg = u[sampledPos];
02525                                         vAvg = v[sampledPos];
02526                                         aAvg = Clamp8(a[sampledPos] + yuvOffset);
02527                                 } else {
02528                                         uAvg = u[yPos];
02529                                         vAvg = v[yPos];
02530                                         aAvg = Clamp8(a[yPos] + yuvOffset);
02531                                 }
02532                                 // Yuv
02533                                 buff[cnt + channelMap[0]] = y[yPos];
02534                                 buff[cnt + channelMap[1]] = uAvg;
02535                                 buff[cnt + channelMap[2]] = vAvg;
02536                                 buff[cnt + channelMap[3]] = aAvg;
02537                                 yPos++; 
02538                                 cnt += channels;
02539                                 if (j%2) sampledPos++;
02540                         }
02541                         buff += pitch2;
02542                         if (wOdd) sampledPos++;
02543 
02544                         if (cb) {
02545                                 percent += dP;
02546                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02547                         }
02548                 }
02549         }
02550 }
02551 
02566 void CPGFImage::ImportYUV(int pitch, DataT *buff, BYTE bpp, int channelMap[] /*= NULL*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
02567         ASSERT(buff);
02568         const double dP = 1.0/m_header.height;
02569         const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
02570         const int pitch2 = pitch/DataTSize;
02571         const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
02572 
02573         int yPos = 0, cnt = 0;
02574         double percent = 0;
02575         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
02576 
02577         if (channelMap == NULL) channelMap = defMap;
02578 
02579         if (m_header.channels == 3)     {
02580                 ASSERT(bpp%dataBits == 0);
02581 
02582                 DataT* y = m_channel[0]; ASSERT(y);
02583                 DataT* u = m_channel[1]; ASSERT(u);
02584                 DataT* v = m_channel[2]; ASSERT(v);
02585                 const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
02586 
02587                 for (UINT32 h=0; h < m_header.height; h++) {
02588                         if (cb) {
02589                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02590                                 percent += dP;
02591                         }
02592 
02593                         cnt = 0;
02594                         for (UINT32 w=0; w < m_header.width; w++) {
02595                                 y[yPos] = buff[cnt + channelMap[0]];
02596                                 u[yPos] = buff[cnt + channelMap[1]];
02597                                 v[yPos] = buff[cnt + channelMap[2]];
02598                                 yPos++;
02599                                 cnt += channels;
02600                         }
02601                         buff += pitch2;
02602                 }       
02603         } else if (m_header.channels == 4) {
02604                 ASSERT(bpp%dataBits == 0);
02605 
02606                 DataT* y = m_channel[0]; ASSERT(y);
02607                 DataT* u = m_channel[1]; ASSERT(u);
02608                 DataT* v = m_channel[2]; ASSERT(v);
02609                 DataT* a = m_channel[3]; ASSERT(a);
02610                 const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
02611 
02612                 for (UINT32 h=0; h < m_header.height; h++) {
02613                         if (cb) {
02614                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02615                                 percent += dP;
02616                         }
02617 
02618                         cnt = 0;
02619                         for (UINT32 w=0; w < m_header.width; w++) {
02620                                 y[yPos] = buff[cnt + channelMap[0]];
02621                                 u[yPos] = buff[cnt + channelMap[1]];
02622                                 v[yPos] = buff[cnt + channelMap[2]];
02623                                 a[yPos] = buff[cnt + channelMap[3]] - yuvOffset;
02624                                 yPos++;
02625                                 cnt += channels;
02626                         }
02627                         buff += pitch2;
02628                 }       
02629         }
02630 
02631         if (m_downsample) {
02632                 // Subsampling of the chrominance and alpha channels
02633                 for (int i=1; i < m_header.channels; i++) {
02634                         Downsample(i);
02635                 }
02636         }
02637 }
02638