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