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