libpgf 6.11.32
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 #define MaxValue                2147483648              // 2^MaxBitPlanes = 2^31
00041 
00043 // global methods and variables
00044 #ifdef NEXCEPTIONS
00045         OSError _PGF_Error_;
00046 
00047         OSError GetLastPGFError() {
00048                 OSError tmp = _PGF_Error_;
00049                 _PGF_Error_ = NoError;
00050                 return tmp;
00051         }
00052 #endif
00053 
00055 // Standard constructor: It is used to create a PGF instance for opening and reading.
00056 CPGFImage::CPGFImage() 
00057 : m_decoder(0)
00058 , m_encoder(0)
00059 , m_levelLength(0)
00060 , m_quant(0)
00061 , m_downsample(false)
00062 , m_favorSpeedOverSize(false)
00063 , m_useOMPinEncoder(true)
00064 , m_useOMPinDecoder(true)
00065 #ifdef __PGFROISUPPORT__
00066 , m_levelwise(true)
00067 , m_streamReinitialized(false)
00068 #endif
00069 , m_cb(0)
00070 , m_cbArg(0)
00071 {
00072 
00073         // init preHeader
00074         memcpy(m_preHeader.magic, Magic, 3);
00075         m_preHeader.version = PGFVersion;
00076         m_preHeader.hSize = 0;
00077 
00078         // init postHeader
00079         m_postHeader.userData = 0;
00080         m_postHeader.userDataLen = 0;
00081 
00082         // init channels
00083         for (int i=0; i < MaxChannels; i++) {
00084                 m_channel[i] = 0;
00085                 m_wtChannel[i] = 0;
00086         }
00087 
00088         // set image width and height
00089         m_width[0] = 0;
00090         m_height[0] = 0;
00091 }
00092 
00094 // Destructor: Destroy internal data structures.
00095 CPGFImage::~CPGFImage() {
00096         Destroy();
00097 }
00098 
00100 // Destroy internal data structures.
00101 // Destructor calls this method during destruction.
00102 void CPGFImage::Destroy() {
00103         Close();
00104 
00105         for (int i=0; i < m_header.channels; i++) {
00106                 delete m_wtChannel[i]; m_wtChannel[i]=0; // also deletes m_channel
00107                 m_channel[i] = 0;
00108         }
00109         delete[] m_postHeader.userData; m_postHeader.userData = 0; m_postHeader.userDataLen = 0;
00110         delete[] m_levelLength; m_levelLength = 0;
00111         delete m_encoder; m_encoder = NULL;
00112 }
00113 
00115 // Close PGF image after opening and reading.
00116 // Destructor calls this method during destruction.
00117 void CPGFImage::Close() {
00118         delete m_decoder; m_decoder = 0;
00119 }
00120 
00122 // Open a PGF image at current stream position: read pre-header, header, levelLength, and ckeck image type.
00123 // Precondition: The stream has been opened for reading.
00124 // It might throw an IOException.
00125 // @param stream A PGF stream
00126 void CPGFImage::Open(CPGFStream *stream) THROW_ {
00127         ASSERT(stream);
00128 
00129         m_decoder = new CDecoder(stream, m_preHeader, m_header, m_postHeader, m_levelLength, m_useOMPinDecoder);
00130 
00131         if (m_header.nLevels > MaxLevel) ReturnWithError(FormatCannotRead);
00132 
00133         // set current level
00134         m_currentLevel = m_header.nLevels;
00135 
00136         // set image width and height
00137         m_width[0] = m_header.width;
00138         m_height[0] = m_header.height;
00139 
00140         // complete header
00141         CompleteHeader();
00142 
00143         // interpret quant parameter
00144         if (m_header.quality > DownsampleThreshold && 
00145                 (m_header.mode == ImageModeRGBColor || 
00146                  m_header.mode == ImageModeRGBA || 
00147                  m_header.mode == ImageModeRGB48 || 
00148                  m_header.mode == ImageModeCMYKColor || 
00149                  m_header.mode == ImageModeCMYK64 || 
00150                  m_header.mode == ImageModeLabColor || 
00151                  m_header.mode == ImageModeLab48)) {
00152                 m_downsample = true;
00153                 m_quant = m_header.quality - 1;
00154         } else {
00155                 m_downsample = false;
00156                 m_quant = m_header.quality;
00157         }
00158 
00159         // set channel dimensions (chrominance is subsampled by factor 2)
00160         if (m_downsample) {
00161                 for (int i=1; i < m_header.channels; i++) {
00162                         m_width[i] = (m_width[0] + 1)/2;
00163                         m_height[i] = (m_height[0] + 1)/2;
00164                 }
00165         } else {
00166                 for (int i=1; i < m_header.channels; i++) {
00167                         m_width[i] = m_width[0];
00168                         m_height[i] = m_height[0];
00169                 }
00170         }
00171 
00172         if (m_header.nLevels > 0) {
00173                 // init wavelet subbands
00174                 for (int i=0; i < m_header.channels; i++) {
00175                         m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels);
00176                 }
00177         } else {
00178                 // very small image: we don't use DWT and encoding
00179 
00180                 // read channels
00181                 for (int c=0; c < m_header.channels; c++) {
00182                         const UINT32 size = m_width[c]*m_height[c];
00183                         m_channel[c] = new DataT[size];
00184 
00185                         // read channel data from stream
00186                         for (UINT32 i=0; i < size; i++) {
00187                                 int count = DataTSize;
00188                                 stream->Read(&count, &m_channel[c][i]);
00189                                 if (count != DataTSize) ReturnWithError(MissingData);
00190                         }
00191                 }
00192         }
00193 }
00194 
00196 void CPGFImage::CompleteHeader() {
00197         if (m_header.mode == ImageModeUnknown) {
00198                 // undefined mode
00199                 switch(m_header.bpp) {
00200                 case 1: m_header.mode = ImageModeBitmap; break;
00201                 case 8: m_header.mode = ImageModeGrayScale; break;
00202                 case 12: m_header.mode = ImageModeRGB12; break;
00203                 case 16: m_header.mode = ImageModeRGB16; break;
00204                 case 24: m_header.mode = ImageModeRGBColor; break;
00205                 case 32: m_header.mode = ImageModeRGBA; break;
00206                 case 48: m_header.mode = ImageModeRGB48; break;
00207                 default: m_header.mode = ImageModeRGBColor; break;
00208                 }
00209         }
00210         if (!m_header.bpp) {
00211                 // undefined bpp
00212                 switch(m_header.mode) {
00213                 case ImageModeBitmap: 
00214                         m_header.bpp = 1;
00215                         break;
00216                 case ImageModeIndexedColor:
00217                 case ImageModeGrayScale:
00218                         m_header.bpp = 8;
00219                         break;
00220                 case ImageModeRGB12:
00221                         m_header.bpp = 12;
00222                         break;
00223                 case ImageModeRGB16:
00224                 case ImageModeGray16:
00225                         m_header.bpp = 16;
00226                         break;
00227                 case ImageModeRGBColor:
00228                 case ImageModeLabColor:
00229                         m_header.bpp = 24;
00230                         break;
00231                 case ImageModeRGBA:
00232                 case ImageModeCMYKColor:
00233         #ifdef __PGF32SUPPORT__
00234                 case ImageModeGray31:
00235         #endif                  
00236                         m_header.bpp = 32;
00237                         break;
00238                 case ImageModeRGB48:
00239                 case ImageModeLab48:
00240                         m_header.bpp = 48;
00241                         break;
00242                 case ImageModeCMYK64:
00243                         m_header.bpp = 64;
00244                         break;
00245                 default:
00246                         ASSERT(false);
00247                         m_header.bpp = 24;
00248                 }
00249         } 
00250         if (m_header.mode == ImageModeRGBColor && m_header.bpp == 32) {
00251                 // change mode
00252                 m_header.mode = ImageModeRGBA;
00253         }
00254         ASSERT(m_header.mode != ImageModeBitmap || m_header.bpp == 1);
00255         ASSERT(m_header.mode != ImageModeGrayScale || m_header.bpp == 8);
00256         ASSERT(m_header.mode != ImageModeGray16 || m_header.bpp == 16);
00257         ASSERT(m_header.mode != ImageModeRGBColor || m_header.bpp == 24);
00258         ASSERT(m_header.mode != ImageModeRGBA || m_header.bpp == 32);
00259         ASSERT(m_header.mode != ImageModeRGB12 || m_header.bpp == 12);
00260         ASSERT(m_header.mode != ImageModeRGB16 || m_header.bpp == 16);
00261         ASSERT(m_header.mode != ImageModeRGB48 || m_header.bpp == 48);
00262         ASSERT(m_header.mode != ImageModeLabColor || m_header.bpp == 24);
00263         ASSERT(m_header.mode != ImageModeLab48 || m_header.bpp == 48);
00264         ASSERT(m_header.mode != ImageModeCMYKColor || m_header.bpp == 32);
00265         ASSERT(m_header.mode != ImageModeCMYK64 || m_header.bpp == 64);
00266 
00267         // set number of channels
00268         if (!m_header.channels) {
00269                 switch(m_header.mode) {
00270                 case ImageModeBitmap: 
00271                 case ImageModeIndexedColor:
00272                 case ImageModeGrayScale:
00273                 case ImageModeGray16:
00274         #ifdef __PGF32SUPPORT__
00275                 case ImageModeGray31:
00276         #endif
00277                         m_header.channels = 1; 
00278                         break;
00279                 case ImageModeRGBColor:
00280                 case ImageModeRGB12:
00281                 case ImageModeRGB16:
00282                 case ImageModeRGB48:
00283                 case ImageModeLabColor:
00284                 case ImageModeLab48:
00285                         m_header.channels = 3;
00286                         break;
00287                 case ImageModeRGBA:
00288                 case ImageModeCMYKColor:
00289                 case ImageModeCMYK64:
00290                         m_header.channels = 4;
00291                         break;
00292                 default:
00293                         ASSERT(false);
00294                         m_header.channels = 3;
00295                 }
00296         }
00297 }
00298 
00303 const UINT8* CPGFImage::GetUserData(UINT32& size) const {
00304         size = m_postHeader.userDataLen;
00305         return m_postHeader.userData;
00306 }
00307 
00313 void CPGFImage::Reconstruct(int level /*= 0*/) THROW_ {
00314         if (m_header.nLevels == 0) {
00315                 // image didn't use wavelet transform
00316                 if (level == 0) {
00317                         for (int i=0; i < m_header.channels; i++) {
00318                                 ASSERT(m_wtChannel[i]);
00319                                 m_channel[i] = m_wtChannel[i]->GetSubband(0, LL)->GetBuffer();
00320                         }
00321                 }
00322         } else {
00323                 int currentLevel = m_header.nLevels;
00324 
00325                 if (ROIisSupported()) {
00326                         // enable ROI reading
00327                         SetROI(PGFRect(0, 0, m_header.width, m_header.height));
00328                 }
00329 
00330                 while (currentLevel > level) {
00331                         for (int i=0; i < m_header.channels; i++) {
00332                                 ASSERT(m_wtChannel[i]);
00333                                 // dequantize subbands
00334                                 if (currentLevel == m_header.nLevels) { 
00335                                         // last level also has LL band
00336                                         m_wtChannel[i]->GetSubband(currentLevel, LL)->Dequantize(m_quant);
00337                                 }
00338                                 m_wtChannel[i]->GetSubband(currentLevel, HL)->Dequantize(m_quant);
00339                                 m_wtChannel[i]->GetSubband(currentLevel, LH)->Dequantize(m_quant);
00340                                 m_wtChannel[i]->GetSubband(currentLevel, HH)->Dequantize(m_quant);
00341 
00342                                 // inverse transform from m_wtChannel to m_channel
00343                                 if (!m_wtChannel[i]->InverseTransform(currentLevel, &m_width[i], &m_height[i], &m_channel[i])) ReturnWithError(InsufficientMemory);
00344                                 ASSERT(m_channel[i]);
00345                         }
00346 
00347                         currentLevel--;
00348                 }
00349         }
00350 }
00351 
00353 // Read and decode some levels of a PGF image at current stream position.
00354 // A PGF image is structered in levels, numbered between 0 and Levels() - 1.
00355 // Each level can be seen as a single image, containing the same content
00356 // as all other levels, but in a different size (width, height).
00357 // The image size at level i is double the size (width, height) of the image at level i+1.
00358 // The image at level 0 contains the original size.
00359 // Precondition: The PGF image has been opened with a call of Open(...).
00360 // It might throw an IOException.
00361 // @param level The image level of the resulting image in the internal image buffer.
00362 // @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.
00363 // @param data Data Pointer to C++ class container to host callback procedure.
00364 void CPGFImage::Read(int level /*= 0*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
00365         ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
00366         ASSERT(m_decoder);
00367 
00368 #ifdef __PGFROISUPPORT__
00369         if (ROIisSupported() && m_header.nLevels > 0) {
00370                 // new encoding scheme supporting ROI
00371                 PGFRect rect(0, 0, m_header.width, m_header.height);
00372                 Read(rect, level, cb, data);
00373                 return;
00374         }
00375 #endif
00376 
00377         if (m_header.nLevels == 0) {
00378                 if (level == 0) {
00379                         // the data has already been read during open
00380                         // now update progress
00381                         if (cb) {
00382                                 if ((*cb)(1.0, true, data)) ReturnWithError(EscapePressed);
00383                         }
00384                 }
00385         } else {
00386                 const int levelDiff = m_currentLevel - level;
00387                 double percent = pow(0.25, levelDiff);
00388 
00389                 // encoding scheme without ROI
00390                 while (m_currentLevel > level) {
00391                         for (int i=0; i < m_header.channels; i++) {
00392                                 ASSERT(m_wtChannel[i]);
00393                                 // decode file and write stream to m_wtChannel
00394                                 if (m_currentLevel == m_header.nLevels) { 
00395                                         // last level also has LL band
00396                                         m_wtChannel[i]->GetSubband(m_currentLevel, LL)->PlaceTile(*m_decoder, m_quant);
00397                                 }
00398                                 if (m_preHeader.version & Version5) {
00399                                         // since version 5
00400                                         m_wtChannel[i]->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant);
00401                                         m_wtChannel[i]->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant);
00402                                 } else {
00403                                         // until version 4
00404                                         m_decoder->DecodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant);
00405                                 }
00406                                 m_wtChannel[i]->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant);
00407                         }
00408 
00409                         volatile OSError error = NoError; // volatile prevents optimizations
00410                         #pragma omp parallel for default(shared) 
00411                         for (int i=0; i < m_header.channels; i++) {
00412                                 // inverse transform from m_wtChannel to m_channel
00413                                 if (error == NoError) {
00414                                         OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);       
00415                                         if (err != NoError) error = err;
00416                                 }
00417                                 ASSERT(m_channel[i]);
00418                         }
00419                         if (error != NoError) ReturnWithError(error);
00420 
00421                         // set new level: must be done before refresh callback
00422                         m_currentLevel--;
00423 
00424                         // now we have to refresh the display
00425                         if (m_cb) m_cb(m_cbArg);
00426 
00427                         // now update progress
00428                         if (cb) {
00429                                 percent += 3*percent;
00430                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
00431                         }
00432                 }
00433         }
00434 
00435         // automatically closing
00436         if (m_currentLevel == 0) Close();
00437 }
00438 
00439 #ifdef __PGFROISUPPORT__
00440 
00441 
00442 
00443 
00444 
00445 
00446 
00447 
00448 
00449 void CPGFImage::Read(PGFRect& rect, int level /*= 0*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
00450         ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
00451         ASSERT(m_decoder);
00452 
00453         if (m_header.nLevels == 0 || !ROIisSupported()) {
00454                 rect.left = rect.top = 0;
00455                 rect.right = m_header.width; rect.bottom = m_header.height;
00456                 Read(level, cb, data);
00457         } else {
00458                 ASSERT(ROIisSupported());
00459                 // new encoding scheme supporting ROI
00460                 ASSERT(rect.left < m_header.width && rect.top < m_header.height);
00461                 const int levelDiff = m_currentLevel - level;
00462                 double percent = pow(0.25, levelDiff);
00463                 
00464                 // check level difference
00465                 if (levelDiff <= 0) {
00466                         // it is a new read call, probably with a new ROI
00467                         m_currentLevel = m_header.nLevels;
00468                         m_decoder->SetStreamPosToData();
00469                 }
00470 
00471                 // check rectangle
00472                 if (rect.right == 0 || rect.right > m_header.width) rect.right = m_header.width;
00473                 if (rect.bottom == 0 || rect.bottom > m_header.height) rect.bottom = m_header.height;
00474                 
00475                 // enable ROI decoding and reading
00476                 SetROI(rect);
00477 
00478                 while (m_currentLevel > level) {
00479                         for (int i=0; i < m_header.channels; i++) {
00480                                 ASSERT(m_wtChannel[i]);
00481 
00482                                 // get number of tiles and tile indices
00483                                 const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel);
00484                                 const PGFRect& tileIndices = m_wtChannel[i]->GetTileIndices(m_currentLevel);
00485 
00486                                 // decode file and write stream to m_wtChannel
00487                                 if (m_currentLevel == m_header.nLevels) { // last level also has LL band
00488                                         ASSERT(nTiles == 1);
00489                                         m_decoder->DecodeTileBuffer();
00490                                         m_wtChannel[i]->GetSubband(m_currentLevel, LL)->PlaceTile(*m_decoder, m_quant);
00491                                 }
00492                                 for (UINT32 tileY=0; tileY < nTiles; tileY++) {
00493                                         for (UINT32 tileX=0; tileX < nTiles; tileX++) {
00494                                                 // check relevance of tile
00495                                                 if (tileIndices.IsInside(tileX, tileY)) {
00496                                                         m_decoder->DecodeTileBuffer();
00497                                                         m_wtChannel[i]->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
00498                                                         m_wtChannel[i]->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
00499                                                         m_wtChannel[i]->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
00500                                                 } else {
00501                                                         // skip tile
00502                                                         m_decoder->SkipTileBuffer();
00503                                                 }
00504                                         }
00505                                 }
00506                         }
00507 
00508                         volatile OSError error = NoError; // volatile prevents optimizations
00509                         #pragma omp parallel for default(shared) 
00510                         for (int i=0; i < m_header.channels; i++) {
00511                                 // inverse transform from m_wtChannel to m_channel
00512                                 if (error == NoError) {
00513                                         OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
00514                                         if (err != NoError) error = err;
00515                                 }
00516                                 ASSERT(m_channel[i]);
00517                         }
00518                         if (error != NoError) ReturnWithError(error);
00519 
00520                         // set new level: must be done before refresh callback
00521                         m_currentLevel--;
00522 
00523                         // now we have to refresh the display
00524                         if (m_cb) m_cb(m_cbArg);
00525 
00526                         // now update progress
00527                         if (cb) {
00528                                 percent += 3*percent;
00529                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
00530                         }
00531                 }
00532         }
00533 
00534         // automatically closing
00535         if (m_currentLevel == 0) Close();
00536 }
00537 
00541 void CPGFImage::SetROI(PGFRect rect) {
00542         ASSERT(m_decoder);
00543         ASSERT(ROIisSupported());
00544 
00545         // store ROI for a later call of GetBitmap
00546         m_roi = rect;
00547 
00548         // enable ROI decoding
00549         m_decoder->SetROI();
00550 
00551         // enlarge ROI because of border artefacts
00552         const UINT32 dx = FilterWidth/2*(1 << m_currentLevel);
00553         const UINT32 dy = FilterHeight/2*(1 << m_currentLevel);
00554 
00555         if (rect.left < dx) rect.left = 0;
00556         else rect.left -= dx;
00557         if (rect.top < dy) rect.top = 0;
00558         else rect.top -= dy;
00559         rect.right += dx;
00560         if (rect.right > m_header.width) rect.right = m_header.width;
00561         rect.bottom += dy;
00562         if (rect.bottom > m_header.height) rect.bottom = m_header.height;
00563 
00564         // prepare wavelet channels for using ROI
00565         ASSERT(m_wtChannel[0]);
00566         m_wtChannel[0]->SetROI(rect);
00567         if (m_downsample && m_header.channels > 1) {
00568                 // all further channels are downsampled, therefore downsample ROI
00569                 rect.left >>= 1;
00570                 rect.top >>= 1;
00571                 rect.right >>= 1;
00572                 rect.bottom >>= 1;
00573         }
00574         for (int i=1; i < m_header.channels; i++) {
00575                 ASSERT(m_wtChannel[i]);
00576                 m_wtChannel[i]->SetROI(rect);
00577         }
00578 }
00579 
00580 #endif // __PGFROISUPPORT__
00581 
00586 UINT32 CPGFImage::GetEncodedHeaderLength() const { 
00587         ASSERT(m_decoder); 
00588         return m_decoder->GetEncodedHeaderLength(); 
00589 }
00590 
00598 UINT32 CPGFImage::ReadEncodedHeader(UINT8* target, UINT32 targetLen) const THROW_ {
00599         ASSERT(target);
00600         ASSERT(targetLen > 0);
00601         ASSERT(m_decoder);
00602 
00603         // reset stream position
00604         m_decoder->SetStreamPosToStart();
00605 
00606         // compute number of bytes to read
00607         UINT32 len = __min(targetLen, GetEncodedHeaderLength());
00608 
00609         // read data
00610         len = m_decoder->ReadEncodedData(target, len);
00611         ASSERT(len >= 0 && len <= targetLen);
00612 
00613         return len;
00614 }
00615 
00618 void CPGFImage::ResetStreamPos() THROW_ {
00619         ASSERT(m_decoder);
00620         return m_decoder->SetStreamPosToStart(); 
00621 }
00622 
00632 UINT32 CPGFImage::ReadEncodedData(int level, UINT8* target, UINT32 targetLen) const THROW_ {
00633         ASSERT(level >= 0 && level < m_header.nLevels);
00634         ASSERT(target);
00635         ASSERT(targetLen > 0);
00636         ASSERT(m_decoder);
00637 
00638         // reset stream position
00639         m_decoder->SetStreamPosToData();
00640 
00641         // position stream
00642         UINT64 offset = 0;
00643 
00644         for (int i=m_header.nLevels - 1; i > level; i--) {
00645                 offset += m_levelLength[m_header.nLevels - 1 - i];
00646         }
00647         m_decoder->Skip(offset);
00648 
00649         // compute number of bytes to read
00650         UINT32 len = __min(targetLen, GetEncodedLevelLength(level));
00651 
00652         // read data
00653         len = m_decoder->ReadEncodedData(target, len);
00654         ASSERT(len >= 0 && len <= targetLen);
00655 
00656         return len;
00657 }
00658 
00660 // Set background of an RGB image with transparency channel or reset to default background.
00661 // @param bg A pointer to a background color or NULL (reset to default background)
00662 void CPGFImage::SetBackground(const RGBTRIPLE* bg) { 
00663         if (bg) { 
00664                 m_header.background = *bg; 
00665 //              m_backgroundSet = true; 
00666         } else {
00667                 m_header.background.rgbtBlue = DefaultBGColor;
00668                 m_header.background.rgbtGreen = DefaultBGColor;
00669                 m_header.background.rgbtRed = DefaultBGColor;
00670 //              m_backgroundSet = false;
00671         }
00672 }
00673 
00678 void CPGFImage::SetMaxValue(UINT32 maxValue) {
00679         BYTE pot = 0;
00680 
00681         while(maxValue > 0) {
00682                 pot++;
00683                 maxValue >>= 1;
00684         }
00685         // store bits per channel
00686         if (pot > 31) pot = 31;
00687         m_header.background.rgbtBlue = pot;
00688 }
00689 
00694 BYTE CPGFImage::UsedBitsPerChannel() const {
00695         BYTE bpc = m_header.bpp/m_header.channels;
00696 
00697         if (bpc > 8) {
00698                 // see also GetMaxValue()
00699                 return m_header.background.rgbtBlue;
00700         } else {
00701                 return bpc;
00702         }
00703 }
00704 
00707 BYTE CPGFImage::Version() const {
00708         if (m_preHeader.version & Version6) return 6;
00709         if (m_preHeader.version & Version5) return 5;
00710         if (m_preHeader.version & Version2) return 2;
00711         return 1;
00712 }
00713 
00715 // Import an image from a specified image buffer.
00716 // This method is usually called before Write(...) and after SetHeader(...).
00717 // It might throw an IOException.
00718 // The absolute value of pitch is the number of bytes of an image row.
00719 // If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row).
00720 // If pitch is positive, then buff points to the first row of a top-down image (first byte).
00721 // 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
00722 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
00723 // If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
00724 // @param pitch The number of bytes of a row of the image buffer.
00725 // @param buff An image buffer.
00726 // @param bpp The number of bits per pixel used in image buffer.
00727 // @param channelMap A integer array containing the mapping of input channel ordering to expected channel ordering.
00728 // @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.
00729 // @param data Data Pointer to C++ class container to host callback procedure.
00730 void CPGFImage::ImportBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[] /*= NULL */, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
00731         ASSERT(buff);
00732         ASSERT(m_channel[0]);
00733 
00734         // color transform
00735         RgbToYuv(pitch, buff, bpp, channelMap, cb, data);
00736 
00737         if (m_downsample) {
00738                 // Subsampling of the chrominance and alpha channels
00739                 for (int i=1; i < m_header.channels; i++) {
00740                         Downsample(i);
00741                 }
00742         }
00743 }
00744 
00746 // Bilinerar Subsampling of channel ch by a factor 2
00747 void CPGFImage::Downsample(int ch) {
00748         ASSERT(ch > 0);
00749 
00750         const int w = m_width[0];
00751         const int w2 = w/2;
00752         const int h2 = m_height[0]/2;
00753         const int oddW = w%2;                           // don't use bool -> problems with MaxSpeed optimization
00754         const int oddH = m_height[0]%2;         // "
00755         int i, j;
00756         int loPos = 0;
00757         int hiPos = w;
00758         int sampledPos = 0;
00759         DataT* buff = m_channel[ch]; ASSERT(buff);
00760 
00761         for (i=0; i < h2; i++) {
00762                 for (j=0; j < w2; j++) {
00763                         // compute average of pixel block
00764                         buff[sampledPos] = (buff[loPos] + buff[loPos + 1] + buff[hiPos] + buff[hiPos + 1]) >> 2;
00765                         loPos += 2; hiPos += 2;
00766                         sampledPos++;
00767                 }
00768                 if (oddW) { 
00769                         buff[sampledPos] = (buff[loPos] + buff[hiPos]) >> 1;
00770                         loPos++; hiPos++;
00771                         sampledPos++;
00772                 }
00773                 loPos += w; hiPos += w;
00774         }
00775         if (oddH) {
00776                 for (j=0; j < w2; j++) {
00777                         buff[sampledPos] = (buff[loPos] + buff[loPos+1]) >> 1;
00778                         loPos += 2; hiPos += 2;
00779                         sampledPos++;
00780                 }
00781                 if (oddW) {
00782                         buff[sampledPos] = buff[loPos];
00783                 }
00784         }
00785 
00786         // downsampled image has half width and half height
00787         m_width[ch] = (m_width[ch] + 1)/2;
00788         m_height[ch] = (m_height[ch] + 1)/2;
00789 }
00790 
00792 void CPGFImage::ComputeLevels() {
00793         const int maxThumbnailWidth = 20*FilterWidth;
00794         const int m = __min(m_header.width, m_header.height);
00795         int s = m;
00796 
00797         if (m_header.nLevels < 1 || m_header.nLevels > MaxLevel) {
00798                 m_header.nLevels = 1;
00799                 // compute a good value depending on the size of the image
00800                 while (s > maxThumbnailWidth) {
00801                         m_header.nLevels++;
00802                         s = s/2;
00803                 }
00804         }
00805 
00806         int levels = m_header.nLevels; // we need a signed value during level reduction
00807 
00808         // reduce number of levels if the image size is smaller than FilterWidth*2^levels
00809         s = FilterWidth*(1 << levels);  // must be at least the double filter size because of subsampling
00810         while (m < s) {
00811                 levels--;
00812                 s = s/2;
00813         }
00814         if (levels > MaxLevel) m_header.nLevels = MaxLevel;
00815         else if (levels < 0) m_header.nLevels = 0;
00816         else m_header.nLevels = (UINT8)levels;
00817 
00818         ASSERT(0 <= m_header.nLevels && m_header.nLevels <= MaxLevel);
00819 }
00820 
00829 void CPGFImage::SetHeader(const PGFHeader& header, BYTE flags /*=0*/, UINT8* userData /*= 0*/, UINT32 userDataLength /*= 0*/) THROW_ {
00830         ASSERT(!m_decoder);     // current image must be closed
00831         ASSERT(header.quality <= MaxQuality);
00832 
00833         // init state
00834 #ifdef __PGFROISUPPORT__
00835         m_levelwise = true;
00836         m_streamReinitialized = false;
00837 #endif
00838 
00839         // init preHeader
00840         memcpy(m_preHeader.magic, Magic, 3);
00841         m_preHeader.version = PGFVersion | flags;
00842         m_preHeader.hSize = HeaderSize;
00843 
00844         // copy header
00845         memcpy(&m_header, &header, HeaderSize);
00846 
00847         // complete header
00848         CompleteHeader();
00849 
00850         // check and set number of levels
00851         ComputeLevels();
00852 
00853         // misuse background value to store bits per channel
00854         BYTE bpc = m_header.bpp/m_header.channels;
00855         if (bpc > 8) {
00856                 if (bpc > 31) bpc = 31;
00857                 m_header.background.rgbtBlue = bpc;
00858         }
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 ImageModeGray31:
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 w2 = (m_header.width + 7)/8;
01296                         DataT* y = m_channel[0]; ASSERT(y);
01297 
01298                         for (UINT32 h=0; h < m_header.height; h++) {
01299                                 if (cb) {
01300                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01301                                         percent += dP;
01302                                 }
01303 
01304                                 for (UINT32 w=0; w < w2; w++) {
01305                                         y[yPos++] = buff[w] - YUVoffset8;
01306                                 }
01307                                 buff += pitch;  
01308                         }
01309                 }
01310                 break;
01311         case ImageModeIndexedColor:
01312         case ImageModeGrayScale:
01313         case ImageModeHSLColor:
01314         case ImageModeHSBColor:
01315         case ImageModeLabColor:
01316                 {
01317                         ASSERT(m_header.channels >= 1);
01318                         ASSERT(m_header.bpp == m_header.channels*8);
01319                         ASSERT(bpp%8 == 0);
01320                         const int channels = bpp/8; ASSERT(channels >= m_header.channels);
01321 
01322                         for (UINT32 h=0; h < m_header.height; h++) {
01323                                 if (cb) {
01324                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01325                                         percent += dP;
01326                                 }
01327 
01328                                 cnt = 0;
01329                                 for (UINT32 w=0; w < m_header.width; w++) {
01330                                         for (int c=0; c < m_header.channels; c++) {
01331                                                 m_channel[c][yPos] = buff[cnt + channelMap[c]] - YUVoffset8;
01332                                         }
01333                                         cnt += channels;
01334                                         yPos++;
01335                                 }
01336                                 buff += pitch;  
01337                         }
01338                 }
01339                 break;
01340         case ImageModeGray16:
01341         case ImageModeLab48:
01342                 {
01343                         ASSERT(m_header.channels >= 1);
01344                         ASSERT(m_header.bpp == m_header.channels*16);
01345                         ASSERT(bpp%16 == 0);
01346 
01347                         UINT16 *buff16 = (UINT16 *)buff;
01348                         const int pitch16 = pitch/2;
01349                         const int channels = bpp/16; ASSERT(channels >= m_header.channels);
01350                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01351 
01352                         for (UINT32 h=0; h < m_header.height; h++) {
01353                                 if (cb) {
01354                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01355                                         percent += dP;
01356                                 }
01357 
01358                                 cnt = 0;
01359                                 for (UINT32 w=0; w < m_header.width; w++) {
01360                                         for (int c=0; c < m_header.channels; c++) {
01361                                                 m_channel[c][yPos] = buff16[cnt + channelMap[c]] - yuvOffset16;
01362                                         }
01363                                         cnt += channels;
01364                                         yPos++;
01365                                 }
01366                                 buff16 += pitch16;
01367                         }
01368                 }
01369                 break;
01370         case ImageModeRGBColor:
01371                 {
01372                         ASSERT(m_header.channels == 3);
01373                         ASSERT(m_header.bpp == m_header.channels*8);
01374                         ASSERT(bpp%8 == 0);
01375 
01376                         DataT* y = m_channel[0]; ASSERT(y);
01377                         DataT* u = m_channel[1]; ASSERT(u);
01378                         DataT* v = m_channel[2]; ASSERT(v);
01379                         const int channels = bpp/8; ASSERT(channels >= m_header.channels);
01380                         UINT8 b, g, r;
01381 
01382                         for (UINT32 h=0; h < m_header.height; h++) {
01383                                 if (cb) {
01384                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01385                                         percent += dP;
01386                                 }
01387 
01388                                 cnt = 0;
01389                                 for (UINT32 w=0; w < m_header.width; w++) {
01390                                         b = buff[cnt + channelMap[0]];
01391                                         g = buff[cnt + channelMap[1]];
01392                                         r = buff[cnt + channelMap[2]];
01393                                         // Yuv
01394                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
01395                                         u[yPos] = r - g;
01396                                         v[yPos] = b - g;
01397                                         yPos++;
01398                                         cnt += channels;
01399                                 }
01400                                 buff += pitch;
01401                         }       
01402                 }
01403                 break;
01404         case ImageModeRGB48:
01405                 {
01406                         ASSERT(m_header.channels == 3);
01407                         ASSERT(m_header.bpp == m_header.channels*16);
01408                         ASSERT(bpp%16 == 0);
01409 
01410                         UINT16 *buff16 = (UINT16 *)buff;
01411                         const int pitch16 = pitch/2;
01412                         const int channels = bpp/16; ASSERT(channels >= m_header.channels);
01413                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01414 
01415                         DataT* y = m_channel[0]; ASSERT(y);
01416                         DataT* u = m_channel[1]; ASSERT(u);
01417                         DataT* v = m_channel[2]; ASSERT(v);
01418                         UINT16 b, g, r;
01419 
01420                         for (UINT32 h=0; h < m_header.height; h++) {
01421                                 if (cb) {
01422                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01423                                         percent += dP;
01424                                 }
01425 
01426                                 cnt = 0;
01427                                 for (UINT32 w=0; w < m_header.width; w++) {
01428                                         b = buff16[cnt + channelMap[0]];
01429                                         g = buff16[cnt + channelMap[1]];
01430                                         r = buff16[cnt + channelMap[2]];
01431                                         // Yuv
01432                                         y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
01433                                         u[yPos] = r - g;
01434                                         v[yPos] = b - g;
01435                                         yPos++;
01436                                         cnt += channels;
01437                                 }
01438                                 buff16 += pitch16;
01439                         }       
01440                 }
01441                 break;
01442         case ImageModeRGBA:
01443         case ImageModeCMYKColor:
01444                 {
01445                         ASSERT(m_header.channels == 4);
01446                         ASSERT(m_header.bpp == m_header.channels*8);
01447                         ASSERT(bpp%8 == 0);
01448                         const int channels = bpp/8; ASSERT(channels >= m_header.channels);
01449 
01450                         DataT* y = m_channel[0]; ASSERT(y);
01451                         DataT* u = m_channel[1]; ASSERT(u);
01452                         DataT* v = m_channel[2]; ASSERT(v);
01453                         DataT* a = m_channel[3]; ASSERT(a);
01454                         UINT8 b, g, r;
01455 
01456                         for (UINT32 h=0; h < m_header.height; h++) {
01457                                 if (cb) {
01458                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01459                                         percent += dP;
01460                                 }
01461 
01462                                 cnt = 0;
01463                                 for (UINT32 w=0; w < m_header.width; w++) {
01464                                         b = buff[cnt + channelMap[0]];
01465                                         g = buff[cnt + channelMap[1]];
01466                                         r = buff[cnt + channelMap[2]];
01467                                         // Yuv
01468                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
01469                                         u[yPos] = r - g;
01470                                         v[yPos] = b - g;
01471                                         a[yPos++] = buff[cnt + channelMap[3]] - YUVoffset8;
01472                                         cnt += channels;
01473                                 }
01474                                 buff += pitch;
01475                         }       
01476                 }
01477                 break;
01478         case ImageModeCMYK64:
01479                 {
01480                         ASSERT(m_header.channels == 4);
01481                         ASSERT(m_header.bpp == m_header.channels*16);
01482                         ASSERT(bpp%16 == 0);
01483 
01484                         UINT16 *buff16 = (UINT16 *)buff;
01485                         const int pitch16 = pitch/2;
01486                         const int channels = bpp/16; ASSERT(channels >= m_header.channels);
01487                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01488                         
01489                         DataT* y = m_channel[0]; ASSERT(y);
01490                         DataT* u = m_channel[1]; ASSERT(u);
01491                         DataT* v = m_channel[2]; ASSERT(v);
01492                         DataT* a = m_channel[3]; ASSERT(a);
01493                         UINT16 b, g, r;
01494 
01495                         for (UINT32 h=0; h < m_header.height; h++) {
01496                                 if (cb) {
01497                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01498                                         percent += dP;
01499                                 }
01500 
01501                                 cnt = 0;
01502                                 for (UINT32 w=0; w < m_header.width; w++) {
01503                                         b = buff16[cnt + channelMap[0]];
01504                                         g = buff16[cnt + channelMap[1]];
01505                                         r = buff16[cnt + channelMap[2]];
01506                                         // Yuv
01507                                         y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
01508                                         u[yPos] = r - g;
01509                                         v[yPos] = b - g;
01510                                         a[yPos++] = buff16[cnt + channelMap[3]] - yuvOffset16;
01511                                         cnt += channels;
01512                                 }
01513                                 buff16 += pitch16;
01514                         }       
01515                 }
01516                 break;
01517 #ifdef __PGF32SUPPORT__
01518         case ImageModeGray31:
01519                 {
01520                         ASSERT(m_header.channels == 1);
01521                         ASSERT(m_header.bpp == 32);
01522                         ASSERT(bpp == 32);
01523                         ASSERT(DataTSize == sizeof(UINT32));
01524 
01525                         DataT* y = m_channel[0]; ASSERT(y);
01526 
01527                         UINT32 *buff32 = (UINT32 *)buff;
01528                         const int pitch32 = pitch/4;
01529                         const DataT yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
01530 
01531                         for (UINT32 h=0; h < m_header.height; h++) {
01532                                 if (cb) {
01533                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01534                                         percent += dP;
01535                                 }
01536 
01537                                 for (UINT32 w=0; w < m_header.width; w++) {
01538                                         ASSERT(buff32[cnt] < MaxValue);
01539                                         y[yPos++] = buff32[w] - yuvOffset31;
01540                                 }
01541                                 buff32 += pitch32;
01542                         }
01543                 }
01544                 break;
01545 #endif
01546         case ImageModeRGB12:
01547                 {
01548                         ASSERT(m_header.channels == 3);
01549                         ASSERT(m_header.bpp == m_header.channels*4);
01550                         ASSERT(bpp == m_header.channels*4);
01551 
01552                         DataT* y = m_channel[0]; ASSERT(y);
01553                         DataT* u = m_channel[1]; ASSERT(u);
01554                         DataT* v = m_channel[2]; ASSERT(v);
01555 
01556                         UINT8 rgb = 0, b, g, r;
01557 
01558                         for (UINT32 h=0; h < m_header.height; h++) {
01559                                 if (cb) {
01560                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01561                                         percent += dP;
01562                                 }
01563 
01564                                 cnt = 0;
01565                                 for (UINT32 w=0; w < m_header.width; w++) {
01566                                         if (w%2 == 0) {
01567                                                 // even pixel position
01568                                                 rgb = buff[cnt];
01569                                                 b = rgb & 0x0F;
01570                                                 g = (rgb & 0xF0) >> 4;
01571                                                 cnt++;
01572                                                 rgb = buff[cnt];
01573                                                 r = rgb & 0x0F;
01574                                         } else {
01575                                                 // odd pixel position
01576                                                 b = (rgb & 0xF0) >> 4;
01577                                                 cnt++;
01578                                                 rgb = buff[cnt];
01579                                                 g = rgb & 0x0F;
01580                                                 r = (rgb & 0xF0) >> 4;
01581                                                 cnt++;
01582                                         }
01583 
01584                                         // Yuv
01585                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset4;
01586                                         u[yPos] = r - g;
01587                                         v[yPos] = b - g;
01588                                         yPos++;
01589                                 }
01590                                 buff += pitch;
01591                         }       
01592                 }
01593                 break;
01594         case ImageModeRGB16:
01595                 {
01596                         ASSERT(m_header.channels == 3);
01597                         ASSERT(m_header.bpp == 16);
01598                         ASSERT(bpp == 16);
01599                         
01600                         DataT* y = m_channel[0]; ASSERT(y);
01601                         DataT* u = m_channel[1]; ASSERT(u);
01602                         DataT* v = m_channel[2]; ASSERT(v);
01603 
01604                         UINT16 *buff16 = (UINT16 *)buff;
01605                         UINT16 rgb, b, g, r;
01606                         const int pitch16 = pitch/2;
01607 
01608                         for (UINT32 h=0; h < m_header.height; h++) {
01609                                 if (cb) {
01610                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01611                                         percent += dP;
01612                                 }
01613                                 for (UINT32 w=0; w < m_header.width; w++) {
01614                                         rgb = buff16[w]; 
01615                                         r = (rgb & 0xF800) >> 10;       // highest 5 bits
01616                                         g = (rgb & 0x07E0) >> 5;        // middle 6 bits
01617                                         b = (rgb & 0x001F) << 1;        // lowest 5 bits
01618                                         // Yuv
01619                                         y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset6;
01620                                         u[yPos] = r - g;
01621                                         v[yPos] = b - g;
01622                                         yPos++;
01623                                 }
01624 
01625                                 buff16 += pitch16;
01626                         }       
01627                 }
01628                 break;
01629         default:
01630                 ASSERT(false);
01631         }
01632 }
01633 
01635 // Get image data in interleaved format: (ordering of RGB data is BGR[A])
01636 // Upsampling, YUV to RGB transform and interleaving are done here to reduce the number 
01637 // of passes over the data.
01638 // The absolute value of pitch is the number of bytes of an image row of the given image buffer.
01639 // If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row).
01640 // if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte).
01641 // 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
01642 // provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode.
01643 // If your provided image buffer expects a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
01644 // It might throw an IOException.
01645 // @param pitch The number of bytes of a row of the image buffer.
01646 // @param buff An image buffer.
01647 // @param bpp The number of bits per pixel used in image buffer.
01648 // @param channelMap A integer array containing the mapping of PGF channel ordering to expected channel ordering.
01649 // @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.
01650 // @param data Data Pointer to C++ class container to host callback procedure.
01651 void CPGFImage::GetBitmap(int pitch, UINT8* buff, BYTE bpp, int channelMap[] /*= NULL */, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) const THROW_ {
01652         ASSERT(buff);
01653         UINT32 w = m_width[0];
01654         UINT32 h = m_height[0];
01655         UINT8* targetBuff = 0;  // used if ROI is used
01656         UINT8* buffStart = 0;   // used if ROI is used
01657         int targetPitch = 0;    // used if ROI is used
01658 
01659 #ifdef __PGFROISUPPORT__
01660         const PGFRect& roi = (ROIisSupported()) ? m_wtChannel[0]->GetROI(m_currentLevel) : PGFRect(0, 0, w, h); // roi is usually larger than m_roi
01661         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));
01662         ASSERT(w == roi.Width() && h == roi.Height());
01663         ASSERT(roi.left <= levelRoi.left && levelRoi.right <= roi.right); 
01664         ASSERT(roi.top <= levelRoi.top && levelRoi.bottom <= roi.bottom); 
01665 
01666         if (ROIisSupported() && (levelRoi.Width() < w || levelRoi.Height() < h)) {
01667                 // ROI is used -> create a temporary image buffer for roi
01668                 // compute pitch
01669                 targetPitch = pitch;
01670                 pitch = AlignWordPos(w*bpp)/8;
01671 
01672                 // create temporary output buffer
01673                 targetBuff = buff;
01674                 buff = buffStart = new(std::nothrow) UINT8[pitch*h];
01675                 if (!buff) ReturnWithError(InsufficientMemory);
01676         }
01677 #endif
01678 
01679         const bool wOdd = (1 == w%2);
01680 
01681         const double dP = 1.0/h;
01682         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
01683         if (channelMap == NULL) channelMap = defMap;
01684         int sampledPos = 0, yPos = 0;
01685         DataT uAvg, vAvg;
01686         double percent = 0;
01687         UINT32 i, j;
01688 
01689         switch(m_header.mode) {
01690         case ImageModeBitmap:
01691                 {
01692                         ASSERT(m_header.channels == 1);
01693                         ASSERT(m_header.bpp == 1);
01694                         ASSERT(bpp == 1);
01695 
01696                         const UINT32 w2 = (w + 7)/8;
01697                         DataT* y = m_channel[0]; ASSERT(y);
01698 
01699                         for (i=0; i < h; i++) {
01700                                 for (j=0; j < w2; j++) {
01701                                         buff[j] = Clamp(y[yPos++] + YUVoffset8);
01702                                 }
01703                                 buff += pitch;
01704 
01705                                 if (cb) {
01706                                         percent += dP;
01707                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01708                                 }
01709                         }
01710                         break;
01711                 }
01712         case ImageModeIndexedColor:
01713         case ImageModeGrayScale:
01714         case ImageModeHSLColor:
01715         case ImageModeHSBColor:
01716                 {
01717                         ASSERT(m_header.channels >= 1);
01718                         ASSERT(m_header.bpp == m_header.channels*8);
01719                         ASSERT(bpp%8 == 0);
01720 
01721                         int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
01722 
01723                         for (i=0; i < h; i++) {
01724                                 cnt = 0;
01725                                 for (j=0; j < w; j++) {
01726                                         for (int c=0; c < m_header.channels; c++) {
01727                                                 buff[cnt + channelMap[c]] = Clamp(m_channel[c][yPos] + YUVoffset8);
01728                                         }
01729                                         cnt += channels;
01730                                         yPos++;
01731                                 }
01732                                 buff += pitch;
01733 
01734                                 if (cb) {
01735                                         percent += dP;
01736                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01737                                 }
01738                         }
01739                         break;
01740                 }
01741         case ImageModeGray16:
01742                 {
01743                         ASSERT(m_header.channels >= 1);
01744                         ASSERT(m_header.bpp == m_header.channels*16);
01745 
01746                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01747                         const int shift = UsedBitsPerChannel() - 8;
01748                         int cnt, channels;
01749 
01750                         if (bpp%16 == 0) {
01751                                 UINT16 *buff16 = (UINT16 *)buff;
01752                                 int pitch16 = pitch/2;
01753                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
01754 
01755                                 for (i=0; i < h; i++) {
01756                                         cnt = 0;
01757                                         for (j=0; j < w; j++) {
01758                                                 for (int c=0; c < m_header.channels; c++) {
01759                                                         buff16[cnt + channelMap[c]] = Clamp16(m_channel[c][yPos] + yuvOffset16);
01760                                                 }
01761                                                 cnt += channels;
01762                                                 yPos++;
01763                                         }
01764                                         buff16 += pitch16;
01765 
01766                                         if (cb) {
01767                                                 percent += dP;
01768                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01769                                         }
01770                                 }
01771                         } else {
01772                                 ASSERT(bpp%8 == 0);
01773                                 channels = bpp/8; ASSERT(channels >= m_header.channels);
01774                                 
01775                                 for (i=0; i < h; i++) {
01776                                         cnt = 0;
01777                                         for (j=0; j < w; j++) {
01778                                                 for (int c=0; c < m_header.channels; c++) {
01779                                                         buff[cnt + channelMap[c]] = UINT8(Clamp16(m_channel[c][yPos] + yuvOffset16) >> shift);
01780                                                 }
01781                                                 cnt += channels;
01782                                                 yPos++;
01783                                         }
01784                                         buff += pitch;
01785 
01786                                         if (cb) {
01787                                                 percent += dP;
01788                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01789                                         }
01790                                 }
01791                         }
01792                         break;
01793                 }
01794         case ImageModeRGBColor:
01795                 {
01796                         ASSERT(m_header.channels == 3);
01797                         ASSERT(m_header.bpp == m_header.channels*8);
01798                         ASSERT(bpp%8 == 0);
01799                         ASSERT(bpp >= m_header.bpp);
01800 
01801                         DataT* y = m_channel[0]; ASSERT(y);
01802                         DataT* u = m_channel[1]; ASSERT(u);
01803                         DataT* v = m_channel[2]; ASSERT(v);
01804                         UINT8 *buffg = &buff[channelMap[1]],
01805                                   *buffr = &buff[channelMap[2]],
01806                                   *buffb = &buff[channelMap[0]];
01807                         UINT8 g;
01808                         int cnt, channels = bpp/8;
01809                         if(m_downsample){
01810                                 for (i=0; i < h; i++) {
01811                                         if (i%2) sampledPos -= (w + 1)/2;
01812                                         cnt = 0;
01813                                         for (j=0; j < w; j++) {
01814                                                 // image was downsampled
01815                                                 uAvg = u[sampledPos];
01816                                                 vAvg = v[sampledPos];
01817                                                 // Yuv
01818                                                 buffg[cnt] = g = Clamp(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
01819                                                 buffr[cnt] = Clamp(uAvg + g);
01820                                                 buffb[cnt] = Clamp(vAvg + g);
01821                                                 yPos++;
01822                                                 cnt += channels;
01823                                                 if (j%2) sampledPos++;
01824                                         }
01825                                         buffb += pitch;
01826                                         buffg += pitch;
01827                                         buffr += pitch;
01828                                         if (wOdd) sampledPos++;
01829                                         if (cb) {
01830                                                 percent += dP;
01831                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01832                                         }
01833                                 }
01834                         }else{
01835                                 for (i=0; i < h; i++) {
01836                                         cnt = 0;
01837                                         for (j = 0; j < w; j++) {
01838                                                 uAvg = u[yPos];
01839                                                 vAvg = v[yPos];
01840                                                 // Yuv
01841                                                 buffg[cnt] = g = Clamp(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
01842                                                 buffr[cnt] = Clamp(uAvg + g);
01843                                                 buffb[cnt] = Clamp(vAvg + g);
01844                                                 yPos++;
01845                                                 cnt += channels;
01846                                         }
01847                                         buffb += pitch;
01848                                         buffg += pitch;
01849                                         buffr += pitch;
01850 
01851                                         if (cb) {
01852                                                 percent += dP;
01853                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01854                                         }
01855                                 }
01856                         }
01857                         break;
01858                 }
01859         case ImageModeRGB48:
01860                 {
01861                         ASSERT(m_header.channels == 3);
01862                         ASSERT(m_header.bpp == 48);
01863 
01864                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01865                         const int shift = UsedBitsPerChannel() - 8;
01866 
01867                         DataT* y = m_channel[0]; ASSERT(y);
01868                         DataT* u = m_channel[1]; ASSERT(u);
01869                         DataT* v = m_channel[2]; ASSERT(v);
01870                         UINT16 g;
01871                         int cnt, channels;
01872 
01873                         if (bpp >= 48 && bpp%16 == 0) {
01874                                 UINT16 *buff16 = (UINT16 *)buff;
01875                                 int pitch16 = pitch/2;
01876                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
01877 
01878                                 for (i=0; i < h; i++) {
01879                                         if (i%2) sampledPos -= (w + 1)/2;
01880                                         cnt = 0;
01881                                         for (j=0; j < w; j++) {
01882                                                 if (m_downsample) {
01883                                                         // image was downsampled
01884                                                         uAvg = u[sampledPos];
01885                                                         vAvg = v[sampledPos];
01886                                                 } else {
01887                                                         uAvg = u[yPos];
01888                                                         vAvg = v[yPos];
01889                                                 }
01890                                                 // Yuv
01891                                                 buff16[cnt + channelMap[1]] = g = Clamp16(y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
01892                                                 buff16[cnt + channelMap[2]] = Clamp16(uAvg + g);
01893                                                 buff16[cnt + channelMap[0]] = Clamp16(vAvg + g);
01894                                                 yPos++; 
01895                                                 cnt += channels;
01896                                                 if (j%2) sampledPos++;
01897                                         }
01898                                         buff16 += pitch16;
01899                                         if (wOdd) sampledPos++;
01900 
01901                                         if (cb) {
01902                                                 percent += dP;
01903                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01904                                         }
01905                                 }
01906                         } else {
01907                                 ASSERT(bpp%8 == 0);
01908                                 channels = bpp/8; 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                                                 buff[cnt + channelMap[1]] = UINT8(g >> shift); 
01925                                                 buff[cnt + channelMap[2]] = UINT8(Clamp16(uAvg + g) >> shift);
01926                                                 buff[cnt + channelMap[0]] = UINT8(Clamp16(vAvg + g) >> shift);
01927                                                 yPos++; 
01928                                                 cnt += channels;
01929                                                 if (j%2) sampledPos++;
01930                                         }
01931                                         buff += pitch;
01932                                         if (wOdd) sampledPos++;
01933 
01934                                         if (cb) {
01935                                                 percent += dP;
01936                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01937                                         }
01938                                 }
01939                         }
01940                         break;
01941                 }
01942         case ImageModeLabColor:
01943                 {
01944                         ASSERT(m_header.channels == 3);
01945                         ASSERT(m_header.bpp == m_header.channels*8);
01946                         ASSERT(bpp%8 == 0);
01947 
01948                         DataT* l = m_channel[0]; ASSERT(l);
01949                         DataT* a = m_channel[1]; ASSERT(a);
01950                         DataT* b = m_channel[2]; ASSERT(b);
01951                         int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
01952 
01953                         for (i=0; i < h; i++) {
01954                                 if (i%2) sampledPos -= (w + 1)/2;
01955                                 cnt = 0;
01956                                 for (j=0; j < w; j++) {
01957                                         if (m_downsample) {
01958                                                 // image was downsampled
01959                                                 uAvg = a[sampledPos];
01960                                                 vAvg = b[sampledPos];
01961                                         } else {
01962                                                 uAvg = a[yPos];
01963                                                 vAvg = b[yPos];
01964                                         }
01965                                         buff[cnt + channelMap[0]] = Clamp(l[yPos] + YUVoffset8);
01966                                         buff[cnt + channelMap[1]] = Clamp(uAvg + YUVoffset8); 
01967                                         buff[cnt + channelMap[2]] = Clamp(vAvg + YUVoffset8);
01968                                         cnt += channels;
01969                                         yPos++;
01970                                         if (j%2) sampledPos++;
01971                                 }
01972                                 buff += pitch;
01973                                 if (wOdd) sampledPos++;
01974 
01975                                 if (cb) {
01976                                         percent += dP;
01977                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
01978                                 }
01979                         }
01980                         break;
01981                 }
01982         case ImageModeLab48:
01983                 {
01984                         ASSERT(m_header.channels == 3);
01985                         ASSERT(m_header.bpp == m_header.channels*16);
01986 
01987                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
01988                         const int shift = UsedBitsPerChannel() - 8;
01989 
01990                         DataT* l = m_channel[0]; ASSERT(l);
01991                         DataT* a = m_channel[1]; ASSERT(a);
01992                         DataT* b = m_channel[2]; ASSERT(b);
01993                         int cnt, channels;
01994 
01995                         if (bpp%16 == 0) {
01996                                 UINT16 *buff16 = (UINT16 *)buff;
01997                                 int pitch16 = pitch/2;
01998                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
01999 
02000                                 for (i=0; i < h; i++) {
02001                                         if (i%2) sampledPos -= (w + 1)/2;
02002                                         cnt = 0;
02003                                         for (j=0; j < w; j++) {
02004                                                 if (m_downsample) {
02005                                                         // image was downsampled
02006                                                         uAvg = a[sampledPos];
02007                                                         vAvg = b[sampledPos];
02008                                                 } else {
02009                                                         uAvg = a[yPos];
02010                                                         vAvg = b[yPos];
02011                                                 }
02012                                                 buff16[cnt + channelMap[0]] = Clamp16(l[yPos] + yuvOffset16);
02013                                                 buff16[cnt + channelMap[1]] = Clamp16(uAvg + yuvOffset16);
02014                                                 buff16[cnt + channelMap[2]] = Clamp16(vAvg + yuvOffset16);
02015                                                 cnt += channels;
02016                                                 yPos++;
02017                                                 if (j%2) sampledPos++;
02018                                         }
02019                                         buff16 += pitch16;
02020                                         if (wOdd) sampledPos++;
02021 
02022                                         if (cb) {
02023                                                 percent += dP;
02024                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02025                                         }
02026                                 }
02027                         } else {
02028                                 ASSERT(bpp%8 == 0);
02029                                 channels = bpp/8; ASSERT(channels >= m_header.channels);
02030 
02031                                 for (i=0; i < h; i++) {
02032                                         if (i%2) sampledPos -= (w + 1)/2;
02033                                         cnt = 0;
02034                                         for (j=0; j < w; j++) {
02035                                                 if (m_downsample) {
02036                                                         // image was downsampled
02037                                                         uAvg = a[sampledPos];
02038                                                         vAvg = b[sampledPos];
02039                                                 } else {
02040                                                         uAvg = a[yPos];
02041                                                         vAvg = b[yPos];
02042                                                 }
02043                                                 buff[cnt + channelMap[0]] = UINT8(Clamp16(l[yPos] + yuvOffset16) >> shift);
02044                                                 buff[cnt + channelMap[1]] = UINT8(Clamp16(uAvg + yuvOffset16) >> shift);
02045                                                 buff[cnt + channelMap[2]] = UINT8(Clamp16(vAvg + yuvOffset16) >> shift);
02046                                                 cnt += channels;
02047                                                 yPos++;
02048                                                 if (j%2) sampledPos++;
02049                                         }
02050                                         buff += pitch;
02051                                         if (wOdd) sampledPos++;
02052 
02053                                         if (cb) {
02054                                                 percent += dP;
02055                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02056                                         }
02057                                 }
02058                         }
02059                         break;
02060                 }
02061         case ImageModeRGBA:
02062         case ImageModeCMYKColor:
02063                 {
02064                         ASSERT(m_header.channels == 4);
02065                         ASSERT(m_header.bpp == m_header.channels*8);
02066                         ASSERT(bpp%8 == 0);
02067 
02068                         DataT* y = m_channel[0]; ASSERT(y);
02069                         DataT* u = m_channel[1]; ASSERT(u);
02070                         DataT* v = m_channel[2]; ASSERT(v);
02071                         DataT* a = m_channel[3]; ASSERT(a);
02072                         UINT8 g, aAvg;
02073                         int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
02074 
02075                         for (i=0; i < h; i++) {
02076                                 if (i%2) sampledPos -= (w + 1)/2;
02077                                 cnt = 0;
02078                                 for (j=0; j < w; j++) {
02079                                         if (m_downsample) {
02080                                                 // image was downsampled
02081                                                 uAvg = u[sampledPos];
02082                                                 vAvg = v[sampledPos];
02083                                                 aAvg = Clamp(a[sampledPos] + YUVoffset8);
02084                                         } else {
02085                                                 uAvg = u[yPos];
02086                                                 vAvg = v[yPos];
02087                                                 aAvg = Clamp(a[yPos] + YUVoffset8);
02088                                         }
02089                                         // Yuv
02090                                         buff[cnt + channelMap[1]] = g = Clamp(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
02091                                         buff[cnt + channelMap[2]] = Clamp(uAvg + g);
02092                                         buff[cnt + channelMap[0]] = Clamp(vAvg + g);
02093                                         buff[cnt + channelMap[3]] = aAvg;
02094                                         yPos++; 
02095                                         cnt += channels;
02096                                         if (j%2) sampledPos++;
02097                                 }
02098                                 buff += pitch;
02099                                 if (wOdd) sampledPos++;
02100 
02101                                 if (cb) {
02102                                         percent += dP;
02103                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02104                                 }
02105                         }
02106                         break;
02107                 }
02108         case ImageModeCMYK64: 
02109                 {
02110                         ASSERT(m_header.channels == 4);
02111                         ASSERT(m_header.bpp == 64);
02112 
02113                         const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
02114                         const int shift = UsedBitsPerChannel() - 8;
02115 
02116                         DataT* y = m_channel[0]; ASSERT(y);
02117                         DataT* u = m_channel[1]; ASSERT(u);
02118                         DataT* v = m_channel[2]; ASSERT(v);
02119                         DataT* a = m_channel[3]; ASSERT(a);
02120                         UINT16 g, aAvg;
02121                         int cnt, channels;
02122 
02123                         if (bpp%16 == 0) {
02124                                 UINT16 *buff16 = (UINT16 *)buff;
02125                                 int pitch16 = pitch/2;
02126                                 channels = bpp/16; ASSERT(channels >= m_header.channels);
02127 
02128                                 for (i=0; i < h; i++) {
02129                                         if (i%2) sampledPos -= (w + 1)/2;
02130                                         cnt = 0;
02131                                         for (j=0; j < w; j++) {
02132                                                 if (m_downsample) {
02133                                                         // image was downsampled
02134                                                         uAvg = u[sampledPos];
02135                                                         vAvg = v[sampledPos];
02136                                                         aAvg = Clamp16(a[sampledPos] + yuvOffset16);
02137                                                 } else {
02138                                                         uAvg = u[yPos];
02139                                                         vAvg = v[yPos];
02140                                                         aAvg = Clamp16(a[yPos] + yuvOffset16);
02141                                                 }
02142                                                 // Yuv
02143                                                 buff16[cnt + channelMap[1]] = g = Clamp16(y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
02144                                                 buff16[cnt + channelMap[2]] = Clamp16(uAvg + g);
02145                                                 buff16[cnt + channelMap[0]] = Clamp16(vAvg + g);
02146                                                 buff16[cnt + channelMap[3]] = aAvg;
02147                                                 yPos++; 
02148                                                 cnt += channels;
02149                                                 if (j%2) sampledPos++;
02150                                         }
02151                                         buff16 += pitch16;
02152                                         if (wOdd) sampledPos++;
02153 
02154                                         if (cb) {
02155                                                 percent += dP;
02156                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02157                                         }
02158                                 }
02159                         } else {
02160                                 ASSERT(bpp%8 == 0);
02161                                 channels = bpp/8; 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                                                 buff[cnt + channelMap[1]] = UINT8(g >> shift); 
02180                                                 buff[cnt + channelMap[2]] = UINT8(Clamp16(uAvg + g) >> shift);
02181                                                 buff[cnt + channelMap[0]] = UINT8(Clamp16(vAvg + g) >> shift);
02182                                                 buff[cnt + channelMap[3]] = UINT8(aAvg >> shift);
02183                                                 yPos++; 
02184                                                 cnt += channels;
02185                                                 if (j%2) sampledPos++;
02186                                         }
02187                                         buff += pitch;
02188                                         if (wOdd) sampledPos++;
02189 
02190                                         if (cb) {
02191                                                 percent += dP;
02192                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02193                                         }
02194                                 }
02195                         }
02196                         break;
02197                 }
02198 #ifdef __PGF32SUPPORT__
02199         case ImageModeGray31:
02200                 {
02201                         ASSERT(m_header.channels == 1);
02202                         ASSERT(m_header.bpp == 32);
02203 
02204                         const int yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
02205                         const int shift = UsedBitsPerChannel() - 8;
02206 
02207                         DataT* y = m_channel[0]; ASSERT(y);
02208 
02209                         if (bpp == 32) {
02210                                 UINT32 *buff32 = (UINT32 *)buff;
02211                                 int pitch32 = pitch/4;
02212 
02213                                 for (i=0; i < h; i++) {
02214                                         for (j=0; j < w; j++) {
02215                                                 buff32[j] = Clamp31(y[yPos++] + yuvOffset31);
02216                                         }
02217                                         buff32 += pitch32;
02218 
02219                                         if (cb) {
02220                                                 percent += dP;
02221                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02222                                         }
02223                                 }
02224                         } else {
02225                                 ASSERT(bpp == 8);
02226                                 
02227                                 for (i=0; i < h; i++) {
02228                                         for (j=0; j < w; j++) {
02229                                                 buff[j] = UINT8(Clamp31(y[yPos++] + yuvOffset31) >> shift);
02230                                         }
02231                                         buff += pitch;
02232 
02233                                         if (cb) {
02234                                                 percent += dP;
02235                                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02236                                         }
02237                                 }
02238                         }
02239                         break;  
02240                 }
02241 #endif
02242         case ImageModeRGB12: 
02243                 {
02244                         ASSERT(m_header.channels == 3);
02245                         ASSERT(m_header.bpp == m_header.channels*4);
02246                         ASSERT(bpp == m_header.channels*4);
02247                         ASSERT(!m_downsample);
02248 
02249                         DataT* y = m_channel[0]; ASSERT(y);
02250                         DataT* u = m_channel[1]; ASSERT(u);
02251                         DataT* v = m_channel[2]; ASSERT(v);
02252                         UINT16 yval;
02253                         int cnt;
02254 
02255                         for (i=0; i < h; i++) {
02256                                 cnt = 0;
02257                                 for (j=0; j < w; j++) {
02258                                         // Yuv
02259                                         uAvg = u[yPos];
02260                                         vAvg = v[yPos];
02261                                         yval = Clamp4(y[yPos++] + YUVoffset4 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
02262                                         if (j%2 == 0) {
02263                                                 buff[cnt] = UINT8(Clamp4(vAvg + yval) | (yval << 4));
02264                                                 cnt++;
02265                                                 buff[cnt] = Clamp4(uAvg + yval);
02266                                         } else {
02267                                                 buff[cnt] |= Clamp4(vAvg + yval) << 4;
02268                                                 cnt++;
02269                                                 buff[cnt] = UINT8(yval | (Clamp4(uAvg + yval) << 4));
02270                                                 cnt++;
02271                                         }
02272                                 }
02273                                 buff += pitch;
02274 
02275                                 if (cb) {
02276                                         percent += dP;
02277                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02278                                 }
02279                         }
02280                         break;
02281                 }
02282         case ImageModeRGB16: 
02283                 {
02284                         ASSERT(m_header.channels == 3);
02285                         ASSERT(m_header.bpp == 16);
02286                         ASSERT(bpp == 16);
02287                         ASSERT(!m_downsample);
02288 
02289                         DataT* y = m_channel[0]; ASSERT(y);
02290                         DataT* u = m_channel[1]; ASSERT(u);
02291                         DataT* v = m_channel[2]; ASSERT(v);
02292                         UINT16 yval;
02293                         UINT16 *buff16 = (UINT16 *)buff;
02294                         int pitch16 = pitch/2;
02295 
02296                         for (i=0; i < h; i++) {
02297                                 for (j=0; j < w; j++) {
02298                                         // Yuv
02299                                         uAvg = u[yPos];
02300                                         vAvg = v[yPos];
02301                                         yval = Clamp6(y[yPos++] + YUVoffset6 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
02302                                         buff16[j] = (yval << 5) | ((Clamp6(uAvg + yval) >> 1) << 11) | (Clamp6(vAvg + yval) >> 1);
02303                                 }
02304                                 buff16 += pitch16;
02305 
02306                                 if (cb) {
02307                                         percent += dP;
02308                                         if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02309                                 }
02310                         }
02311                         break;
02312                 }
02313         default:
02314                 ASSERT(false);
02315         }
02316 
02317 #ifdef __PGFROISUPPORT__
02318         if (targetBuff) {
02319                 // copy valid ROI (m_roi) from temporary buffer (roi) to target buffer
02320                 if (bpp%8 == 0) {
02321                         BYTE bypp = bpp/8;
02322                         buff = buffStart + (levelRoi.top - roi.top)*pitch + (levelRoi.left - roi.left)*bypp;
02323                         w = levelRoi.Width()*bypp;
02324                         h = levelRoi.Height();
02325 
02326                         for (i=0; i < h; i++) {
02327                                 for (j=0; j < w; j++) {
02328                                         targetBuff[j] = buff[j];
02329                                 }
02330                                 targetBuff += targetPitch;
02331                                 buff += pitch;
02332                         }
02333                 } else {
02334                         // to do
02335                 }
02336 
02337                 delete[] buffStart;
02338         }
02339 #endif
02340 }                       
02341 
02356 void CPGFImage::GetYUV(int pitch, DataT* buff, BYTE bpp, int channelMap[] /*= NULL*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) const THROW_ {
02357         ASSERT(buff);
02358         const UINT32 w = m_width[0];
02359         const UINT32 h = m_height[0];
02360         const bool wOdd = (1 == w%2);
02361         const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
02362         const int pitch2 = pitch/DataTSize;
02363         const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
02364         const double dP = 1.0/h;
02365 
02366         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
02367         if (channelMap == NULL) channelMap = defMap;
02368         int sampledPos = 0, yPos = 0;
02369         DataT uAvg, vAvg;
02370         double percent = 0;
02371         UINT32 i, j;
02372 
02373         if (m_header.channels == 3) { 
02374                 ASSERT(bpp%dataBits == 0);
02375 
02376                 DataT* y = m_channel[0]; ASSERT(y);
02377                 DataT* u = m_channel[1]; ASSERT(u);
02378                 DataT* v = m_channel[2]; ASSERT(v);
02379                 int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
02380 
02381                 for (i=0; i < h; i++) {
02382                         if (i%2) sampledPos -= (w + 1)/2;
02383                         cnt = 0;
02384                         for (j=0; j < w; j++) {
02385                                 if (m_downsample) {
02386                                         // image was downsampled
02387                                         uAvg = u[sampledPos];
02388                                         vAvg = v[sampledPos];
02389                                 } else {
02390                                         uAvg = u[yPos];
02391                                         vAvg = v[yPos];
02392                                 }
02393                                 buff[cnt + channelMap[0]] = y[yPos];
02394                                 buff[cnt + channelMap[1]] = uAvg;
02395                                 buff[cnt + channelMap[2]] = vAvg;
02396                                 yPos++; 
02397                                 cnt += channels;
02398                                 if (j%2) sampledPos++;
02399                         }
02400                         buff += pitch2;
02401                         if (wOdd) sampledPos++;
02402 
02403                         if (cb) {
02404                                 percent += dP;
02405                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02406                         }
02407                 }
02408         } else if (m_header.channels == 4) {
02409                 ASSERT(m_header.bpp == m_header.channels*8);
02410                 ASSERT(bpp%dataBits == 0);
02411 
02412                 DataT* y = m_channel[0]; ASSERT(y);
02413                 DataT* u = m_channel[1]; ASSERT(u);
02414                 DataT* v = m_channel[2]; ASSERT(v);
02415                 DataT* a = m_channel[3]; ASSERT(a);
02416                 UINT8 aAvg;
02417                 int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
02418 
02419                 for (i=0; i < h; i++) {
02420                         if (i%2) sampledPos -= (w + 1)/2;
02421                         cnt = 0;
02422                         for (j=0; j < w; j++) {
02423                                 if (m_downsample) {
02424                                         // image was downsampled
02425                                         uAvg = u[sampledPos];
02426                                         vAvg = v[sampledPos];
02427                                         aAvg = Clamp(a[sampledPos] + yuvOffset);
02428                                 } else {
02429                                         uAvg = u[yPos];
02430                                         vAvg = v[yPos];
02431                                         aAvg = Clamp(a[yPos] + yuvOffset);
02432                                 }
02433                                 // Yuv
02434                                 buff[cnt + channelMap[0]] = y[yPos];
02435                                 buff[cnt + channelMap[1]] = uAvg;
02436                                 buff[cnt + channelMap[2]] = vAvg;
02437                                 buff[cnt + channelMap[3]] = aAvg;
02438                                 yPos++; 
02439                                 cnt += channels;
02440                                 if (j%2) sampledPos++;
02441                         }
02442                         buff += pitch2;
02443                         if (wOdd) sampledPos++;
02444 
02445                         if (cb) {
02446                                 percent += dP;
02447                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02448                         }
02449                 }
02450         }
02451 }
02452 
02467 void CPGFImage::ImportYUV(int pitch, DataT *buff, BYTE bpp, int channelMap[] /*= NULL*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
02468         ASSERT(buff);
02469         const double dP = 1.0/m_header.height;
02470         const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
02471         const int pitch2 = pitch/DataTSize;
02472         const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
02473 
02474         int yPos = 0, cnt = 0;
02475         double percent = 0;
02476         int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
02477 
02478         if (channelMap == NULL) channelMap = defMap;
02479 
02480         if (m_header.channels == 3)     {
02481                 ASSERT(bpp%dataBits == 0);
02482 
02483                 DataT* y = m_channel[0]; ASSERT(y);
02484                 DataT* u = m_channel[1]; ASSERT(u);
02485                 DataT* v = m_channel[2]; ASSERT(v);
02486                 const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
02487 
02488                 for (UINT32 h=0; h < m_header.height; h++) {
02489                         if (cb) {
02490                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02491                                 percent += dP;
02492                         }
02493 
02494                         cnt = 0;
02495                         for (UINT32 w=0; w < m_header.width; w++) {
02496                                 y[yPos] = buff[cnt + channelMap[0]];
02497                                 u[yPos] = buff[cnt + channelMap[1]];
02498                                 v[yPos] = buff[cnt + channelMap[2]];
02499                                 yPos++;
02500                                 cnt += channels;
02501                         }
02502                         buff += pitch2;
02503                 }       
02504         } else if (m_header.channels == 4) {
02505                 ASSERT(bpp%dataBits == 0);
02506 
02507                 DataT* y = m_channel[0]; ASSERT(y);
02508                 DataT* u = m_channel[1]; ASSERT(u);
02509                 DataT* v = m_channel[2]; ASSERT(v);
02510                 DataT* a = m_channel[3]; ASSERT(a);
02511                 const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
02512 
02513                 for (UINT32 h=0; h < m_header.height; h++) {
02514                         if (cb) {
02515                                 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
02516                                 percent += dP;
02517                         }
02518 
02519                         cnt = 0;
02520                         for (UINT32 w=0; w < m_header.width; w++) {
02521                                 y[yPos] = buff[cnt + channelMap[0]];
02522                                 u[yPos] = buff[cnt + channelMap[1]];
02523                                 v[yPos] = buff[cnt + channelMap[2]];
02524                                 a[yPos] = buff[cnt + channelMap[3]] - yuvOffset;
02525                                 yPos++;
02526                                 cnt += channels;
02527                         }
02528                         buff += pitch2;
02529                 }       
02530         }
02531 
02532         if (m_downsample) {
02533                 // Subsampling of the chrominance and alpha channels
02534                 for (int i=1; i < m_header.channels; i++) {
02535                         Downsample(i);
02536                 }
02537         }
02538 }
02539 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines