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