2021-05-07 15:00:41 +00:00
// jpgd.cpp - C++ class for JPEG decompression. Written by Richard Geldreich <richgel99@gmail.com> between 1994-2020.
// Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2.
// Supports box and linear chroma upsampling.
//
// Released under two licenses. You are free to choose which license you want:
// License 1:
// Public Domain
//
// License 2:
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Alex Evans: Linear memory allocator (taken from jpge.h).
// v1.04, May. 19, 2012: Code tweaks to fix VS2008 static code analysis warnings
// v2.00, March 20, 2020: Fuzzed with zzuf and afl. Fixed several issues, converted most assert()'s to run-time checks. Added chroma upsampling. Removed freq. domain upsampling. gcc/clang warnings.
//
# include "jpgd.h"
# include <string.h>
# include <algorithm>
# include <assert.h>
# ifdef _MSC_VER
# pragma warning (disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable
# endif
# define JPGD_TRUE (1)
# define JPGD_FALSE (0)
# define JPGD_MAX(a,b) (((a)>(b)) ? (a) : (b))
# define JPGD_MIN(a,b) (((a)<(b)) ? (a) : (b))
namespace jpgd {
static inline void * jpgd_malloc ( size_t nSize ) { return malloc ( nSize ) ; }
static inline void jpgd_free ( void * p ) { free ( p ) ; }
// DCT coefficients are stored in this sequence.
static int g_ZAG [ 64 ] = { 0 , 1 , 8 , 16 , 9 , 2 , 3 , 10 , 17 , 24 , 32 , 25 , 18 , 11 , 4 , 5 , 12 , 19 , 26 , 33 , 40 , 48 , 41 , 34 , 27 , 20 , 13 , 6 , 7 , 14 , 21 , 28 , 35 , 42 , 49 , 56 , 57 , 50 , 43 , 36 , 29 , 22 , 15 , 23 , 30 , 37 , 44 , 51 , 58 , 59 , 52 , 45 , 38 , 31 , 39 , 46 , 53 , 60 , 61 , 54 , 47 , 55 , 62 , 63 } ;
enum JPEG_MARKER
{
M_SOF0 = 0xC0 , M_SOF1 = 0xC1 , M_SOF2 = 0xC2 , M_SOF3 = 0xC3 , M_SOF5 = 0xC5 , M_SOF6 = 0xC6 , M_SOF7 = 0xC7 , M_JPG = 0xC8 ,
M_SOF9 = 0xC9 , M_SOF10 = 0xCA , M_SOF11 = 0xCB , M_SOF13 = 0xCD , M_SOF14 = 0xCE , M_SOF15 = 0xCF , M_DHT = 0xC4 , M_DAC = 0xCC ,
M_RST0 = 0xD0 , M_RST1 = 0xD1 , M_RST2 = 0xD2 , M_RST3 = 0xD3 , M_RST4 = 0xD4 , M_RST5 = 0xD5 , M_RST6 = 0xD6 , M_RST7 = 0xD7 ,
M_SOI = 0xD8 , M_EOI = 0xD9 , M_SOS = 0xDA , M_DQT = 0xDB , M_DNL = 0xDC , M_DRI = 0xDD , M_DHP = 0xDE , M_EXP = 0xDF ,
M_APP0 = 0xE0 , M_APP15 = 0xEF , M_JPG0 = 0xF0 , M_JPG13 = 0xFD , M_COM = 0xFE , M_TEM = 0x01 , M_ERROR = 0x100 , RST0 = 0xD0
} ;
enum JPEG_SUBSAMPLING { JPGD_GRAYSCALE = 0 , JPGD_YH1V1 , JPGD_YH2V1 , JPGD_YH1V2 , JPGD_YH2V2 } ;
# define CONST_BITS 13
# define PASS1_BITS 2
# define SCALEDONE ((int32)1)
# define FIX_0_298631336 ((int32)2446) /* FIX(0.298631336) */
# define FIX_0_390180644 ((int32)3196) /* FIX(0.390180644) */
# define FIX_0_541196100 ((int32)4433) /* FIX(0.541196100) */
# define FIX_0_765366865 ((int32)6270) /* FIX(0.765366865) */
# define FIX_0_899976223 ((int32)7373) /* FIX(0.899976223) */
# define FIX_1_175875602 ((int32)9633) /* FIX(1.175875602) */
# define FIX_1_501321110 ((int32)12299) /* FIX(1.501321110) */
# define FIX_1_847759065 ((int32)15137) /* FIX(1.847759065) */
# define FIX_1_961570560 ((int32)16069) /* FIX(1.961570560) */
# define FIX_2_053119869 ((int32)16819) /* FIX(2.053119869) */
# define FIX_2_562915447 ((int32)20995) /* FIX(2.562915447) */
# define FIX_3_072711026 ((int32)25172) /* FIX(3.072711026) */
# define DESCALE(x,n) (((x) + (SCALEDONE << ((n)-1))) >> (n))
# define DESCALE_ZEROSHIFT(x,n) (((x) + (128 << (n)) + (SCALEDONE << ((n)-1))) >> (n))
# define MULTIPLY(var, cnst) ((var) * (cnst))
# define CLAMP(i) ((static_cast<uint>(i) > 255) ? (((~i) >> 31) & 0xFF) : (i))
static inline int left_shifti ( int val , uint32_t bits )
{
return static_cast < int > ( static_cast < uint32_t > ( val ) < < bits ) ;
}
// Compiler creates a fast path 1D IDCT for X non-zero columns
template < int NONZERO_COLS >
struct Row
{
static void idct ( int * pTemp , const jpgd_block_t * pSrc )
{
// ACCESS_COL() will be optimized at compile time to either an array access, or 0. Good compilers will then optimize out muls against 0.
# define ACCESS_COL(x) (((x) < NONZERO_COLS) ? (int)pSrc[x] : 0)
const int z2 = ACCESS_COL ( 2 ) , z3 = ACCESS_COL ( 6 ) ;
const int z1 = MULTIPLY ( z2 + z3 , FIX_0_541196100 ) ;
const int tmp2 = z1 + MULTIPLY ( z3 , - FIX_1_847759065 ) ;
const int tmp3 = z1 + MULTIPLY ( z2 , FIX_0_765366865 ) ;
const int tmp0 = left_shifti ( ACCESS_COL ( 0 ) + ACCESS_COL ( 4 ) , CONST_BITS ) ;
const int tmp1 = left_shifti ( ACCESS_COL ( 0 ) - ACCESS_COL ( 4 ) , CONST_BITS ) ;
const int tmp10 = tmp0 + tmp3 , tmp13 = tmp0 - tmp3 , tmp11 = tmp1 + tmp2 , tmp12 = tmp1 - tmp2 ;
const int atmp0 = ACCESS_COL ( 7 ) , atmp1 = ACCESS_COL ( 5 ) , atmp2 = ACCESS_COL ( 3 ) , atmp3 = ACCESS_COL ( 1 ) ;
const int bz1 = atmp0 + atmp3 , bz2 = atmp1 + atmp2 , bz3 = atmp0 + atmp2 , bz4 = atmp1 + atmp3 ;
const int bz5 = MULTIPLY ( bz3 + bz4 , FIX_1_175875602 ) ;
const int az1 = MULTIPLY ( bz1 , - FIX_0_899976223 ) ;
const int az2 = MULTIPLY ( bz2 , - FIX_2_562915447 ) ;
const int az3 = MULTIPLY ( bz3 , - FIX_1_961570560 ) + bz5 ;
const int az4 = MULTIPLY ( bz4 , - FIX_0_390180644 ) + bz5 ;
const int btmp0 = MULTIPLY ( atmp0 , FIX_0_298631336 ) + az1 + az3 ;
const int btmp1 = MULTIPLY ( atmp1 , FIX_2_053119869 ) + az2 + az4 ;
const int btmp2 = MULTIPLY ( atmp2 , FIX_3_072711026 ) + az2 + az3 ;
const int btmp3 = MULTIPLY ( atmp3 , FIX_1_501321110 ) + az1 + az4 ;
pTemp [ 0 ] = DESCALE ( tmp10 + btmp3 , CONST_BITS - PASS1_BITS ) ;
pTemp [ 7 ] = DESCALE ( tmp10 - btmp3 , CONST_BITS - PASS1_BITS ) ;
pTemp [ 1 ] = DESCALE ( tmp11 + btmp2 , CONST_BITS - PASS1_BITS ) ;
pTemp [ 6 ] = DESCALE ( tmp11 - btmp2 , CONST_BITS - PASS1_BITS ) ;
pTemp [ 2 ] = DESCALE ( tmp12 + btmp1 , CONST_BITS - PASS1_BITS ) ;
pTemp [ 5 ] = DESCALE ( tmp12 - btmp1 , CONST_BITS - PASS1_BITS ) ;
pTemp [ 3 ] = DESCALE ( tmp13 + btmp0 , CONST_BITS - PASS1_BITS ) ;
pTemp [ 4 ] = DESCALE ( tmp13 - btmp0 , CONST_BITS - PASS1_BITS ) ;
}
} ;
template < >
struct Row < 0 >
{
static void idct ( int * pTemp , const jpgd_block_t * pSrc )
{
( void ) pTemp ;
( void ) pSrc ;
}
} ;
template < >
struct Row < 1 >
{
static void idct ( int * pTemp , const jpgd_block_t * pSrc )
{
const int dcval = left_shifti ( pSrc [ 0 ] , PASS1_BITS ) ;
pTemp [ 0 ] = dcval ;
pTemp [ 1 ] = dcval ;
pTemp [ 2 ] = dcval ;
pTemp [ 3 ] = dcval ;
pTemp [ 4 ] = dcval ;
pTemp [ 5 ] = dcval ;
pTemp [ 6 ] = dcval ;
pTemp [ 7 ] = dcval ;
}
} ;
// Compiler creates a fast path 1D IDCT for X non-zero rows
template < int NONZERO_ROWS >
struct Col
{
static void idct ( uint8 * pDst_ptr , const int * pTemp )
{
// ACCESS_ROW() will be optimized at compile time to either an array access, or 0.
# define ACCESS_ROW(x) (((x) < NONZERO_ROWS) ? pTemp[x * 8] : 0)
const int z2 = ACCESS_ROW ( 2 ) ;
const int z3 = ACCESS_ROW ( 6 ) ;
const int z1 = MULTIPLY ( z2 + z3 , FIX_0_541196100 ) ;
const int tmp2 = z1 + MULTIPLY ( z3 , - FIX_1_847759065 ) ;
const int tmp3 = z1 + MULTIPLY ( z2 , FIX_0_765366865 ) ;
const int tmp0 = left_shifti ( ACCESS_ROW ( 0 ) + ACCESS_ROW ( 4 ) , CONST_BITS ) ;
const int tmp1 = left_shifti ( ACCESS_ROW ( 0 ) - ACCESS_ROW ( 4 ) , CONST_BITS ) ;
const int tmp10 = tmp0 + tmp3 , tmp13 = tmp0 - tmp3 , tmp11 = tmp1 + tmp2 , tmp12 = tmp1 - tmp2 ;
const int atmp0 = ACCESS_ROW ( 7 ) , atmp1 = ACCESS_ROW ( 5 ) , atmp2 = ACCESS_ROW ( 3 ) , atmp3 = ACCESS_ROW ( 1 ) ;
const int bz1 = atmp0 + atmp3 , bz2 = atmp1 + atmp2 , bz3 = atmp0 + atmp2 , bz4 = atmp1 + atmp3 ;
const int bz5 = MULTIPLY ( bz3 + bz4 , FIX_1_175875602 ) ;
const int az1 = MULTIPLY ( bz1 , - FIX_0_899976223 ) ;
const int az2 = MULTIPLY ( bz2 , - FIX_2_562915447 ) ;
const int az3 = MULTIPLY ( bz3 , - FIX_1_961570560 ) + bz5 ;
const int az4 = MULTIPLY ( bz4 , - FIX_0_390180644 ) + bz5 ;
const int btmp0 = MULTIPLY ( atmp0 , FIX_0_298631336 ) + az1 + az3 ;
const int btmp1 = MULTIPLY ( atmp1 , FIX_2_053119869 ) + az2 + az4 ;
const int btmp2 = MULTIPLY ( atmp2 , FIX_3_072711026 ) + az2 + az3 ;
const int btmp3 = MULTIPLY ( atmp3 , FIX_1_501321110 ) + az1 + az4 ;
int i = DESCALE_ZEROSHIFT ( tmp10 + btmp3 , CONST_BITS + PASS1_BITS + 3 ) ;
pDst_ptr [ 8 * 0 ] = ( uint8 ) CLAMP ( i ) ;
i = DESCALE_ZEROSHIFT ( tmp10 - btmp3 , CONST_BITS + PASS1_BITS + 3 ) ;
pDst_ptr [ 8 * 7 ] = ( uint8 ) CLAMP ( i ) ;
i = DESCALE_ZEROSHIFT ( tmp11 + btmp2 , CONST_BITS + PASS1_BITS + 3 ) ;
pDst_ptr [ 8 * 1 ] = ( uint8 ) CLAMP ( i ) ;
i = DESCALE_ZEROSHIFT ( tmp11 - btmp2 , CONST_BITS + PASS1_BITS + 3 ) ;
pDst_ptr [ 8 * 6 ] = ( uint8 ) CLAMP ( i ) ;
i = DESCALE_ZEROSHIFT ( tmp12 + btmp1 , CONST_BITS + PASS1_BITS + 3 ) ;
pDst_ptr [ 8 * 2 ] = ( uint8 ) CLAMP ( i ) ;
i = DESCALE_ZEROSHIFT ( tmp12 - btmp1 , CONST_BITS + PASS1_BITS + 3 ) ;
pDst_ptr [ 8 * 5 ] = ( uint8 ) CLAMP ( i ) ;
i = DESCALE_ZEROSHIFT ( tmp13 + btmp0 , CONST_BITS + PASS1_BITS + 3 ) ;
pDst_ptr [ 8 * 3 ] = ( uint8 ) CLAMP ( i ) ;
i = DESCALE_ZEROSHIFT ( tmp13 - btmp0 , CONST_BITS + PASS1_BITS + 3 ) ;
pDst_ptr [ 8 * 4 ] = ( uint8 ) CLAMP ( i ) ;
}
} ;
template < >
struct Col < 1 >
{
static void idct ( uint8 * pDst_ptr , const int * pTemp )
{
int dcval = DESCALE_ZEROSHIFT ( pTemp [ 0 ] , PASS1_BITS + 3 ) ;
const uint8 dcval_clamped = ( uint8 ) CLAMP ( dcval ) ;
pDst_ptr [ 0 * 8 ] = dcval_clamped ;
pDst_ptr [ 1 * 8 ] = dcval_clamped ;
pDst_ptr [ 2 * 8 ] = dcval_clamped ;
pDst_ptr [ 3 * 8 ] = dcval_clamped ;
pDst_ptr [ 4 * 8 ] = dcval_clamped ;
pDst_ptr [ 5 * 8 ] = dcval_clamped ;
pDst_ptr [ 6 * 8 ] = dcval_clamped ;
pDst_ptr [ 7 * 8 ] = dcval_clamped ;
}
} ;
static const uint8 s_idct_row_table [ ] =
{
1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 2 , 1 , 0 , 0 , 0 , 0 , 0 , 0 , 2 , 1 , 1 , 0 , 0 , 0 , 0 , 0 , 2 , 2 , 1 , 0 , 0 , 0 , 0 , 0 , 3 , 2 , 1 , 0 , 0 , 0 , 0 , 0 , 4 , 2 , 1 , 0 , 0 , 0 , 0 , 0 , 4 , 3 , 1 , 0 , 0 , 0 , 0 , 0 ,
4 , 3 , 2 , 0 , 0 , 0 , 0 , 0 , 4 , 3 , 2 , 1 , 0 , 0 , 0 , 0 , 4 , 3 , 2 , 1 , 1 , 0 , 0 , 0 , 4 , 3 , 2 , 2 , 1 , 0 , 0 , 0 , 4 , 3 , 3 , 2 , 1 , 0 , 0 , 0 , 4 , 4 , 3 , 2 , 1 , 0 , 0 , 0 , 5 , 4 , 3 , 2 , 1 , 0 , 0 , 0 , 6 , 4 , 3 , 2 , 1 , 0 , 0 , 0 ,
6 , 5 , 3 , 2 , 1 , 0 , 0 , 0 , 6 , 5 , 4 , 2 , 1 , 0 , 0 , 0 , 6 , 5 , 4 , 3 , 1 , 0 , 0 , 0 , 6 , 5 , 4 , 3 , 2 , 0 , 0 , 0 , 6 , 5 , 4 , 3 , 2 , 1 , 0 , 0 , 6 , 5 , 4 , 3 , 2 , 1 , 1 , 0 , 6 , 5 , 4 , 3 , 2 , 2 , 1 , 0 , 6 , 5 , 4 , 3 , 3 , 2 , 1 , 0 ,
6 , 5 , 4 , 4 , 3 , 2 , 1 , 0 , 6 , 5 , 5 , 4 , 3 , 2 , 1 , 0 , 6 , 6 , 5 , 4 , 3 , 2 , 1 , 0 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 , 8 , 6 , 5 , 4 , 3 , 2 , 1 , 0 , 8 , 7 , 5 , 4 , 3 , 2 , 1 , 0 , 8 , 7 , 6 , 4 , 3 , 2 , 1 , 0 , 8 , 7 , 6 , 5 , 3 , 2 , 1 , 0 ,
8 , 7 , 6 , 5 , 4 , 2 , 1 , 0 , 8 , 7 , 6 , 5 , 4 , 3 , 1 , 0 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 0 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 2 , 8 , 7 , 6 , 5 , 4 , 3 , 3 , 2 , 8 , 7 , 6 , 5 , 4 , 4 , 3 , 2 , 8 , 7 , 6 , 5 , 5 , 4 , 3 , 2 ,
8 , 7 , 6 , 6 , 5 , 4 , 3 , 2 , 8 , 7 , 7 , 6 , 5 , 4 , 3 , 2 , 8 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 8 , 8 , 8 , 6 , 5 , 4 , 3 , 2 , 8 , 8 , 8 , 7 , 5 , 4 , 3 , 2 , 8 , 8 , 8 , 7 , 6 , 4 , 3 , 2 , 8 , 8 , 8 , 7 , 6 , 5 , 3 , 2 , 8 , 8 , 8 , 7 , 6 , 5 , 4 , 2 ,
8 , 8 , 8 , 7 , 6 , 5 , 4 , 3 , 8 , 8 , 8 , 7 , 6 , 5 , 4 , 4 , 8 , 8 , 8 , 7 , 6 , 5 , 5 , 4 , 8 , 8 , 8 , 7 , 6 , 6 , 5 , 4 , 8 , 8 , 8 , 7 , 7 , 6 , 5 , 4 , 8 , 8 , 8 , 8 , 7 , 6 , 5 , 4 , 8 , 8 , 8 , 8 , 8 , 6 , 5 , 4 , 8 , 8 , 8 , 8 , 8 , 7 , 5 , 4 ,
8 , 8 , 8 , 8 , 8 , 7 , 6 , 4 , 8 , 8 , 8 , 8 , 8 , 7 , 6 , 5 , 8 , 8 , 8 , 8 , 8 , 7 , 6 , 6 , 8 , 8 , 8 , 8 , 8 , 7 , 7 , 6 , 8 , 8 , 8 , 8 , 8 , 8 , 7 , 6 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 6 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 7 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 ,
} ;
static const uint8 s_idct_col_table [ ] =
{
1 , 1 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 4 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 6 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 ,
7 , 7 , 7 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8
} ;
// Scalar "fast pathing" IDCT.
static void idct ( const jpgd_block_t * pSrc_ptr , uint8 * pDst_ptr , int block_max_zag )
{
assert ( block_max_zag > = 1 ) ;
assert ( block_max_zag < = 64 ) ;
if ( block_max_zag < = 1 )
{
int k = ( ( pSrc_ptr [ 0 ] + 4 ) > > 3 ) + 128 ;
k = CLAMP ( k ) ;
k = k | ( k < < 8 ) ;
k = k | ( k < < 16 ) ;
for ( int i = 8 ; i > 0 ; i - - )
{
* ( int * ) & pDst_ptr [ 0 ] = k ;
* ( int * ) & pDst_ptr [ 4 ] = k ;
pDst_ptr + = 8 ;
}
return ;
}
int temp [ 64 ] ;
const jpgd_block_t * pSrc = pSrc_ptr ;
int * pTemp = temp ;
const uint8 * pRow_tab = & s_idct_row_table [ ( block_max_zag - 1 ) * 8 ] ;
int i ;
for ( i = 8 ; i > 0 ; i - - , pRow_tab + + )
{
switch ( * pRow_tab )
{
case 0 : Row < 0 > : : idct ( pTemp , pSrc ) ; break ;
case 1 : Row < 1 > : : idct ( pTemp , pSrc ) ; break ;
case 2 : Row < 2 > : : idct ( pTemp , pSrc ) ; break ;
case 3 : Row < 3 > : : idct ( pTemp , pSrc ) ; break ;
case 4 : Row < 4 > : : idct ( pTemp , pSrc ) ; break ;
case 5 : Row < 5 > : : idct ( pTemp , pSrc ) ; break ;
case 6 : Row < 6 > : : idct ( pTemp , pSrc ) ; break ;
case 7 : Row < 7 > : : idct ( pTemp , pSrc ) ; break ;
case 8 : Row < 8 > : : idct ( pTemp , pSrc ) ; break ;
}
pSrc + = 8 ;
pTemp + = 8 ;
}
pTemp = temp ;
const int nonzero_rows = s_idct_col_table [ block_max_zag - 1 ] ;
for ( i = 8 ; i > 0 ; i - - )
{
switch ( nonzero_rows )
{
case 1 : Col < 1 > : : idct ( pDst_ptr , pTemp ) ; break ;
case 2 : Col < 2 > : : idct ( pDst_ptr , pTemp ) ; break ;
case 3 : Col < 3 > : : idct ( pDst_ptr , pTemp ) ; break ;
case 4 : Col < 4 > : : idct ( pDst_ptr , pTemp ) ; break ;
case 5 : Col < 5 > : : idct ( pDst_ptr , pTemp ) ; break ;
case 6 : Col < 6 > : : idct ( pDst_ptr , pTemp ) ; break ;
case 7 : Col < 7 > : : idct ( pDst_ptr , pTemp ) ; break ;
case 8 : Col < 8 > : : idct ( pDst_ptr , pTemp ) ; break ;
}
pTemp + + ;
pDst_ptr + + ;
}
}
// Retrieve one character from the input stream.
inline uint jpeg_decoder : : get_char ( )
{
// Any bytes remaining in buffer?
if ( ! m_in_buf_left )
{
// Try to get more bytes.
prep_in_buffer ( ) ;
// Still nothing to get?
if ( ! m_in_buf_left )
{
// Pad the end of the stream with 0xFF 0xD9 (EOI marker)
int t = m_tem_flag ;
m_tem_flag ^ = 1 ;
if ( t )
return 0xD9 ;
else
return 0xFF ;
}
}
uint c = * m_pIn_buf_ofs + + ;
m_in_buf_left - - ;
return c ;
}
// Same as previous method, except can indicate if the character is a pad character or not.
inline uint jpeg_decoder : : get_char ( bool * pPadding_flag )
{
if ( ! m_in_buf_left )
{
prep_in_buffer ( ) ;
if ( ! m_in_buf_left )
{
* pPadding_flag = true ;
int t = m_tem_flag ;
m_tem_flag ^ = 1 ;
if ( t )
return 0xD9 ;
else
return 0xFF ;
}
}
* pPadding_flag = false ;
uint c = * m_pIn_buf_ofs + + ;
m_in_buf_left - - ;
return c ;
}
// Inserts a previously retrieved character back into the input buffer.
inline void jpeg_decoder : : stuff_char ( uint8 q )
{
// This could write before the input buffer, but we've placed another array there.
* ( - - m_pIn_buf_ofs ) = q ;
m_in_buf_left + + ;
}
// Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered.
inline uint8 jpeg_decoder : : get_octet ( )
{
bool padding_flag ;
int c = get_char ( & padding_flag ) ;
if ( c = = 0xFF )
{
if ( padding_flag )
return 0xFF ;
c = get_char ( & padding_flag ) ;
if ( padding_flag )
{
stuff_char ( 0xFF ) ;
return 0xFF ;
}
if ( c = = 0x00 )
return 0xFF ;
else
{
stuff_char ( static_cast < uint8 > ( c ) ) ;
stuff_char ( 0xFF ) ;
return 0xFF ;
}
}
return static_cast < uint8 > ( c ) ;
}
// Retrieves a variable number of bits from the input stream. Does not recognize markers.
inline uint jpeg_decoder : : get_bits ( int num_bits )
{
if ( ! num_bits )
return 0 ;
uint i = m_bit_buf > > ( 32 - num_bits ) ;
if ( ( m_bits_left - = num_bits ) < = 0 )
{
m_bit_buf < < = ( num_bits + = m_bits_left ) ;
uint c1 = get_char ( ) ;
uint c2 = get_char ( ) ;
m_bit_buf = ( m_bit_buf & 0xFFFF0000 ) | ( c1 < < 8 ) | c2 ;
m_bit_buf < < = - m_bits_left ;
m_bits_left + = 16 ;
assert ( m_bits_left > = 0 ) ;
}
else
m_bit_buf < < = num_bits ;
return i ;
}
// Retrieves a variable number of bits from the input stream. Markers will not be read into the input bit buffer. Instead, an infinite number of all 1's will be returned when a marker is encountered.
inline uint jpeg_decoder : : get_bits_no_markers ( int num_bits )
{
if ( ! num_bits )
return 0 ;
assert ( num_bits < = 16 ) ;
uint i = m_bit_buf > > ( 32 - num_bits ) ;
if ( ( m_bits_left - = num_bits ) < = 0 )
{
m_bit_buf < < = ( num_bits + = m_bits_left ) ;
if ( ( m_in_buf_left < 2 ) | | ( m_pIn_buf_ofs [ 0 ] = = 0xFF ) | | ( m_pIn_buf_ofs [ 1 ] = = 0xFF ) )
{
uint c1 = get_octet ( ) ;
uint c2 = get_octet ( ) ;
m_bit_buf | = ( c1 < < 8 ) | c2 ;
}
else
{
m_bit_buf | = ( ( uint ) m_pIn_buf_ofs [ 0 ] < < 8 ) | m_pIn_buf_ofs [ 1 ] ;
m_in_buf_left - = 2 ;
m_pIn_buf_ofs + = 2 ;
}
m_bit_buf < < = - m_bits_left ;
m_bits_left + = 16 ;
assert ( m_bits_left > = 0 ) ;
}
else
m_bit_buf < < = num_bits ;
return i ;
}
// Decodes a Huffman encoded symbol.
inline int jpeg_decoder : : huff_decode ( huff_tables * pH )
{
if ( ! pH )
stop_decoding ( JPGD_DECODE_ERROR ) ;
int symbol ;
// Check first 8-bits: do we have a complete symbol?
if ( ( symbol = pH - > look_up [ m_bit_buf > > 24 ] ) < 0 )
{
// Decode more bits, use a tree traversal to find symbol.
int ofs = 23 ;
do
{
unsigned int idx = - ( int ) ( symbol + ( ( m_bit_buf > > ofs ) & 1 ) ) ;
// This should never happen, but to be safe I'm turning these asserts into a run-time check.
if ( ( idx > = JPGD_HUFF_TREE_MAX_LENGTH ) | | ( ofs < 0 ) )
stop_decoding ( JPGD_DECODE_ERROR ) ;
symbol = pH - > tree [ idx ] ;
ofs - - ;
} while ( symbol < 0 ) ;
get_bits_no_markers ( 8 + ( 23 - ofs ) ) ;
}
else
{
assert ( symbol < JPGD_HUFF_CODE_SIZE_MAX_LENGTH ) ;
get_bits_no_markers ( pH - > code_size [ symbol ] ) ;
}
return symbol ;
}
// Decodes a Huffman encoded symbol.
inline int jpeg_decoder : : huff_decode ( huff_tables * pH , int & extra_bits )
{
int symbol ;
if ( ! pH )
stop_decoding ( JPGD_DECODE_ERROR ) ;
// Check first 8-bits: do we have a complete symbol?
if ( ( symbol = pH - > look_up2 [ m_bit_buf > > 24 ] ) < 0 )
{
// Use a tree traversal to find symbol.
int ofs = 23 ;
do
{
unsigned int idx = - ( int ) ( symbol + ( ( m_bit_buf > > ofs ) & 1 ) ) ;
// This should never happen, but to be safe I'm turning these asserts into a run-time check.
if ( ( idx > = JPGD_HUFF_TREE_MAX_LENGTH ) | | ( ofs < 0 ) )
stop_decoding ( JPGD_DECODE_ERROR ) ;
symbol = pH - > tree [ idx ] ;
ofs - - ;
} while ( symbol < 0 ) ;
get_bits_no_markers ( 8 + ( 23 - ofs ) ) ;
extra_bits = get_bits_no_markers ( symbol & 0xF ) ;
}
else
{
if ( symbol & 0x8000 )
{
//get_bits_no_markers((symbol >> 8) & 31);
assert ( ( ( symbol > > 8 ) & 31 ) < = 15 ) ;
get_bits_no_markers ( ( symbol > > 8 ) & 15 ) ;
extra_bits = symbol > > 16 ;
}
else
{
int code_size = ( symbol > > 8 ) & 31 ;
int num_extra_bits = symbol & 0xF ;
int bits = code_size + num_extra_bits ;
if ( bits < = 16 )
extra_bits = get_bits_no_markers ( bits ) & ( ( 1 < < num_extra_bits ) - 1 ) ;
else
{
get_bits_no_markers ( code_size ) ;
extra_bits = get_bits_no_markers ( num_extra_bits ) ;
}
}
symbol & = 0xFF ;
}
return symbol ;
}
// Tables and macro used to fully decode the DPCM differences.
static const int s_extend_test [ 16 ] = { 0 , 0x0001 , 0x0002 , 0x0004 , 0x0008 , 0x0010 , 0x0020 , 0x0040 , 0x0080 , 0x0100 , 0x0200 , 0x0400 , 0x0800 , 0x1000 , 0x2000 , 0x4000 } ;
static const int s_extend_offset [ 16 ] = { 0 , - 1 , - 3 , - 7 , - 15 , - 31 , - 63 , - 127 , - 255 , - 511 , - 1023 , - 2047 , - 4095 , - 8191 , - 16383 , - 32767 } ;
//static const int s_extend_mask[] = { 0, (1 << 0), (1 << 1), (1 << 2), (1 << 3), (1 << 4), (1 << 5), (1 << 6), (1 << 7), (1 << 8), (1 << 9), (1 << 10), (1 << 11), (1 << 12), (1 << 13), (1 << 14), (1 << 15), (1 << 16) };
# define JPGD_HUFF_EXTEND(x, s) (((x) < s_extend_test[s & 15]) ? ((x) + s_extend_offset[s & 15]) : (x))
// Unconditionally frees all allocated m_blocks.
void jpeg_decoder : : free_all_blocks ( )
{
m_pStream = nullptr ;
for ( mem_block * b = m_pMem_blocks ; b ; )
{
mem_block * n = b - > m_pNext ;
jpgd_free ( b ) ;
b = n ;
}
m_pMem_blocks = nullptr ;
}
// This method handles all errors. It will never return.
// It could easily be changed to use C++ exceptions.
JPGD_NORETURN void jpeg_decoder : : stop_decoding ( jpgd_status status )
{
m_error_code = status ;
free_all_blocks ( ) ;
longjmp ( m_jmp_state , status ) ;
}
void * jpeg_decoder : : alloc ( size_t nSize , bool zero )
{
nSize = ( JPGD_MAX ( nSize , 1 ) + 3 ) & ~ 3 ;
char * rv = nullptr ;
for ( mem_block * b = m_pMem_blocks ; b ; b = b - > m_pNext )
{
if ( ( b - > m_used_count + nSize ) < = b - > m_size )
{
rv = b - > m_data + b - > m_used_count ;
b - > m_used_count + = nSize ;
break ;
}
}
if ( ! rv )
{
int capacity = JPGD_MAX ( 32768 - 256 , ( ( int ) nSize + 2047 ) & ~ 2047 ) ;
mem_block * b = ( mem_block * ) jpgd_malloc ( sizeof ( mem_block ) + capacity ) ;
if ( ! b )
{
stop_decoding ( JPGD_NOTENOUGHMEM ) ;
}
b - > m_pNext = m_pMem_blocks ;
m_pMem_blocks = b ;
b - > m_used_count = nSize ;
b - > m_size = capacity ;
rv = b - > m_data ;
}
if ( zero ) memset ( rv , 0 , nSize ) ;
return rv ;
}
void jpeg_decoder : : word_clear ( void * p , uint16 c , uint n )
{
uint8 * pD = ( uint8 * ) p ;
const uint8 l = c & 0xFF , h = ( c > > 8 ) & 0xFF ;
while ( n )
{
pD [ 0 ] = l ;
pD [ 1 ] = h ;
pD + = 2 ;
n - - ;
}
}
// Refill the input buffer.
// This method will sit in a loop until (A) the buffer is full or (B)
// the stream's read() method reports and end of file condition.
void jpeg_decoder : : prep_in_buffer ( )
{
m_in_buf_left = 0 ;
m_pIn_buf_ofs = m_in_buf ;
if ( m_eof_flag )
return ;
do
{
int bytes_read = m_pStream - > read ( m_in_buf + m_in_buf_left , JPGD_IN_BUF_SIZE - m_in_buf_left , & m_eof_flag ) ;
if ( bytes_read = = - 1 )
stop_decoding ( JPGD_STREAM_READ ) ;
m_in_buf_left + = bytes_read ;
} while ( ( m_in_buf_left < JPGD_IN_BUF_SIZE ) & & ( ! m_eof_flag ) ) ;
m_total_bytes_read + = m_in_buf_left ;
// Pad the end of the block with M_EOI (prevents the decompressor from going off the rails if the stream is invalid).
// (This dates way back to when this decompressor was written in C/asm, and the all-asm Huffman decoder did some fancy things to increase perf.)
word_clear ( m_pIn_buf_ofs + m_in_buf_left , 0xD9FF , 64 ) ;
}
// Read a Huffman code table.
void jpeg_decoder : : read_dht_marker ( )
{
int i , index , count ;
uint8 huff_num [ 17 ] ;
uint8 huff_val [ 256 ] ;
uint num_left = get_bits ( 16 ) ;
if ( num_left < 2 )
stop_decoding ( JPGD_BAD_DHT_MARKER ) ;
num_left - = 2 ;
while ( num_left )
{
index = get_bits ( 8 ) ;
huff_num [ 0 ] = 0 ;
count = 0 ;
for ( i = 1 ; i < = 16 ; i + + )
{
huff_num [ i ] = static_cast < uint8 > ( get_bits ( 8 ) ) ;
count + = huff_num [ i ] ;
}
if ( count > 255 )
stop_decoding ( JPGD_BAD_DHT_COUNTS ) ;
bool symbol_present [ 256 ] ;
memset ( symbol_present , 0 , sizeof ( symbol_present ) ) ;
for ( i = 0 ; i < count ; i + + )
{
const int s = get_bits ( 8 ) ;
// Check for obviously bogus tables.
if ( symbol_present [ s ] )
stop_decoding ( JPGD_BAD_DHT_COUNTS ) ;
huff_val [ i ] = static_cast < uint8_t > ( s ) ;
symbol_present [ s ] = true ;
}
i = 1 + 16 + count ;
if ( num_left < ( uint ) i )
stop_decoding ( JPGD_BAD_DHT_MARKER ) ;
num_left - = i ;
if ( ( index & 0x10 ) > 0x10 )
stop_decoding ( JPGD_BAD_DHT_INDEX ) ;
index = ( index & 0x0F ) + ( ( index & 0x10 ) > > 4 ) * ( JPGD_MAX_HUFF_TABLES > > 1 ) ;
if ( index > = JPGD_MAX_HUFF_TABLES )
stop_decoding ( JPGD_BAD_DHT_INDEX ) ;
if ( ! m_huff_num [ index ] )
m_huff_num [ index ] = ( uint8 * ) alloc ( 17 ) ;
if ( ! m_huff_val [ index ] )
m_huff_val [ index ] = ( uint8 * ) alloc ( 256 ) ;
m_huff_ac [ index ] = ( index & 0x10 ) ! = 0 ;
memcpy ( m_huff_num [ index ] , huff_num , 17 ) ;
memcpy ( m_huff_val [ index ] , huff_val , 256 ) ;
}
}
// Read a quantization table.
void jpeg_decoder : : read_dqt_marker ( )
{
int n , i , prec ;
uint num_left ;
uint temp ;
num_left = get_bits ( 16 ) ;
if ( num_left < 2 )
stop_decoding ( JPGD_BAD_DQT_MARKER ) ;
num_left - = 2 ;
while ( num_left )
{
n = get_bits ( 8 ) ;
prec = n > > 4 ;
n & = 0x0F ;
if ( n > = JPGD_MAX_QUANT_TABLES )
stop_decoding ( JPGD_BAD_DQT_TABLE ) ;
if ( ! m_quant [ n ] )
m_quant [ n ] = ( jpgd_quant_t * ) alloc ( 64 * sizeof ( jpgd_quant_t ) ) ;
// read quantization entries, in zag order
for ( i = 0 ; i < 64 ; i + + )
{
temp = get_bits ( 8 ) ;
if ( prec )
temp = ( temp < < 8 ) + get_bits ( 8 ) ;
m_quant [ n ] [ i ] = static_cast < jpgd_quant_t > ( temp ) ;
}
i = 64 + 1 ;
if ( prec )
i + = 64 ;
if ( num_left < ( uint ) i )
stop_decoding ( JPGD_BAD_DQT_LENGTH ) ;
num_left - = i ;
}
}
// Read the start of frame (SOF) marker.
void jpeg_decoder : : read_sof_marker ( )
{
int i ;
uint num_left ;
num_left = get_bits ( 16 ) ;
/* precision: sorry, only 8-bit precision is supported */
if ( get_bits ( 8 ) ! = 8 )
stop_decoding ( JPGD_BAD_PRECISION ) ;
m_image_y_size = get_bits ( 16 ) ;
if ( ( m_image_y_size < 1 ) | | ( m_image_y_size > JPGD_MAX_HEIGHT ) )
stop_decoding ( JPGD_BAD_HEIGHT ) ;
m_image_x_size = get_bits ( 16 ) ;
if ( ( m_image_x_size < 1 ) | | ( m_image_x_size > JPGD_MAX_WIDTH ) )
stop_decoding ( JPGD_BAD_WIDTH ) ;
m_comps_in_frame = get_bits ( 8 ) ;
if ( m_comps_in_frame > JPGD_MAX_COMPONENTS )
stop_decoding ( JPGD_TOO_MANY_COMPONENTS ) ;
if ( num_left ! = ( uint ) ( m_comps_in_frame * 3 + 8 ) )
stop_decoding ( JPGD_BAD_SOF_LENGTH ) ;
for ( i = 0 ; i < m_comps_in_frame ; i + + )
{
m_comp_ident [ i ] = get_bits ( 8 ) ;
m_comp_h_samp [ i ] = get_bits ( 4 ) ;
m_comp_v_samp [ i ] = get_bits ( 4 ) ;
if ( ! m_comp_h_samp [ i ] | | ! m_comp_v_samp [ i ] | | ( m_comp_h_samp [ i ] > 2 ) | | ( m_comp_v_samp [ i ] > 2 ) )
stop_decoding ( JPGD_UNSUPPORTED_SAMP_FACTORS ) ;
m_comp_quant [ i ] = get_bits ( 8 ) ;
if ( m_comp_quant [ i ] > = JPGD_MAX_QUANT_TABLES )
stop_decoding ( JPGD_DECODE_ERROR ) ;
}
}
// Used to skip unrecognized markers.
void jpeg_decoder : : skip_variable_marker ( )
{
uint num_left ;
num_left = get_bits ( 16 ) ;
if ( num_left < 2 )
stop_decoding ( JPGD_BAD_VARIABLE_MARKER ) ;
num_left - = 2 ;
while ( num_left )
{
get_bits ( 8 ) ;
num_left - - ;
}
}
// Read a define restart interval (DRI) marker.
void jpeg_decoder : : read_dri_marker ( )
{
if ( get_bits ( 16 ) ! = 4 )
stop_decoding ( JPGD_BAD_DRI_LENGTH ) ;
m_restart_interval = get_bits ( 16 ) ;
}
// Read a start of scan (SOS) marker.
void jpeg_decoder : : read_sos_marker ( )
{
uint num_left ;
int i , ci , n , c , cc ;
num_left = get_bits ( 16 ) ;
n = get_bits ( 8 ) ;
m_comps_in_scan = n ;
num_left - = 3 ;
if ( ( num_left ! = ( uint ) ( n * 2 + 3 ) ) | | ( n < 1 ) | | ( n > JPGD_MAX_COMPS_IN_SCAN ) )
stop_decoding ( JPGD_BAD_SOS_LENGTH ) ;
for ( i = 0 ; i < n ; i + + )
{
cc = get_bits ( 8 ) ;
c = get_bits ( 8 ) ;
num_left - = 2 ;
for ( ci = 0 ; ci < m_comps_in_frame ; ci + + )
if ( cc = = m_comp_ident [ ci ] )
break ;
if ( ci > = m_comps_in_frame )
stop_decoding ( JPGD_BAD_SOS_COMP_ID ) ;
if ( ci > = JPGD_MAX_COMPONENTS )
stop_decoding ( JPGD_DECODE_ERROR ) ;
m_comp_list [ i ] = ci ;
m_comp_dc_tab [ ci ] = ( c > > 4 ) & 15 ;
m_comp_ac_tab [ ci ] = ( c & 15 ) + ( JPGD_MAX_HUFF_TABLES > > 1 ) ;
if ( m_comp_dc_tab [ ci ] > = JPGD_MAX_HUFF_TABLES )
stop_decoding ( JPGD_DECODE_ERROR ) ;
if ( m_comp_ac_tab [ ci ] > = JPGD_MAX_HUFF_TABLES )
stop_decoding ( JPGD_DECODE_ERROR ) ;
}
m_spectral_start = get_bits ( 8 ) ;
m_spectral_end = get_bits ( 8 ) ;
m_successive_high = get_bits ( 4 ) ;
m_successive_low = get_bits ( 4 ) ;
if ( ! m_progressive_flag )
{
m_spectral_start = 0 ;
m_spectral_end = 63 ;
}
num_left - = 3 ;
/* read past whatever is num_left */
while ( num_left )
{
get_bits ( 8 ) ;
num_left - - ;
}
}
// Finds the next marker.
int jpeg_decoder : : next_marker ( )
{
uint c , bytes ;
bytes = 0 ;
do
{
do
{
bytes + + ;
c = get_bits ( 8 ) ;
} while ( c ! = 0xFF ) ;
do
{
c = get_bits ( 8 ) ;
} while ( c = = 0xFF ) ;
} while ( c = = 0 ) ;
// If bytes > 0 here, there where extra bytes before the marker (not good).
return c ;
}
// Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is
// encountered.
int jpeg_decoder : : process_markers ( )
{
int c ;
for ( ; ; )
{
c = next_marker ( ) ;
switch ( c )
{
case M_SOF0 :
case M_SOF1 :
case M_SOF2 :
case M_SOF3 :
case M_SOF5 :
case M_SOF6 :
case M_SOF7 :
// case M_JPG:
case M_SOF9 :
case M_SOF10 :
case M_SOF11 :
case M_SOF13 :
case M_SOF14 :
case M_SOF15 :
case M_SOI :
case M_EOI :
case M_SOS :
{
return c ;
}
case M_DHT :
{
read_dht_marker ( ) ;
break ;
}
// No arithmitic support - dumb patents!
case M_DAC :
{
stop_decoding ( JPGD_NO_ARITHMITIC_SUPPORT ) ;
break ;
}
case M_DQT :
{
read_dqt_marker ( ) ;
break ;
}
case M_DRI :
{
read_dri_marker ( ) ;
break ;
}
//case M_APP0: /* no need to read the JFIF marker */
case M_JPG :
case M_RST0 : /* no parameters */
case M_RST1 :
case M_RST2 :
case M_RST3 :
case M_RST4 :
case M_RST5 :
case M_RST6 :
case M_RST7 :
case M_TEM :
{
stop_decoding ( JPGD_UNEXPECTED_MARKER ) ;
break ;
}
default : /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */
{
skip_variable_marker ( ) ;
break ;
}
}
}
}
// Finds the start of image (SOI) marker.
void jpeg_decoder : : locate_soi_marker ( )
{
uint lastchar , thischar ;
uint bytesleft ;
lastchar = get_bits ( 8 ) ;
thischar = get_bits ( 8 ) ;
/* ok if it's a normal JPEG file without a special header */
if ( ( lastchar = = 0xFF ) & & ( thischar = = M_SOI ) )
return ;
bytesleft = 4096 ;
for ( ; ; )
{
if ( - - bytesleft = = 0 )
stop_decoding ( JPGD_NOT_JPEG ) ;
lastchar = thischar ;
thischar = get_bits ( 8 ) ;
if ( lastchar = = 0xFF )
{
if ( thischar = = M_SOI )
break ;
else if ( thischar = = M_EOI ) // get_bits will keep returning M_EOI if we read past the end
stop_decoding ( JPGD_NOT_JPEG ) ;
}
}
// Check the next character after marker: if it's not 0xFF, it can't be the start of the next marker, so the file is bad.
thischar = ( m_bit_buf > > 24 ) & 0xFF ;
if ( thischar ! = 0xFF )
stop_decoding ( JPGD_NOT_JPEG ) ;
}
// Find a start of frame (SOF) marker.
void jpeg_decoder : : locate_sof_marker ( )
{
locate_soi_marker ( ) ;
int c = process_markers ( ) ;
switch ( c )
{
case M_SOF2 :
{
m_progressive_flag = JPGD_TRUE ;
read_sof_marker ( ) ;
break ;
}
case M_SOF0 : /* baseline DCT */
case M_SOF1 : /* extended sequential DCT */
{
read_sof_marker ( ) ;
break ;
}
case M_SOF9 : /* Arithmitic coding */
{
stop_decoding ( JPGD_NO_ARITHMITIC_SUPPORT ) ;
break ;
}
default :
{
stop_decoding ( JPGD_UNSUPPORTED_MARKER ) ;
break ;
}
}
}
// Find a start of scan (SOS) marker.
int jpeg_decoder : : locate_sos_marker ( )
{
int c ;
c = process_markers ( ) ;
if ( c = = M_EOI )
return JPGD_FALSE ;
else if ( c ! = M_SOS )
stop_decoding ( JPGD_UNEXPECTED_MARKER ) ;
read_sos_marker ( ) ;
return JPGD_TRUE ;
}
// Reset everything to default/uninitialized state.
void jpeg_decoder : : init ( jpeg_decoder_stream * pStream , uint32_t flags )
{
m_flags = flags ;
m_pMem_blocks = nullptr ;
m_error_code = JPGD_SUCCESS ;
m_ready_flag = false ;
m_image_x_size = m_image_y_size = 0 ;
m_pStream = pStream ;
m_progressive_flag = JPGD_FALSE ;
memset ( m_huff_ac , 0 , sizeof ( m_huff_ac ) ) ;
memset ( m_huff_num , 0 , sizeof ( m_huff_num ) ) ;
memset ( m_huff_val , 0 , sizeof ( m_huff_val ) ) ;
memset ( m_quant , 0 , sizeof ( m_quant ) ) ;
m_scan_type = 0 ;
m_comps_in_frame = 0 ;
memset ( m_comp_h_samp , 0 , sizeof ( m_comp_h_samp ) ) ;
memset ( m_comp_v_samp , 0 , sizeof ( m_comp_v_samp ) ) ;
memset ( m_comp_quant , 0 , sizeof ( m_comp_quant ) ) ;
memset ( m_comp_ident , 0 , sizeof ( m_comp_ident ) ) ;
memset ( m_comp_h_blocks , 0 , sizeof ( m_comp_h_blocks ) ) ;
memset ( m_comp_v_blocks , 0 , sizeof ( m_comp_v_blocks ) ) ;
m_comps_in_scan = 0 ;
memset ( m_comp_list , 0 , sizeof ( m_comp_list ) ) ;
memset ( m_comp_dc_tab , 0 , sizeof ( m_comp_dc_tab ) ) ;
memset ( m_comp_ac_tab , 0 , sizeof ( m_comp_ac_tab ) ) ;
m_spectral_start = 0 ;
m_spectral_end = 0 ;
m_successive_low = 0 ;
m_successive_high = 0 ;
m_max_mcu_x_size = 0 ;
m_max_mcu_y_size = 0 ;
m_blocks_per_mcu = 0 ;
m_max_blocks_per_row = 0 ;
m_mcus_per_row = 0 ;
m_mcus_per_col = 0 ;
memset ( m_mcu_org , 0 , sizeof ( m_mcu_org ) ) ;
m_total_lines_left = 0 ;
m_mcu_lines_left = 0 ;
m_num_buffered_scanlines = 0 ;
m_real_dest_bytes_per_scan_line = 0 ;
m_dest_bytes_per_scan_line = 0 ;
m_dest_bytes_per_pixel = 0 ;
memset ( m_pHuff_tabs , 0 , sizeof ( m_pHuff_tabs ) ) ;
memset ( m_dc_coeffs , 0 , sizeof ( m_dc_coeffs ) ) ;
memset ( m_ac_coeffs , 0 , sizeof ( m_ac_coeffs ) ) ;
memset ( m_block_y_mcu , 0 , sizeof ( m_block_y_mcu ) ) ;
m_eob_run = 0 ;
m_pIn_buf_ofs = m_in_buf ;
m_in_buf_left = 0 ;
m_eof_flag = false ;
m_tem_flag = 0 ;
memset ( m_in_buf_pad_start , 0 , sizeof ( m_in_buf_pad_start ) ) ;
memset ( m_in_buf , 0 , sizeof ( m_in_buf ) ) ;
memset ( m_in_buf_pad_end , 0 , sizeof ( m_in_buf_pad_end ) ) ;
m_restart_interval = 0 ;
m_restarts_left = 0 ;
m_next_restart_num = 0 ;
m_max_mcus_per_row = 0 ;
m_max_blocks_per_mcu = 0 ;
m_max_mcus_per_col = 0 ;
memset ( m_last_dc_val , 0 , sizeof ( m_last_dc_val ) ) ;
m_pMCU_coefficients = nullptr ;
m_pSample_buf = nullptr ;
m_pSample_buf_prev = nullptr ;
m_sample_buf_prev_valid = false ;
m_total_bytes_read = 0 ;
m_pScan_line_0 = nullptr ;
m_pScan_line_1 = nullptr ;
// Ready the input buffer.
prep_in_buffer ( ) ;
// Prime the bit buffer.
m_bits_left = 16 ;
m_bit_buf = 0 ;
get_bits ( 16 ) ;
get_bits ( 16 ) ;
for ( int i = 0 ; i < JPGD_MAX_BLOCKS_PER_MCU ; i + + )
m_mcu_block_max_zag [ i ] = 64 ;
}
# define SCALEBITS 16
# define ONE_HALF ((int) 1 << (SCALEBITS-1))
# define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5f))
// Create a few tables that allow us to quickly convert YCbCr to RGB.
void jpeg_decoder : : create_look_ups ( )
{
for ( int i = 0 ; i < = 255 ; i + + )
{
int k = i - 128 ;
m_crr [ i ] = ( FIX ( 1.40200f ) * k + ONE_HALF ) > > SCALEBITS ;
m_cbb [ i ] = ( FIX ( 1.77200f ) * k + ONE_HALF ) > > SCALEBITS ;
m_crg [ i ] = ( - FIX ( 0.71414f ) ) * k ;
m_cbg [ i ] = ( - FIX ( 0.34414f ) ) * k + ONE_HALF ;
}
}
// This method throws back into the stream any bytes that where read
// into the bit buffer during initial marker scanning.
void jpeg_decoder : : fix_in_buffer ( )
{
// In case any 0xFF's where pulled into the buffer during marker scanning.
assert ( ( m_bits_left & 7 ) = = 0 ) ;
if ( m_bits_left = = 16 )
stuff_char ( ( uint8 ) ( m_bit_buf & 0xFF ) ) ;
if ( m_bits_left > = 8 )
stuff_char ( ( uint8 ) ( ( m_bit_buf > > 8 ) & 0xFF ) ) ;
stuff_char ( ( uint8 ) ( ( m_bit_buf > > 16 ) & 0xFF ) ) ;
stuff_char ( ( uint8 ) ( ( m_bit_buf > > 24 ) & 0xFF ) ) ;
m_bits_left = 16 ;
get_bits_no_markers ( 16 ) ;
get_bits_no_markers ( 16 ) ;
}
void jpeg_decoder : : transform_mcu ( int mcu_row )
{
jpgd_block_t * pSrc_ptr = m_pMCU_coefficients ;
if ( mcu_row * m_blocks_per_mcu > = m_max_blocks_per_row )
stop_decoding ( JPGD_DECODE_ERROR ) ;
uint8 * pDst_ptr = m_pSample_buf + mcu_row * m_blocks_per_mcu * 64 ;
for ( int mcu_block = 0 ; mcu_block < m_blocks_per_mcu ; mcu_block + + )
{
idct ( pSrc_ptr , pDst_ptr , m_mcu_block_max_zag [ mcu_block ] ) ;
pSrc_ptr + = 64 ;
pDst_ptr + = 64 ;
}
}
// Loads and dequantizes the next row of (already decoded) coefficients.
// Progressive images only.
void jpeg_decoder : : load_next_row ( )
{
int i ;
jpgd_block_t * p ;
jpgd_quant_t * q ;
int mcu_row , mcu_block , row_block = 0 ;
int component_num , component_id ;
int block_x_mcu [ JPGD_MAX_COMPONENTS ] ;
memset ( block_x_mcu , 0 , JPGD_MAX_COMPONENTS * sizeof ( int ) ) ;
for ( mcu_row = 0 ; mcu_row < m_mcus_per_row ; mcu_row + + )
{
int block_x_mcu_ofs = 0 , block_y_mcu_ofs = 0 ;
for ( mcu_block = 0 ; mcu_block < m_blocks_per_mcu ; mcu_block + + )
{
component_id = m_mcu_org [ mcu_block ] ;
if ( m_comp_quant [ component_id ] > = JPGD_MAX_QUANT_TABLES )
stop_decoding ( JPGD_DECODE_ERROR ) ;
q = m_quant [ m_comp_quant [ component_id ] ] ;
p = m_pMCU_coefficients + 64 * mcu_block ;
jpgd_block_t * pAC = coeff_buf_getp ( m_ac_coeffs [ component_id ] , block_x_mcu [ component_id ] + block_x_mcu_ofs , m_block_y_mcu [ component_id ] + block_y_mcu_ofs ) ;
jpgd_block_t * pDC = coeff_buf_getp ( m_dc_coeffs [ component_id ] , block_x_mcu [ component_id ] + block_x_mcu_ofs , m_block_y_mcu [ component_id ] + block_y_mcu_ofs ) ;
p [ 0 ] = pDC [ 0 ] ;
memcpy ( & p [ 1 ] , & pAC [ 1 ] , 63 * sizeof ( jpgd_block_t ) ) ;
for ( i = 63 ; i > 0 ; i - - )
if ( p [ g_ZAG [ i ] ] )
break ;
m_mcu_block_max_zag [ mcu_block ] = i + 1 ;
for ( ; i > = 0 ; i - - )
if ( p [ g_ZAG [ i ] ] )
p [ g_ZAG [ i ] ] = static_cast < jpgd_block_t > ( p [ g_ZAG [ i ] ] * q [ i ] ) ;
row_block + + ;
if ( m_comps_in_scan = = 1 )
block_x_mcu [ component_id ] + + ;
else
{
if ( + + block_x_mcu_ofs = = m_comp_h_samp [ component_id ] )
{
block_x_mcu_ofs = 0 ;
if ( + + block_y_mcu_ofs = = m_comp_v_samp [ component_id ] )
{
block_y_mcu_ofs = 0 ;
block_x_mcu [ component_id ] + = m_comp_h_samp [ component_id ] ;
}
}
}
}
transform_mcu ( mcu_row ) ;
}
if ( m_comps_in_scan = = 1 )
m_block_y_mcu [ m_comp_list [ 0 ] ] + + ;
else
{
for ( component_num = 0 ; component_num < m_comps_in_scan ; component_num + + )
{
component_id = m_comp_list [ component_num ] ;
m_block_y_mcu [ component_id ] + = m_comp_v_samp [ component_id ] ;
}
}
}
// Restart interval processing.
void jpeg_decoder : : process_restart ( )
{
int i ;
int c = 0 ;
// Align to a byte boundry
// FIXME: Is this really necessary? get_bits_no_markers() never reads in markers!
//get_bits_no_markers(m_bits_left & 7);
// Let's scan a little bit to find the marker, but not _too_ far.
// 1536 is a "fudge factor" that determines how much to scan.
for ( i = 1536 ; i > 0 ; i - - )
if ( get_char ( ) = = 0xFF )
break ;
if ( i = = 0 )
stop_decoding ( JPGD_BAD_RESTART_MARKER ) ;
for ( ; i > 0 ; i - - )
if ( ( c = get_char ( ) ) ! = 0xFF )
break ;
if ( i = = 0 )
stop_decoding ( JPGD_BAD_RESTART_MARKER ) ;
// Is it the expected marker? If not, something bad happened.
if ( c ! = ( m_next_restart_num + M_RST0 ) )
stop_decoding ( JPGD_BAD_RESTART_MARKER ) ;
// Reset each component's DC prediction values.
memset ( & m_last_dc_val , 0 , m_comps_in_frame * sizeof ( uint ) ) ;
m_eob_run = 0 ;
m_restarts_left = m_restart_interval ;
m_next_restart_num = ( m_next_restart_num + 1 ) & 7 ;
// Get the bit buffer going again...
m_bits_left = 16 ;
get_bits_no_markers ( 16 ) ;
get_bits_no_markers ( 16 ) ;
}
static inline int dequantize_ac ( int c , int q ) { c * = q ; return c ; }
// Decodes and dequantizes the next row of coefficients.
void jpeg_decoder : : decode_next_row ( )
{
int row_block = 0 ;
for ( int mcu_row = 0 ; mcu_row < m_mcus_per_row ; mcu_row + + )
{
if ( ( m_restart_interval ) & & ( m_restarts_left = = 0 ) )
process_restart ( ) ;
jpgd_block_t * p = m_pMCU_coefficients ;
for ( int mcu_block = 0 ; mcu_block < m_blocks_per_mcu ; mcu_block + + , p + = 64 )
{
int component_id = m_mcu_org [ mcu_block ] ;
if ( m_comp_quant [ component_id ] > = JPGD_MAX_QUANT_TABLES )
stop_decoding ( JPGD_DECODE_ERROR ) ;
jpgd_quant_t * q = m_quant [ m_comp_quant [ component_id ] ] ;
int r , s ;
s = huff_decode ( m_pHuff_tabs [ m_comp_dc_tab [ component_id ] ] , r ) ;
if ( s > = 16 )
stop_decoding ( JPGD_DECODE_ERROR ) ;
s = JPGD_HUFF_EXTEND ( r , s ) ;
m_last_dc_val [ component_id ] = ( s + = m_last_dc_val [ component_id ] ) ;
p [ 0 ] = static_cast < jpgd_block_t > ( s * q [ 0 ] ) ;
int prev_num_set = m_mcu_block_max_zag [ mcu_block ] ;
huff_tables * pH = m_pHuff_tabs [ m_comp_ac_tab [ component_id ] ] ;
int k ;
for ( k = 1 ; k < 64 ; k + + )
{
int extra_bits ;
s = huff_decode ( pH , extra_bits ) ;
r = s > > 4 ;
s & = 15 ;
if ( s )
{
if ( r )
{
if ( ( k + r ) > 63 )
stop_decoding ( JPGD_DECODE_ERROR ) ;
if ( k < prev_num_set )
{
int n = JPGD_MIN ( r , prev_num_set - k ) ;
int kt = k ;
while ( n - - )
p [ g_ZAG [ kt + + ] ] = 0 ;
}
k + = r ;
}
s = JPGD_HUFF_EXTEND ( extra_bits , s ) ;
if ( k > = 64 )
stop_decoding ( JPGD_DECODE_ERROR ) ;
p [ g_ZAG [ k ] ] = static_cast < jpgd_block_t > ( dequantize_ac ( s , q [ k ] ) ) ; //s * q[k];
}
else
{
if ( r = = 15 )
{
if ( ( k + 16 ) > 64 )
stop_decoding ( JPGD_DECODE_ERROR ) ;
if ( k < prev_num_set )
{
int n = JPGD_MIN ( 16 , prev_num_set - k ) ;
int kt = k ;
while ( n - - )
{
if ( kt > 63 )
stop_decoding ( JPGD_DECODE_ERROR ) ;
p [ g_ZAG [ kt + + ] ] = 0 ;
}
}
k + = 16 - 1 ; // - 1 because the loop counter is k
if ( p [ g_ZAG [ k & 63 ] ] ! = 0 )
stop_decoding ( JPGD_DECODE_ERROR ) ;
}
else
break ;
}
}
if ( k < prev_num_set )
{
int kt = k ;
while ( kt < prev_num_set )
p [ g_ZAG [ kt + + ] ] = 0 ;
}
m_mcu_block_max_zag [ mcu_block ] = k ;
row_block + + ;
}
transform_mcu ( mcu_row ) ;
m_restarts_left - - ;
}
}
// YCbCr H1V1 (1x1:1:1, 3 m_blocks per MCU) to RGB
void jpeg_decoder : : H1V1Convert ( )
{
int row = m_max_mcu_y_size - m_mcu_lines_left ;
uint8 * d = m_pScan_line_0 ;
uint8 * s = m_pSample_buf + row * 8 ;
for ( int i = m_max_mcus_per_row ; i > 0 ; i - - )
{
for ( int j = 0 ; j < 8 ; j + + )
{
int y = s [ j ] ;
int cb = s [ 64 + j ] ;
int cr = s [ 128 + j ] ;
d [ 0 ] = clamp ( y + m_crr [ cr ] ) ;
d [ 1 ] = clamp ( y + ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ) ;
d [ 2 ] = clamp ( y + m_cbb [ cb ] ) ;
d [ 3 ] = 255 ;
d + = 4 ;
}
s + = 64 * 3 ;
}
}
// YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB
void jpeg_decoder : : H2V1Convert ( )
{
int row = m_max_mcu_y_size - m_mcu_lines_left ;
uint8 * d0 = m_pScan_line_0 ;
uint8 * y = m_pSample_buf + row * 8 ;
uint8 * c = m_pSample_buf + 2 * 64 + row * 8 ;
for ( int i = m_max_mcus_per_row ; i > 0 ; i - - )
{
for ( int l = 0 ; l < 2 ; l + + )
{
for ( int j = 0 ; j < 4 ; j + + )
{
int cb = c [ 0 ] ;
int cr = c [ 64 ] ;
int rc = m_crr [ cr ] ;
int gc = ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ;
int bc = m_cbb [ cb ] ;
int yy = y [ j < < 1 ] ;
d0 [ 0 ] = clamp ( yy + rc ) ;
d0 [ 1 ] = clamp ( yy + gc ) ;
d0 [ 2 ] = clamp ( yy + bc ) ;
d0 [ 3 ] = 255 ;
yy = y [ ( j < < 1 ) + 1 ] ;
d0 [ 4 ] = clamp ( yy + rc ) ;
d0 [ 5 ] = clamp ( yy + gc ) ;
d0 [ 6 ] = clamp ( yy + bc ) ;
d0 [ 7 ] = 255 ;
d0 + = 8 ;
c + + ;
}
y + = 64 ;
}
y + = 64 * 4 - 64 * 2 ;
c + = 64 * 4 - 8 ;
}
}
// YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB
void jpeg_decoder : : H2V1ConvertFiltered ( )
{
const uint BLOCKS_PER_MCU = 4 ;
int row = m_max_mcu_y_size - m_mcu_lines_left ;
uint8 * d0 = m_pScan_line_0 ;
const int half_image_x_size = ( m_image_x_size > > 1 ) - 1 ;
const int row_x8 = row * 8 ;
for ( int x = 0 ; x < m_image_x_size ; x + + )
{
int y = m_pSample_buf [ check_sample_buf_ofs ( ( x > > 4 ) * BLOCKS_PER_MCU * 64 + ( ( x & 8 ) ? 64 : 0 ) + ( x & 7 ) + row_x8 ) ] ;
int c_x0 = ( x - 1 ) > > 1 ;
int c_x1 = JPGD_MIN ( c_x0 + 1 , half_image_x_size ) ;
c_x0 = JPGD_MAX ( c_x0 , 0 ) ;
int a = ( c_x0 > > 3 ) * BLOCKS_PER_MCU * 64 + ( c_x0 & 7 ) + row_x8 + 128 ;
int cb0 = m_pSample_buf [ check_sample_buf_ofs ( a ) ] ;
int cr0 = m_pSample_buf [ check_sample_buf_ofs ( a + 64 ) ] ;
int b = ( c_x1 > > 3 ) * BLOCKS_PER_MCU * 64 + ( c_x1 & 7 ) + row_x8 + 128 ;
int cb1 = m_pSample_buf [ check_sample_buf_ofs ( b ) ] ;
int cr1 = m_pSample_buf [ check_sample_buf_ofs ( b + 64 ) ] ;
int w0 = ( x & 1 ) ? 3 : 1 ;
int w1 = ( x & 1 ) ? 1 : 3 ;
int cb = ( cb0 * w0 + cb1 * w1 + 2 ) > > 2 ;
int cr = ( cr0 * w0 + cr1 * w1 + 2 ) > > 2 ;
int rc = m_crr [ cr ] ;
int gc = ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ;
int bc = m_cbb [ cb ] ;
d0 [ 0 ] = clamp ( y + rc ) ;
d0 [ 1 ] = clamp ( y + gc ) ;
d0 [ 2 ] = clamp ( y + bc ) ;
d0 [ 3 ] = 255 ;
d0 + = 4 ;
}
}
// YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB
void jpeg_decoder : : H1V2Convert ( )
{
int row = m_max_mcu_y_size - m_mcu_lines_left ;
uint8 * d0 = m_pScan_line_0 ;
uint8 * d1 = m_pScan_line_1 ;
uint8 * y ;
uint8 * c ;
if ( row < 8 )
y = m_pSample_buf + row * 8 ;
else
y = m_pSample_buf + 64 * 1 + ( row & 7 ) * 8 ;
c = m_pSample_buf + 64 * 2 + ( row > > 1 ) * 8 ;
for ( int i = m_max_mcus_per_row ; i > 0 ; i - - )
{
for ( int j = 0 ; j < 8 ; j + + )
{
int cb = c [ 0 + j ] ;
int cr = c [ 64 + j ] ;
int rc = m_crr [ cr ] ;
int gc = ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ;
int bc = m_cbb [ cb ] ;
int yy = y [ j ] ;
d0 [ 0 ] = clamp ( yy + rc ) ;
d0 [ 1 ] = clamp ( yy + gc ) ;
d0 [ 2 ] = clamp ( yy + bc ) ;
d0 [ 3 ] = 255 ;
yy = y [ 8 + j ] ;
d1 [ 0 ] = clamp ( yy + rc ) ;
d1 [ 1 ] = clamp ( yy + gc ) ;
d1 [ 2 ] = clamp ( yy + bc ) ;
d1 [ 3 ] = 255 ;
d0 + = 4 ;
d1 + = 4 ;
}
y + = 64 * 4 ;
c + = 64 * 4 ;
}
}
// YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB
void jpeg_decoder : : H1V2ConvertFiltered ( )
{
const uint BLOCKS_PER_MCU = 4 ;
int y = m_image_y_size - m_total_lines_left ;
int row = y & 15 ;
const int half_image_y_size = ( m_image_y_size > > 1 ) - 1 ;
uint8 * d0 = m_pScan_line_0 ;
const int w0 = ( row & 1 ) ? 3 : 1 ;
const int w1 = ( row & 1 ) ? 1 : 3 ;
int c_y0 = ( y - 1 ) > > 1 ;
int c_y1 = JPGD_MIN ( c_y0 + 1 , half_image_y_size ) ;
const uint8_t * p_YSamples = m_pSample_buf ;
const uint8_t * p_C0Samples = m_pSample_buf ;
if ( ( c_y0 > = 0 ) & & ( ( ( row & 15 ) = = 0 ) | | ( ( row & 15 ) = = 15 ) ) & & ( m_total_lines_left > 1 ) )
{
assert ( y > 0 ) ;
assert ( m_sample_buf_prev_valid ) ;
if ( ( row & 15 ) = = 15 )
p_YSamples = m_pSample_buf_prev ;
p_C0Samples = m_pSample_buf_prev ;
}
const int y_sample_base_ofs = ( ( row & 8 ) ? 64 : 0 ) + ( row & 7 ) * 8 ;
const int y0_base = ( c_y0 & 7 ) * 8 + 128 ;
const int y1_base = ( c_y1 & 7 ) * 8 + 128 ;
for ( int x = 0 ; x < m_image_x_size ; x + + )
{
const int base_ofs = ( x > > 3 ) * BLOCKS_PER_MCU * 64 + ( x & 7 ) ;
int y_sample = p_YSamples [ check_sample_buf_ofs ( base_ofs + y_sample_base_ofs ) ] ;
int a = base_ofs + y0_base ;
int cb0_sample = p_C0Samples [ check_sample_buf_ofs ( a ) ] ;
int cr0_sample = p_C0Samples [ check_sample_buf_ofs ( a + 64 ) ] ;
int b = base_ofs + y1_base ;
int cb1_sample = m_pSample_buf [ check_sample_buf_ofs ( b ) ] ;
int cr1_sample = m_pSample_buf [ check_sample_buf_ofs ( b + 64 ) ] ;
int cb = ( cb0_sample * w0 + cb1_sample * w1 + 2 ) > > 2 ;
int cr = ( cr0_sample * w0 + cr1_sample * w1 + 2 ) > > 2 ;
int rc = m_crr [ cr ] ;
int gc = ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ;
int bc = m_cbb [ cb ] ;
d0 [ 0 ] = clamp ( y_sample + rc ) ;
d0 [ 1 ] = clamp ( y_sample + gc ) ;
d0 [ 2 ] = clamp ( y_sample + bc ) ;
d0 [ 3 ] = 255 ;
d0 + = 4 ;
}
}
// YCbCr H2V2 (2x2:1:1, 6 m_blocks per MCU) to RGB
void jpeg_decoder : : H2V2Convert ( )
{
int row = m_max_mcu_y_size - m_mcu_lines_left ;
uint8 * d0 = m_pScan_line_0 ;
uint8 * d1 = m_pScan_line_1 ;
uint8 * y ;
uint8 * c ;
if ( row < 8 )
y = m_pSample_buf + row * 8 ;
else
y = m_pSample_buf + 64 * 2 + ( row & 7 ) * 8 ;
c = m_pSample_buf + 64 * 4 + ( row > > 1 ) * 8 ;
for ( int i = m_max_mcus_per_row ; i > 0 ; i - - )
{
for ( int l = 0 ; l < 2 ; l + + )
{
for ( int j = 0 ; j < 8 ; j + = 2 )
{
int cb = c [ 0 ] ;
int cr = c [ 64 ] ;
int rc = m_crr [ cr ] ;
int gc = ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ;
int bc = m_cbb [ cb ] ;
int yy = y [ j ] ;
d0 [ 0 ] = clamp ( yy + rc ) ;
d0 [ 1 ] = clamp ( yy + gc ) ;
d0 [ 2 ] = clamp ( yy + bc ) ;
d0 [ 3 ] = 255 ;
yy = y [ j + 1 ] ;
d0 [ 4 ] = clamp ( yy + rc ) ;
d0 [ 5 ] = clamp ( yy + gc ) ;
d0 [ 6 ] = clamp ( yy + bc ) ;
d0 [ 7 ] = 255 ;
yy = y [ j + 8 ] ;
d1 [ 0 ] = clamp ( yy + rc ) ;
d1 [ 1 ] = clamp ( yy + gc ) ;
d1 [ 2 ] = clamp ( yy + bc ) ;
d1 [ 3 ] = 255 ;
yy = y [ j + 8 + 1 ] ;
d1 [ 4 ] = clamp ( yy + rc ) ;
d1 [ 5 ] = clamp ( yy + gc ) ;
d1 [ 6 ] = clamp ( yy + bc ) ;
d1 [ 7 ] = 255 ;
d0 + = 8 ;
d1 + = 8 ;
c + + ;
}
y + = 64 ;
}
y + = 64 * 6 - 64 * 2 ;
c + = 64 * 6 - 8 ;
}
}
uint32_t jpeg_decoder : : H2V2ConvertFiltered ( )
{
const uint BLOCKS_PER_MCU = 6 ;
int y = m_image_y_size - m_total_lines_left ;
int row = y & 15 ;
const int half_image_y_size = ( m_image_y_size > > 1 ) - 1 ;
uint8 * d0 = m_pScan_line_0 ;
int c_y0 = ( y - 1 ) > > 1 ;
int c_y1 = JPGD_MIN ( c_y0 + 1 , half_image_y_size ) ;
const uint8_t * p_YSamples = m_pSample_buf ;
const uint8_t * p_C0Samples = m_pSample_buf ;
if ( ( c_y0 > = 0 ) & & ( ( ( row & 15 ) = = 0 ) | | ( ( row & 15 ) = = 15 ) ) & & ( m_total_lines_left > 1 ) )
{
assert ( y > 0 ) ;
assert ( m_sample_buf_prev_valid ) ;
if ( ( row & 15 ) = = 15 )
p_YSamples = m_pSample_buf_prev ;
p_C0Samples = m_pSample_buf_prev ;
}
const int y_sample_base_ofs = ( ( row & 8 ) ? 128 : 0 ) + ( row & 7 ) * 8 ;
const int y0_base = ( c_y0 & 7 ) * 8 + 256 ;
const int y1_base = ( c_y1 & 7 ) * 8 + 256 ;
const int half_image_x_size = ( m_image_x_size > > 1 ) - 1 ;
static const uint8_t s_muls [ 2 ] [ 2 ] [ 4 ] =
{
{ { 1 , 3 , 3 , 9 } , { 3 , 9 , 1 , 3 } , } ,
{ { 3 , 1 , 9 , 3 } , { 9 , 3 , 3 , 1 } }
} ;
if ( ( ( row & 15 ) > = 1 ) & & ( ( row & 15 ) < = 14 ) )
{
assert ( ( row & 1 ) = = 1 ) ;
assert ( ( ( y + 1 - 1 ) > > 1 ) = = c_y0 ) ;
assert ( p_YSamples = = m_pSample_buf ) ;
assert ( p_C0Samples = = m_pSample_buf ) ;
uint8 * d1 = m_pScan_line_1 ;
const int y_sample_base_ofs1 = ( ( ( row + 1 ) & 8 ) ? 128 : 0 ) + ( ( row + 1 ) & 7 ) * 8 ;
for ( int x = 0 ; x < m_image_x_size ; x + + )
{
int k = ( x > > 4 ) * BLOCKS_PER_MCU * 64 + ( ( x & 8 ) ? 64 : 0 ) + ( x & 7 ) ;
int y_sample0 = p_YSamples [ check_sample_buf_ofs ( k + y_sample_base_ofs ) ] ;
int y_sample1 = p_YSamples [ check_sample_buf_ofs ( k + y_sample_base_ofs1 ) ] ;
int c_x0 = ( x - 1 ) > > 1 ;
int c_x1 = JPGD_MIN ( c_x0 + 1 , half_image_x_size ) ;
c_x0 = JPGD_MAX ( c_x0 , 0 ) ;
int a = ( c_x0 > > 3 ) * BLOCKS_PER_MCU * 64 + ( c_x0 & 7 ) ;
int cb00_sample = p_C0Samples [ check_sample_buf_ofs ( a + y0_base ) ] ;
int cr00_sample = p_C0Samples [ check_sample_buf_ofs ( a + y0_base + 64 ) ] ;
int cb01_sample = m_pSample_buf [ check_sample_buf_ofs ( a + y1_base ) ] ;
int cr01_sample = m_pSample_buf [ check_sample_buf_ofs ( a + y1_base + 64 ) ] ;
int b = ( c_x1 > > 3 ) * BLOCKS_PER_MCU * 64 + ( c_x1 & 7 ) ;
int cb10_sample = p_C0Samples [ check_sample_buf_ofs ( b + y0_base ) ] ;
int cr10_sample = p_C0Samples [ check_sample_buf_ofs ( b + y0_base + 64 ) ] ;
int cb11_sample = m_pSample_buf [ check_sample_buf_ofs ( b + y1_base ) ] ;
int cr11_sample = m_pSample_buf [ check_sample_buf_ofs ( b + y1_base + 64 ) ] ;
{
const uint8_t * pMuls = & s_muls [ row & 1 ] [ x & 1 ] [ 0 ] ;
int cb = ( cb00_sample * pMuls [ 0 ] + cb01_sample * pMuls [ 1 ] + cb10_sample * pMuls [ 2 ] + cb11_sample * pMuls [ 3 ] + 8 ) > > 4 ;
int cr = ( cr00_sample * pMuls [ 0 ] + cr01_sample * pMuls [ 1 ] + cr10_sample * pMuls [ 2 ] + cr11_sample * pMuls [ 3 ] + 8 ) > > 4 ;
int rc = m_crr [ cr ] ;
int gc = ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ;
int bc = m_cbb [ cb ] ;
d0 [ 0 ] = clamp ( y_sample0 + rc ) ;
d0 [ 1 ] = clamp ( y_sample0 + gc ) ;
d0 [ 2 ] = clamp ( y_sample0 + bc ) ;
d0 [ 3 ] = 255 ;
d0 + = 4 ;
}
{
const uint8_t * pMuls = & s_muls [ ( row + 1 ) & 1 ] [ x & 1 ] [ 0 ] ;
int cb = ( cb00_sample * pMuls [ 0 ] + cb01_sample * pMuls [ 1 ] + cb10_sample * pMuls [ 2 ] + cb11_sample * pMuls [ 3 ] + 8 ) > > 4 ;
int cr = ( cr00_sample * pMuls [ 0 ] + cr01_sample * pMuls [ 1 ] + cr10_sample * pMuls [ 2 ] + cr11_sample * pMuls [ 3 ] + 8 ) > > 4 ;
int rc = m_crr [ cr ] ;
int gc = ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ;
int bc = m_cbb [ cb ] ;
d1 [ 0 ] = clamp ( y_sample1 + rc ) ;
d1 [ 1 ] = clamp ( y_sample1 + gc ) ;
d1 [ 2 ] = clamp ( y_sample1 + bc ) ;
d1 [ 3 ] = 255 ;
d1 + = 4 ;
}
if ( ( ( x & 1 ) = = 1 ) & & ( x < m_image_x_size - 1 ) )
{
const int nx = x + 1 ;
assert ( c_x0 = = ( nx - 1 ) > > 1 ) ;
k = ( nx > > 4 ) * BLOCKS_PER_MCU * 64 + ( ( nx & 8 ) ? 64 : 0 ) + ( nx & 7 ) ;
y_sample0 = p_YSamples [ check_sample_buf_ofs ( k + y_sample_base_ofs ) ] ;
y_sample1 = p_YSamples [ check_sample_buf_ofs ( k + y_sample_base_ofs1 ) ] ;
{
const uint8_t * pMuls = & s_muls [ row & 1 ] [ nx & 1 ] [ 0 ] ;
int cb = ( cb00_sample * pMuls [ 0 ] + cb01_sample * pMuls [ 1 ] + cb10_sample * pMuls [ 2 ] + cb11_sample * pMuls [ 3 ] + 8 ) > > 4 ;
int cr = ( cr00_sample * pMuls [ 0 ] + cr01_sample * pMuls [ 1 ] + cr10_sample * pMuls [ 2 ] + cr11_sample * pMuls [ 3 ] + 8 ) > > 4 ;
int rc = m_crr [ cr ] ;
int gc = ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ;
int bc = m_cbb [ cb ] ;
d0 [ 0 ] = clamp ( y_sample0 + rc ) ;
d0 [ 1 ] = clamp ( y_sample0 + gc ) ;
d0 [ 2 ] = clamp ( y_sample0 + bc ) ;
d0 [ 3 ] = 255 ;
d0 + = 4 ;
}
{
const uint8_t * pMuls = & s_muls [ ( row + 1 ) & 1 ] [ nx & 1 ] [ 0 ] ;
int cb = ( cb00_sample * pMuls [ 0 ] + cb01_sample * pMuls [ 1 ] + cb10_sample * pMuls [ 2 ] + cb11_sample * pMuls [ 3 ] + 8 ) > > 4 ;
int cr = ( cr00_sample * pMuls [ 0 ] + cr01_sample * pMuls [ 1 ] + cr10_sample * pMuls [ 2 ] + cr11_sample * pMuls [ 3 ] + 8 ) > > 4 ;
int rc = m_crr [ cr ] ;
int gc = ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ;
int bc = m_cbb [ cb ] ;
d1 [ 0 ] = clamp ( y_sample1 + rc ) ;
d1 [ 1 ] = clamp ( y_sample1 + gc ) ;
d1 [ 2 ] = clamp ( y_sample1 + bc ) ;
d1 [ 3 ] = 255 ;
d1 + = 4 ;
}
+ + x ;
}
}
return 2 ;
}
else
{
for ( int x = 0 ; x < m_image_x_size ; x + + )
{
int y_sample = p_YSamples [ check_sample_buf_ofs ( ( x > > 4 ) * BLOCKS_PER_MCU * 64 + ( ( x & 8 ) ? 64 : 0 ) + ( x & 7 ) + y_sample_base_ofs ) ] ;
int c_x0 = ( x - 1 ) > > 1 ;
int c_x1 = JPGD_MIN ( c_x0 + 1 , half_image_x_size ) ;
c_x0 = JPGD_MAX ( c_x0 , 0 ) ;
int a = ( c_x0 > > 3 ) * BLOCKS_PER_MCU * 64 + ( c_x0 & 7 ) ;
int cb00_sample = p_C0Samples [ check_sample_buf_ofs ( a + y0_base ) ] ;
int cr00_sample = p_C0Samples [ check_sample_buf_ofs ( a + y0_base + 64 ) ] ;
int cb01_sample = m_pSample_buf [ check_sample_buf_ofs ( a + y1_base ) ] ;
int cr01_sample = m_pSample_buf [ check_sample_buf_ofs ( a + y1_base + 64 ) ] ;
int b = ( c_x1 > > 3 ) * BLOCKS_PER_MCU * 64 + ( c_x1 & 7 ) ;
int cb10_sample = p_C0Samples [ check_sample_buf_ofs ( b + y0_base ) ] ;
int cr10_sample = p_C0Samples [ check_sample_buf_ofs ( b + y0_base + 64 ) ] ;
int cb11_sample = m_pSample_buf [ check_sample_buf_ofs ( b + y1_base ) ] ;
int cr11_sample = m_pSample_buf [ check_sample_buf_ofs ( b + y1_base + 64 ) ] ;
const uint8_t * pMuls = & s_muls [ row & 1 ] [ x & 1 ] [ 0 ] ;
int cb = ( cb00_sample * pMuls [ 0 ] + cb01_sample * pMuls [ 1 ] + cb10_sample * pMuls [ 2 ] + cb11_sample * pMuls [ 3 ] + 8 ) > > 4 ;
int cr = ( cr00_sample * pMuls [ 0 ] + cr01_sample * pMuls [ 1 ] + cr10_sample * pMuls [ 2 ] + cr11_sample * pMuls [ 3 ] + 8 ) > > 4 ;
int rc = m_crr [ cr ] ;
int gc = ( ( m_crg [ cr ] + m_cbg [ cb ] ) > > 16 ) ;
int bc = m_cbb [ cb ] ;
d0 [ 0 ] = clamp ( y_sample + rc ) ;
d0 [ 1 ] = clamp ( y_sample + gc ) ;
d0 [ 2 ] = clamp ( y_sample + bc ) ;
d0 [ 3 ] = 255 ;
d0 + = 4 ;
}
return 1 ;
}
}
// Y (1 block per MCU) to 8-bit grayscale
void jpeg_decoder : : gray_convert ( )
{
int row = m_max_mcu_y_size - m_mcu_lines_left ;
uint8 * d = m_pScan_line_0 ;
uint8 * s = m_pSample_buf + row * 8 ;
for ( int i = m_max_mcus_per_row ; i > 0 ; i - - )
{
* ( uint * ) d = * ( uint * ) s ;
* ( uint * ) ( & d [ 4 ] ) = * ( uint * ) ( & s [ 4 ] ) ;
s + = 64 ;
d + = 8 ;
}
}
// Find end of image (EOI) marker, so we can return to the user the exact size of the input stream.
void jpeg_decoder : : find_eoi ( )
{
if ( ! m_progressive_flag )
{
// Attempt to read the EOI marker.
//get_bits_no_markers(m_bits_left & 7);
// Prime the bit buffer
m_bits_left = 16 ;
get_bits ( 16 ) ;
get_bits ( 16 ) ;
// The next marker _should_ be EOI
process_markers ( ) ;
}
m_total_bytes_read - = m_in_buf_left ;
}
int jpeg_decoder : : decode_next_mcu_row ( )
{
if ( setjmp ( m_jmp_state ) )
return JPGD_FAILED ;
2022-03-24 19:39:24 +00:00
const bool chroma_y_filtering = ( m_flags & cFlagLinearChromaFiltering ) & & ( ( m_scan_type = = JPGD_YH2V2 ) | | ( m_scan_type = = JPGD_YH1V2 ) ) & & ( m_image_x_size > = 2 ) & & ( m_image_y_size > = 2 ) ;
2021-05-07 15:00:41 +00:00
if ( chroma_y_filtering )
{
std : : swap ( m_pSample_buf , m_pSample_buf_prev ) ;
m_sample_buf_prev_valid = true ;
}
if ( m_progressive_flag )
load_next_row ( ) ;
else
decode_next_row ( ) ;
// Find the EOI marker if that was the last row.
if ( m_total_lines_left < = m_max_mcu_y_size )
find_eoi ( ) ;
m_mcu_lines_left = m_max_mcu_y_size ;
return 0 ;
}
int jpeg_decoder : : decode ( const void * * pScan_line , uint * pScan_line_len )
{
if ( ( m_error_code ) | | ( ! m_ready_flag ) )
return JPGD_FAILED ;
if ( m_total_lines_left = = 0 )
return JPGD_DONE ;
2022-03-24 19:39:24 +00:00
const bool chroma_y_filtering = ( m_flags & cFlagLinearChromaFiltering ) & & ( ( m_scan_type = = JPGD_YH2V2 ) | | ( m_scan_type = = JPGD_YH1V2 ) ) & & ( m_image_x_size > = 2 ) & & ( m_image_y_size > = 2 ) ;
2021-05-07 15:00:41 +00:00
bool get_another_mcu_row = false ;
bool got_mcu_early = false ;
if ( chroma_y_filtering )
{
if ( m_total_lines_left = = m_image_y_size )
get_another_mcu_row = true ;
else if ( ( m_mcu_lines_left = = 1 ) & & ( m_total_lines_left > 1 ) )
{
get_another_mcu_row = true ;
got_mcu_early = true ;
}
}
else
{
get_another_mcu_row = ( m_mcu_lines_left = = 0 ) ;
}
if ( get_another_mcu_row )
{
int status = decode_next_mcu_row ( ) ;
if ( status ! = 0 )
return status ;
}
switch ( m_scan_type )
{
case JPGD_YH2V2 :
{
2022-03-24 19:39:24 +00:00
if ( ( m_flags & cFlagLinearChromaFiltering ) & & ( m_image_x_size > = 2 ) & & ( m_image_y_size > = 2 ) )
2021-05-07 15:00:41 +00:00
{
if ( m_num_buffered_scanlines = = 1 )
{
* pScan_line = m_pScan_line_1 ;
}
else if ( m_num_buffered_scanlines = = 0 )
{
m_num_buffered_scanlines = H2V2ConvertFiltered ( ) ;
* pScan_line = m_pScan_line_0 ;
}
m_num_buffered_scanlines - - ;
}
else
{
if ( ( m_mcu_lines_left & 1 ) = = 0 )
{
H2V2Convert ( ) ;
* pScan_line = m_pScan_line_0 ;
}
else
* pScan_line = m_pScan_line_1 ;
}
break ;
}
case JPGD_YH2V1 :
{
2022-03-24 19:39:24 +00:00
if ( ( m_flags & cFlagLinearChromaFiltering ) & & ( m_image_x_size > = 2 ) & & ( m_image_y_size > = 2 ) )
2021-05-07 15:00:41 +00:00
H2V1ConvertFiltered ( ) ;
else
H2V1Convert ( ) ;
* pScan_line = m_pScan_line_0 ;
break ;
}
case JPGD_YH1V2 :
{
if ( chroma_y_filtering )
{
H1V2ConvertFiltered ( ) ;
* pScan_line = m_pScan_line_0 ;
}
else
{
if ( ( m_mcu_lines_left & 1 ) = = 0 )
{
H1V2Convert ( ) ;
* pScan_line = m_pScan_line_0 ;
}
else
* pScan_line = m_pScan_line_1 ;
}
break ;
}
case JPGD_YH1V1 :
{
H1V1Convert ( ) ;
* pScan_line = m_pScan_line_0 ;
break ;
}
case JPGD_GRAYSCALE :
{
gray_convert ( ) ;
* pScan_line = m_pScan_line_0 ;
break ;
}
}
* pScan_line_len = m_real_dest_bytes_per_scan_line ;
if ( ! got_mcu_early )
{
m_mcu_lines_left - - ;
}
m_total_lines_left - - ;
return JPGD_SUCCESS ;
}
// Creates the tables needed for efficient Huffman decoding.
void jpeg_decoder : : make_huff_table ( int index , huff_tables * pH )
{
int p , i , l , si ;
uint8 huffsize [ 258 ] ;
uint huffcode [ 258 ] ;
uint code ;
uint subtree ;
int code_size ;
int lastp ;
int nextfreeentry ;
int currententry ;
pH - > ac_table = m_huff_ac [ index ] ! = 0 ;
p = 0 ;
for ( l = 1 ; l < = 16 ; l + + )
{
for ( i = 1 ; i < = m_huff_num [ index ] [ l ] ; i + + )
{
if ( p > = 257 )
stop_decoding ( JPGD_DECODE_ERROR ) ;
huffsize [ p + + ] = static_cast < uint8 > ( l ) ;
}
}
assert ( p < 258 ) ;
huffsize [ p ] = 0 ;
lastp = p ;
code = 0 ;
si = huffsize [ 0 ] ;
p = 0 ;
while ( huffsize [ p ] )
{
while ( huffsize [ p ] = = si )
{
if ( p > = 257 )
stop_decoding ( JPGD_DECODE_ERROR ) ;
huffcode [ p + + ] = code ;
code + + ;
}
code < < = 1 ;
si + + ;
}
memset ( pH - > look_up , 0 , sizeof ( pH - > look_up ) ) ;
memset ( pH - > look_up2 , 0 , sizeof ( pH - > look_up2 ) ) ;
memset ( pH - > tree , 0 , sizeof ( pH - > tree ) ) ;
memset ( pH - > code_size , 0 , sizeof ( pH - > code_size ) ) ;
nextfreeentry = - 1 ;
p = 0 ;
while ( p < lastp )
{
i = m_huff_val [ index ] [ p ] ;
code = huffcode [ p ] ;
code_size = huffsize [ p ] ;
assert ( i < JPGD_HUFF_CODE_SIZE_MAX_LENGTH ) ;
pH - > code_size [ i ] = static_cast < uint8 > ( code_size ) ;
if ( code_size < = 8 )
{
code < < = ( 8 - code_size ) ;
for ( l = 1 < < ( 8 - code_size ) ; l > 0 ; l - - )
{
if ( code > = 256 )
stop_decoding ( JPGD_DECODE_ERROR ) ;
pH - > look_up [ code ] = i ;
bool has_extrabits = false ;
int extra_bits = 0 ;
int num_extra_bits = i & 15 ;
int bits_to_fetch = code_size ;
if ( num_extra_bits )
{
int total_codesize = code_size + num_extra_bits ;
if ( total_codesize < = 8 )
{
has_extrabits = true ;
extra_bits = ( ( 1 < < num_extra_bits ) - 1 ) & ( code > > ( 8 - total_codesize ) ) ;
if ( extra_bits > 0x7FFF )
stop_decoding ( JPGD_DECODE_ERROR ) ;
bits_to_fetch + = num_extra_bits ;
}
}
if ( ! has_extrabits )
pH - > look_up2 [ code ] = i | ( bits_to_fetch < < 8 ) ;
else
pH - > look_up2 [ code ] = i | 0x8000 | ( extra_bits < < 16 ) | ( bits_to_fetch < < 8 ) ;
code + + ;
}
}
else
{
subtree = ( code > > ( code_size - 8 ) ) & 0xFF ;
currententry = pH - > look_up [ subtree ] ;
if ( currententry = = 0 )
{
pH - > look_up [ subtree ] = currententry = nextfreeentry ;
pH - > look_up2 [ subtree ] = currententry = nextfreeentry ;
nextfreeentry - = 2 ;
}
code < < = ( 16 - ( code_size - 8 ) ) ;
for ( l = code_size ; l > 9 ; l - - )
{
if ( ( code & 0x8000 ) = = 0 )
currententry - - ;
unsigned int idx = - currententry - 1 ;
if ( idx > = JPGD_HUFF_TREE_MAX_LENGTH )
stop_decoding ( JPGD_DECODE_ERROR ) ;
if ( pH - > tree [ idx ] = = 0 )
{
pH - > tree [ idx ] = nextfreeentry ;
currententry = nextfreeentry ;
nextfreeentry - = 2 ;
}
else
{
currententry = pH - > tree [ idx ] ;
}
code < < = 1 ;
}
if ( ( code & 0x8000 ) = = 0 )
currententry - - ;
if ( ( - currententry - 1 ) > = JPGD_HUFF_TREE_MAX_LENGTH )
stop_decoding ( JPGD_DECODE_ERROR ) ;
pH - > tree [ - currententry - 1 ] = i ;
}
p + + ;
}
}
// Verifies the quantization tables needed for this scan are available.
void jpeg_decoder : : check_quant_tables ( )
{
for ( int i = 0 ; i < m_comps_in_scan ; i + + )
if ( m_quant [ m_comp_quant [ m_comp_list [ i ] ] ] = = nullptr )
stop_decoding ( JPGD_UNDEFINED_QUANT_TABLE ) ;
}
// Verifies that all the Huffman tables needed for this scan are available.
void jpeg_decoder : : check_huff_tables ( )
{
for ( int i = 0 ; i < m_comps_in_scan ; i + + )
{
if ( ( m_spectral_start = = 0 ) & & ( m_huff_num [ m_comp_dc_tab [ m_comp_list [ i ] ] ] = = nullptr ) )
stop_decoding ( JPGD_UNDEFINED_HUFF_TABLE ) ;
if ( ( m_spectral_end > 0 ) & & ( m_huff_num [ m_comp_ac_tab [ m_comp_list [ i ] ] ] = = nullptr ) )
stop_decoding ( JPGD_UNDEFINED_HUFF_TABLE ) ;
}
for ( int i = 0 ; i < JPGD_MAX_HUFF_TABLES ; i + + )
if ( m_huff_num [ i ] )
{
if ( ! m_pHuff_tabs [ i ] )
m_pHuff_tabs [ i ] = ( huff_tables * ) alloc ( sizeof ( huff_tables ) ) ;
make_huff_table ( i , m_pHuff_tabs [ i ] ) ;
}
}
// Determines the component order inside each MCU.
// Also calcs how many MCU's are on each row, etc.
bool jpeg_decoder : : calc_mcu_block_order ( )
{
int component_num , component_id ;
int max_h_samp = 0 , max_v_samp = 0 ;
for ( component_id = 0 ; component_id < m_comps_in_frame ; component_id + + )
{
if ( m_comp_h_samp [ component_id ] > max_h_samp )
max_h_samp = m_comp_h_samp [ component_id ] ;
if ( m_comp_v_samp [ component_id ] > max_v_samp )
max_v_samp = m_comp_v_samp [ component_id ] ;
}
for ( component_id = 0 ; component_id < m_comps_in_frame ; component_id + + )
{
m_comp_h_blocks [ component_id ] = ( ( ( ( m_image_x_size * m_comp_h_samp [ component_id ] ) + ( max_h_samp - 1 ) ) / max_h_samp ) + 7 ) / 8 ;
m_comp_v_blocks [ component_id ] = ( ( ( ( m_image_y_size * m_comp_v_samp [ component_id ] ) + ( max_v_samp - 1 ) ) / max_v_samp ) + 7 ) / 8 ;
}
if ( m_comps_in_scan = = 1 )
{
m_mcus_per_row = m_comp_h_blocks [ m_comp_list [ 0 ] ] ;
m_mcus_per_col = m_comp_v_blocks [ m_comp_list [ 0 ] ] ;
}
else
{
m_mcus_per_row = ( ( ( m_image_x_size + 7 ) / 8 ) + ( max_h_samp - 1 ) ) / max_h_samp ;
m_mcus_per_col = ( ( ( m_image_y_size + 7 ) / 8 ) + ( max_v_samp - 1 ) ) / max_v_samp ;
}
if ( m_comps_in_scan = = 1 )
{
m_mcu_org [ 0 ] = m_comp_list [ 0 ] ;
m_blocks_per_mcu = 1 ;
}
else
{
m_blocks_per_mcu = 0 ;
for ( component_num = 0 ; component_num < m_comps_in_scan ; component_num + + )
{
int num_blocks ;
component_id = m_comp_list [ component_num ] ;
num_blocks = m_comp_h_samp [ component_id ] * m_comp_v_samp [ component_id ] ;
while ( num_blocks - - )
m_mcu_org [ m_blocks_per_mcu + + ] = component_id ;
}
}
if ( m_blocks_per_mcu > m_max_blocks_per_mcu )
return false ;
for ( int mcu_block = 0 ; mcu_block < m_blocks_per_mcu ; mcu_block + + )
{
int comp_id = m_mcu_org [ mcu_block ] ;
if ( comp_id > = JPGD_MAX_QUANT_TABLES )
return false ;
}
return true ;
}
// Starts a new scan.
int jpeg_decoder : : init_scan ( )
{
if ( ! locate_sos_marker ( ) )
return JPGD_FALSE ;
if ( ! calc_mcu_block_order ( ) )
return JPGD_FALSE ;
check_huff_tables ( ) ;
check_quant_tables ( ) ;
memset ( m_last_dc_val , 0 , m_comps_in_frame * sizeof ( uint ) ) ;
m_eob_run = 0 ;
if ( m_restart_interval )
{
m_restarts_left = m_restart_interval ;
m_next_restart_num = 0 ;
}
fix_in_buffer ( ) ;
return JPGD_TRUE ;
}
// Starts a frame. Determines if the number of components or sampling factors
// are supported.
void jpeg_decoder : : init_frame ( )
{
int i ;
if ( m_comps_in_frame = = 1 )
{
if ( ( m_comp_h_samp [ 0 ] ! = 1 ) | | ( m_comp_v_samp [ 0 ] ! = 1 ) )
stop_decoding ( JPGD_UNSUPPORTED_SAMP_FACTORS ) ;
m_scan_type = JPGD_GRAYSCALE ;
m_max_blocks_per_mcu = 1 ;
m_max_mcu_x_size = 8 ;
m_max_mcu_y_size = 8 ;
}
else if ( m_comps_in_frame = = 3 )
{
if ( ( ( m_comp_h_samp [ 1 ] ! = 1 ) | | ( m_comp_v_samp [ 1 ] ! = 1 ) ) | |
( ( m_comp_h_samp [ 2 ] ! = 1 ) | | ( m_comp_v_samp [ 2 ] ! = 1 ) ) )
stop_decoding ( JPGD_UNSUPPORTED_SAMP_FACTORS ) ;
if ( ( m_comp_h_samp [ 0 ] = = 1 ) & & ( m_comp_v_samp [ 0 ] = = 1 ) )
{
m_scan_type = JPGD_YH1V1 ;
m_max_blocks_per_mcu = 3 ;
m_max_mcu_x_size = 8 ;
m_max_mcu_y_size = 8 ;
}
else if ( ( m_comp_h_samp [ 0 ] = = 2 ) & & ( m_comp_v_samp [ 0 ] = = 1 ) )
{
m_scan_type = JPGD_YH2V1 ;
m_max_blocks_per_mcu = 4 ;
m_max_mcu_x_size = 16 ;
m_max_mcu_y_size = 8 ;
}
else if ( ( m_comp_h_samp [ 0 ] = = 1 ) & & ( m_comp_v_samp [ 0 ] = = 2 ) )
{
m_scan_type = JPGD_YH1V2 ;
m_max_blocks_per_mcu = 4 ;
m_max_mcu_x_size = 8 ;
m_max_mcu_y_size = 16 ;
}
else if ( ( m_comp_h_samp [ 0 ] = = 2 ) & & ( m_comp_v_samp [ 0 ] = = 2 ) )
{
m_scan_type = JPGD_YH2V2 ;
m_max_blocks_per_mcu = 6 ;
m_max_mcu_x_size = 16 ;
m_max_mcu_y_size = 16 ;
}
else
stop_decoding ( JPGD_UNSUPPORTED_SAMP_FACTORS ) ;
}
else
stop_decoding ( JPGD_UNSUPPORTED_COLORSPACE ) ;
m_max_mcus_per_row = ( m_image_x_size + ( m_max_mcu_x_size - 1 ) ) / m_max_mcu_x_size ;
m_max_mcus_per_col = ( m_image_y_size + ( m_max_mcu_y_size - 1 ) ) / m_max_mcu_y_size ;
// These values are for the *destination* pixels: after conversion.
if ( m_scan_type = = JPGD_GRAYSCALE )
m_dest_bytes_per_pixel = 1 ;
else
m_dest_bytes_per_pixel = 4 ;
m_dest_bytes_per_scan_line = ( ( m_image_x_size + 15 ) & 0xFFF0 ) * m_dest_bytes_per_pixel ;
m_real_dest_bytes_per_scan_line = ( m_image_x_size * m_dest_bytes_per_pixel ) ;
// Initialize two scan line buffers.
m_pScan_line_0 = ( uint8 * ) alloc ( m_dest_bytes_per_scan_line , true ) ;
if ( ( m_scan_type = = JPGD_YH1V2 ) | | ( m_scan_type = = JPGD_YH2V2 ) )
m_pScan_line_1 = ( uint8 * ) alloc ( m_dest_bytes_per_scan_line , true ) ;
m_max_blocks_per_row = m_max_mcus_per_row * m_max_blocks_per_mcu ;
// Should never happen
if ( m_max_blocks_per_row > JPGD_MAX_BLOCKS_PER_ROW )
stop_decoding ( JPGD_DECODE_ERROR ) ;
// Allocate the coefficient buffer, enough for one MCU
m_pMCU_coefficients = ( jpgd_block_t * ) alloc ( m_max_blocks_per_mcu * 64 * sizeof ( jpgd_block_t ) ) ;
for ( i = 0 ; i < m_max_blocks_per_mcu ; i + + )
m_mcu_block_max_zag [ i ] = 64 ;
m_pSample_buf = ( uint8 * ) alloc ( m_max_blocks_per_row * 64 ) ;
m_pSample_buf_prev = ( uint8 * ) alloc ( m_max_blocks_per_row * 64 ) ;
m_total_lines_left = m_image_y_size ;
m_mcu_lines_left = 0 ;
create_look_ups ( ) ;
}
// The coeff_buf series of methods originally stored the coefficients
// into a "virtual" file which was located in EMS, XMS, or a disk file. A cache
// was used to make this process more efficient. Now, we can store the entire
// thing in RAM.
jpeg_decoder : : coeff_buf * jpeg_decoder : : coeff_buf_open ( int block_num_x , int block_num_y , int block_len_x , int block_len_y )
{
coeff_buf * cb = ( coeff_buf * ) alloc ( sizeof ( coeff_buf ) ) ;
cb - > block_num_x = block_num_x ;
cb - > block_num_y = block_num_y ;
cb - > block_len_x = block_len_x ;
cb - > block_len_y = block_len_y ;
cb - > block_size = ( block_len_x * block_len_y ) * sizeof ( jpgd_block_t ) ;
cb - > pData = ( uint8 * ) alloc ( cb - > block_size * block_num_x * block_num_y , true ) ;
return cb ;
}
inline jpgd_block_t * jpeg_decoder : : coeff_buf_getp ( coeff_buf * cb , int block_x , int block_y )
{
if ( ( block_x > = cb - > block_num_x ) | | ( block_y > = cb - > block_num_y ) )
stop_decoding ( JPGD_DECODE_ERROR ) ;
return ( jpgd_block_t * ) ( cb - > pData + block_x * cb - > block_size + block_y * ( cb - > block_size * cb - > block_num_x ) ) ;
}
// The following methods decode the various types of m_blocks encountered
// in progressively encoded images.
void jpeg_decoder : : decode_block_dc_first ( jpeg_decoder * pD , int component_id , int block_x , int block_y )
{
int s , r ;
jpgd_block_t * p = pD - > coeff_buf_getp ( pD - > m_dc_coeffs [ component_id ] , block_x , block_y ) ;
if ( ( s = pD - > huff_decode ( pD - > m_pHuff_tabs [ pD - > m_comp_dc_tab [ component_id ] ] ) ) ! = 0 )
{
if ( s > = 16 )
pD - > stop_decoding ( JPGD_DECODE_ERROR ) ;
r = pD - > get_bits_no_markers ( s ) ;
s = JPGD_HUFF_EXTEND ( r , s ) ;
}
pD - > m_last_dc_val [ component_id ] = ( s + = pD - > m_last_dc_val [ component_id ] ) ;
p [ 0 ] = static_cast < jpgd_block_t > ( s < < pD - > m_successive_low ) ;
}
void jpeg_decoder : : decode_block_dc_refine ( jpeg_decoder * pD , int component_id , int block_x , int block_y )
{
if ( pD - > get_bits_no_markers ( 1 ) )
{
jpgd_block_t * p = pD - > coeff_buf_getp ( pD - > m_dc_coeffs [ component_id ] , block_x , block_y ) ;
p [ 0 ] | = ( 1 < < pD - > m_successive_low ) ;
}
}
void jpeg_decoder : : decode_block_ac_first ( jpeg_decoder * pD , int component_id , int block_x , int block_y )
{
int k , s , r ;
if ( pD - > m_eob_run )
{
pD - > m_eob_run - - ;
return ;
}
jpgd_block_t * p = pD - > coeff_buf_getp ( pD - > m_ac_coeffs [ component_id ] , block_x , block_y ) ;
for ( k = pD - > m_spectral_start ; k < = pD - > m_spectral_end ; k + + )
{
unsigned int idx = pD - > m_comp_ac_tab [ component_id ] ;
if ( idx > = JPGD_MAX_HUFF_TABLES )
pD - > stop_decoding ( JPGD_DECODE_ERROR ) ;
s = pD - > huff_decode ( pD - > m_pHuff_tabs [ idx ] ) ;
r = s > > 4 ;
s & = 15 ;
if ( s )
{
if ( ( k + = r ) > 63 )
pD - > stop_decoding ( JPGD_DECODE_ERROR ) ;
r = pD - > get_bits_no_markers ( s ) ;
s = JPGD_HUFF_EXTEND ( r , s ) ;
p [ g_ZAG [ k ] ] = static_cast < jpgd_block_t > ( s < < pD - > m_successive_low ) ;
}
else
{
if ( r = = 15 )
{
if ( ( k + = 15 ) > 63 )
pD - > stop_decoding ( JPGD_DECODE_ERROR ) ;
}
else
{
pD - > m_eob_run = 1 < < r ;
if ( r )
pD - > m_eob_run + = pD - > get_bits_no_markers ( r ) ;
pD - > m_eob_run - - ;
break ;
}
}
}
}
void jpeg_decoder : : decode_block_ac_refine ( jpeg_decoder * pD , int component_id , int block_x , int block_y )
{
int s , k , r ;
int p1 = 1 < < pD - > m_successive_low ;
//int m1 = (-1) << pD->m_successive_low;
int m1 = static_cast < int > ( ( UINT32_MAX < < pD - > m_successive_low ) ) ;
jpgd_block_t * p = pD - > coeff_buf_getp ( pD - > m_ac_coeffs [ component_id ] , block_x , block_y ) ;
if ( pD - > m_spectral_end > 63 )
pD - > stop_decoding ( JPGD_DECODE_ERROR ) ;
k = pD - > m_spectral_start ;
if ( pD - > m_eob_run = = 0 )
{
for ( ; k < = pD - > m_spectral_end ; k + + )
{
unsigned int idx = pD - > m_comp_ac_tab [ component_id ] ;
if ( idx > = JPGD_MAX_HUFF_TABLES )
pD - > stop_decoding ( JPGD_DECODE_ERROR ) ;
s = pD - > huff_decode ( pD - > m_pHuff_tabs [ idx ] ) ;
r = s > > 4 ;
s & = 15 ;
if ( s )
{
if ( s ! = 1 )
pD - > stop_decoding ( JPGD_DECODE_ERROR ) ;
if ( pD - > get_bits_no_markers ( 1 ) )
s = p1 ;
else
s = m1 ;
}
else
{
if ( r ! = 15 )
{
pD - > m_eob_run = 1 < < r ;
if ( r )
pD - > m_eob_run + = pD - > get_bits_no_markers ( r ) ;
break ;
}
}
do
{
jpgd_block_t * this_coef = p + g_ZAG [ k & 63 ] ;
if ( * this_coef ! = 0 )
{
if ( pD - > get_bits_no_markers ( 1 ) )
{
if ( ( * this_coef & p1 ) = = 0 )
{
if ( * this_coef > = 0 )
* this_coef = static_cast < jpgd_block_t > ( * this_coef + p1 ) ;
else
* this_coef = static_cast < jpgd_block_t > ( * this_coef + m1 ) ;
}
}
}
else
{
if ( - - r < 0 )
break ;
}
k + + ;
} while ( k < = pD - > m_spectral_end ) ;
if ( ( s ) & & ( k < 64 ) )
{
p [ g_ZAG [ k ] ] = static_cast < jpgd_block_t > ( s ) ;
}
}
}
if ( pD - > m_eob_run > 0 )
{
for ( ; k < = pD - > m_spectral_end ; k + + )
{
jpgd_block_t * this_coef = p + g_ZAG [ k & 63 ] ; // logical AND to shut up static code analysis
if ( * this_coef ! = 0 )
{
if ( pD - > get_bits_no_markers ( 1 ) )
{
if ( ( * this_coef & p1 ) = = 0 )
{
if ( * this_coef > = 0 )
* this_coef = static_cast < jpgd_block_t > ( * this_coef + p1 ) ;
else
* this_coef = static_cast < jpgd_block_t > ( * this_coef + m1 ) ;
}
}
}
}
pD - > m_eob_run - - ;
}
}
// Decode a scan in a progressively encoded image.
void jpeg_decoder : : decode_scan ( pDecode_block_func decode_block_func )
{
int mcu_row , mcu_col , mcu_block ;
int block_x_mcu [ JPGD_MAX_COMPONENTS ] , block_y_mcu [ JPGD_MAX_COMPONENTS ] ;
memset ( block_y_mcu , 0 , sizeof ( block_y_mcu ) ) ;
for ( mcu_col = 0 ; mcu_col < m_mcus_per_col ; mcu_col + + )
{
int component_num , component_id ;
memset ( block_x_mcu , 0 , sizeof ( block_x_mcu ) ) ;
for ( mcu_row = 0 ; mcu_row < m_mcus_per_row ; mcu_row + + )
{
int block_x_mcu_ofs = 0 , block_y_mcu_ofs = 0 ;
if ( ( m_restart_interval ) & & ( m_restarts_left = = 0 ) )
process_restart ( ) ;
for ( mcu_block = 0 ; mcu_block < m_blocks_per_mcu ; mcu_block + + )
{
component_id = m_mcu_org [ mcu_block ] ;
decode_block_func ( this , component_id , block_x_mcu [ component_id ] + block_x_mcu_ofs , block_y_mcu [ component_id ] + block_y_mcu_ofs ) ;
if ( m_comps_in_scan = = 1 )
block_x_mcu [ component_id ] + + ;
else
{
if ( + + block_x_mcu_ofs = = m_comp_h_samp [ component_id ] )
{
block_x_mcu_ofs = 0 ;
if ( + + block_y_mcu_ofs = = m_comp_v_samp [ component_id ] )
{
block_y_mcu_ofs = 0 ;
block_x_mcu [ component_id ] + = m_comp_h_samp [ component_id ] ;
}
}
}
}
m_restarts_left - - ;
}
if ( m_comps_in_scan = = 1 )
block_y_mcu [ m_comp_list [ 0 ] ] + + ;
else
{
for ( component_num = 0 ; component_num < m_comps_in_scan ; component_num + + )
{
component_id = m_comp_list [ component_num ] ;
block_y_mcu [ component_id ] + = m_comp_v_samp [ component_id ] ;
}
}
}
}
// Decode a progressively encoded image.
void jpeg_decoder : : init_progressive ( )
{
int i ;
if ( m_comps_in_frame = = 4 )
stop_decoding ( JPGD_UNSUPPORTED_COLORSPACE ) ;
// Allocate the coefficient buffers.
for ( i = 0 ; i < m_comps_in_frame ; i + + )
{
m_dc_coeffs [ i ] = coeff_buf_open ( m_max_mcus_per_row * m_comp_h_samp [ i ] , m_max_mcus_per_col * m_comp_v_samp [ i ] , 1 , 1 ) ;
m_ac_coeffs [ i ] = coeff_buf_open ( m_max_mcus_per_row * m_comp_h_samp [ i ] , m_max_mcus_per_col * m_comp_v_samp [ i ] , 8 , 8 ) ;
}
// See https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf
uint32_t total_scans = 0 ;
const uint32_t MAX_SCANS_TO_PROCESS = 1000 ;
for ( ; ; )
{
int dc_only_scan , refinement_scan ;
pDecode_block_func decode_block_func ;
if ( ! init_scan ( ) )
break ;
dc_only_scan = ( m_spectral_start = = 0 ) ;
refinement_scan = ( m_successive_high ! = 0 ) ;
if ( ( m_spectral_start > m_spectral_end ) | | ( m_spectral_end > 63 ) )
stop_decoding ( JPGD_BAD_SOS_SPECTRAL ) ;
if ( dc_only_scan )
{
if ( m_spectral_end )
stop_decoding ( JPGD_BAD_SOS_SPECTRAL ) ;
}
else if ( m_comps_in_scan ! = 1 ) /* AC scans can only contain one component */
stop_decoding ( JPGD_BAD_SOS_SPECTRAL ) ;
if ( ( refinement_scan ) & & ( m_successive_low ! = m_successive_high - 1 ) )
stop_decoding ( JPGD_BAD_SOS_SUCCESSIVE ) ;
if ( dc_only_scan )
{
if ( refinement_scan )
decode_block_func = decode_block_dc_refine ;
else
decode_block_func = decode_block_dc_first ;
}
else
{
if ( refinement_scan )
decode_block_func = decode_block_ac_refine ;
else
decode_block_func = decode_block_ac_first ;
}
decode_scan ( decode_block_func ) ;
m_bits_left = 16 ;
get_bits ( 16 ) ;
get_bits ( 16 ) ;
total_scans + + ;
if ( total_scans > MAX_SCANS_TO_PROCESS )
stop_decoding ( JPGD_TOO_MANY_SCANS ) ;
}
m_comps_in_scan = m_comps_in_frame ;
for ( i = 0 ; i < m_comps_in_frame ; i + + )
m_comp_list [ i ] = i ;
if ( ! calc_mcu_block_order ( ) )
stop_decoding ( JPGD_DECODE_ERROR ) ;
}
void jpeg_decoder : : init_sequential ( )
{
if ( ! init_scan ( ) )
stop_decoding ( JPGD_UNEXPECTED_MARKER ) ;
}
void jpeg_decoder : : decode_start ( )
{
init_frame ( ) ;
if ( m_progressive_flag )
init_progressive ( ) ;
else
init_sequential ( ) ;
}
void jpeg_decoder : : decode_init ( jpeg_decoder_stream * pStream , uint32_t flags )
{
init ( pStream , flags ) ;
locate_sof_marker ( ) ;
}
jpeg_decoder : : jpeg_decoder ( jpeg_decoder_stream * pStream , uint32_t flags )
{
if ( setjmp ( m_jmp_state ) )
return ;
decode_init ( pStream , flags ) ;
}
int jpeg_decoder : : begin_decoding ( )
{
if ( m_ready_flag )
return JPGD_SUCCESS ;
if ( m_error_code )
return JPGD_FAILED ;
if ( setjmp ( m_jmp_state ) )
return JPGD_FAILED ;
decode_start ( ) ;
m_ready_flag = true ;
return JPGD_SUCCESS ;
}
jpeg_decoder : : ~ jpeg_decoder ( )
{
free_all_blocks ( ) ;
}
jpeg_decoder_file_stream : : jpeg_decoder_file_stream ( )
{
m_pFile = nullptr ;
m_eof_flag = false ;
m_error_flag = false ;
}
void jpeg_decoder_file_stream : : close ( )
{
if ( m_pFile )
{
fclose ( m_pFile ) ;
m_pFile = nullptr ;
}
m_eof_flag = false ;
m_error_flag = false ;
}
jpeg_decoder_file_stream : : ~ jpeg_decoder_file_stream ( )
{
close ( ) ;
}
bool jpeg_decoder_file_stream : : open ( const char * Pfilename )
{
close ( ) ;
m_eof_flag = false ;
m_error_flag = false ;
# if defined(_MSC_VER)
m_pFile = nullptr ;
fopen_s ( & m_pFile , Pfilename , " rb " ) ;
# else
m_pFile = fopen ( Pfilename , " rb " ) ;
# endif
return m_pFile ! = nullptr ;
}
int jpeg_decoder_file_stream : : read ( uint8 * pBuf , int max_bytes_to_read , bool * pEOF_flag )
{
if ( ! m_pFile )
return - 1 ;
if ( m_eof_flag )
{
* pEOF_flag = true ;
return 0 ;
}
if ( m_error_flag )
return - 1 ;
int bytes_read = static_cast < int > ( fread ( pBuf , 1 , max_bytes_to_read , m_pFile ) ) ;
if ( bytes_read < max_bytes_to_read )
{
if ( ferror ( m_pFile ) )
{
m_error_flag = true ;
return - 1 ;
}
m_eof_flag = true ;
* pEOF_flag = true ;
}
return bytes_read ;
}
bool jpeg_decoder_mem_stream : : open ( const uint8 * pSrc_data , uint size )
{
close ( ) ;
m_pSrc_data = pSrc_data ;
m_ofs = 0 ;
m_size = size ;
return true ;
}
int jpeg_decoder_mem_stream : : read ( uint8 * pBuf , int max_bytes_to_read , bool * pEOF_flag )
{
* pEOF_flag = false ;
if ( ! m_pSrc_data )
return - 1 ;
uint bytes_remaining = m_size - m_ofs ;
if ( ( uint ) max_bytes_to_read > bytes_remaining )
{
max_bytes_to_read = bytes_remaining ;
* pEOF_flag = true ;
}
memcpy ( pBuf , m_pSrc_data + m_ofs , max_bytes_to_read ) ;
m_ofs + = max_bytes_to_read ;
return max_bytes_to_read ;
}
unsigned char * decompress_jpeg_image_from_stream ( jpeg_decoder_stream * pStream , int * width , int * height , int * actual_comps , int req_comps , uint32_t flags )
{
if ( ! actual_comps )
return nullptr ;
* actual_comps = 0 ;
if ( ( ! pStream ) | | ( ! width ) | | ( ! height ) | | ( ! req_comps ) )
return nullptr ;
if ( ( req_comps ! = 1 ) & & ( req_comps ! = 3 ) & & ( req_comps ! = 4 ) )
return nullptr ;
jpeg_decoder decoder ( pStream , flags ) ;
if ( decoder . get_error_code ( ) ! = JPGD_SUCCESS )
return nullptr ;
const int image_width = decoder . get_width ( ) , image_height = decoder . get_height ( ) ;
* width = image_width ;
* height = image_height ;
* actual_comps = decoder . get_num_components ( ) ;
if ( decoder . begin_decoding ( ) ! = JPGD_SUCCESS )
return nullptr ;
const int dst_bpl = image_width * req_comps ;
uint8 * pImage_data = ( uint8 * ) jpgd_malloc ( dst_bpl * image_height ) ;
if ( ! pImage_data )
return nullptr ;
for ( int y = 0 ; y < image_height ; y + + )
{
const uint8 * pScan_line ;
uint scan_line_len ;
if ( decoder . decode ( ( const void * * ) & pScan_line , & scan_line_len ) ! = JPGD_SUCCESS )
{
jpgd_free ( pImage_data ) ;
return nullptr ;
}
uint8 * pDst = pImage_data + y * dst_bpl ;
if ( ( ( req_comps = = 1 ) & & ( decoder . get_num_components ( ) = = 1 ) ) | | ( ( req_comps = = 4 ) & & ( decoder . get_num_components ( ) = = 3 ) ) )
memcpy ( pDst , pScan_line , dst_bpl ) ;
else if ( decoder . get_num_components ( ) = = 1 )
{
if ( req_comps = = 3 )
{
for ( int x = 0 ; x < image_width ; x + + )
{
uint8 luma = pScan_line [ x ] ;
pDst [ 0 ] = luma ;
pDst [ 1 ] = luma ;
pDst [ 2 ] = luma ;
pDst + = 3 ;
}
}
else
{
for ( int x = 0 ; x < image_width ; x + + )
{
uint8 luma = pScan_line [ x ] ;
pDst [ 0 ] = luma ;
pDst [ 1 ] = luma ;
pDst [ 2 ] = luma ;
pDst [ 3 ] = 255 ;
pDst + = 4 ;
}
}
}
else if ( decoder . get_num_components ( ) = = 3 )
{
if ( req_comps = = 1 )
{
const int YR = 19595 , YG = 38470 , YB = 7471 ;
for ( int x = 0 ; x < image_width ; x + + )
{
int r = pScan_line [ x * 4 + 0 ] ;
int g = pScan_line [ x * 4 + 1 ] ;
int b = pScan_line [ x * 4 + 2 ] ;
* pDst + + = static_cast < uint8 > ( ( r * YR + g * YG + b * YB + 32768 ) > > 16 ) ;
}
}
else
{
for ( int x = 0 ; x < image_width ; x + + )
{
pDst [ 0 ] = pScan_line [ x * 4 + 0 ] ;
pDst [ 1 ] = pScan_line [ x * 4 + 1 ] ;
pDst [ 2 ] = pScan_line [ x * 4 + 2 ] ;
pDst + = 3 ;
}
}
}
}
return pImage_data ;
}
unsigned char * decompress_jpeg_image_from_memory ( const unsigned char * pSrc_data , int src_data_size , int * width , int * height , int * actual_comps , int req_comps , uint32_t flags )
{
jpgd : : jpeg_decoder_mem_stream mem_stream ( pSrc_data , src_data_size ) ;
return decompress_jpeg_image_from_stream ( & mem_stream , width , height , actual_comps , req_comps , flags ) ;
}
unsigned char * decompress_jpeg_image_from_file ( const char * pSrc_filename , int * width , int * height , int * actual_comps , int req_comps , uint32_t flags )
{
jpgd : : jpeg_decoder_file_stream file_stream ;
if ( ! file_stream . open ( pSrc_filename ) )
return nullptr ;
return decompress_jpeg_image_from_stream ( & file_stream , width , height , actual_comps , req_comps , flags ) ;
}
} // namespace jpgd