1 /*
2 * The Progressive Graphics File; http://www.libpgf.org
3 *
4 * $Date: 2006-06-04 22:05:59 +0200 (So, 04 Jun 2006) $
5 * $Revision: 229 $
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
24 //////////////////////////////////////////////////////////////////////
25 /// @file Subband.cpp
26 /// @brief PGF wavelet subband class implementation
27 /// @author C. Stamm
28
29 #include "Subband.h"
30 #include "Encoder.h"
31 #include "Decoder.h"
32
33 /////////////////////////////////////////////////////////////////////
34 // Default constructor
CSubband()35 CSubband::CSubband()
36 : m_width(0)
37 , m_height(0)
38 , m_size(0)
39 , m_level(0)
40 , m_orientation(LL)
41 , m_data(0)
42 , m_dataPos(0)
43 #ifdef __PGFROISUPPORT__
44 , m_nTiles(0)
45 #endif
46 {
47 }
48
49 /////////////////////////////////////////////////////////////////////
50 // Destructor
~CSubband()51 CSubband::~CSubband() {
52 FreeMemory();
53 }
54
55 /////////////////////////////////////////////////////////////////////
56 // Initialize subband parameters
Initialize(UINT32 width,UINT32 height,int level,Orientation orient)57 void CSubband::Initialize(UINT32 width, UINT32 height, int level, Orientation orient) {
58 m_width = width;
59 m_height = height;
60 m_size = m_width*m_height;
61 m_level = level;
62 m_orientation = orient;
63 m_data = 0;
64 m_dataPos = 0;
65 #ifdef __PGFROISUPPORT__
66 m_ROI.left = 0;
67 m_ROI.top = 0;
68 m_ROI.right = m_width;
69 m_ROI.bottom = m_height;
70 m_nTiles = 0;
71 #endif
72 }
73
74 /////////////////////////////////////////////////////////////////////
75 // Allocate a memory buffer to store all wavelet coefficients of this subband.
76 // @return True if the allocation works without any problems
AllocMemory()77 bool CSubband::AllocMemory() {
78 UINT32 oldSize = m_size;
79
80 #ifdef __PGFROISUPPORT__
81 m_size = BufferWidth()*m_ROI.Height();
82 #endif
83 ASSERT(m_size > 0);
84
85 if (m_data) {
86 if (oldSize >= m_size) {
87 return true;
88 } else {
89 delete[] m_data;
90 m_data = new(std::nothrow) DataT[m_size];
91 return (m_data != 0);
92 }
93 } else {
94 m_data = new(std::nothrow) DataT[m_size];
95 return (m_data != 0);
96 }
97 }
98
99 /////////////////////////////////////////////////////////////////////
100 // Delete the memory buffer of this subband.
FreeMemory()101 void CSubband::FreeMemory() {
102 if (m_data) {
103 delete[] m_data; m_data = 0;
104 }
105 }
106
107 /////////////////////////////////////////////////////////////////////
108 // Perform subband quantization with given quantization parameter.
109 // A scalar quantization (with dead-zone) is used. A large quantization value
110 // results in strong quantization and therefore in big quality loss.
111 // @param quantParam A quantization parameter (larger or equal to 0)
Quantize(int quantParam)112 void CSubband::Quantize(int quantParam) {
113 if (m_orientation == LL) {
114 quantParam -= (m_level + 1);
115 // uniform rounding quantization
116 if (quantParam > 0) {
117 quantParam--;
118 for (UINT32 i=0; i < m_size; i++) {
119 if (m_data[i] < 0) {
120 m_data[i] = -(((-m_data[i] >> quantParam) + 1) >> 1);
121 } else {
122 m_data[i] = ((m_data[i] >> quantParam) + 1) >> 1;
123 }
124 }
125 }
126 } else {
127 if (m_orientation == HH) {
128 quantParam -= (m_level - 1);
129 } else {
130 quantParam -= m_level;
131 }
132 // uniform deadzone quantization
133 if (quantParam > 0) {
134 int threshold = ((1 << quantParam) * 7)/5; // good value
135 quantParam--;
136 for (UINT32 i=0; i < m_size; i++) {
137 if (m_data[i] < -threshold) {
138 m_data[i] = -(((-m_data[i] >> quantParam) + 1) >> 1);
139 } else if (m_data[i] > threshold) {
140 m_data[i] = ((m_data[i] >> quantParam) + 1) >> 1;
141 } else {
142 m_data[i] = 0;
143 }
144 }
145 }
146 }
147 }
148
149 //////////////////////////////////////////////////////////////////////
150 /// Perform subband dequantization with given quantization parameter.
151 /// A scalar quantization (with dead-zone) is used. A large quantization value
152 /// results in strong quantization and therefore in big quality loss.
153 /// @param quantParam A quantization parameter (larger or equal to 0)
Dequantize(int quantParam)154 void CSubband::Dequantize(int quantParam) {
155 if (m_orientation == LL) {
156 quantParam -= m_level + 1;
157 } else if (m_orientation == HH) {
158 quantParam -= m_level - 1;
159 } else {
160 quantParam -= m_level;
161 }
162 if (quantParam > 0) {
163 for (UINT32 i=0; i < m_size; i++) {
164 m_data[i] <<= quantParam;
165 }
166 }
167 }
168
169 /////////////////////////////////////////////////////////////////////
170 /// Extracts a rectangular subregion of this subband.
171 /// Write wavelet coefficients into buffer.
172 /// It might throw an IOException.
173 /// @param encoder An encoder instance
174 /// @param tile True if just a rectangular region is extracted, false if the entire subband is extracted.
175 /// @param tileX Tile index in x-direction
176 /// @param tileY Tile index in y-direction
ExtractTile(CEncoder & encoder,bool tile,UINT32 tileX,UINT32 tileY)177 void CSubband::ExtractTile(CEncoder& encoder, bool tile /*= false*/, UINT32 tileX /*= 0*/, UINT32 tileY /*= 0*/) {
178 #ifdef __PGFROISUPPORT__
179 if (tile) {
180 // compute tile position and size
181 UINT32 xPos, yPos, w, h;
182 TilePosition(tileX, tileY, xPos, yPos, w, h);
183
184 // write values into buffer using partitiong scheme
185 encoder.Partition(this, w, h, xPos + yPos*m_width, m_width);
186 } else
187 #endif
188 {
189 tileX; tileY; tile; // prevents from unreferenced formal parameter warning
190 // write values into buffer using partitiong scheme
191 encoder.Partition(this, m_width, m_height, 0, m_width);
192 }
193 }
194
195 /////////////////////////////////////////////////////////////////////
196 /// Decoding and dequantization of this subband.
197 /// It might throw an IOException.
198 /// @param decoder A decoder instance
199 /// @param quantParam Dequantization value
200 /// @param tile True if just a rectangular region is placed, false if the entire subband is placed.
201 /// @param tileX Tile index in x-direction
202 /// @param tileY Tile index in y-direction
PlaceTile(CDecoder & decoder,int quantParam,bool tile,UINT32 tileX,UINT32 tileY)203 void CSubband::PlaceTile(CDecoder& decoder, int quantParam, bool tile /*= false*/, UINT32 tileX /*= 0*/, UINT32 tileY /*= 0*/) {
204 // allocate memory
205 if (!AllocMemory()) ReturnWithError(InsufficientMemory);
206
207 // correct quantParam with normalization factor
208 if (m_orientation == LL) {
209 quantParam -= m_level + 1;
210 } else if (m_orientation == HH) {
211 quantParam -= m_level - 1;
212 } else {
213 quantParam -= m_level;
214 }
215 if (quantParam < 0) quantParam = 0;
216
217 #ifdef __PGFROISUPPORT__
218 if (tile) {
219 UINT32 xPos, yPos, w, h;
220
221 // compute tile position and size
222 TilePosition(tileX, tileY, xPos, yPos, w, h);
223
224 ASSERT(xPos >= m_ROI.left && yPos >= m_ROI.top);
225 decoder.Partition(this, quantParam, w, h, (xPos - m_ROI.left) + (yPos - m_ROI.top)*BufferWidth(), BufferWidth());
226 } else
227 #endif
228 {
229 tileX; tileY; tile; // prevents from unreferenced formal parameter warning
230 // read values into buffer using partitiong scheme
231 decoder.Partition(this, quantParam, m_width, m_height, 0, m_width);
232 }
233 }
234
235
236
237 #ifdef __PGFROISUPPORT__
238 //////////////////////////////////////////////////////////////////////
239 /// Set ROI
SetAlignedROI(const PGFRect & roi)240 void CSubband::SetAlignedROI(const PGFRect& roi) {
241 ASSERT(roi.left <= m_width);
242 ASSERT(roi.top <= m_height);
243
244 m_ROI = roi;
245 if (m_ROI.right > m_width) m_ROI.right = m_width;
246 if (m_ROI.bottom > m_height) m_ROI.bottom = m_height;
247 }
248
249 //////////////////////////////////////////////////////////////////////
250 /// Compute tile position and size.
251 /// @param tileX Tile index in x-direction
252 /// @param tileY Tile index in y-direction
253 /// @param xPos [out] Offset to left
254 /// @param yPos [out] Offset to top
255 /// @param w [out] Tile width
256 /// @param h [out] Tile height
TilePosition(UINT32 tileX,UINT32 tileY,UINT32 & xPos,UINT32 & yPos,UINT32 & w,UINT32 & h) const257 void CSubband::TilePosition(UINT32 tileX, UINT32 tileY, UINT32& xPos, UINT32& yPos, UINT32& w, UINT32& h) const {
258 ASSERT(tileX < m_nTiles); ASSERT(tileY < m_nTiles);
259 // example
260 // band = HH, w = 30, ldTiles = 2 -> 4 tiles in a row/column
261 // --> tile widths
262 // 8 7 8 7
263 //
264 // tile partitioning scheme
265 // 0 1 2 3
266 // 4 5 6 7
267 // 8 9 A B
268 // C D E F
269
270 UINT32 nTiles = m_nTiles;
271 UINT32 m;
272 UINT32 left = 0, right = nTiles;
273 UINT32 top = 0, bottom = nTiles;
274
275 xPos = 0;
276 yPos = 0;
277 w = m_width;
278 h = m_height;
279
280 while (nTiles > 1) {
281 // compute xPos and w with binary search
282 m = left + ((right - left) >> 1);
283 if (tileX >= m) {
284 xPos += (w + 1) >> 1;
285 w >>= 1;
286 left = m;
287 } else {
288 w = (w + 1) >> 1;
289 right = m;
290 }
291 // compute yPos and h with binary search
292 m = top + ((bottom - top) >> 1);
293 if (tileY >= m) {
294 yPos += (h + 1) >> 1;
295 h >>= 1;
296 top = m;
297 } else {
298 h = (h + 1) >> 1;
299 bottom = m;
300 }
301 nTiles >>= 1;
302 }
303 ASSERT(xPos < m_width && (xPos + w <= m_width));
304 ASSERT(yPos < m_height && (yPos + h <= m_height));
305 }
306
307 //////////////////////////////////////////////////////////////////////
308 /// Compute tile index and extrem position (x,y) of given position (xPos, yPos).
TileIndex(bool topLeft,UINT32 xPos,UINT32 yPos,UINT32 & tileX,UINT32 & tileY,UINT32 & x,UINT32 & y) const309 void CSubband::TileIndex(bool topLeft, UINT32 xPos, UINT32 yPos, UINT32& tileX, UINT32& tileY, UINT32& x, UINT32& y) const {
310 UINT32 m;
311 UINT32 left = 0, right = m_width;
312 UINT32 top = 0, bottom = m_height;
313 UINT32 nTiles = m_nTiles;
314
315 if (xPos > m_width) xPos = m_width;
316 if (yPos > m_height) yPos = m_height;
317
318 if (topLeft) {
319 // compute tileX with binary search
320 tileX = 0;
321 while (nTiles > 1) {
322 nTiles >>= 1;
323 m = left + ((right - left + 1) >> 1);
324 if (xPos < m) {
325 // exclusive m
326 right = m;
327 } else {
328 tileX += nTiles;
329 left = m;
330 }
331 }
332 x = left;
333 ASSERT(tileX >= 0 && tileX < m_nTiles);
334
335 // compute tileY with binary search
336 nTiles = m_nTiles;
337 tileY = 0;
338 while (nTiles > 1) {
339 nTiles >>= 1;
340 m = top + ((bottom - top + 1) >> 1);
341 if (yPos < m) {
342 // exclusive m
343 bottom = m;
344 } else {
345 tileY += nTiles;
346 top = m;
347 }
348 }
349 y = top;
350 ASSERT(tileY >= 0 && tileY < m_nTiles);
351
352 } else {
353 // compute tileX with binary search
354 tileX = 1;
355 while (nTiles > 1) {
356 nTiles >>= 1;
357 m = left + ((right - left + 1) >> 1);
358 if (xPos <= m) {
359 // inclusive m
360 right = m;
361 } else {
362 tileX += nTiles;
363 left = m;
364 }
365 }
366 x = right;
367 ASSERT(tileX > 0 && tileX <= m_nTiles);
368
369 // compute tileY with binary search
370 nTiles = m_nTiles;
371 tileY = 1;
372 while (nTiles > 1) {
373 nTiles >>= 1;
374 m = top + ((bottom - top + 1) >> 1);
375 if (yPos <= m) {
376 // inclusive m
377 bottom = m;
378 } else {
379 tileY += nTiles;
380 top = m;
381 }
382 }
383 y = bottom;
384 ASSERT(tileY > 0 && tileY <= m_nTiles);
385 }
386 }
387
388 #endif
389