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