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