LCOV - code coverage report
Current view: directory - frmts/hfa - hfacompress.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 127 100 78.7 %
Date: 2010-01-09 Functions: 9 9 100.0 %

       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                 : 

Generated by: LCOV version 1.7