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