1 : /******************************************************************************
2 : * $Id: hfacompress.cpp 17547 2009-08-21 10:02:01Z rouault $
3 : *
4 : * Name: hfadataset.cpp
5 : * Project: Erdas Imagine Driver
6 : * Purpose: Imagine Compression code.
7 : * Author: Sam Gillingham <sam.gillingham at nrm.qld.gov>
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2005, Sam Gillingham
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "hfa_p.h"
32 :
33 : CPL_CVSID("$Id: hfacompress.cpp 17547 2009-08-21 10:02:01Z rouault $");
34 :
35 11 : HFACompress::HFACompress( void *pData, GUInt32 nBlockSize, int nDataType )
36 : {
37 11 : m_pData = pData;
38 11 : m_nDataType = nDataType;
39 11 : m_nDataTypeNumBits = HFAGetDataTypeBits( m_nDataType );
40 11 : m_nBlockSize = nBlockSize;
41 11 : m_nBlockCount = (nBlockSize * 8) / m_nDataTypeNumBits;
42 :
43 : /* Allocate some memory for the count and values - probably too big */
44 : /* About right for worst case scenario tho */
45 11 : m_pCounts = (GByte*)CPLMalloc( m_nBlockCount * sizeof(GUInt32) + sizeof(GUInt32) );
46 11 : m_nSizeCounts = 0;
47 :
48 11 : m_pValues = (GByte*)CPLMalloc( m_nBlockCount * sizeof(GUInt32) + sizeof(GUInt32) );
49 11 : m_nSizeValues = 0;
50 :
51 11 : m_nMin = 0;
52 11 : m_nNumRuns = 0;
53 11 : m_nNumBits = 0;
54 11 : }
55 :
56 11 : HFACompress::~HFACompress()
57 : {
58 : /* free the compressed data */
59 11 : CPLFree( m_pCounts );
60 11 : CPLFree( m_pValues );
61 11 : }
62 :
63 : /* returns the number of bits needed to encode a count */
64 8 : GByte _FindNumBits( GUInt32 range )
65 : {
66 8 : if( range < 0xff )
67 : {
68 1 : return 8;
69 : }
70 7 : else if( range < 0xffff )
71 : {
72 6 : return 16;
73 : }
74 : else
75 : {
76 1 : return 32;
77 : }
78 : }
79 :
80 : /* Gets the value from the uncompressed block as a GUInt32 no matter the data type */
81 63490 : GUInt32 HFACompress::valueAsUInt32( GUInt32 iPixel )
82 : {
83 63490 : GUInt32 val = 0;
84 :
85 63490 : if( m_nDataTypeNumBits == 8 )
86 : {
87 24576 : val = ((GByte*)m_pData)[iPixel];
88 : }
89 38914 : else if( m_nDataTypeNumBits == 16 )
90 : {
91 30722 : val = ((GUInt16*)m_pData)[iPixel];
92 : }
93 8192 : else if( m_nDataTypeNumBits == 32 )
94 : {
95 0 : val = ((GUInt32*)m_pData)[iPixel];
96 : }
97 8192 : else if( m_nDataTypeNumBits == 4 )
98 : {
99 0 : if( iPixel % 2 == 0 )
100 0 : val = ((GByte*)m_pData)[iPixel/2] & 0x0f;
101 : else
102 0 : val = (((GByte*)m_pData)[iPixel/2] & 0xf0) >> 4;
103 : }
104 8192 : else if( m_nDataTypeNumBits == 2 )
105 : {
106 0 : if( iPixel % 4 == 0 )
107 0 : val = ((GByte*)m_pData)[iPixel/4] & 0x03;
108 0 : else if( iPixel % 4 == 1 )
109 0 : val = (((GByte*)m_pData)[iPixel/4] & 0x0c) >> 2;
110 0 : else if( iPixel % 4 == 2 )
111 0 : val = (((GByte*)m_pData)[iPixel/4] & 0x30) >> 4;
112 : else
113 0 : val = (((GByte*)m_pData)[iPixel/4] & 0xc0) >> 6;
114 : }
115 8192 : else if( m_nDataTypeNumBits == 1 )
116 : {
117 8192 : if( ((GByte*)m_pData)[iPixel >> 3] & (0x1 << (iPixel & 0x07)) )
118 504 : val = 1;
119 : else
120 7688 : val = 0;
121 : }
122 : else
123 : {
124 : /* Should not get to here - check in compressBlock() should return false if
125 : we can't compress this blcok because we don't know about the type */
126 : CPLError( CE_Failure, CPLE_FileIO, "Imagine Datatype 0x%x (0x%x bits) not supported\n",
127 : m_nDataType,
128 0 : m_nDataTypeNumBits );
129 : CPLAssert( FALSE );
130 : }
131 :
132 63490 : return val;
133 : }
134 :
135 : /* Finds the minimum value in a type specific fashion. This value is
136 : subtracted from each value in the compressed dataset. The maxmimum
137 : value is also found and the number of bits that the range can be stored
138 : is also returned. */
139 : /* TODO: Minimum value returned as pNumBits is now 8 - Imagine
140 : can handle 1, 2, and 4 bits as well */
141 8 : GUInt32 HFACompress::findMin( GByte *pNumBits )
142 : {
143 : GUInt32 u32Val;
144 : GUInt32 u32Min, u32Max;
145 :
146 8 : u32Min = valueAsUInt32( 0 );
147 8 : u32Max = u32Min;
148 :
149 32768 : for( GUInt32 count = 1; count < m_nBlockCount; count++ )
150 : {
151 32760 : u32Val = valueAsUInt32( count );
152 32760 : if( u32Val < u32Min )
153 7 : u32Min = u32Val;
154 32753 : else if( u32Val > u32Max )
155 55 : u32Max = u32Val;
156 : }
157 :
158 8 : *pNumBits = _FindNumBits( u32Max - u32Min );
159 :
160 8 : return u32Min;
161 : }
162 :
163 : /* Codes the count in the way expected by Imagine - ie the lower 2 bits specify how many bytes
164 : the count takes up */
165 4417 : void HFACompress::makeCount( GUInt32 count, GByte *pCounter, GUInt32 *pnSizeCount )
166 : {
167 : /* Because Imagine stores the number of bits used in the
168 : lower 2 bits of the data it restricts what we can use */
169 4417 : if( count < 0x40 )
170 : {
171 4410 : pCounter[0] = count;
172 4410 : *pnSizeCount = 1;
173 : }
174 7 : else if( count < 0x8000 )
175 : {
176 7 : pCounter[1] = count & 0xff;
177 7 : count /= 256;
178 7 : pCounter[0] = count | 0x40;
179 7 : *pnSizeCount = 2;
180 : }
181 0 : else if( count < 0x800000 )
182 : {
183 0 : pCounter[2] = count & 0xff;
184 0 : count /= 256;
185 0 : pCounter[1] = count & 0xff;
186 0 : count /= 256;
187 0 : pCounter[0] = count | 0x80;
188 0 : *pnSizeCount = 3;
189 : }
190 : else
191 : {
192 0 : pCounter[3] = count & 0xff;
193 0 : count /= 256;
194 0 : pCounter[2] = count & 0xff;
195 0 : count /= 256;
196 0 : pCounter[1] = count & 0xff;
197 0 : count /= 256;
198 0 : pCounter[0] = count | 0xc0;
199 0 : *pnSizeCount = 4;
200 : }
201 4417 : }
202 :
203 : /* Encodes the value depending on the number of bits we are using */
204 4417 : void HFACompress::encodeValue( GUInt32 val, GUInt32 repeat )
205 : {
206 : GUInt32 nSizeCount;
207 :
208 4417 : makeCount( repeat, m_pCurrCount, &nSizeCount );
209 4417 : m_pCurrCount += nSizeCount;
210 4417 : if( m_nNumBits == 8 )
211 : {
212 : /* Only storing 8 bits per value as the range is small */
213 196 : *(GByte*)m_pCurrValues = GByte(val - m_nMin);
214 196 : m_pCurrValues += sizeof( GByte );
215 : }
216 4221 : else if( m_nNumBits == 16 )
217 : {
218 : /* Only storing 16 bits per value as the range is small */
219 2172 : *(GUInt16*)m_pCurrValues = GUInt16(val - m_nMin);
220 : #ifndef CPL_MSB
221 2172 : CPL_SWAP16PTR( m_pCurrValues );
222 : #endif /* ndef CPL_MSB */
223 2172 : m_pCurrValues += sizeof( GUInt16 );
224 : }
225 : else
226 : {
227 2049 : *(GUInt32*)m_pCurrValues = GUInt32(val - m_nMin);
228 : #ifndef CPL_MSB
229 2049 : CPL_SWAP32PTR( m_pCurrValues );
230 : #endif /* ndef CPL_MSB */
231 2049 : m_pCurrValues += sizeof( GUInt32 );
232 : }
233 4417 : }
234 :
235 : /* This is the guts of the file - call this to compress the block */
236 : /* returns false if the compression fails - ie compressed block bigger than input */
237 11 : bool HFACompress::compressBlock()
238 : {
239 11 : GUInt32 nLastUnique = 0;
240 :
241 : /* Check we know about the datatype to be compressed.
242 : If we can't compress it we should return false so that
243 : the block cannot be compressed (we can handle just about
244 : any type uncompressed) */
245 11 : if( ! QueryDataTypeSupported( m_nDataType ) )
246 : {
247 : CPLDebug( "HFA", "Cannot compress HFA datatype 0x%x (0x%x bits). Writing uncompressed instead.\n",
248 : m_nDataType,
249 3 : m_nDataTypeNumBits );
250 3 : return false;
251 : }
252 :
253 : /* reset our pointers */
254 8 : m_pCurrCount = m_pCounts;
255 8 : m_pCurrValues = m_pValues;
256 :
257 : /* Get the minimum value - this can be subtracted from each value in the image */
258 8 : m_nMin = findMin( &m_nNumBits );
259 :
260 : /* Go thru the block */
261 : GUInt32 u32Last, u32Val;
262 8 : u32Last = valueAsUInt32( 0 );
263 8 : u32Val = u32Last;
264 30721 : for( GUInt32 count = 1; count < m_nBlockCount; count++ )
265 : {
266 30714 : u32Val = valueAsUInt32( count );
267 30714 : if( u32Val != u32Last )
268 : {
269 : /* The values have changed - ie a run has come to and end */
270 4410 : encodeValue( u32Last, count - nLastUnique );
271 :
272 4410 : if( ( m_pCurrValues - m_pValues ) > (int) m_nBlockSize )
273 : {
274 1 : return false;
275 : }
276 :
277 4409 : m_nNumRuns++;
278 4409 : u32Last = u32Val;
279 4409 : nLastUnique = count;
280 : }
281 : }
282 :
283 : /* OK we have done the block but haven't got the last run because we were only looking for a change in values */
284 7 : encodeValue( u32Last, m_nBlockCount - nLastUnique );
285 7 : m_nNumRuns++;
286 :
287 : /* set the size variables */
288 7 : m_nSizeCounts = m_pCurrCount - m_pCounts;
289 7 : m_nSizeValues = m_pCurrValues - m_pValues;
290 :
291 : // The 13 is for the header size - maybe this should live with some constants somewhere?
292 7 : return ( m_nSizeCounts + m_nSizeValues + 13 ) < m_nBlockSize;
293 : }
294 :
295 11 : bool HFACompress::QueryDataTypeSupported( int nHFADataType )
296 : {
297 11 : int nBits = HFAGetDataTypeBits( nHFADataType );
298 :
299 : return ( nBits == 8 ) || ( nBits == 16 ) || ( nBits == 32 ) || (nBits == 4)
300 11 : || (nBits == 2) || (nBits == 1);
301 : }
302 :
|