libpgf 6.14.12
PGF - Progressive Graphics File
PGFimage.cpp
Go to the documentation of this file.
1/*
2 * The Progressive Graphics File; http://www.libpgf.org
3 *
4 * $Date: 2007-02-03 13:04:21 +0100 (Sa, 03 Feb 2007) $
5 * $Revision: 280 $
6 *
7 * This file Copyright (C) 2006 xeraina GmbH, Switzerland
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
28
29#include "PGFimage.h"
30#include "Decoder.h"
31#include "Encoder.h"
32#include <cmath>
33#include <cstring>
34
35#define YUVoffset4 8 // 2^3
36#define YUVoffset6 32 // 2^5
37#define YUVoffset8 128 // 2^7
38#define YUVoffset16 32768 // 2^15
39//#define YUVoffset31 1073741824 // 2^30
40
42// global methods and variables
43#ifdef NEXCEPTIONS
44 OSError _PGF_Error_;
45
46 OSError GetLastPGFError() {
47 OSError tmp = _PGF_Error_;
48 _PGF_Error_ = NoError;
49 return tmp;
50 }
51#endif
52
54// Standard constructor: It is used to create a PGF instance for opening and reading.
56: m_decoder(0)
57, m_encoder(0)
58, m_levelLength(0)
59, m_currentLevel(0)
60, m_quant(0)
61, m_userDataPos(0)
62, m_downsample(false)
63, m_favorSpeedOverSize(false)
64, m_useOMPinEncoder(true)
65, m_useOMPinDecoder(true)
66, m_skipUserData(false)
68, m_streamReinitialized(false)
69#endif
70, m_cb(0)
71, m_cbArg(0)
72, m_progressMode(PM_Relative)
73, m_percent(0)
74{
75
76 // init preHeader
77 memcpy(m_preHeader.magic, PGFMagic, 3);
80
81 // init postHeader
84
85 // init channels
86 for (int i=0; i < MaxChannels; i++) {
87 m_channel[i] = 0;
88 m_wtChannel[i] = 0;
89 }
90
91 // set image width and height
92 m_width[0] = 0;
93 m_height[0] = 0;
94}
95
97// Destructor: Destroy internal data structures.
99 Destroy();
100}
101
103// Destroy internal data structures.
104// Destructor calls this method during destruction.
106 Close();
107
108 for (int i=0; i < m_header.channels; i++) {
109 delete m_wtChannel[i]; m_wtChannel[i]=0; // also deletes m_channel
110 m_channel[i] = 0;
111 }
113 delete[] m_levelLength; m_levelLength = 0;
114 delete m_encoder; m_encoder = NULL;
115
116 m_userDataPos = 0;
117}
118
120// Close PGF image after opening and reading.
121// Destructor calls this method during destruction.
123 delete m_decoder; m_decoder = 0;
124}
125
127// Open a PGF image at current stream position: read pre-header, header, levelLength, and ckeck image type.
128// Precondition: The stream has been opened for reading.
129// It might throw an IOException.
130// @param stream A PGF stream
131void CPGFImage::Open(CPGFStream *stream) THROW_ {
132 ASSERT(stream);
133
134 // create decoder and read PGFPreHeader PGFHeader PGFPostHeader LevelLengths
135 m_decoder = new CDecoder(stream, m_preHeader, m_header, m_postHeader, m_levelLength,
136 m_userDataPos, m_useOMPinDecoder, m_skipUserData);
137
138 if (m_header.nLevels > MaxLevel) ReturnWithError(FormatCannotRead);
139
140 // set current level
141 m_currentLevel = m_header.nLevels;
142
143 // set image width and height
144 m_width[0] = m_header.width;
145 m_height[0] = m_header.height;
146
147 // complete header
148 if (!CompleteHeader()) ReturnWithError(FormatCannotRead);
149
150 // interpret quant parameter
151 if (m_header.quality > DownsampleThreshold &&
152 (m_header.mode == ImageModeRGBColor ||
153 m_header.mode == ImageModeRGBA ||
154 m_header.mode == ImageModeRGB48 ||
155 m_header.mode == ImageModeCMYKColor ||
156 m_header.mode == ImageModeCMYK64 ||
157 m_header.mode == ImageModeLabColor ||
158 m_header.mode == ImageModeLab48)) {
159 m_downsample = true;
160 m_quant = m_header.quality - 1;
161 } else {
162 m_downsample = false;
163 m_quant = m_header.quality;
164 }
165
166 // set channel dimensions (chrominance is subsampled by factor 2)
167 if (m_downsample) {
168 for (int i=1; i < m_header.channels; i++) {
169 m_width[i] = (m_width[0] + 1)/2;
170 m_height[i] = (m_height[0] + 1)/2;
171 }
172 } else {
173 for (int i=1; i < m_header.channels; i++) {
174 m_width[i] = m_width[0];
175 m_height[i] = m_height[0];
176 }
177 }
178
179 if (m_header.nLevels > 0) {
180 // init wavelet subbands
181 for (int i=0; i < m_header.channels; i++) {
182 m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels);
183 }
184
185 // used in Read when PM_Absolute
186 m_percent = pow(0.25, m_header.nLevels);
187
188 } else {
189 // very small image: we don't use DWT and encoding
190
191 // read channels
192 for (int c=0; c < m_header.channels; c++) {
193 const UINT32 size = m_width[c]*m_height[c];
194 m_channel[c] = new(std::nothrow) DataT[size];
195 if (!m_channel[c]) ReturnWithError(InsufficientMemory);
196
197 // read channel data from stream
198 for (UINT32 i=0; i < size; i++) {
199 int count = DataTSize;
200 stream->Read(&count, &m_channel[c][i]);
201 if (count != DataTSize) ReturnWithError(MissingData);
202 }
203 }
204 }
205}
206
210 // undefined mode
211 switch(m_header.bpp) {
212 case 1: m_header.mode = ImageModeBitmap; break;
213 case 8: m_header.mode = ImageModeGrayScale; break;
214 case 12: m_header.mode = ImageModeRGB12; break;
215 case 16: m_header.mode = ImageModeRGB16; break;
216 case 24: m_header.mode = ImageModeRGBColor; break;
217 case 32: m_header.mode = ImageModeRGBA; break;
218 case 48: m_header.mode = ImageModeRGB48; break;
219 default: m_header.mode = ImageModeRGBColor; break;
220 }
221 }
222 if (!m_header.bpp) {
223 // undefined bpp
224 switch(m_header.mode) {
225 case ImageModeBitmap:
226 m_header.bpp = 1;
227 break;
230 m_header.bpp = 8;
231 break;
232 case ImageModeRGB12:
233 m_header.bpp = 12;
234 break;
235 case ImageModeRGB16:
236 case ImageModeGray16:
237 m_header.bpp = 16;
238 break;
241 m_header.bpp = 24;
242 break;
243 case ImageModeRGBA:
245 case ImageModeGray32:
246 m_header.bpp = 32;
247 break;
248 case ImageModeRGB48:
249 case ImageModeLab48:
250 m_header.bpp = 48;
251 break;
252 case ImageModeCMYK64:
253 m_header.bpp = 64;
254 break;
255 default:
256 ASSERT(false);
257 m_header.bpp = 24;
258 }
259 }
260 if (m_header.mode == ImageModeRGBColor && m_header.bpp == 32) {
261 // change mode
263 }
264
265 if (m_header.mode == ImageModeBitmap && m_header.bpp != 1) return false;
266 if (m_header.mode == ImageModeIndexedColor && m_header.bpp != 8) return false;
267 if (m_header.mode == ImageModeGrayScale && m_header.bpp != 8) return false;
268 if (m_header.mode == ImageModeGray16 && m_header.bpp != 16) return false;
269 if (m_header.mode == ImageModeGray32 && m_header.bpp != 32) return false;
270 if (m_header.mode == ImageModeRGBColor && m_header.bpp != 24) return false;
271 if (m_header.mode == ImageModeRGBA && m_header.bpp != 32) return false;
272 if (m_header.mode == ImageModeRGB12 && m_header.bpp != 12) return false;
273 if (m_header.mode == ImageModeRGB16 && m_header.bpp != 16) return false;
274 if (m_header.mode == ImageModeRGB48 && m_header.bpp != 48) return false;
275 if (m_header.mode == ImageModeLabColor && m_header.bpp != 24) return false;
276 if (m_header.mode == ImageModeLab48 && m_header.bpp != 48) return false;
277 if (m_header.mode == ImageModeCMYKColor && m_header.bpp != 32) return false;
278 if (m_header.mode == ImageModeCMYK64 && m_header.bpp != 64) return false;
279
280 // set number of channels
281 if (!m_header.channels) {
282 switch(m_header.mode) {
283 case ImageModeBitmap:
286 case ImageModeGray16:
287 case ImageModeGray32:
288 m_header.channels = 1;
289 break;
291 case ImageModeRGB12:
292 case ImageModeRGB16:
293 case ImageModeRGB48:
295 case ImageModeLab48:
296 m_header.channels = 3;
297 break;
298 case ImageModeRGBA:
300 case ImageModeCMYK64:
301 m_header.channels = 4;
302 break;
303 default:
304 return false;
305 }
306 }
307
308 // store used bits per channel
309 UINT8 bpc = m_header.bpp/m_header.channels;
310 if (bpc > 31) bpc = 31;
313 }
314
315 return true;
316}
317
323const UINT8* CPGFImage::GetUserData(UINT32& size) const {
325 return m_postHeader.userData;
326}
327
333void CPGFImage::Reconstruct(int level /*= 0*/) THROW_ {
334 if (m_header.nLevels == 0) {
335 // image didn't use wavelet transform
336 if (level == 0) {
337 for (int i=0; i < m_header.channels; i++) {
338 ASSERT(m_wtChannel[i]);
339 m_channel[i] = m_wtChannel[i]->GetSubband(0, LL)->GetBuffer();
340 }
341 }
342 } else {
343 int currentLevel = m_header.nLevels;
344
345 if (ROIisSupported()) {
346 // enable ROI reading
347 SetROI(PGFRect(0, 0, m_header.width, m_header.height));
348 }
349
350 while (currentLevel > level) {
351 for (int i=0; i < m_header.channels; i++) {
352 ASSERT(m_wtChannel[i]);
353 // dequantize subbands
354 if (currentLevel == m_header.nLevels) {
355 // last level also has LL band
356 m_wtChannel[i]->GetSubband(currentLevel, LL)->Dequantize(m_quant);
357 }
358 m_wtChannel[i]->GetSubband(currentLevel, HL)->Dequantize(m_quant);
359 m_wtChannel[i]->GetSubband(currentLevel, LH)->Dequantize(m_quant);
360 m_wtChannel[i]->GetSubband(currentLevel, HH)->Dequantize(m_quant);
361
362 // inverse transform from m_wtChannel to m_channel
363 OSError err = m_wtChannel[i]->InverseTransform(currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
364 if (err != NoError) ReturnWithError(err);
365 ASSERT(m_channel[i]);
366 }
367
368 currentLevel--;
369 }
370 }
371}
372
374// Read and decode some levels of a PGF image at current stream position.
375// A PGF image is structered in levels, numbered between 0 and Levels() - 1.
376// Each level can be seen as a single image, containing the same content
377// as all other levels, but in a different size (width, height).
378// The image size at level i is double the size (width, height) of the image at level i+1.
379// The image at level 0 contains the original size.
380// Precondition: The PGF image has been opened with a call of Open(...).
381// It might throw an IOException.
382// @param level The image level of the resulting image in the internal image buffer.
383// @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.
384// @param data Data Pointer to C++ class container to host callback procedure.
385void CPGFImage::Read(int level /*= 0*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
386 ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
387 ASSERT(m_decoder);
388
389#ifdef __PGFROISUPPORT__
390 if (ROIisSupported() && m_header.nLevels > 0) {
391 // new encoding scheme supporting ROI
392 PGFRect rect(0, 0, m_header.width, m_header.height);
393 Read(rect, level, cb, data);
394 return;
395 }
396#endif
397
398 if (m_header.nLevels == 0) {
399 if (level == 0) {
400 // the data has already been read during open
401 // now update progress
402 if (cb) {
403 if ((*cb)(1.0, true, data)) ReturnWithError(EscapePressed);
404 }
405 }
406 } else {
407 const int levelDiff = m_currentLevel - level;
408 double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
409
410 // encoding scheme without ROI
411 while (m_currentLevel > level) {
412 for (int i=0; i < m_header.channels; i++) {
413 ASSERT(m_wtChannel[i]);
414 // decode file and write stream to m_wtChannel
415 if (m_currentLevel == m_header.nLevels) {
416 // last level also has LL band
417 m_wtChannel[i]->GetSubband(m_currentLevel, LL)->PlaceTile(*m_decoder, m_quant);
418 }
419 if (m_preHeader.version & Version5) {
420 // since version 5
421 m_wtChannel[i]->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant);
422 m_wtChannel[i]->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant);
423 } else {
424 // until version 4
425 m_decoder->DecodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant);
426 }
427 m_wtChannel[i]->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant);
428 }
429
430 volatile OSError error = NoError; // volatile prevents optimizations
431#ifdef LIBPGF_USE_OPENMP
432 #pragma omp parallel for default(shared)
433#endif
434 for (int i=0; i < m_header.channels; i++) {
435 // inverse transform from m_wtChannel to m_channel
436 if (error == NoError) {
437 OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
438 if (err != NoError) error = err;
439 }
440 ASSERT(m_channel[i]);
441 }
442 if (error != NoError) ReturnWithError(error);
443
444 // set new level: must be done before refresh callback
445 m_currentLevel--;
446
447 // now we have to refresh the display
448 if (m_cb) m_cb(m_cbArg);
449
450 // now update progress
451 if (cb) {
452 percent *= 4;
453 if (m_progressMode == PM_Absolute) m_percent = percent;
454 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
455 }
456 }
457 }
458
459 // automatically closing
460 if (m_currentLevel == 0) Close();
461}
462
463#ifdef __PGFROISUPPORT__
473void CPGFImage::Read(PGFRect& rect, int level /*= 0*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
474 ASSERT((level >= 0 && level < m_header.nLevels) || m_header.nLevels == 0); // m_header.nLevels == 0: image didn't use wavelet transform
475 ASSERT(m_decoder);
476
477 if (m_header.nLevels == 0 || !ROIisSupported()) {
478 rect.left = rect.top = 0;
479 rect.right = m_header.width; rect.bottom = m_header.height;
480 Read(level, cb, data);
481 } else {
482 ASSERT(ROIisSupported());
483 // new encoding scheme supporting ROI
484 ASSERT(rect.left < m_header.width && rect.top < m_header.height);
485
486 const int levelDiff = m_currentLevel - level;
487 double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
488
489 // check level difference
490 if (levelDiff <= 0) {
491 // it is a new read call, probably with a new ROI
492 m_currentLevel = m_header.nLevels;
493 m_decoder->SetStreamPosToData();
494 }
495
496 // check rectangle
497 if (rect.right == 0 || rect.right > m_header.width) rect.right = m_header.width;
498 if (rect.bottom == 0 || rect.bottom > m_header.height) rect.bottom = m_header.height;
499
500 // enable ROI decoding and reading
501 SetROI(rect);
502
503 while (m_currentLevel > level) {
504 for (int i=0; i < m_header.channels; i++) {
505 ASSERT(m_wtChannel[i]);
506
507 // get number of tiles and tile indices
508 const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel);
509 const PGFRect& tileIndices = m_wtChannel[i]->GetTileIndices(m_currentLevel);
510
511 // decode file and write stream to m_wtChannel
512 if (m_currentLevel == m_header.nLevels) { // last level also has LL band
513 ASSERT(nTiles == 1);
514 m_decoder->DecodeTileBuffer();
515 m_wtChannel[i]->GetSubband(m_currentLevel, LL)->PlaceTile(*m_decoder, m_quant);
516 }
517 for (UINT32 tileY=0; tileY < nTiles; tileY++) {
518 for (UINT32 tileX=0; tileX < nTiles; tileX++) {
519 // check relevance of tile
520 if (tileIndices.IsInside(tileX, tileY)) {
521 m_decoder->DecodeTileBuffer();
522 m_wtChannel[i]->GetSubband(m_currentLevel, HL)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
523 m_wtChannel[i]->GetSubband(m_currentLevel, LH)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
524 m_wtChannel[i]->GetSubband(m_currentLevel, HH)->PlaceTile(*m_decoder, m_quant, true, tileX, tileY);
525 } else {
526 // skip tile
527 m_decoder->SkipTileBuffer();
528 }
529 }
530 }
531 }
532
533 volatile OSError error = NoError; // volatile prevents optimizations
534#ifdef LIBPGF_USE_OPENMP
535 #pragma omp parallel for default(shared)
536#endif
537 for (int i=0; i < m_header.channels; i++) {
538 // inverse transform from m_wtChannel to m_channel
539 if (error == NoError) {
540 OSError err = m_wtChannel[i]->InverseTransform(m_currentLevel, &m_width[i], &m_height[i], &m_channel[i]);
541 if (err != NoError) error = err;
542 }
543 ASSERT(m_channel[i]);
544 }
545 if (error != NoError) ReturnWithError(error);
546
547 // set new level: must be done before refresh callback
548 m_currentLevel--;
549
550 // now we have to refresh the display
551 if (m_cb) m_cb(m_cbArg);
552
553 // now update progress
554 if (cb) {
555 percent *= 4;
556 if (m_progressMode == PM_Absolute) m_percent = percent;
557 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
558 }
559 }
560 }
561
562 // automatically closing
563 if (m_currentLevel == 0) Close();
564}
565
569void CPGFImage::SetROI(PGFRect rect) {
570 ASSERT(m_decoder);
571 ASSERT(ROIisSupported());
572
573 // store ROI for a later call of GetBitmap
574 m_roi = rect;
575
576 // enable ROI decoding
577 m_decoder->SetROI();
578
579 // enlarge ROI because of border artefacts
580 const UINT32 dx = FilterWidth/2*(1 << m_currentLevel);
581 const UINT32 dy = FilterHeight/2*(1 << m_currentLevel);
582
583 if (rect.left < dx) rect.left = 0;
584 else rect.left -= dx;
585 if (rect.top < dy) rect.top = 0;
586 else rect.top -= dy;
587 rect.right += dx;
588 if (rect.right > m_header.width) rect.right = m_header.width;
589 rect.bottom += dy;
590 if (rect.bottom > m_header.height) rect.bottom = m_header.height;
591
592 // prepare wavelet channels for using ROI
593 ASSERT(m_wtChannel[0]);
594 m_wtChannel[0]->SetROI(rect);
595 if (m_downsample && m_header.channels > 1) {
596 // all further channels are downsampled, therefore downsample ROI
597 rect.left >>= 1;
598 rect.top >>= 1;
599 rect.right >>= 1;
600 rect.bottom >>= 1;
601 }
602 for (int i=1; i < m_header.channels; i++) {
603 ASSERT(m_wtChannel[i]);
604 m_wtChannel[i]->SetROI(rect);
605 }
606}
607
608#endif // __PGFROISUPPORT__
609
615 ASSERT(m_decoder);
617}
618
626UINT32 CPGFImage::ReadEncodedHeader(UINT8* target, UINT32 targetLen) const THROW_ {
627 ASSERT(target);
628 ASSERT(targetLen > 0);
629 ASSERT(m_decoder);
630
631 // reset stream position
632 m_decoder->SetStreamPosToStart();
633
634 // compute number of bytes to read
635 UINT32 len = __min(targetLen, GetEncodedHeaderLength());
636
637 // read data
638 len = m_decoder->ReadEncodedData(target, len);
639 ASSERT(len >= 0 && len <= targetLen);
640
641 return len;
642}
643
647 ASSERT(m_decoder);
649}
650
660UINT32 CPGFImage::ReadEncodedData(int level, UINT8* target, UINT32 targetLen) const THROW_ {
661 ASSERT(level >= 0 && level < m_header.nLevels);
662 ASSERT(target);
663 ASSERT(targetLen > 0);
664 ASSERT(m_decoder);
665
666 // reset stream position
667 m_decoder->SetStreamPosToData();
668
669 // position stream
670 UINT64 offset = 0;
671
672 for (int i=m_header.nLevels - 1; i > level; i--) {
673 offset += m_levelLength[m_header.nLevels - 1 - i];
674 }
675 m_decoder->Skip(offset);
676
677 // compute number of bytes to read
678 UINT32 len = __min(targetLen, GetEncodedLevelLength(level));
679
680 // read data
681 len = m_decoder->ReadEncodedData(target, len);
682 ASSERT(len >= 0 && len <= targetLen);
683
684 return len;
685}
686
691void CPGFImage::SetMaxValue(UINT32 maxValue) {
692 const BYTE bpc = m_header.bpp/m_header.channels;
693 BYTE pot = 0;
694
695 while(maxValue > 0) {
696 pot++;
697 maxValue >>= 1;
698 }
699 // store bits per channel
700 if (pot > bpc) pot = bpc;
701 if (pot > 31) pot = 31;
703}
704
710 const BYTE bpc = m_header.bpp/m_header.channels;
711
712 if (bpc > 8) {
714 } else {
715 return bpc;
716 }
717}
718
721BYTE CPGFImage::CurrentVersion(BYTE version) {
722 if (version & Version6) return 6;
723 if (version & Version5) return 5;
724 if (version & Version2) return 2;
725 return 1;
726}
727
729// Import an image from a specified image buffer.
730// This method is usually called before Write(...) and after SetHeader(...).
731// It might throw an IOException.
732// The absolute value of pitch is the number of bytes of an image row.
733// If pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row).
734// If pitch is positive, then buff points to the first row of a top-down image (first byte).
735// 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
736// provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
737// If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
738// @param pitch The number of bytes of a row of the image buffer.
739// @param buff An image buffer.
740// @param bpp The number of bits per pixel used in image buffer.
741// @param channelMap A integer array containing the mapping of input channel ordering to expected channel ordering.
742// @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.
743// @param data Data Pointer to C++ class container to host callback procedure.
744void CPGFImage::ImportBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[] /*= NULL */, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
745 ASSERT(buff);
746 ASSERT(m_channel[0]);
747
748 // color transform
749 RgbToYuv(pitch, buff, bpp, channelMap, cb, data);
750
751 if (m_downsample) {
752 // Subsampling of the chrominance and alpha channels
753 for (int i=1; i < m_header.channels; i++) {
754 Downsample(i);
755 }
756 }
757}
758
760// Bilinerar Subsampling of channel ch by a factor 2
762 ASSERT(ch > 0);
763
764 const int w = m_width[0];
765 const int w2 = w/2;
766 const int h2 = m_height[0]/2;
767 const int oddW = w%2; // don't use bool -> problems with MaxSpeed optimization
768 const int oddH = m_height[0]%2; // "
769 int loPos = 0;
770 int hiPos = w;
771 int sampledPos = 0;
772 DataT* buff = m_channel[ch]; ASSERT(buff);
773
774 for (int i=0; i < h2; i++) {
775 for (int j=0; j < w2; j++) {
776 // compute average of pixel block
777 buff[sampledPos] = (buff[loPos] + buff[loPos + 1] + buff[hiPos] + buff[hiPos + 1]) >> 2;
778 loPos += 2; hiPos += 2;
779 sampledPos++;
780 }
781 if (oddW) {
782 buff[sampledPos] = (buff[loPos] + buff[hiPos]) >> 1;
783 loPos++; hiPos++;
784 sampledPos++;
785 }
786 loPos += w; hiPos += w;
787 }
788 if (oddH) {
789 for (int j=0; j < w2; j++) {
790 buff[sampledPos] = (buff[loPos] + buff[loPos+1]) >> 1;
791 loPos += 2; hiPos += 2;
792 sampledPos++;
793 }
794 if (oddW) {
795 buff[sampledPos] = buff[loPos];
796 }
797 }
798
799 // downsampled image has half width and half height
800 m_width[ch] = (m_width[ch] + 1)/2;
801 m_height[ch] = (m_height[ch] + 1)/2;
802}
803
806 const int maxThumbnailWidth = 20*FilterWidth;
807 const int m = __min(m_header.width, m_header.height);
808 int s = m;
809
811 m_header.nLevels = 1;
812 // compute a good value depending on the size of the image
813 while (s > maxThumbnailWidth) {
815 s = s/2;
816 }
817 }
818
819 int levels = m_header.nLevels; // we need a signed value during level reduction
820
821 // reduce number of levels if the image size is smaller than FilterWidth*2^levels
822 s = FilterWidth*(1 << levels); // must be at least the double filter size because of subsampling
823 while (m < s) {
824 levels--;
825 s = s/2;
826 }
827 if (levels > MaxLevel) m_header.nLevels = MaxLevel;
828 else if (levels < 0) m_header.nLevels = 0;
829 else m_header.nLevels = (UINT8)levels;
830
831 // used in Write when PM_Absolute
832 m_percent = pow(0.25, m_header.nLevels);
833
834 ASSERT(0 <= m_header.nLevels && m_header.nLevels <= MaxLevel);
835}
836
845void CPGFImage::SetHeader(const PGFHeader& header, BYTE flags /*=0*/, UINT8* userData /*= 0*/, UINT32 userDataLength /*= 0*/) THROW_ {
846 ASSERT(!m_decoder); // current image must be closed
847 ASSERT(header.quality <= MaxQuality);
848
849 // init state
850#ifdef __PGFROISUPPORT__
851 m_streamReinitialized = false;
852#endif
853
854 // init preHeader
855 memcpy(m_preHeader.magic, PGFMagic, 3);
856 m_preHeader.version = PGFVersion | flags;
857 m_preHeader.hSize = HeaderSize;
858
859 // copy header
860 memcpy(&m_header, &header, HeaderSize);
861
862 // complete header
863 CompleteHeader();
864
865 // check and set number of levels
866 ComputeLevels();
867
868 // check for downsample
869 if (m_header.quality > DownsampleThreshold && (m_header.mode == ImageModeRGBColor ||
870 m_header.mode == ImageModeRGBA ||
871 m_header.mode == ImageModeRGB48 ||
872 m_header.mode == ImageModeCMYKColor ||
873 m_header.mode == ImageModeCMYK64 ||
874 m_header.mode == ImageModeLabColor ||
875 m_header.mode == ImageModeLab48)) {
876 m_downsample = true;
877 m_quant = m_header.quality - 1;
878 } else {
879 m_downsample = false;
880 m_quant = m_header.quality;
881 }
882
883 // update header size and copy user data
884 if (m_header.mode == ImageModeIndexedColor) {
885 // update header size
886 m_preHeader.hSize += ColorTableSize;
887 }
888 if (userDataLength && userData) {
889 m_postHeader.userData = new(std::nothrow) UINT8[userDataLength];
890 if (!m_postHeader.userData) ReturnWithError(InsufficientMemory);
891 m_postHeader.userDataLen = userDataLength;
892 memcpy(m_postHeader.userData, userData, userDataLength);
893 // update header size
894 m_preHeader.hSize += userDataLength;
895 }
896
897 // allocate channels
898 for (int i=0; i < m_header.channels; i++) {
899 // set current width and height
900 m_width[i] = m_header.width;
901 m_height[i] = m_header.height;
902
903 // allocate channels
904 ASSERT(!m_channel[i]);
905 m_channel[i] = new(std::nothrow) DataT[m_header.width*m_header.height];
906 if (!m_channel[i]) {
907 if (i) i--;
908 while(i) {
909 delete[] m_channel[i]; m_channel[i] = 0;
910 i--;
911 }
912 ReturnWithError(InsufficientMemory);
913 }
914 }
915}
916
924UINT32 CPGFImage::WriteHeader(CPGFStream* stream) THROW_ {
925 ASSERT(m_header.nLevels <= MaxLevel);
926 ASSERT(m_header.quality <= MaxQuality); // quality is already initialized
927
928 if (m_header.nLevels > 0) {
929 volatile OSError error = NoError; // volatile prevents optimizations
930 // create new wt channels
931#ifdef LIBPGF_USE_OPENMP
932 #pragma omp parallel for default(shared)
933#endif
934 for (int i=0; i < m_header.channels; i++) {
935 DataT *temp = NULL;
936 if (error == NoError) {
937 if (m_wtChannel[i]) {
938 ASSERT(m_channel[i]);
939 // copy m_channel to temp
940 int size = m_height[i]*m_width[i];
941 temp = new(std::nothrow) DataT[size];
942 if (temp) {
943 memcpy(temp, m_channel[i], size*DataTSize);
944 delete m_wtChannel[i]; // also deletes m_channel
945 m_channel[i] = NULL;
946 } else {
947 error = InsufficientMemory;
948 }
949 }
950 if (error == NoError) {
951 if (temp) {
952 ASSERT(!m_channel[i]);
953 m_channel[i] = temp;
954 }
955 m_wtChannel[i] = new CWaveletTransform(m_width[i], m_height[i], m_header.nLevels, m_channel[i]);
956 if (m_wtChannel[i]) {
957 #ifdef __PGFROISUPPORT__
958 m_wtChannel[i]->SetROI(PGFRect(0, 0, m_width[i], m_height[i]));
959 #endif
960
961 // wavelet subband decomposition
962 for (int l=0; error == NoError && l < m_header.nLevels; l++) {
963 OSError err = m_wtChannel[i]->ForwardTransform(l, m_quant);
964 if (err != NoError) error = err;
965 }
966 } else {
967 delete[] m_channel[i];
968 error = InsufficientMemory;
969 }
970 }
971 }
972 }
973 if (error != NoError) {
974 // free already allocated memory
975 for (int i=0; i < m_header.channels; i++) {
976 delete m_wtChannel[i];
977 }
978 ReturnWithError(error);
979 }
980
981 m_currentLevel = m_header.nLevels;
982
983 // create encoder and eventually write headers and levelLength
984 m_encoder = new CEncoder(stream, m_preHeader, m_header, m_postHeader, m_userDataPos, m_useOMPinEncoder);
985 if (m_favorSpeedOverSize) m_encoder->FavorSpeedOverSize();
986
987 #ifdef __PGFROISUPPORT__
988 if (ROIisSupported()) {
989 // new encoding scheme supporting ROI
990 m_encoder->SetROI();
991 }
992 #endif
993
994 } else {
995 // very small image: we don't use DWT and encoding
996
997 // create encoder and eventually write headers and levelLength
998 m_encoder = new CEncoder(stream, m_preHeader, m_header, m_postHeader, m_userDataPos, m_useOMPinEncoder);
999 }
1000
1001 INT64 nBytes = m_encoder->ComputeHeaderLength();
1002 return (nBytes > 0) ? (UINT32)nBytes : 0;
1003}
1004
1006// Encode and write next level of a PGF image at current stream position.
1007// A PGF image is structered in levels, numbered between 0 and Levels() - 1.
1008// Each level can be seen as a single image, containing the same content
1009// as all other levels, but in a different size (width, height).
1010// The image size at level i is double the size (width, height) of the image at level i+1.
1011// The image at level 0 contains the original size.
1012// It might throw an IOException.
1014 ASSERT(m_encoder);
1015 ASSERT(m_currentLevel > 0);
1016 ASSERT(m_header.nLevels > 0);
1017
1018#ifdef __PGFROISUPPORT__
1019 if (ROIisSupported()) {
1020 const int lastChannel = m_header.channels - 1;
1021
1022 for (int i=0; i < m_header.channels; i++) {
1023 // get number of tiles and tile indices
1024 const UINT32 nTiles = m_wtChannel[i]->GetNofTiles(m_currentLevel);
1025 const UINT32 lastTile = nTiles - 1;
1026
1028 // last level also has LL band
1029 ASSERT(nTiles == 1);
1031 m_encoder->EncodeTileBuffer();
1032 }
1033 for (UINT32 tileY=0; tileY < nTiles; tileY++) {
1034 for (UINT32 tileX=0; tileX < nTiles; tileX++) {
1035 m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder, true, tileX, tileY);
1036 m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder, true, tileX, tileY);
1037 m_wtChannel[i]->GetSubband(m_currentLevel, HH)->ExtractTile(*m_encoder, true, tileX, tileY);
1038 if (i == lastChannel && tileY == lastTile && tileX == lastTile) {
1039 // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level.
1041 }
1042 m_encoder->EncodeTileBuffer();
1043 }
1044 }
1045 }
1046 } else
1047#endif
1048 {
1049 for (int i=0; i < m_header.channels; i++) {
1050 ASSERT(m_wtChannel[i]);
1052 // last level also has LL band
1054 }
1055 //encoder.EncodeInterleaved(m_wtChannel[i], m_currentLevel, m_quant); // until version 4
1056 m_wtChannel[i]->GetSubband(m_currentLevel, HL)->ExtractTile(*m_encoder); // since version 5
1057 m_wtChannel[i]->GetSubband(m_currentLevel, LH)->ExtractTile(*m_encoder); // since version 5
1059 }
1060
1061 // all necessary data are buffered. next call of EncodeBuffer will write the last piece of data of the current level.
1063 }
1064}
1065
1067// Return written levelLength bytes
1069 ASSERT(m_encoder);
1070
1071 INT64 offset = m_encoder->ComputeOffset(); ASSERT(offset >= 0);
1072
1073 if (offset > 0) {
1074 // update post-header size and rewrite pre-header
1075 m_preHeader.hSize += (UINT32)offset;
1077 }
1078
1079 // write dummy levelLength into stream
1081}
1082
1093UINT32 CPGFImage::WriteImage(CPGFStream* stream, CallbackPtr cb /*= NULL*/, void *data /*= NULL*/) THROW_ {
1094 ASSERT(stream);
1095 ASSERT(m_preHeader.hSize);
1096
1097 int levels = m_header.nLevels;
1098 double percent = pow(0.25, levels);
1099
1100 // update post-header size, rewrite pre-header, and write dummy levelLength
1101 UINT32 nWrittenBytes = UpdatePostHeaderSize();
1102
1103 if (levels == 0) {
1104 // write channels
1105 for (int c=0; c < m_header.channels; c++) {
1106 const UINT32 size = m_width[c]*m_height[c];
1107
1108 // write channel data into stream
1109 for (UINT32 i=0; i < size; i++) {
1110 int count = DataTSize;
1111 stream->Write(&count, &m_channel[c][i]);
1112 }
1113 }
1114
1115 // now update progress
1116 if (cb) {
1117 if ((*cb)(1, true, data)) ReturnWithError(EscapePressed);
1118 }
1119
1120 } else {
1121 // encode quantized wavelet coefficients and write to PGF file
1122 // encode subbands, higher levels first
1123 // color channels are interleaved
1124
1125 // encode all levels
1126 for (m_currentLevel = levels; m_currentLevel > 0; ) {
1127 WriteLevel(); // decrements m_currentLevel
1128
1129 // now update progress
1130 if (cb) {
1131 percent *= 4;
1132 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1133 }
1134 }
1135
1136 // flush encoder and write level lengths
1137 m_encoder->Flush();
1138 }
1139
1140 // update level lengths
1141 nWrittenBytes += m_encoder->UpdateLevelLength(); // return written image bytes
1142
1143 // delete encoder
1144 delete m_encoder; m_encoder = NULL;
1145
1146 ASSERT(!m_encoder);
1147
1148 return nWrittenBytes;
1149}
1150
1164void CPGFImage::Write(CPGFStream* stream, UINT32* nWrittenBytes /*= NULL*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
1165 ASSERT(stream);
1166 ASSERT(m_preHeader.hSize);
1167
1168 // create wavelet transform channels and encoder
1169 UINT32 nBytes = WriteHeader(stream);
1170
1171 // write image
1172 nBytes += WriteImage(stream, cb, data);
1173
1174 // return written bytes
1175 if (nWrittenBytes) *nWrittenBytes += nBytes;
1176}
1177
1178#ifdef __PGFROISUPPORT__
1180// Encode and write down to given level at current stream position.
1181// A PGF image is structered in levels, numbered between 0 and Levels() - 1.
1182// Each level can be seen as a single image, containing the same content
1183// as all other levels, but in a different size (width, height).
1184// The image size at level i is double the size (width, height) of the image at level i+1.
1185// The image at level 0 contains the original size.
1186// Precondition: the PGF image contains a valid header (see also SetHeader(...)) and WriteHeader() has been called before Write().
1187// The ROI encoding scheme is used.
1188// It might throw an IOException.
1189// @param level The image level of the resulting image in the internal image buffer.
1190// @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.
1191// @param data Data Pointer to C++ class container to host callback procedure.
1192// @return The number of bytes written into stream.
1193UINT32 CPGFImage::Write(int level, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
1194 ASSERT(m_header.nLevels > 0);
1195 ASSERT(0 <= level && level < m_header.nLevels);
1196 ASSERT(m_encoder);
1197 ASSERT(ROIisSupported());
1198
1199 const int levelDiff = m_currentLevel - level;
1200 double percent = (m_progressMode == PM_Relative) ? pow(0.25, levelDiff) : m_percent;
1201 UINT32 nWrittenBytes = 0;
1202
1203 if (m_currentLevel == m_header.nLevels) {
1204 // update post-header size, rewrite pre-header, and write dummy levelLength
1205 nWrittenBytes = UpdatePostHeaderSize();
1206 } else {
1207 // prepare for next level: save current file position, because the stream might have been reinitialized
1208 if (m_encoder->ComputeBufferLength()) {
1209 m_streamReinitialized = true;
1210 }
1211 }
1212
1213 // encoding scheme with ROI
1214 while (m_currentLevel > level) {
1215 WriteLevel(); // decrements m_currentLevel
1216
1217 if (m_levelLength) {
1218 nWrittenBytes += m_levelLength[m_header.nLevels - m_currentLevel - 1];
1219 }
1220
1221 // now update progress
1222 if (cb) {
1223 percent *= 4;
1224 if (m_progressMode == PM_Absolute) m_percent = percent;
1225 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1226 }
1227 }
1228
1229 // automatically closing
1230 if (m_currentLevel == 0) {
1231 if (!m_streamReinitialized) {
1232 // don't write level lengths, if the stream position changed inbetween two Write operations
1233 m_encoder->UpdateLevelLength();
1234 }
1235 // delete encoder
1236 delete m_encoder; m_encoder = NULL;
1237 }
1238
1239 return nWrittenBytes;
1240}
1241#endif // __PGFROISUPPORT__
1242
1243
1245// Check for valid import image mode.
1246// @param mode Image mode
1247// @return True if an image of given mode can be imported with ImportBitmap(...)
1249 size_t size = DataTSize;
1250
1251 if (size >= 2) {
1252 switch(mode) {
1253 case ImageModeBitmap:
1255 case ImageModeGrayScale:
1256 case ImageModeRGBColor:
1257 case ImageModeCMYKColor:
1258 case ImageModeHSLColor:
1259 case ImageModeHSBColor:
1260 //case ImageModeDuotone:
1261 case ImageModeLabColor:
1262 case ImageModeRGB12:
1263 case ImageModeRGB16:
1264 case ImageModeRGBA:
1265 return true;
1266 }
1267 }
1268 if (size >= 3) {
1269 switch(mode) {
1270 case ImageModeGray16:
1271 case ImageModeRGB48:
1272 case ImageModeLab48:
1273 case ImageModeCMYK64:
1274 //case ImageModeDuotone16:
1275 return true;
1276 }
1277 }
1278 if (size >=4) {
1279 switch(mode) {
1280 case ImageModeGray32:
1281 return true;
1282 }
1283 }
1284 return false;
1285}
1286
1293void CPGFImage::GetColorTable(UINT32 iFirstColor, UINT32 nColors, RGBQUAD* prgbColors) const THROW_ {
1294 if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError);
1295
1296 for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
1297 prgbColors[j] = m_postHeader.clut[i];
1298 }
1299}
1300
1307void CPGFImage::SetColorTable(UINT32 iFirstColor, UINT32 nColors, const RGBQUAD* prgbColors) THROW_ {
1308 if (iFirstColor + nColors > ColorTableLen) ReturnWithError(ColorTableError);
1309
1310 for (UINT32 i=iFirstColor, j=0; j < nColors; i++, j++) {
1311 m_postHeader.clut[i] = prgbColors[j];
1312 }
1313}
1314
1316// Buffer transform from interleaved to channel seperated format
1317// the absolute value of pitch is the number of bytes of an image row
1318// if pitch is negative, then buff points to the last row of a bottom-up image (first byte on last row)
1319// if pitch is positive, then buff points to the first row of a top-down image (first byte)
1320// bpp is the number of bits per pixel used in image buffer buff
1321//
1322// RGB is transformed into YUV format (ordering of buffer data is BGR[A])
1323// Y = (R + 2*G + B)/4 -128
1324// U = R - G
1325// V = B - G
1326//
1327// Since PGF Codec version 2.0 images are stored in top-down direction
1328//
1329// 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
1330// provide a channelMap of size of expected channels (depending on image mode). For example, PGF expects in RGB color mode a channel sequence BGR.
1331// If your provided image buffer contains a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
1332void CPGFImage::RgbToYuv(int pitch, UINT8* buff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data /*=NULL*/) THROW_ {
1333 ASSERT(buff);
1334 int yPos = 0, cnt = 0;
1335 double percent = 0;
1336 const double dP = 1.0/m_header.height;
1337 int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
1338
1339 if (channelMap == NULL) channelMap = defMap;
1340
1341 switch(m_header.mode) {
1342 case ImageModeBitmap:
1343 {
1344 ASSERT(m_header.channels == 1);
1345 ASSERT(m_header.bpp == 1);
1346 ASSERT(bpp == 1);
1347
1348 const UINT32 w = m_header.width;
1349 const UINT32 w2 = (m_header.width + 7)/8;
1350 DataT* y = m_channel[0]; ASSERT(y);
1351
1352 for (UINT32 h=0; h < m_header.height; h++) {
1353 if (cb) {
1354 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1355 percent += dP;
1356 }
1357
1358 for (UINT32 j=0; j < w2; j++) {
1359 y[yPos++] = buff[j] - YUVoffset8;
1360 }
1361 for (UINT32 j=w2; j < w; j++) {
1362 y[yPos++] = YUVoffset8;
1363 }
1364
1365 //UINT cnt = w;
1366 //for (UINT32 j=0; j < w2; j++) {
1367 // for (int k=7; k >= 0; k--) {
1368 // if (cnt) {
1369 // y[yPos++] = YUVoffset8 + (1 & (buff[j] >> k));
1370 // cnt--;
1371 // }
1372 // }
1373 //}
1374 buff += pitch;
1375 }
1376 }
1377 break;
1379 case ImageModeGrayScale:
1380 case ImageModeHSLColor:
1381 case ImageModeHSBColor:
1382 case ImageModeLabColor:
1383 {
1384 ASSERT(m_header.channels >= 1);
1385 ASSERT(m_header.bpp == m_header.channels*8);
1386 ASSERT(bpp%8 == 0);
1387 const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1388
1389 for (UINT32 h=0; h < m_header.height; h++) {
1390 if (cb) {
1391 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1392 percent += dP;
1393 }
1394
1395 cnt = 0;
1396 for (UINT32 w=0; w < m_header.width; w++) {
1397 for (int c=0; c < m_header.channels; c++) {
1398 m_channel[c][yPos] = buff[cnt + channelMap[c]] - YUVoffset8;
1399 }
1400 cnt += channels;
1401 yPos++;
1402 }
1403 buff += pitch;
1404 }
1405 }
1406 break;
1407 case ImageModeGray16:
1408 case ImageModeLab48:
1409 {
1410 ASSERT(m_header.channels >= 1);
1411 ASSERT(m_header.bpp == m_header.channels*16);
1412 ASSERT(bpp%16 == 0);
1413
1414 UINT16 *buff16 = (UINT16 *)buff;
1415 const int pitch16 = pitch/2;
1416 const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1417 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1418 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1419
1420 for (UINT32 h=0; h < m_header.height; h++) {
1421 if (cb) {
1422 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1423 percent += dP;
1424 }
1425
1426 cnt = 0;
1427 for (UINT32 w=0; w < m_header.width; w++) {
1428 for (int c=0; c < m_header.channels; c++) {
1429 m_channel[c][yPos] = (buff16[cnt + channelMap[c]] >> shift) - yuvOffset16;
1430 }
1431 cnt += channels;
1432 yPos++;
1433 }
1434 buff16 += pitch16;
1435 }
1436 }
1437 break;
1438 case ImageModeRGBColor:
1439 {
1440 ASSERT(m_header.channels == 3);
1441 ASSERT(m_header.bpp == m_header.channels*8);
1442 ASSERT(bpp%8 == 0);
1443
1444 DataT* y = m_channel[0]; ASSERT(y);
1445 DataT* u = m_channel[1]; ASSERT(u);
1446 DataT* v = m_channel[2]; ASSERT(v);
1447 const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1448 UINT8 b, g, r;
1449
1450 for (UINT32 h=0; h < m_header.height; h++) {
1451 if (cb) {
1452 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1453 percent += dP;
1454 }
1455
1456 cnt = 0;
1457 for (UINT32 w=0; w < m_header.width; w++) {
1458 b = buff[cnt + channelMap[0]];
1459 g = buff[cnt + channelMap[1]];
1460 r = buff[cnt + channelMap[2]];
1461 // Yuv
1462 y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
1463 u[yPos] = r - g;
1464 v[yPos] = b - g;
1465 yPos++;
1466 cnt += channels;
1467 }
1468 buff += pitch;
1469 }
1470 }
1471 break;
1472 case ImageModeRGB48:
1473 {
1474 ASSERT(m_header.channels == 3);
1475 ASSERT(m_header.bpp == m_header.channels*16);
1476 ASSERT(bpp%16 == 0);
1477
1478 UINT16 *buff16 = (UINT16 *)buff;
1479 const int pitch16 = pitch/2;
1480 const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1481 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1482 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1483
1484 DataT* y = m_channel[0]; ASSERT(y);
1485 DataT* u = m_channel[1]; ASSERT(u);
1486 DataT* v = m_channel[2]; ASSERT(v);
1487 UINT16 b, g, r;
1488
1489 for (UINT32 h=0; h < m_header.height; h++) {
1490 if (cb) {
1491 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1492 percent += dP;
1493 }
1494
1495 cnt = 0;
1496 for (UINT32 w=0; w < m_header.width; w++) {
1497 b = buff16[cnt + channelMap[0]] >> shift;
1498 g = buff16[cnt + channelMap[1]] >> shift;
1499 r = buff16[cnt + channelMap[2]] >> shift;
1500 // Yuv
1501 y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
1502 u[yPos] = r - g;
1503 v[yPos] = b - g;
1504 yPos++;
1505 cnt += channels;
1506 }
1507 buff16 += pitch16;
1508 }
1509 }
1510 break;
1511 case ImageModeRGBA:
1512 case ImageModeCMYKColor:
1513 {
1514 ASSERT(m_header.channels == 4);
1515 ASSERT(m_header.bpp == m_header.channels*8);
1516 ASSERT(bpp%8 == 0);
1517 const int channels = bpp/8; ASSERT(channels >= m_header.channels);
1518
1519 DataT* y = m_channel[0]; ASSERT(y);
1520 DataT* u = m_channel[1]; ASSERT(u);
1521 DataT* v = m_channel[2]; ASSERT(v);
1522 DataT* a = m_channel[3]; ASSERT(a);
1523 UINT8 b, g, r;
1524
1525 for (UINT32 h=0; h < m_header.height; h++) {
1526 if (cb) {
1527 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1528 percent += dP;
1529 }
1530
1531 cnt = 0;
1532 for (UINT32 w=0; w < m_header.width; w++) {
1533 b = buff[cnt + channelMap[0]];
1534 g = buff[cnt + channelMap[1]];
1535 r = buff[cnt + channelMap[2]];
1536 // Yuv
1537 y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset8;
1538 u[yPos] = r - g;
1539 v[yPos] = b - g;
1540 a[yPos++] = buff[cnt + channelMap[3]] - YUVoffset8;
1541 cnt += channels;
1542 }
1543 buff += pitch;
1544 }
1545 }
1546 break;
1547 case ImageModeCMYK64:
1548 {
1549 ASSERT(m_header.channels == 4);
1550 ASSERT(m_header.bpp == m_header.channels*16);
1551 ASSERT(bpp%16 == 0);
1552
1553 UINT16 *buff16 = (UINT16 *)buff;
1554 const int pitch16 = pitch/2;
1555 const int channels = bpp/16; ASSERT(channels >= m_header.channels);
1556 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1557 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1558
1559 DataT* y = m_channel[0]; ASSERT(y);
1560 DataT* u = m_channel[1]; ASSERT(u);
1561 DataT* v = m_channel[2]; ASSERT(v);
1562 DataT* a = m_channel[3]; ASSERT(a);
1563 UINT16 b, g, r;
1564
1565 for (UINT32 h=0; h < m_header.height; h++) {
1566 if (cb) {
1567 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1568 percent += dP;
1569 }
1570
1571 cnt = 0;
1572 for (UINT32 w=0; w < m_header.width; w++) {
1573 b = buff16[cnt + channelMap[0]] >> shift;
1574 g = buff16[cnt + channelMap[1]] >> shift;
1575 r = buff16[cnt + channelMap[2]] >> shift;
1576 // Yuv
1577 y[yPos] = ((b + (g << 1) + r) >> 2) - yuvOffset16;
1578 u[yPos] = r - g;
1579 v[yPos] = b - g;
1580 a[yPos++] = (buff16[cnt + channelMap[3]] >> shift) - yuvOffset16;
1581 cnt += channels;
1582 }
1583 buff16 += pitch16;
1584 }
1585 }
1586 break;
1587#ifdef __PGF32SUPPORT__
1588 case ImageModeGray32:
1589 {
1590 ASSERT(m_header.channels == 1);
1591 ASSERT(m_header.bpp == 32);
1592 ASSERT(bpp == 32);
1593 ASSERT(DataTSize == sizeof(UINT32));
1594
1595 DataT* y = m_channel[0]; ASSERT(y);
1596
1597 UINT32 *buff32 = (UINT32 *)buff;
1598 const int pitch32 = pitch/4;
1599 const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1600 const DataT yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
1601
1602 for (UINT32 h=0; h < m_header.height; h++) {
1603 if (cb) {
1604 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1605 percent += dP;
1606 }
1607
1608 for (UINT32 w=0; w < m_header.width; w++) {
1609 y[yPos++] = (buff32[w] >> shift) - yuvOffset31;
1610 }
1611 buff32 += pitch32;
1612 }
1613 }
1614 break;
1615#endif
1616 case ImageModeRGB12:
1617 {
1618 ASSERT(m_header.channels == 3);
1619 ASSERT(m_header.bpp == m_header.channels*4);
1620 ASSERT(bpp == m_header.channels*4);
1621
1622 DataT* y = m_channel[0]; ASSERT(y);
1623 DataT* u = m_channel[1]; ASSERT(u);
1624 DataT* v = m_channel[2]; ASSERT(v);
1625
1626 UINT8 rgb = 0, b, g, r;
1627
1628 for (UINT32 h=0; h < m_header.height; h++) {
1629 if (cb) {
1630 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1631 percent += dP;
1632 }
1633
1634 cnt = 0;
1635 for (UINT32 w=0; w < m_header.width; w++) {
1636 if (w%2 == 0) {
1637 // even pixel position
1638 rgb = buff[cnt];
1639 b = rgb & 0x0F;
1640 g = (rgb & 0xF0) >> 4;
1641 cnt++;
1642 rgb = buff[cnt];
1643 r = rgb & 0x0F;
1644 } else {
1645 // odd pixel position
1646 b = (rgb & 0xF0) >> 4;
1647 cnt++;
1648 rgb = buff[cnt];
1649 g = rgb & 0x0F;
1650 r = (rgb & 0xF0) >> 4;
1651 cnt++;
1652 }
1653
1654 // Yuv
1655 y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset4;
1656 u[yPos] = r - g;
1657 v[yPos] = b - g;
1658 yPos++;
1659 }
1660 buff += pitch;
1661 }
1662 }
1663 break;
1664 case ImageModeRGB16:
1665 {
1666 ASSERT(m_header.channels == 3);
1667 ASSERT(m_header.bpp == 16);
1668 ASSERT(bpp == 16);
1669
1670 DataT* y = m_channel[0]; ASSERT(y);
1671 DataT* u = m_channel[1]; ASSERT(u);
1672 DataT* v = m_channel[2]; ASSERT(v);
1673
1674 UINT16 *buff16 = (UINT16 *)buff;
1675 UINT16 rgb, b, g, r;
1676 const int pitch16 = pitch/2;
1677
1678 for (UINT32 h=0; h < m_header.height; h++) {
1679 if (cb) {
1680 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1681 percent += dP;
1682 }
1683 for (UINT32 w=0; w < m_header.width; w++) {
1684 rgb = buff16[w];
1685 r = (rgb & 0xF800) >> 10; // highest 5 bits
1686 g = (rgb & 0x07E0) >> 5; // middle 6 bits
1687 b = (rgb & 0x001F) << 1; // lowest 5 bits
1688 // Yuv
1689 y[yPos] = ((b + (g << 1) + r) >> 2) - YUVoffset6;
1690 u[yPos] = r - g;
1691 v[yPos] = b - g;
1692 yPos++;
1693 }
1694
1695 buff16 += pitch16;
1696 }
1697 }
1698 break;
1699 default:
1700 ASSERT(false);
1701 }
1702}
1703
1705// Get image data in interleaved format: (ordering of RGB data is BGR[A])
1706// Upsampling, YUV to RGB transform and interleaving are done here to reduce the number
1707// of passes over the data.
1708// The absolute value of pitch is the number of bytes of an image row of the given image buffer.
1709// If pitch is negative, then the image buffer must point to the last row of a bottom-up image (first byte on last row).
1710// if pitch is positive, then the image buffer must point to the first row of a top-down image (first byte).
1711// 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
1712// provide a channelMap of size of expected channels (depending on image mode). For example, PGF provides a channel sequence BGR in RGB color mode.
1713// If your provided image buffer expects a channel sequence ARGB, then the channelMap looks like { 3, 2, 1 }.
1714// It might throw an IOException.
1715// @param pitch The number of bytes of a row of the image buffer.
1716// @param buff An image buffer.
1717// @param bpp The number of bits per pixel used in image buffer.
1718// @param channelMap A integer array containing the mapping of PGF channel ordering to expected channel ordering.
1719// @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.
1720// @param data Data Pointer to C++ class container to host callback procedure.
1721void CPGFImage::GetBitmap(int pitch, UINT8* buff, BYTE bpp, int channelMap[] /*= NULL */, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) const THROW_ {
1722 ASSERT(buff);
1723 UINT32 w = m_width[0];
1724 UINT32 h = m_height[0];
1725 UINT8* targetBuff = 0; // used if ROI is used
1726 UINT8* buffStart = 0; // used if ROI is used
1727 int targetPitch = 0; // used if ROI is used
1728
1729#ifdef __PGFROISUPPORT__
1730 const PGFRect& roi = (ROIisSupported()) ? m_wtChannel[0]->GetROI(m_currentLevel) : PGFRect(0, 0, w, h); // roi is usually larger than m_roi
1731 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));
1732 ASSERT(w <= roi.Width() && h <= roi.Height());
1733 ASSERT(roi.left <= levelRoi.left && levelRoi.right <= roi.right);
1734 ASSERT(roi.top <= levelRoi.top && levelRoi.bottom <= roi.bottom);
1735
1736 if (ROIisSupported() && (levelRoi.Width() < w || levelRoi.Height() < h)) {
1737 // ROI is used -> create a temporary image buffer for roi
1738 // compute pitch
1739 targetPitch = pitch;
1740 pitch = AlignWordPos(w*bpp)/8;
1741
1742 // create temporary output buffer
1743 targetBuff = buff;
1744 buff = buffStart = new(std::nothrow) UINT8[pitch*h];
1745 if (!buff) ReturnWithError(InsufficientMemory);
1746 }
1747#endif
1748
1749 const bool wOdd = (1 == w%2);
1750
1751 const double dP = 1.0/h;
1752 int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
1753 if (channelMap == NULL) channelMap = defMap;
1754 int sampledPos = 0, yPos = 0;
1755 DataT uAvg, vAvg;
1756 double percent = 0;
1757 UINT32 i, j;
1758
1759 switch(m_header.mode) {
1760 case ImageModeBitmap:
1761 {
1762 ASSERT(m_header.channels == 1);
1763 ASSERT(m_header.bpp == 1);
1764 ASSERT(bpp == 1);
1765
1766 const UINT32 w2 = (w + 7)/8;
1767 DataT* y = m_channel[0]; ASSERT(y);
1768
1769 for (i=0; i < h; i++) {
1770
1771 for (j=0; j < w2; j++) {
1772 buff[j] = Clamp8(y[yPos++] + YUVoffset8);
1773 }
1774 yPos += w - w2;
1775
1776 //UINT32 cnt = w;
1777 //for (j=0; j < w2; j++) {
1778 // buff[j] = 0;
1779 // for (int k=0; k < 8; k++) {
1780 // if (cnt) {
1781 // buff[j] <<= 1;
1782 // buff[j] |= (1 & (y[yPos++] - YUVoffset8));
1783 // cnt--;
1784 // }
1785 // }
1786 //}
1787 buff += pitch;
1788
1789 if (cb) {
1790 percent += dP;
1791 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1792 }
1793 }
1794 break;
1795 }
1797 case ImageModeGrayScale:
1798 case ImageModeHSLColor:
1799 case ImageModeHSBColor:
1800 {
1801 ASSERT(m_header.channels >= 1);
1802 ASSERT(m_header.bpp == m_header.channels*8);
1803 ASSERT(bpp%8 == 0);
1804
1805 int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
1806
1807 for (i=0; i < h; i++) {
1808 cnt = 0;
1809 for (j=0; j < w; j++) {
1810 for (int c=0; c < m_header.channels; c++) {
1811 buff[cnt + channelMap[c]] = Clamp8(m_channel[c][yPos] + YUVoffset8);
1812 }
1813 cnt += channels;
1814 yPos++;
1815 }
1816 buff += pitch;
1817
1818 if (cb) {
1819 percent += dP;
1820 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1821 }
1822 }
1823 break;
1824 }
1825 case ImageModeGray16:
1826 {
1827 ASSERT(m_header.channels >= 1);
1828 ASSERT(m_header.bpp == m_header.channels*16);
1829
1830 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1831 int cnt, channels;
1832
1833 if (bpp%16 == 0) {
1834 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1835 UINT16 *buff16 = (UINT16 *)buff;
1836 int pitch16 = pitch/2;
1837 channels = bpp/16; ASSERT(channels >= m_header.channels);
1838
1839 for (i=0; i < h; i++) {
1840 cnt = 0;
1841 for (j=0; j < w; j++) {
1842 for (int c=0; c < m_header.channels; c++) {
1843 buff16[cnt + channelMap[c]] = Clamp16((m_channel[c][yPos] + yuvOffset16) << shift);
1844 }
1845 cnt += channels;
1846 yPos++;
1847 }
1848 buff16 += pitch16;
1849
1850 if (cb) {
1851 percent += dP;
1852 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1853 }
1854 }
1855 } else {
1856 ASSERT(bpp%8 == 0);
1857 const int shift = __max(0, UsedBitsPerChannel() - 8);
1858 channels = bpp/8; ASSERT(channels >= m_header.channels);
1859
1860 for (i=0; i < h; i++) {
1861 cnt = 0;
1862 for (j=0; j < w; j++) {
1863 for (int c=0; c < m_header.channels; c++) {
1864 buff[cnt + channelMap[c]] = Clamp8((m_channel[c][yPos] + yuvOffset16) >> shift);
1865 }
1866 cnt += channels;
1867 yPos++;
1868 }
1869 buff += pitch;
1870
1871 if (cb) {
1872 percent += dP;
1873 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1874 }
1875 }
1876 }
1877 break;
1878 }
1879 case ImageModeRGBColor:
1880 {
1881 ASSERT(m_header.channels == 3);
1882 ASSERT(m_header.bpp == m_header.channels*8);
1883 ASSERT(bpp%8 == 0);
1884 ASSERT(bpp >= m_header.bpp);
1885
1886 DataT* y = m_channel[0]; ASSERT(y);
1887 DataT* u = m_channel[1]; ASSERT(u);
1888 DataT* v = m_channel[2]; ASSERT(v);
1889 UINT8 *buffg = &buff[channelMap[1]],
1890 *buffr = &buff[channelMap[2]],
1891 *buffb = &buff[channelMap[0]];
1892 UINT8 g;
1893 int cnt, channels = bpp/8;
1894 if(m_downsample){
1895 for (i=0; i < h; i++) {
1896 if (i%2) sampledPos -= (w + 1)/2;
1897 cnt = 0;
1898 for (j=0; j < w; j++) {
1899 // image was downsampled
1900 uAvg = u[sampledPos];
1901 vAvg = v[sampledPos];
1902 // Yuv
1903 buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
1904 buffr[cnt] = Clamp8(uAvg + g);
1905 buffb[cnt] = Clamp8(vAvg + g);
1906 yPos++;
1907 cnt += channels;
1908 if (j%2) sampledPos++;
1909 }
1910 buffb += pitch;
1911 buffg += pitch;
1912 buffr += pitch;
1913 if (wOdd) sampledPos++;
1914 if (cb) {
1915 percent += dP;
1916 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1917 }
1918 }
1919 }else{
1920 for (i=0; i < h; i++) {
1921 cnt = 0;
1922 for (j = 0; j < w; j++) {
1923 uAvg = u[yPos];
1924 vAvg = v[yPos];
1925 // Yuv
1926 buffg[cnt] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
1927 buffr[cnt] = Clamp8(uAvg + g);
1928 buffb[cnt] = Clamp8(vAvg + g);
1929 yPos++;
1930 cnt += channels;
1931 }
1932 buffb += pitch;
1933 buffg += pitch;
1934 buffr += pitch;
1935
1936 if (cb) {
1937 percent += dP;
1938 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1939 }
1940 }
1941 }
1942 break;
1943 }
1944 case ImageModeRGB48:
1945 {
1946 ASSERT(m_header.channels == 3);
1947 ASSERT(m_header.bpp == 48);
1948
1949 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
1950
1951 DataT* y = m_channel[0]; ASSERT(y);
1952 DataT* u = m_channel[1]; ASSERT(u);
1953 DataT* v = m_channel[2]; ASSERT(v);
1954 int cnt, channels;
1955 DataT g;
1956
1957 if (bpp >= 48 && bpp%16 == 0) {
1958 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
1959 UINT16 *buff16 = (UINT16 *)buff;
1960 int pitch16 = pitch/2;
1961 channels = bpp/16; ASSERT(channels >= m_header.channels);
1962
1963 for (i=0; i < h; i++) {
1964 if (i%2) sampledPos -= (w + 1)/2;
1965 cnt = 0;
1966 for (j=0; j < w; j++) {
1967 if (m_downsample) {
1968 // image was downsampled
1969 uAvg = u[sampledPos];
1970 vAvg = v[sampledPos];
1971 } else {
1972 uAvg = u[yPos];
1973 vAvg = v[yPos];
1974 }
1975 // Yuv
1976 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
1977 buff16[cnt + channelMap[1]] = Clamp16(g << shift);
1978 buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
1979 buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
1980 yPos++;
1981 cnt += channels;
1982 if (j%2) sampledPos++;
1983 }
1984 buff16 += pitch16;
1985 if (wOdd) sampledPos++;
1986
1987 if (cb) {
1988 percent += dP;
1989 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
1990 }
1991 }
1992 } else {
1993 ASSERT(bpp%8 == 0);
1994 const int shift = __max(0, UsedBitsPerChannel() - 8);
1995 channels = bpp/8; ASSERT(channels >= m_header.channels);
1996
1997 for (i=0; i < h; i++) {
1998 if (i%2) sampledPos -= (w + 1)/2;
1999 cnt = 0;
2000 for (j=0; j < w; j++) {
2001 if (m_downsample) {
2002 // image was downsampled
2003 uAvg = u[sampledPos];
2004 vAvg = v[sampledPos];
2005 } else {
2006 uAvg = u[yPos];
2007 vAvg = v[yPos];
2008 }
2009 // Yuv
2010 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2011 buff[cnt + channelMap[1]] = Clamp8(g >> shift);
2012 buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
2013 buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
2014 yPos++;
2015 cnt += channels;
2016 if (j%2) sampledPos++;
2017 }
2018 buff += pitch;
2019 if (wOdd) sampledPos++;
2020
2021 if (cb) {
2022 percent += dP;
2023 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2024 }
2025 }
2026 }
2027 break;
2028 }
2029 case ImageModeLabColor:
2030 {
2031 ASSERT(m_header.channels == 3);
2032 ASSERT(m_header.bpp == m_header.channels*8);
2033 ASSERT(bpp%8 == 0);
2034
2035 DataT* l = m_channel[0]; ASSERT(l);
2036 DataT* a = m_channel[1]; ASSERT(a);
2037 DataT* b = m_channel[2]; ASSERT(b);
2038 int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
2039
2040 for (i=0; i < h; i++) {
2041 if (i%2) sampledPos -= (w + 1)/2;
2042 cnt = 0;
2043 for (j=0; j < w; j++) {
2044 if (m_downsample) {
2045 // image was downsampled
2046 uAvg = a[sampledPos];
2047 vAvg = b[sampledPos];
2048 } else {
2049 uAvg = a[yPos];
2050 vAvg = b[yPos];
2051 }
2052 buff[cnt + channelMap[0]] = Clamp8(l[yPos] + YUVoffset8);
2053 buff[cnt + channelMap[1]] = Clamp8(uAvg + YUVoffset8);
2054 buff[cnt + channelMap[2]] = Clamp8(vAvg + YUVoffset8);
2055 cnt += channels;
2056 yPos++;
2057 if (j%2) sampledPos++;
2058 }
2059 buff += pitch;
2060 if (wOdd) sampledPos++;
2061
2062 if (cb) {
2063 percent += dP;
2064 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2065 }
2066 }
2067 break;
2068 }
2069 case ImageModeLab48:
2070 {
2071 ASSERT(m_header.channels == 3);
2072 ASSERT(m_header.bpp == m_header.channels*16);
2073
2074 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2075
2076 DataT* l = m_channel[0]; ASSERT(l);
2077 DataT* a = m_channel[1]; ASSERT(a);
2078 DataT* b = m_channel[2]; ASSERT(b);
2079 int cnt, channels;
2080
2081 if (bpp%16 == 0) {
2082 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2083 UINT16 *buff16 = (UINT16 *)buff;
2084 int pitch16 = pitch/2;
2085 channels = bpp/16; ASSERT(channels >= m_header.channels);
2086
2087 for (i=0; i < h; i++) {
2088 if (i%2) sampledPos -= (w + 1)/2;
2089 cnt = 0;
2090 for (j=0; j < w; j++) {
2091 if (m_downsample) {
2092 // image was downsampled
2093 uAvg = a[sampledPos];
2094 vAvg = b[sampledPos];
2095 } else {
2096 uAvg = a[yPos];
2097 vAvg = b[yPos];
2098 }
2099 buff16[cnt + channelMap[0]] = Clamp16((l[yPos] + yuvOffset16) << shift);
2100 buff16[cnt + channelMap[1]] = Clamp16((uAvg + yuvOffset16) << shift);
2101 buff16[cnt + channelMap[2]] = Clamp16((vAvg + yuvOffset16) << shift);
2102 cnt += channels;
2103 yPos++;
2104 if (j%2) sampledPos++;
2105 }
2106 buff16 += pitch16;
2107 if (wOdd) sampledPos++;
2108
2109 if (cb) {
2110 percent += dP;
2111 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2112 }
2113 }
2114 } else {
2115 ASSERT(bpp%8 == 0);
2116 const int shift = __max(0, UsedBitsPerChannel() - 8);
2117 channels = bpp/8; ASSERT(channels >= m_header.channels);
2118
2119 for (i=0; i < h; i++) {
2120 if (i%2) sampledPos -= (w + 1)/2;
2121 cnt = 0;
2122 for (j=0; j < w; j++) {
2123 if (m_downsample) {
2124 // image was downsampled
2125 uAvg = a[sampledPos];
2126 vAvg = b[sampledPos];
2127 } else {
2128 uAvg = a[yPos];
2129 vAvg = b[yPos];
2130 }
2131 buff[cnt + channelMap[0]] = Clamp8((l[yPos] + yuvOffset16) >> shift);
2132 buff[cnt + channelMap[1]] = Clamp8((uAvg + yuvOffset16) >> shift);
2133 buff[cnt + channelMap[2]] = Clamp8((vAvg + yuvOffset16) >> shift);
2134 cnt += channels;
2135 yPos++;
2136 if (j%2) sampledPos++;
2137 }
2138 buff += pitch;
2139 if (wOdd) sampledPos++;
2140
2141 if (cb) {
2142 percent += dP;
2143 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2144 }
2145 }
2146 }
2147 break;
2148 }
2149 case ImageModeRGBA:
2150 case ImageModeCMYKColor:
2151 {
2152 ASSERT(m_header.channels == 4);
2153 ASSERT(m_header.bpp == m_header.channels*8);
2154 ASSERT(bpp%8 == 0);
2155
2156 DataT* y = m_channel[0]; ASSERT(y);
2157 DataT* u = m_channel[1]; ASSERT(u);
2158 DataT* v = m_channel[2]; ASSERT(v);
2159 DataT* a = m_channel[3]; ASSERT(a);
2160 UINT8 g, aAvg;
2161 int cnt, channels = bpp/8; ASSERT(channels >= m_header.channels);
2162
2163 for (i=0; i < h; i++) {
2164 if (i%2) sampledPos -= (w + 1)/2;
2165 cnt = 0;
2166 for (j=0; j < w; j++) {
2167 if (m_downsample) {
2168 // image was downsampled
2169 uAvg = u[sampledPos];
2170 vAvg = v[sampledPos];
2171 aAvg = Clamp8(a[sampledPos] + YUVoffset8);
2172 } else {
2173 uAvg = u[yPos];
2174 vAvg = v[yPos];
2175 aAvg = Clamp8(a[yPos] + YUVoffset8);
2176 }
2177 // Yuv
2178 buff[cnt + channelMap[1]] = g = Clamp8(y[yPos] + YUVoffset8 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2179 buff[cnt + channelMap[2]] = Clamp8(uAvg + g);
2180 buff[cnt + channelMap[0]] = Clamp8(vAvg + g);
2181 buff[cnt + channelMap[3]] = aAvg;
2182 yPos++;
2183 cnt += channels;
2184 if (j%2) sampledPos++;
2185 }
2186 buff += pitch;
2187 if (wOdd) sampledPos++;
2188
2189 if (cb) {
2190 percent += dP;
2191 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2192 }
2193 }
2194 break;
2195 }
2196 case ImageModeCMYK64:
2197 {
2198 ASSERT(m_header.channels == 4);
2199 ASSERT(m_header.bpp == 64);
2200
2201 const DataT yuvOffset16 = 1 << (UsedBitsPerChannel() - 1);
2202
2203 DataT* y = m_channel[0]; ASSERT(y);
2204 DataT* u = m_channel[1]; ASSERT(u);
2205 DataT* v = m_channel[2]; ASSERT(v);
2206 DataT* a = m_channel[3]; ASSERT(a);
2207 DataT g, aAvg;
2208 int cnt, channels;
2209
2210 if (bpp%16 == 0) {
2211 const int shift = 16 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2212 UINT16 *buff16 = (UINT16 *)buff;
2213 int pitch16 = pitch/2;
2214 channels = bpp/16; ASSERT(channels >= m_header.channels);
2215
2216 for (i=0; i < h; i++) {
2217 if (i%2) sampledPos -= (w + 1)/2;
2218 cnt = 0;
2219 for (j=0; j < w; j++) {
2220 if (m_downsample) {
2221 // image was downsampled
2222 uAvg = u[sampledPos];
2223 vAvg = v[sampledPos];
2224 aAvg = a[sampledPos] + yuvOffset16;
2225 } else {
2226 uAvg = u[yPos];
2227 vAvg = v[yPos];
2228 aAvg = a[yPos] + yuvOffset16;
2229 }
2230 // Yuv
2231 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2232 buff16[cnt + channelMap[1]] = Clamp16(g << shift);
2233 buff16[cnt + channelMap[2]] = Clamp16((uAvg + g) << shift);
2234 buff16[cnt + channelMap[0]] = Clamp16((vAvg + g) << shift);
2235 buff16[cnt + channelMap[3]] = Clamp16(aAvg << shift);
2236 yPos++;
2237 cnt += channels;
2238 if (j%2) sampledPos++;
2239 }
2240 buff16 += pitch16;
2241 if (wOdd) sampledPos++;
2242
2243 if (cb) {
2244 percent += dP;
2245 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2246 }
2247 }
2248 } else {
2249 ASSERT(bpp%8 == 0);
2250 const int shift = __max(0, UsedBitsPerChannel() - 8);
2251 channels = bpp/8; ASSERT(channels >= m_header.channels);
2252
2253 for (i=0; i < h; i++) {
2254 if (i%2) sampledPos -= (w + 1)/2;
2255 cnt = 0;
2256 for (j=0; j < w; j++) {
2257 if (m_downsample) {
2258 // image was downsampled
2259 uAvg = u[sampledPos];
2260 vAvg = v[sampledPos];
2261 aAvg = a[sampledPos] + yuvOffset16;
2262 } else {
2263 uAvg = u[yPos];
2264 vAvg = v[yPos];
2265 aAvg = a[yPos] + yuvOffset16;
2266 }
2267 // Yuv
2268 g = y[yPos] + yuvOffset16 - ((uAvg + vAvg ) >> 2); // must be logical shift operator
2269 buff[cnt + channelMap[1]] = Clamp8(g >> shift);
2270 buff[cnt + channelMap[2]] = Clamp8((uAvg + g) >> shift);
2271 buff[cnt + channelMap[0]] = Clamp8((vAvg + g) >> shift);
2272 buff[cnt + channelMap[3]] = Clamp8(aAvg >> shift);
2273 yPos++;
2274 cnt += channels;
2275 if (j%2) sampledPos++;
2276 }
2277 buff += pitch;
2278 if (wOdd) sampledPos++;
2279
2280 if (cb) {
2281 percent += dP;
2282 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2283 }
2284 }
2285 }
2286 break;
2287 }
2288#ifdef __PGF32SUPPORT__
2289 case ImageModeGray32:
2290 {
2291 ASSERT(m_header.channels == 1);
2292 ASSERT(m_header.bpp == 32);
2293
2294 const int yuvOffset31 = 1 << (UsedBitsPerChannel() - 1);
2295
2296 DataT* y = m_channel[0]; ASSERT(y);
2297
2298 if (bpp == 32) {
2299 const int shift = 31 - UsedBitsPerChannel(); ASSERT(shift >= 0);
2300 UINT32 *buff32 = (UINT32 *)buff;
2301 int pitch32 = pitch/4;
2302
2303 for (i=0; i < h; i++) {
2304 for (j=0; j < w; j++) {
2305 buff32[j] = Clamp31((y[yPos++] + yuvOffset31) << shift);
2306 }
2307 buff32 += pitch32;
2308
2309 if (cb) {
2310 percent += dP;
2311 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2312 }
2313 }
2314 } else if (bpp == 16) {
2315 const int usedBits = UsedBitsPerChannel();
2316 UINT16 *buff16 = (UINT16 *)buff;
2317 int pitch16 = pitch/2;
2318
2319 if (usedBits < 16) {
2320 const int shift = 16 - usedBits;
2321 for (i=0; i < h; i++) {
2322 for (j=0; j < w; j++) {
2323 buff16[j] = Clamp16((y[yPos++] + yuvOffset31) << shift);
2324 }
2325 buff16 += pitch16;
2326
2327 if (cb) {
2328 percent += dP;
2329 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2330 }
2331 }
2332 } else {
2333 const int shift = __max(0, usedBits - 16);
2334 for (i=0; i < h; i++) {
2335 for (j=0; j < w; j++) {
2336 buff16[j] = Clamp16((y[yPos++] + yuvOffset31) >> shift);
2337 }
2338 buff16 += pitch16;
2339
2340 if (cb) {
2341 percent += dP;
2342 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2343 }
2344 }
2345 }
2346 } else {
2347 ASSERT(bpp == 8);
2348 const int shift = __max(0, UsedBitsPerChannel() - 8);
2349
2350 for (i=0; i < h; i++) {
2351 for (j=0; j < w; j++) {
2352 buff[j] = Clamp8((y[yPos++] + yuvOffset31) >> shift);
2353 }
2354 buff += pitch;
2355
2356 if (cb) {
2357 percent += dP;
2358 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2359 }
2360 }
2361 }
2362 break;
2363 }
2364#endif
2365 case ImageModeRGB12:
2366 {
2367 ASSERT(m_header.channels == 3);
2368 ASSERT(m_header.bpp == m_header.channels*4);
2369 ASSERT(bpp == m_header.channels*4);
2370 ASSERT(!m_downsample);
2371
2372 DataT* y = m_channel[0]; ASSERT(y);
2373 DataT* u = m_channel[1]; ASSERT(u);
2374 DataT* v = m_channel[2]; ASSERT(v);
2375 UINT16 yval;
2376 int cnt;
2377
2378 for (i=0; i < h; i++) {
2379 cnt = 0;
2380 for (j=0; j < w; j++) {
2381 // Yuv
2382 uAvg = u[yPos];
2383 vAvg = v[yPos];
2384 yval = Clamp4(y[yPos++] + YUVoffset4 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2385 if (j%2 == 0) {
2386 buff[cnt] = UINT8(Clamp4(vAvg + yval) | (yval << 4));
2387 cnt++;
2388 buff[cnt] = Clamp4(uAvg + yval);
2389 } else {
2390 buff[cnt] |= Clamp4(vAvg + yval) << 4;
2391 cnt++;
2392 buff[cnt] = UINT8(yval | (Clamp4(uAvg + yval) << 4));
2393 cnt++;
2394 }
2395 }
2396 buff += pitch;
2397
2398 if (cb) {
2399 percent += dP;
2400 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2401 }
2402 }
2403 break;
2404 }
2405 case ImageModeRGB16:
2406 {
2407 ASSERT(m_header.channels == 3);
2408 ASSERT(m_header.bpp == 16);
2409 ASSERT(bpp == 16);
2410 ASSERT(!m_downsample);
2411
2412 DataT* y = m_channel[0]; ASSERT(y);
2413 DataT* u = m_channel[1]; ASSERT(u);
2414 DataT* v = m_channel[2]; ASSERT(v);
2415 UINT16 yval;
2416 UINT16 *buff16 = (UINT16 *)buff;
2417 int pitch16 = pitch/2;
2418
2419 for (i=0; i < h; i++) {
2420 for (j=0; j < w; j++) {
2421 // Yuv
2422 uAvg = u[yPos];
2423 vAvg = v[yPos];
2424 yval = Clamp6(y[yPos++] + YUVoffset6 - ((uAvg + vAvg ) >> 2)); // must be logical shift operator
2425 buff16[j] = (yval << 5) | ((Clamp6(uAvg + yval) >> 1) << 11) | (Clamp6(vAvg + yval) >> 1);
2426 }
2427 buff16 += pitch16;
2428
2429 if (cb) {
2430 percent += dP;
2431 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2432 }
2433 }
2434 break;
2435 }
2436 default:
2437 ASSERT(false);
2438 }
2439
2440#ifdef __PGFROISUPPORT__
2441 if (targetBuff) {
2442 // copy valid ROI (m_roi) from temporary buffer (roi) to target buffer
2443 if (bpp%8 == 0) {
2444 BYTE bypp = bpp/8;
2445 buff = buffStart + (levelRoi.top - roi.top)*pitch + (levelRoi.left - roi.left)*bypp;
2446 w = levelRoi.Width()*bypp;
2447 h = levelRoi.Height();
2448
2449 for (i=0; i < h; i++) {
2450 for (j=0; j < w; j++) {
2451 targetBuff[j] = buff[j];
2452 }
2453 targetBuff += targetPitch;
2454 buff += pitch;
2455 }
2456 } else {
2457 // to do
2458 }
2459
2460 delete[] buffStart; buffStart = 0;
2461 }
2462#endif
2463}
2464
2479void CPGFImage::GetYUV(int pitch, DataT* buff, BYTE bpp, int channelMap[] /*= NULL*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) const THROW_ {
2480 ASSERT(buff);
2481 const UINT32 w = m_width[0];
2482 const UINT32 h = m_height[0];
2483 const bool wOdd = (1 == w%2);
2484 const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
2485 const int pitch2 = pitch/DataTSize;
2486 const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
2487 const double dP = 1.0/h;
2488
2489 int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
2490 if (channelMap == NULL) channelMap = defMap;
2491 int sampledPos = 0, yPos = 0;
2492 DataT uAvg, vAvg;
2493 double percent = 0;
2494 UINT32 i, j;
2495
2496 if (m_header.channels == 3) {
2497 ASSERT(bpp%dataBits == 0);
2498
2499 DataT* y = m_channel[0]; ASSERT(y);
2500 DataT* u = m_channel[1]; ASSERT(u);
2501 DataT* v = m_channel[2]; ASSERT(v);
2502 int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2503
2504 for (i=0; i < h; i++) {
2505 if (i%2) sampledPos -= (w + 1)/2;
2506 cnt = 0;
2507 for (j=0; j < w; j++) {
2508 if (m_downsample) {
2509 // image was downsampled
2510 uAvg = u[sampledPos];
2511 vAvg = v[sampledPos];
2512 } else {
2513 uAvg = u[yPos];
2514 vAvg = v[yPos];
2515 }
2516 buff[cnt + channelMap[0]] = y[yPos];
2517 buff[cnt + channelMap[1]] = uAvg;
2518 buff[cnt + channelMap[2]] = vAvg;
2519 yPos++;
2520 cnt += channels;
2521 if (j%2) sampledPos++;
2522 }
2523 buff += pitch2;
2524 if (wOdd) sampledPos++;
2525
2526 if (cb) {
2527 percent += dP;
2528 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2529 }
2530 }
2531 } else if (m_header.channels == 4) {
2532 ASSERT(m_header.bpp == m_header.channels*8);
2533 ASSERT(bpp%dataBits == 0);
2534
2535 DataT* y = m_channel[0]; ASSERT(y);
2536 DataT* u = m_channel[1]; ASSERT(u);
2537 DataT* v = m_channel[2]; ASSERT(v);
2538 DataT* a = m_channel[3]; ASSERT(a);
2539 UINT8 aAvg;
2540 int cnt, channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2541
2542 for (i=0; i < h; i++) {
2543 if (i%2) sampledPos -= (w + 1)/2;
2544 cnt = 0;
2545 for (j=0; j < w; j++) {
2546 if (m_downsample) {
2547 // image was downsampled
2548 uAvg = u[sampledPos];
2549 vAvg = v[sampledPos];
2550 aAvg = Clamp8(a[sampledPos] + yuvOffset);
2551 } else {
2552 uAvg = u[yPos];
2553 vAvg = v[yPos];
2554 aAvg = Clamp8(a[yPos] + yuvOffset);
2555 }
2556 // Yuv
2557 buff[cnt + channelMap[0]] = y[yPos];
2558 buff[cnt + channelMap[1]] = uAvg;
2559 buff[cnt + channelMap[2]] = vAvg;
2560 buff[cnt + channelMap[3]] = aAvg;
2561 yPos++;
2562 cnt += channels;
2563 if (j%2) sampledPos++;
2564 }
2565 buff += pitch2;
2566 if (wOdd) sampledPos++;
2567
2568 if (cb) {
2569 percent += dP;
2570 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2571 }
2572 }
2573 }
2574}
2575
2590void CPGFImage::ImportYUV(int pitch, DataT *buff, BYTE bpp, int channelMap[] /*= NULL*/, CallbackPtr cb /*= NULL*/, void *data /*=NULL*/) THROW_ {
2591 ASSERT(buff);
2592 const double dP = 1.0/m_header.height;
2593 const int dataBits = DataTSize*8; ASSERT(dataBits == 16 || dataBits == 32);
2594 const int pitch2 = pitch/DataTSize;
2595 const int yuvOffset = (dataBits == 16) ? YUVoffset8 : YUVoffset16;
2596
2597 int yPos = 0, cnt = 0;
2598 double percent = 0;
2599 int defMap[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; ASSERT(sizeof(defMap)/sizeof(defMap[0]) == MaxChannels);
2600
2601 if (channelMap == NULL) channelMap = defMap;
2602
2603 if (m_header.channels == 3) {
2604 ASSERT(bpp%dataBits == 0);
2605
2606 DataT* y = m_channel[0]; ASSERT(y);
2607 DataT* u = m_channel[1]; ASSERT(u);
2608 DataT* v = m_channel[2]; ASSERT(v);
2609 const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2610
2611 for (UINT32 h=0; h < m_header.height; h++) {
2612 if (cb) {
2613 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2614 percent += dP;
2615 }
2616
2617 cnt = 0;
2618 for (UINT32 w=0; w < m_header.width; w++) {
2619 y[yPos] = buff[cnt + channelMap[0]];
2620 u[yPos] = buff[cnt + channelMap[1]];
2621 v[yPos] = buff[cnt + channelMap[2]];
2622 yPos++;
2623 cnt += channels;
2624 }
2625 buff += pitch2;
2626 }
2627 } else if (m_header.channels == 4) {
2628 ASSERT(bpp%dataBits == 0);
2629
2630 DataT* y = m_channel[0]; ASSERT(y);
2631 DataT* u = m_channel[1]; ASSERT(u);
2632 DataT* v = m_channel[2]; ASSERT(v);
2633 DataT* a = m_channel[3]; ASSERT(a);
2634 const int channels = bpp/dataBits; ASSERT(channels >= m_header.channels);
2635
2636 for (UINT32 h=0; h < m_header.height; h++) {
2637 if (cb) {
2638 if ((*cb)(percent, true, data)) ReturnWithError(EscapePressed);
2639 percent += dP;
2640 }
2641
2642 cnt = 0;
2643 for (UINT32 w=0; w < m_header.width; w++) {
2644 y[yPos] = buff[cnt + channelMap[0]];
2645 u[yPos] = buff[cnt + channelMap[1]];
2646 v[yPos] = buff[cnt + channelMap[2]];
2647 a[yPos] = buff[cnt + channelMap[3]] - yuvOffset;
2648 yPos++;
2649 cnt += channels;
2650 }
2651 buff += pitch2;
2652 }
2653 }
2654
2655 if (m_downsample) {
2656 // Subsampling of the chrominance and alpha channels
2657 for (int i=1; i < m_header.channels; i++) {
2658 Downsample(i);
2659 }
2660 }
2661}
2662
UINT32 AlignWordPos(UINT32 pos)
Definition: BitStream.h:260
PGF decoder class.
PGF encoder class.
#define YUVoffset8
Definition: PGFimage.cpp:37
#define YUVoffset4
Definition: PGFimage.cpp:35
#define YUVoffset16
Definition: PGFimage.cpp:38
#define YUVoffset6
Definition: PGFimage.cpp:36
PGF image class.
@ PM_Relative
Definition: PGFimage.h:36
@ PM_Absolute
Definition: PGFimage.h:36
#define ImageModeRGBColor
Definition: PGFplatform.h:101
#define ImageModeRGB12
Definition: PGFplatform.h:117
#define ImageModeGray32
Definition: PGFplatform.h:116
#define ImageModeHSLColor
Definition: PGFplatform.h:103
#define ImageModeUnknown
Definition: PGFplatform.h:119
#define ImageModeBitmap
Definition: PGFplatform.h:98
#define __PGFROISUPPORT__
Definition: PGFplatform.h:60
#define ImageModeLabColor
Definition: PGFplatform.h:107
#define ImageModeRGB16
Definition: PGFplatform.h:118
#define ImageModeRGBA
Definition: PGFplatform.h:115
#define ImageModeRGB48
Definition: PGFplatform.h:109
#define ImageModeCMYK64
Definition: PGFplatform.h:111
#define ImageModeGrayScale
Definition: PGFplatform.h:99
#define ImageModeHSBColor
Definition: PGFplatform.h:104
#define __min(x, y)
Definition: PGFplatform.h:91
#define ImageModeLab48
Definition: PGFplatform.h:110
#define ImageModeGray16
Definition: PGFplatform.h:108
#define ImageModeIndexedColor
Definition: PGFplatform.h:100
#define ImageModeCMYKColor
Definition: PGFplatform.h:102
#define __max(x, y)
Definition: PGFplatform.h:92
#define MaxLevel
maximum number of transform levels
Definition: PGFtypes.h:56
#define HeaderSize
Definition: PGFtypes.h:231
#define ColorTableSize
Definition: PGFtypes.h:232
#define PGFMagic
PGF identification.
Definition: PGFtypes.h:55
#define MaxQuality
maximum quality
Definition: PGFtypes.h:87
@ LL
Definition: PGFtypes.h:92
@ HL
Definition: PGFtypes.h:92
@ LH
Definition: PGFtypes.h:92
@ HH
Definition: PGFtypes.h:92
#define MaxChannels
maximum number of (color) channels
Definition: PGFtypes.h:58
#define Version5
new coding scheme since major version 5
Definition: PGFtypes.h:65
#define ColorTableLen
size of color lookup table (clut)
Definition: PGFtypes.h:60
#define Version2
data structure PGFHeader of major version 2
Definition: PGFtypes.h:62
#define Version6
new HeaderSize: 32 bits instead of 16 bits
Definition: PGFtypes.h:66
#define PGFVersion
current standard version
Definition: PGFtypes.h:69
#define DownsampleThreshold
if quality is larger than this threshold than downsampling is used
Definition: PGFtypes.h:59
INT32 DataT
Definition: PGFtypes.h:219
#define DataTSize
Definition: PGFtypes.h:233
#define FilterHeight
number of coefficients of the column wavelet filter
#define FilterWidth
number of coefficients of the row wavelet filter
PGF decoder.
Definition: Decoder.h:46
void SetStreamPosToStart() THROW_
Reset stream position to beginning of PGF pre-header.
Definition: Decoder.h:141
UINT32 GetEncodedHeaderLength() const
Definition: Decoder.h:137
PGF encoder.
Definition: Encoder.h:46
INT64 ComputeOffset() const
Definition: Encoder.h:184
UINT32 WriteLevelLength(UINT32 *&levelLength) THROW_
Definition: Encoder.cpp:177
void SetEncodedLevel(int currentLevel)
Definition: Encoder.h:162
void UpdatePostHeaderSize(PGFPreHeader preHeader) THROW_
Definition: Encoder.cpp:160
void SetColorTable(UINT32 iFirstColor, UINT32 nColors, const RGBQUAD *prgbColors) THROW_
Definition: PGFimage.cpp:1307
UINT32 WriteImage(CPGFStream *stream, CallbackPtr cb=NULL, void *data=NULL) THROW_
Definition: PGFimage.cpp:1093
bool CompleteHeader()
Definition: PGFimage.cpp:208
CDecoder * m_decoder
PGF decoder.
Definition: PGFimage.h:513
void RgbToYuv(int pitch, UINT8 *rgbBuff, BYTE bpp, int channelMap[], CallbackPtr cb, void *data) THROW_
Definition: PGFimage.cpp:1332
void SetHeader(const PGFHeader &header, BYTE flags=0, UINT8 *userData=0, UINT32 userDataLength=0) THROW_
Definition: PGFimage.cpp:845
UINT32 * m_levelLength
length of each level in bytes; first level starts immediately after this array
Definition: PGFimage.h:515
UINT32 m_height[MaxChannels]
height of each channel at current level
Definition: PGFimage.h:517
PGFHeader m_header
PGF file header.
Definition: PGFimage.h:519
virtual ~CPGFImage()
Destructor: Destroy internal data structures.
Definition: PGFimage.cpp:98
void Downsample(int nChannel)
Definition: PGFimage.cpp:761
UINT32 UpdatePostHeaderSize() THROW_
Definition: PGFimage.cpp:1068
int m_currentLevel
transform level of current image
Definition: PGFimage.h:522
UINT32 ReadEncodedHeader(UINT8 *target, UINT32 targetLen) const THROW_
Definition: PGFimage.cpp:626
void WriteLevel() THROW_
Definition: PGFimage.cpp:1013
DataT * m_channel[MaxChannels]
untransformed channels in YUV format
Definition: PGFimage.h:512
void Write(CPGFStream *stream, UINT32 *nWrittenBytes=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_
Definition: PGFimage.cpp:1164
static BYTE CurrentVersion(BYTE version=PGFVersion)
Return version.
Definition: PGFimage.cpp:721
UINT32 WriteHeader(CPGFStream *stream) THROW_
Definition: PGFimage.cpp:924
const UINT8 * GetUserData(UINT32 &size) const
Definition: PGFimage.cpp:323
virtual void Destroy()
Definition: PGFimage.cpp:105
static bool ImportIsSupported(BYTE mode)
Definition: PGFimage.cpp:1248
void SetMaxValue(UINT32 maxValue)
Definition: PGFimage.cpp:691
BYTE UsedBitsPerChannel() const
Definition: PGFimage.cpp:709
CEncoder * m_encoder
PGF encoder.
Definition: PGFimage.h:514
PGFRect m_roi
region of interest
Definition: PGFimage.h:531
void SetROI(PGFRect rect)
void Read(int level=0, CallbackPtr cb=NULL, void *data=NULL) THROW_
Definition: PGFimage.cpp:385
bool m_downsample
chrominance channels are downsampled
Definition: PGFimage.h:524
bool ROIisSupported() const
Definition: PGFimage.h:465
void ResetStreamPos() THROW_
Reset stream position to start of PGF pre-header.
Definition: PGFimage.cpp:646
void Open(CPGFStream *stream) THROW_
Definition: PGFimage.cpp:131
void Reconstruct(int level=0) THROW_
Definition: PGFimage.cpp:333
UINT32 m_width[MaxChannels]
width of each channel at current level
Definition: PGFimage.h:516
PGFPostHeader m_postHeader
PGF post-header.
Definition: PGFimage.h:520
void GetYUV(int pitch, DataT *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) const THROW_
Definition: PGFimage.cpp:2479
const RGBQUAD * GetColorTable() const
Definition: PGFimage.h:334
UINT64 m_userDataPos
stream position of user data
Definition: PGFimage.h:521
UINT32 GetEncodedHeaderLength() const
Definition: PGFimage.cpp:614
void ComputeLevels()
Definition: PGFimage.cpp:805
PGFPreHeader m_preHeader
PGF pre-header.
Definition: PGFimage.h:518
double m_percent
progress [0..1]
Definition: PGFimage.h:537
void ImportYUV(int pitch, DataT *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_
Definition: PGFimage.cpp:2590
CWaveletTransform * m_wtChannel[MaxChannels]
wavelet transformed color channels
Definition: PGFimage.h:511
virtual void Close()
Definition: PGFimage.cpp:122
CPGFImage()
Standard constructor: It is used to create a PGF instance for opening and reading.
Definition: PGFimage.cpp:55
void ImportBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) THROW_
Definition: PGFimage.cpp:744
UINT32 ReadEncodedData(int level, UINT8 *target, UINT32 targetLen) const THROW_
Definition: PGFimage.cpp:660
void GetBitmap(int pitch, UINT8 *buff, BYTE bpp, int channelMap[]=NULL, CallbackPtr cb=NULL, void *data=NULL) const THROW_
Definition: PGFimage.cpp:1721
Abstract stream base class.
Definition: PGFstream.h:39
void ExtractTile(CEncoder &encoder, bool tile=false, UINT32 tileX=0, UINT32 tileY=0) THROW_
Definition: Subband.cpp:177
PGF wavelet transform.
CSubband * GetSubband(int level, Orientation orientation)
PGF header.
Definition: PGFtypes.h:123
UINT8 mode
image mode according to Adobe's image modes
Definition: PGFtypes.h:131
UINT32 height
image height in pixels
Definition: PGFtypes.h:126
UINT32 width
image width in pixels
Definition: PGFtypes.h:125
UINT8 nLevels
number of DWT levels
Definition: PGFtypes.h:127
UINT8 channels
number of channels
Definition: PGFtypes.h:130
UINT8 usedBitsPerChannel
number of used bits per channel in 16- and 32-bit per channel modes
Definition: PGFtypes.h:132
UINT8 bpp
bits per pixel
Definition: PGFtypes.h:129
char magic[3]
PGF identification = "PGF".
Definition: PGFtypes.h:105
UINT8 version
PGF version.
Definition: PGFtypes.h:106
UINT32 userDataLen
user data size in bytes
Definition: PGFtypes.h:144
UINT8 * userData
user data of size userDataLen
Definition: PGFtypes.h:143
UINT32 hSize
total size of PGFHeader, [ColorTable], and [UserData] in bytes
Definition: PGFtypes.h:115
Rectangle.
Definition: PGFtypes.h:194
UINT32 Height() const
Definition: PGFtypes.h:207
bool IsInside(UINT32 x, UINT32 y) const
Definition: PGFtypes.h:213
UINT32 Width() const
Definition: PGFtypes.h:205
UINT32 top
Definition: PGFtypes.h:215
UINT32 bottom
Definition: PGFtypes.h:215
UINT32 right
Definition: PGFtypes.h:215
UINT32 left
Definition: PGFtypes.h:215