📄 grfmt_jpeg.cpp
字号:
lstrm.SetPos( pos + length );
}
}
parsing_end: ;
}
catch( int )
{
}
result = is_jfif && is_sof && is_qt && is_ht && is_sos;
if( !result )
{
m_width = m_height = -1;
m_offset = -1;
m_strm.Close();
}
return result;
}
bool GrFmtJpegReader::LoadQuantTables( int length )
{
uchar buffer[128];
int i, tq_size;
RMByteStream& lstrm = m_strm.m_low_strm;
length -= 2;
while( length > 0 )
{
int tq = lstrm.GetByte();
int size = tq >> 4;
tq &= 15;
tq_size = (64<<size) + 1;
if( tq > 3 || size > 1 || length < tq_size ) return false;
length -= tq_size;
lstrm.GetBytes( buffer, tq_size - 1 );
if( size == 0 ) // 8 bit quant factors
{
for( i = 0; i < 64; i++ )
{
int idx = zigzag[i];
m_tq[tq][idx] = buffer[i] * 16 * idct_prescale[idx];
}
}
else // 16 bit quant factors
{
for( i = 0; i < 64; i++ )
{
int idx = zigzag[i];
m_tq[tq][idx] = ((unsigned short*)buffer)[i] * idct_prescale[idx];
}
}
m_is_tq[tq] = true;
}
return true;
}
bool GrFmtJpegReader::LoadHuffmanTables( int length )
{
const int max_bits = 16;
uchar buffer[1024];
int buffer2[1024];
int i, ht_size;
RMByteStream& lstrm = m_strm.m_low_strm;
length -= 2;
while( length > 0 )
{
int t = lstrm.GetByte();
int hclass = t >> 4;
t &= 15;
if( t > 3 || hclass > 1 || length < 17 ) return false;
length -= 17;
lstrm.GetBytes( buffer, max_bits );
for( i = 0, ht_size = 0; i < max_bits; i++ ) ht_size += buffer[i];
if( length < ht_size ) return false;
length -= ht_size;
lstrm.GetBytes( buffer + max_bits, ht_size );
if( !::bsCreateDecodeHuffmanTable(
::bsCreateSourceHuffmanTable(
buffer, buffer2, max_bits, first_table_bits ),
hclass == 0 ? m_td[t] : m_ta[t],
max_dec_htable_size )) return false;
if( hclass == 0 )
m_is_td[t] = true;
else
m_is_ta[t] = true;
}
return true;
}
bool GrFmtJpegReader::ReadData( uchar* data, int step, int color )
{
if( m_offset < 0 || !m_strm.IsOpened())
return false;
try
{
RMByteStream& lstrm = m_strm.m_low_strm;
lstrm.SetPos( m_offset );
for(;;)
{
int marker = m_strm.FindMarker() & 255;
if( marker == 0xD8 /* SOI */ || marker == 0xD9 /* EOI */ )
goto decoding_end;
// check for standalone markers
if( marker != 0x01 /* TEM */ && !( 0xD0 <= marker && marker <= 0xD7 ))
{
int pos = lstrm.GetPos();
int length = lstrm.GetWord();
switch( marker )
{
case 0xC4: // DHT
if( !LoadHuffmanTables( length )) goto decoding_end;
break;
case 0xDA: // SOS
// read scan header
{
int idx[3] = { -1, -1, -1 };
int i, ns = lstrm.GetByte();
int sum = 0, a; // spectral selection & approximation
if( ns != m_planes ) goto decoding_end;
for( i = 0; i < ns; i++ )
{
int td, ta, c = lstrm.GetByte() - 1;
if( c < 0 || m_planes <= c )
{
c = i; // hack
}
if( idx[c] != -1 ) goto decoding_end;
idx[i] = c;
td = lstrm.GetByte();
ta = td & 15;
td >>= 4;
if( !(ta <= 3 && m_is_ta[ta] &&
td <= 3 && m_is_td[td] &&
m_is_tq[m_ci[c].tq]) )
goto decoding_end;
m_ci[c].td = (char)td;
m_ci[c].ta = (char)ta;
sum += m_ci[c].h*m_ci[c].v;
}
if( sum > 10 ) goto decoding_end;
m_ss = lstrm.GetByte();
m_se = lstrm.GetByte();
a = lstrm.GetByte();
m_al = a & 15;
m_ah = a >> 4;
ProcessScan( idx, ns, data, step, color );
goto decoding_end; // only single scan case is supported now
}
//m_offset = pos - 2;
//break;
case 0xDD: // DRI
m_MCUs = lstrm.GetWord();
break;
}
if( marker != 0xDA ) lstrm.SetPos( pos + length );
}
}
decoding_end: ;
}
catch( int )
{
}
return true;
}
void GrFmtJpegReader::ResetDecoder()
{
m_ci[0].dc_pred = m_ci[1].dc_pred = m_ci[2].dc_pred = 0;
}
void GrFmtJpegReader::ProcessScan( int* idx, int ns, uchar* data, int step, int color )
{
int i, s = 0, mcu, x1 = 0, y1 = 0;
int temp[64];
int blocks[10][64];
int pos[3], h[3], v[3];
int x_shift = 0, y_shift = 0;
int nch = color ? 3 : 1;
assert( ns == m_planes && m_ss == 0 && m_se == 63 &&
m_al == 0 && m_ah == 0 ); // sequental & single scan
assert( idx[0] == 0 && (ns ==1 || (idx[1] == 1 && idx[2] == 2)));
for( i = 0; i < ns; i++ )
{
int c = idx[i];
h[c] = m_ci[c].h*8;
v[c] = m_ci[c].v*8;
pos[c] = s >> 6;
s += h[c]*v[c];
}
if( ns == 3 )
{
x_shift = h[0]/(h[1]*2);
y_shift = v[0]/(v[1]*2);
}
m_strm.Flush();
ResetDecoder();
for( mcu = 0;; mcu++ )
{
int x2, y2, x, y;
int* cmp;
uchar* data1;
if( mcu == m_MCUs && m_MCUs != 0 )
{
ResetDecoder();
m_strm.AlignOnByte();
mcu = 0;
}
// Get mcu
for( i = 0; i < ns; i++ )
{
int c = idx[i];
cmp = blocks[pos[c]];
for( y = 0; y < v[c]; y += 8, cmp += h[c]*8 )
for( x = 0; x < h[c]; x += 8 )
{
GetBlock( temp, c );
if( i < (color ? 3 : 1))
{
aan_idct8x8( temp, cmp + x, h[c] );
}
}
}
y2 = v[0];
x2 = h[0];
if( y1 + y2 > m_height ) y2 = m_height - y1;
if( x1 + x2 > m_width ) x2 = m_width - x1;
cmp = blocks[0];
data1 = data + x1*nch;
if( ns == 1 )
for( y = 0; y < y2; y++, data1 += step, cmp += h[0] )
{
if( color )
{
for( x = 0; x < x2; x++ )
{
int val = descale( cmp[x] + 128*4, 2 );
data1[x*3] = data1[x*3 + 1] = data1[x*3 + 2] = saturate( val );
}
}
else
{
for( x = 0; x < x2; x++ )
{
int val = descale( cmp[x] + 128*4, 2 );
data1[x] = saturate( val );
}
}
}
else
{
for( y = 0; y < y2; y++, data1 += step, cmp += h[0] )
{
if( color )
{
int shift = h[1]*(y >> y_shift);
int* cmpCb = blocks[pos[1]] + shift;
int* cmpCr = blocks[pos[2]] + shift;
for( x = 0; x < x2; x++ )
{
int Y = (cmp[x] + 128*4) << fixc;
int Cb = cmpCb[x >> x_shift];
int Cr = cmpCr[x >> x_shift];
int t = (Y + Cb*b_cb) >> (fixc + 2);
data1[x*3] = saturate(t);
t = (Y + Cb*g_cb + Cr*g_cr) >> (fixc + 2);
data1[x*3 + 1] = saturate(t);
t = (Y + Cr*r_cr) >> (fixc + 2);
data1[x*3 + 2] = saturate(t);
}
}
else
{
for( x = 0; x < x2; x++ )
{
int val = descale( cmp[x] + 128*4, 2 );
data1[x] = saturate(val);
}
}
}
}
x1 += h[0];
if( x1 >= m_width )
{
x1 = 0;
y1 += v[0];
data += v[0]*step;
if( y1 >= m_height ) break;
}
}
}
void GrFmtJpegReader::GetBlock( int* block, int c )
{
memset( block, 0, 64*sizeof(block[0]) );
assert( 0 <= c && c < 3 );
const short* td = m_td[m_ci[c].td];
const short* ta = m_ta[m_ci[c].ta];
const int* tq = m_tq[m_ci[c].tq];
// Get DC coefficient
int i = 0, cat = m_strm.GetHuff( td );
int mask = bs_bit_mask[cat];
int val = m_strm.Get( cat );
val -= (val*2 <= mask ? mask : 0);
m_ci[c].dc_pred = val += m_ci[c].dc_pred;
block[0] = descale(val * tq[0],16);
// Get AC coeffs
for(;;)
{
cat = m_strm.GetHuff( ta );
if( cat == 0 ) break; // end of block
i += (cat >> 4) + 1;
cat &= 15;
mask = bs_bit_mask[cat];
val = m_strm.Get( cat );
cat = zigzag[i];
val -= (val*2 <= mask ? mask : 0);
block[cat] = descale(val * tq[cat], 16);
assert( i <= 63 );
if( i >= 63 ) break;
}
}
////////////////////// WJpegStream ///////////////////////
WJpegBitStream::WJpegBitStream()
{
}
WJpegBitStream::~WJpegBitStream()
{
Close();
m_is_opened = false;
}
bool WJpegBitStream::Open( const char* filename )
{
Close();
Allocate();
m_is_opened = m_low_strm.Open( filename );
if( m_is_opened )
{
m_block_pos = 0;
ResetBuffer();
}
return m_is_opened;
}
void WJpegBitStream::Close()
{
if( m_is_opened )
{
Flush();
m_low_strm.Close();
m_is_opened = false;
}
}
void WJpegBitStream::Flush()
{
Put( -1, m_bit_idx & 31 );
*((ulong*&)m_current)++ = m_val;
WriteBlock();
ResetBuffer();
}
void WJpegBitStream::WriteBlock()
{
uchar* ptr = m_start;
bsBSwapBlock( m_start, m_current );
while( ptr < m_current )
{
int val = *ptr++;
m_low_strm.PutByte( val );
if( val == 0xff )
{
m_low_strm.PutByte( 0 );
}
}
m_current = m_start;
}
/////////////////////// GrFmtJpegWriter ///////////////////
GrFmtJpegWriter::GrFmtJpegWriter()
{
m_description = fmtDescrJpeg;
}
GrFmtJpegWriter::~GrFmtJpegWriter()
{
}
// Standard JPEG quantization tables
static const uchar jpegTableK1_T[] =
{
16, 12, 14, 14, 18, 24, 49, 72,
11, 12, 13, 17, 22, 35, 64, 92,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -