File indexing completed on 2025-01-19 03:56:11

0001 /*
0002  * The Progressive Graphics File; http://www.libpgf.org
0003  *
0004  * $Date: 2006-05-18 16:03:32 +0200 (Do, 18 Mai 2006) $
0005  * $Revision: 194 $
0006  *
0007  * This file Copyright (C) 2006 xeraina GmbH, Switzerland
0008  *
0009  * This program is free software; you can redistribute it and/or
0010  * modify it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
0011  * as published by the Free Software Foundation; either version 2.1
0012  * of the License, or (at your option) any later version.
0013  *
0014  * This program is distributed in the hope that it will be useful,
0015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017  * GNU General Public License for more details.
0018  *
0019  * You should have received a copy of the GNU General Public License
0020  * along with this program; if not, write to the Free Software
0021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0022  */
0023 
0024 //////////////////////////////////////////////////////////////////////
0025 /// @file WaveletTransform.cpp
0026 /// @brief PGF wavelet transform class implementation
0027 /// @author C. Stamm
0028 
0029 #include "WaveletTransform.h"
0030 
0031 #define c1 1    // best value 1
0032 #define c2 2    // best value 2
0033 
0034 //////////////////////////////////////////////////////////////////////////
0035 // Constructor: Constructs a wavelet transform pyramid of given size and levels.
0036 // @param width The width of the original image (at level 0) in pixels
0037 // @param height The height of the original image (at level 0) in pixels
0038 // @param levels The number of levels (>= 0)
0039 // @param data Input data of subband LL at level 0
0040 CWaveletTransform::CWaveletTransform(UINT32 width, UINT32 height, int levels, DataT* data)
0041 : m_nLevels(levels + 1) // m_nLevels in CPGFImage determines the number of FWT steps; this.m_nLevels determines the number subband-planes
0042 , m_subband(nullptr)
0043 #ifdef __PGFROISUPPORT__
0044 , m_indices(nullptr)
0045 #endif
0046 {
0047     ASSERT(m_nLevels > 0 && m_nLevels <= MaxLevel + 1);
0048     InitSubbands(width, height, data);
0049 }
0050 
0051 /////////////////////////////////////////////////////////////////////
0052 // Initialize size subbands on all levels
0053 void CWaveletTransform::InitSubbands(UINT32 width, UINT32 height, DataT* data) {
0054     if (m_subband) Destroy();
0055 
0056     // create subbands
0057     m_subband = new CSubband[m_nLevels][NSubbands];
0058 
0059     // init subbands
0060     UINT32 loWidth = width;
0061     UINT32 hiWidth = width;
0062     UINT32 loHeight = height;
0063     UINT32 hiHeight = height;
0064 
0065     for (int level = 0; level < m_nLevels; level++) {
0066         m_subband[level][LL].Initialize(loWidth, loHeight, level, LL);  // LL
0067         m_subband[level][HL].Initialize(hiWidth, loHeight, level, HL);  //    HL
0068         m_subband[level][LH].Initialize(loWidth, hiHeight, level, LH);  // LH
0069         m_subband[level][HH].Initialize(hiWidth, hiHeight, level, HH);  //    HH
0070         hiWidth = loWidth >> 1;         hiHeight = loHeight >> 1;
0071         loWidth = (loWidth + 1) >> 1;   loHeight = (loHeight + 1) >> 1;
0072     }
0073     if (data) {
0074         m_subband[0][LL].SetBuffer(data);
0075     }
0076 }
0077 
0078 //////////////////////////////////////////////////////////////////////////
0079 // Compute fast forward wavelet transform of LL subband at given level and
0080 // stores result in all 4 subbands of level + 1.
0081 // Wavelet transform used in writing a PGF file
0082 // Forward Transform of srcBand and split and store it into subbands on destLevel
0083 // low pass filter at even positions: 1/8[-1, 2, (6), 2, -1]
0084 // high pass filter at odd positions: 1/4[-2, (4), -2]
0085 // @param level A wavelet transform pyramid level (>= 0 && < Levels())
0086 // @param quant A quantization value (linear scalar quantization)
0087 // @return error in case of a memory allocation problem
0088 OSError CWaveletTransform::ForwardTransform(int level, int quant) {
0089     ASSERT(level >= 0 && level < m_nLevels - 1);
0090     const int destLevel = level + 1;
0091     ASSERT(m_subband[destLevel]);
0092     CSubband* srcBand = &m_subband[level][LL]; ASSERT(srcBand);
0093     const UINT32 width = srcBand->GetWidth();
0094     const UINT32 height = srcBand->GetHeight();
0095     DataT* src = srcBand->GetBuffer(); ASSERT(src);
0096     DataT *row0, *row1, *row2, *row3;
0097 
0098     // Allocate memory for next transform level
0099     for (int i=0; i < NSubbands; i++) {
0100         if (!m_subband[destLevel][i].AllocMemory()) return InsufficientMemory;
0101     }
0102 
0103     if (height >= FilterSize) { // changed from FilterSizeH to FilterSize
0104         // top border handling
0105         row0 = src; row1 = row0 + width; row2 = row1 + width;
0106         ForwardRow(row0, width);
0107         ForwardRow(row1, width);
0108         ForwardRow(row2, width);
0109         for (UINT32 k=0; k < width; k++) {
0110             row1[k] -= ((row0[k] + row2[k] + c1) >> 1); // high pass
0111             row0[k] += ((row1[k] + c1) >> 1); // low pass
0112         }
0113         InterleavedToSubbands(destLevel, row0, row1, width);
0114         row0 = row1; row1 = row2; row2 += width; row3 = row2 + width;
0115 
0116         // middle part
0117         for (UINT32 i=3; i < height-1; i += 2) {
0118             ForwardRow(row2, width);
0119             ForwardRow(row3, width);
0120             for (UINT32 k=0; k < width; k++) {
0121                 row2[k] -= ((row1[k] + row3[k] + c1) >> 1); // high pass filter
0122                 row1[k] += ((row0[k] + row2[k] + c2) >> 2); // low pass filter
0123             }
0124             InterleavedToSubbands(destLevel, row1, row2, width);
0125             row0 = row2; row1 = row3; row2 = row3 + width; row3 = row2 + width;
0126         }
0127 
0128         // bottom border handling
0129         if (height & 1) {
0130             for (UINT32 k=0; k < width; k++) {
0131                 row1[k] += ((row0[k] + c1) >> 1); // low pass
0132             }
0133             InterleavedToSubbands(destLevel, row1, nullptr, width);
0134             row0 = row1; row1 += width;
0135         } else {
0136             ForwardRow(row2, width);
0137             for (UINT32 k=0; k < width; k++) {
0138                 row2[k] -= row1[k]; // high pass
0139                 row1[k] += ((row0[k] + row2[k] + c2) >> 2); // low pass
0140             }
0141             InterleavedToSubbands(destLevel, row1, row2, width);
0142             row0 = row1; row1 = row2; row2 += width;
0143         }
0144     } else {
0145         // if height is too small
0146         row0 = src; row1 = row0 + width;
0147         // first part
0148         for (UINT32 k=0; k < height; k += 2) {
0149             ForwardRow(row0, width);
0150             ForwardRow(row1, width);
0151             InterleavedToSubbands(destLevel, row0, row1, width);
0152             row0 += width << 1; row1 += width << 1;
0153         }
0154         // bottom
0155         if (height & 1) {
0156             InterleavedToSubbands(destLevel, row0, nullptr, width);
0157         }
0158     }
0159 
0160     if (quant > 0) {
0161         // subband quantization (without LL)
0162         for (int i=1; i < NSubbands; i++) {
0163             m_subband[destLevel][i].Quantize(quant);
0164         }
0165         // LL subband quantization
0166         if (destLevel == m_nLevels - 1) {
0167             m_subband[destLevel][LL].Quantize(quant);
0168         }
0169     }
0170 
0171     // free source band
0172     srcBand->FreeMemory();
0173     return NoError;
0174 }
0175 
0176 //////////////////////////////////////////////////////////////
0177 // Forward transform one row
0178 // low pass filter at even positions: 1/8[-1, 2, (6), 2, -1]
0179 // high pass filter at odd positions: 1/4[-2, (4), -2]
0180 void CWaveletTransform::ForwardRow(DataT* src, UINT32 width) {
0181     if (width >= FilterSize) {
0182         UINT32 i = 3;
0183 
0184         // left border handling
0185         src[1] -= ((src[0] + src[2] + c1) >> 1); // high pass
0186         src[0] += ((src[1] + c1) >> 1); // low pass
0187 
0188         // middle part
0189         for (; i < width-1; i += 2) {
0190             src[i] -= ((src[i-1] + src[i+1] + c1) >> 1); // high pass
0191             src[i-1] += ((src[i-2] + src[i] + c2) >> 2); // low pass
0192         }
0193 
0194         // right border handling
0195         if (width & 1) {
0196             src[i-1] += ((src[i-2] + c1) >> 1); // low pass
0197         } else {
0198             src[i] -= src[i-1]; // high pass
0199             src[i-1] += ((src[i-2] + src[i] + c2) >> 2); // low pass
0200         }
0201     }
0202 }
0203 
0204 /////////////////////////////////////////////////////////////////
0205 // Copy transformed and interleaved (L,H,L,H,...) rows loRow and hiRow to subbands LL,HL,LH,HH
0206 void CWaveletTransform::InterleavedToSubbands(int destLevel, DataT* loRow, DataT* hiRow, UINT32 width) {
0207     const UINT32 wquot = width >> 1;
0208     const bool wrem = (width & 1);
0209     CSubband &ll = m_subband[destLevel][LL], &hl = m_subband[destLevel][HL];
0210     CSubband &lh = m_subband[destLevel][LH], &hh = m_subband[destLevel][HH];
0211 
0212     if (hiRow) {
0213         for (UINT32 i=0; i < wquot; i++) {
0214             ll.WriteBuffer(*loRow++);   // first access, than increment
0215             hl.WriteBuffer(*loRow++);
0216             lh.WriteBuffer(*hiRow++);   // first access, than increment
0217             hh.WriteBuffer(*hiRow++);
0218         }
0219         if (wrem) {
0220             ll.WriteBuffer(*loRow);
0221             lh.WriteBuffer(*hiRow);
0222         }
0223     } else {
0224         for (UINT32 i=0; i < wquot; i++) {
0225             ll.WriteBuffer(*loRow++);   // first access, than increment
0226             hl.WriteBuffer(*loRow++);
0227         }
0228         if (wrem) ll.WriteBuffer(*loRow);
0229     }
0230 }
0231 
0232 //////////////////////////////////////////////////////////////////////////
0233 // Compute fast inverse wavelet transform of all 4 subbands of given level and
0234 // stores result in LL subband of level - 1.
0235 // Inverse wavelet transform used in reading a PGF file
0236 // Inverse Transform srcLevel and combine to destBand
0237 // low-pass coefficients at even positions, high-pass coefficients at odd positions
0238 // inverse filter for even positions: 1/4[-1, (4), -1]
0239 // inverse filter for odd positions: 1/8[-1, 4, (6), 4, -1]
0240 // @param srcLevel A wavelet transform pyramid level (> 0 && <= Levels())
0241 // @param w [out] A pointer to the returned width of subband LL (in pixels)
0242 // @param h [out] A pointer to the returned height of subband LL (in pixels)
0243 // @param data [out] A pointer to the returned array of image data
0244 // @return error in case of a memory allocation problem
0245 OSError CWaveletTransform::InverseTransform(int srcLevel, UINT32* w, UINT32* h, DataT** data) {
0246     ASSERT(srcLevel > 0 && srcLevel < m_nLevels);
0247     const int destLevel = srcLevel - 1;
0248     ASSERT(m_subband[destLevel]);
0249     CSubband* destBand = &m_subband[destLevel][LL];
0250     UINT32 width, height;
0251 
0252     // allocate memory for the results of the inverse transform
0253     if (!destBand->AllocMemory()) return InsufficientMemory;
0254     DataT *origin = destBand->GetBuffer(), *row0, *row1, *row2, *row3;
0255 
0256 #ifdef __PGFROISUPPORT__
0257     PGFRect destROI = destBand->GetAlignedROI();
0258     const UINT32 destWidth  = destROI.Width();  // destination buffer width
0259     const UINT32 destHeight = destROI.Height(); // destination buffer height
0260     width = destWidth;      // destination working width
0261     height = destHeight;    // destination working height
0262 
0263     // update destination ROI
0264     if (destROI.top & 1) {
0265         destROI.top++;
0266         origin += destWidth;
0267         height--;
0268     }
0269     if (destROI.left & 1) {
0270         destROI.left++;
0271         origin++;
0272         width--;
0273     }
0274 
0275     // init source buffer position
0276     const UINT32 leftD = destROI.left >> 1;
0277     const UINT32 left0 = m_subband[srcLevel][LL].GetAlignedROI().left;
0278     const UINT32 left1 = m_subband[srcLevel][HL].GetAlignedROI().left;
0279     const UINT32 topD = destROI.top >> 1;
0280     const UINT32 top0 = m_subband[srcLevel][LL].GetAlignedROI().top;
0281     const UINT32 top1 = m_subband[srcLevel][LH].GetAlignedROI().top;
0282     ASSERT(m_subband[srcLevel][LH].GetAlignedROI().left == left0);
0283     ASSERT(m_subband[srcLevel][HH].GetAlignedROI().left == left1);
0284     ASSERT(m_subband[srcLevel][HL].GetAlignedROI().top == top0);
0285     ASSERT(m_subband[srcLevel][HH].GetAlignedROI().top == top1);
0286 
0287     UINT32 srcOffsetX[2] = { 0, 0 };
0288     UINT32 srcOffsetY[2] = { 0, 0 };
0289 
0290     if (leftD >= __max(left0, left1)) {
0291         srcOffsetX[0] = leftD - left0;
0292         srcOffsetX[1] = leftD - left1;
0293     } else {
0294         if (left0 <= left1) {
0295             const UINT32 dx = (left1 - leftD) << 1;
0296             destROI.left += dx;
0297             origin += dx;
0298             width -= dx;
0299             srcOffsetX[0] = left1 - left0;
0300         } else {
0301             const UINT32 dx = (left0 - leftD) << 1;
0302             destROI.left += dx;
0303             origin += dx;
0304             width -= dx;
0305             srcOffsetX[1] = left0 - left1;
0306         }
0307     }
0308     if (topD >= __max(top0, top1)) {
0309         srcOffsetY[0] = topD - top0;
0310         srcOffsetY[1] = topD - top1;
0311     } else {
0312         if (top0 <= top1) {
0313             const UINT32 dy = (top1 - topD) << 1;
0314             destROI.top += dy;
0315             origin += dy*destWidth;
0316             height -= dy;
0317             srcOffsetY[0] = top1 - top0;
0318         } else {
0319             const UINT32 dy = (top0 - topD) << 1;
0320             destROI.top += dy;
0321             origin += dy*destWidth;
0322             height -= dy;
0323             srcOffsetY[1] = top0 - top1;
0324         }
0325     }
0326 
0327     m_subband[srcLevel][LL].InitBuffPos(srcOffsetX[0], srcOffsetY[0]);
0328     m_subband[srcLevel][HL].InitBuffPos(srcOffsetX[1], srcOffsetY[0]);
0329     m_subband[srcLevel][LH].InitBuffPos(srcOffsetX[0], srcOffsetY[1]);
0330     m_subband[srcLevel][HH].InitBuffPos(srcOffsetX[1], srcOffsetY[1]);
0331 
0332 #else
0333     width = destBand->GetWidth();
0334     height = destBand->GetHeight();
0335     PGFRect destROI(0, 0, width, height);
0336     const UINT32 destWidth = width; // destination buffer width
0337     const UINT32 destHeight = height; // destination buffer height
0338 
0339     // init source buffer position
0340     for (int i = 0; i < NSubbands; i++) {
0341         m_subband[srcLevel][i].InitBuffPos();
0342     }
0343 #endif
0344 
0345     if (destHeight >= FilterSize) { // changed from FilterSizeH to FilterSize
0346         // top border handling
0347         row0 = origin; row1 = row0 + destWidth;
0348         SubbandsToInterleaved(srcLevel, row0, row1, width);
0349         for (UINT32 k = 0; k < width; k++) {
0350             row0[k] -= ((row1[k] + c1) >> 1); // even
0351         }
0352 
0353         // middle part
0354         row2 = row1 + destWidth; row3 = row2 + destWidth;
0355         for (UINT32 i = destROI.top + 2; i < destROI.bottom - 1; i += 2) {
0356             SubbandsToInterleaved(srcLevel, row2, row3, width);
0357             for (UINT32 k = 0; k < width; k++) {
0358                 row2[k] -= ((row1[k] + row3[k] + c2) >> 2); // even
0359                 row1[k] += ((row0[k] + row2[k] + c1) >> 1); // odd
0360             }
0361             InverseRow(row0, width);
0362             InverseRow(row1, width);
0363             row0 = row2; row1 = row3; row2 = row1 + destWidth; row3 = row2 + destWidth;
0364         }
0365 
0366         // bottom border handling
0367         if (height & 1) {
0368             SubbandsToInterleaved(srcLevel, row2, nullptr, width);
0369             for (UINT32 k = 0; k < width; k++) {
0370                 row2[k] -= ((row1[k] + c1) >> 1); // even
0371                 row1[k] += ((row0[k] + row2[k] + c1) >> 1); // odd
0372             }
0373             InverseRow(row0, width);
0374             InverseRow(row1, width);
0375             InverseRow(row2, width);
0376             row0 = row1; row1 = row2; row2 += destWidth;
0377         } else {
0378             for (UINT32 k = 0; k < width; k++) {
0379                 row1[k] += row0[k];
0380             }
0381             InverseRow(row0, width);
0382             InverseRow(row1, width);
0383             row0 = row1; row1 += destWidth;
0384         }
0385     } else {
0386         // height is too small
0387         row0 = origin; row1 = row0 + destWidth;
0388         // first part
0389         for (UINT32 k = 0; k < height; k += 2) {
0390             SubbandsToInterleaved(srcLevel, row0, row1, width);
0391             InverseRow(row0, width);
0392             InverseRow(row1, width);
0393             row0 += destWidth << 1; row1 += destWidth << 1;
0394         }
0395         // bottom
0396         if (height & 1) {
0397             SubbandsToInterleaved(srcLevel, row0, nullptr, width);
0398             InverseRow(row0, width);
0399         }
0400     }
0401 
0402     // free memory of the current srcLevel
0403     for (int i = 0; i < NSubbands; i++) {
0404         m_subband[srcLevel][i].FreeMemory();
0405     }
0406 
0407     // return info
0408     *w = destWidth;
0409     *h = destHeight;
0410     *data = destBand->GetBuffer();
0411     return NoError;
0412 }
0413 
0414 //////////////////////////////////////////////////////////////////////
0415 // Inverse Wavelet Transform of one row
0416 // low-pass coefficients at even positions, high-pass coefficients at odd positions
0417 // inverse filter for even positions: 1/4[-1, (4), -1]
0418 // inverse filter for odd positions: 1/8[-1, 4, (6), 4, -1]
0419 void CWaveletTransform::InverseRow(DataT* dest, UINT32 width) {
0420     if (width >= FilterSize) {
0421         UINT32 i = 2;
0422 
0423         // left border handling
0424         dest[0] -= ((dest[1] + c1) >> 1); // even
0425 
0426         // middle part
0427         for (; i < width - 1; i += 2) {
0428             dest[i] -= ((dest[i-1] + dest[i+1] + c2) >> 2); // even
0429             dest[i-1] += ((dest[i-2] + dest[i] + c1) >> 1); // odd
0430         }
0431 
0432         // right border handling
0433         if (width & 1) {
0434             dest[i] -= ((dest[i-1] + c1) >> 1); // even
0435             dest[i-1] += ((dest[i-2] + dest[i] + c1) >> 1); // odd
0436         } else {
0437             dest[i-1] += dest[i-2]; // odd
0438         }
0439     }
0440 }
0441 
0442 ///////////////////////////////////////////////////////////////////
0443 // Copy transformed coefficients from subbands LL,HL,LH,HH to interleaved format (L,H,L,H,...)
0444 void CWaveletTransform::SubbandsToInterleaved(int srcLevel, DataT* loRow, DataT* hiRow, UINT32 width) {
0445     const UINT32 wquot = width >> 1;
0446     const bool wrem = (width & 1);
0447     CSubband &ll = m_subband[srcLevel][LL], &hl = m_subband[srcLevel][HL];
0448     CSubband &lh = m_subband[srcLevel][LH], &hh = m_subband[srcLevel][HH];
0449 
0450     if (hiRow) {
0451     #ifdef __PGFROISUPPORT__
0452         const bool storePos = wquot < ll.BufferWidth();
0453         UINT32 llPos = 0, hlPos = 0, lhPos = 0, hhPos = 0;
0454 
0455         if (storePos) {
0456             // save current src buffer positions
0457             llPos = ll.GetBuffPos();
0458             hlPos = hl.GetBuffPos();
0459             lhPos = lh.GetBuffPos();
0460             hhPos = hh.GetBuffPos();
0461         }
0462     #endif
0463 
0464         for (UINT32 i=0; i < wquot; i++) {
0465             *loRow++ = ll.ReadBuffer();// first access, than increment
0466             *loRow++ = hl.ReadBuffer();// first access, than increment
0467             *hiRow++ = lh.ReadBuffer();// first access, than increment
0468             *hiRow++ = hh.ReadBuffer();// first access, than increment
0469         }
0470 
0471         if (wrem) {
0472             *loRow++ = ll.ReadBuffer();// first access, than increment
0473             *hiRow++ = lh.ReadBuffer();// first access, than increment
0474         }
0475 
0476     #ifdef __PGFROISUPPORT__
0477         if (storePos) {
0478             // increment src buffer positions
0479             ll.IncBuffRow(llPos);
0480             hl.IncBuffRow(hlPos);
0481             lh.IncBuffRow(lhPos);
0482             hh.IncBuffRow(hhPos);
0483         }
0484     #endif
0485 
0486     } else {
0487     #ifdef __PGFROISUPPORT__
0488         const bool storePos = wquot < ll.BufferWidth();
0489         UINT32 llPos = 0, hlPos = 0;
0490 
0491         if (storePos) {
0492             // save current src buffer positions
0493             llPos = ll.GetBuffPos();
0494             hlPos = hl.GetBuffPos();
0495         }
0496     #endif
0497 
0498         for (UINT32 i=0; i < wquot; i++) {
0499             *loRow++ = ll.ReadBuffer();// first access, than increment
0500             *loRow++ = hl.ReadBuffer();// first access, than increment
0501         }
0502         if (wrem) *loRow++ = ll.ReadBuffer();
0503 
0504     #ifdef __PGFROISUPPORT__
0505         if (storePos) {
0506             // increment src buffer positions
0507             ll.IncBuffRow(llPos);
0508             hl.IncBuffRow(hlPos);
0509         }
0510     #endif
0511     }
0512 }
0513 
0514 #ifdef __PGFROISUPPORT__
0515 //////////////////////////////////////////////////////////////////////
0516 /// Compute and store ROIs for nLevels
0517 /// @param roi rectangular region of interest at level 0
0518 void CWaveletTransform::SetROI(PGFRect roi) {
0519     const UINT32 delta = (FilterSize >> 1) << m_nLevels;
0520 
0521     // create tile indices
0522     delete[] m_indices;
0523     m_indices = new PGFRect[m_nLevels];
0524 
0525     // enlarge rect: add margin
0526     roi.left = (roi.left > delta) ? roi.left - delta : 0;
0527     roi.top  = (roi.top  > delta) ? roi.top  - delta : 0;
0528     roi.right += delta;
0529     roi.bottom += delta;
0530 
0531     for (int l = 0; l < m_nLevels; l++) {
0532         PGFRect alignedROI;
0533         PGFRect& indices = m_indices[l];
0534         UINT32 nTiles = GetNofTiles(l);
0535         CSubband& subband = m_subband[l][LL];
0536 
0537         // use roi to determine the necessary tile indices (for all subbands the same) and aligned ROI for LL subband
0538         subband.SetNTiles(nTiles); // must be called before TileIndex()
0539         subband.TileIndex(true, roi.left, roi.top, indices.left, indices.top, alignedROI.left, alignedROI.top);
0540         subband.TileIndex(false, roi.right, roi.bottom, indices.right, indices.bottom, alignedROI.right, alignedROI.bottom);
0541         subband.SetAlignedROI(alignedROI);
0542         ASSERT(l == 0 ||
0543             (m_indices[l-1].left >= 2*m_indices[l].left &&
0544             m_indices[l-1].top >= 2*m_indices[l].top &&
0545             m_indices[l-1].right <= 2*m_indices[l].right &&
0546             m_indices[l-1].bottom <= 2*m_indices[l].bottom));
0547 
0548         // determine aligned ROI of other three subbands
0549         PGFRect aroi;
0550         UINT32 w, h;
0551         for (int b = 1; b < NSubbands; b++) {
0552             CSubband& sb = m_subband[l][b];
0553             sb.SetNTiles(nTiles); // must be called before TilePosition()
0554             sb.TilePosition(indices.left, indices.top, aroi.left, aroi.top, w, h);
0555             sb.TilePosition(indices.right - 1, indices.bottom - 1, aroi.right, aroi.bottom, w, h);
0556             aroi.right += w;
0557             aroi.bottom += h;
0558             sb.SetAlignedROI(aroi);
0559         }
0560 
0561         // use aligned ROI of LL subband for next level
0562         roi.left = alignedROI.left >> 1;
0563         roi.top = alignedROI.top >> 1;
0564         roi.right = (alignedROI.right + 1) >> 1;
0565         roi.bottom = (alignedROI.bottom + 1) >> 1;
0566     }
0567 }
0568 
0569 #endif // __PGFROISUPPORT__