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