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