/***************************************************************************#
# jpegenc: library to encode a jpeg frame from various input palette.       #
# jpegenc works for embedded device without libjpeg                         #
#.                                                                          #
# 		Copyright (C) 2005 Michel Xhaard                            #
#                                                                           #
# This program is free software; you can redistribute it and/or modify      #
# it under the terms of the GNU General Public License as published by      #
# the Free Software Foundation; either version 2 of the License, or         #
# (at your option) any later version.                                       #
#                                                                           #
# This program is distributed in the hope that it will be useful,           #
# but WITHOUT ANY WARRANTY; without even the implied warranty of            #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             #
# GNU General Public License for more details.                              #
#                                                                           #
# You should have received a copy of the GNU General Public License         #
# along with this program; if not, write to the Free Software               #
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA #
#  CREDIT:								    #
# Original code from Nitin Gupta India (?)					    #
#                                                                           #
#***************************************************************************/ 
  
  
#include "jdatatype.h"
  
#include "encoder.h"
#include "huffman.h"

UINT16 luminance_dc_code_table[] = {
	0x0000, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x000E, 0x001E, 0x003E,
   	0x007E, 0x00FE, 0x01FE
};
UINT16 luminance_dc_size_table[] = {
	0x0002, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0004, 0x0005, 0x0006,
	0x0007, 0x0008, 0x0009
};
UINT16 chrominance_dc_code_table[] = {
	0x0000, 0x0001, 0x0002, 0x0006, 0x000E, 0x001E, 0x003E, 0x007E, 0x00FE,
	0x01FE, 0x03FE, 0x07FE
};
UINT16 chrominance_dc_size_table[] = {
	0x0002, 0x0002, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008,
	0x0009, 0x000A, 0x000B 
};

UINT16 luminance_ac_code_table[] = {
    0x000A, 0x0000, 0x0001, 0x0004, 0x000B, 0x001A, 0x0078, 0x00F8, 0x03F6,
    0xFF82, 0xFF83, 0x000C, 0x001B, 0x0079, 0x01F6, 0x07F6, 0xFF84, 0xFF85,
    0xFF86, 0xFF87, 0xFF88, 0x001C, 0x00F9, 0x03F7, 0x0FF4, 0xFF89, 0xFF8A,
    0xFF8b, 0xFF8C, 0xFF8D, 0xFF8E, 0x003A, 0x01F7, 0x0FF5, 0xFF8F, 0xFF90,
    0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0x003B, 0x03F8, 0xFF96, 0xFF97,
    0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0x007A, 0x07F7, 0xFF9E,
    0xFF9F, 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0x007B, 0x0FF6,
    0xFFA6, 0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0x00FA,
    0x0FF7, 0xFFAE, 0xFFAF, 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5,
    0x01F8, 0x7FC0, 0xFFB6, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC,
    0xFFBD, 0x01F9, 0xFFBE, 0xFFBF, 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4,
    0xFFC5, 0xFFC6, 0x01FA, 0xFFC7, 0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC,
    0xFFCD, 0xFFCE, 0xFFCF, 0x03F9, 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4,
    0xFFD5, 0xFFD6, 0xFFD7, 0xFFD8, 0x03FA, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC,
    0xFFDD, 0xFFDE, 0xFFDF, 0xFFE0, 0xFFE1, 0x07F8, 0xFFE2, 0xFFE3, 0xFFE4,
    0xFFE5, 0xFFE6, 0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED,
    0xFFEE, 0xFFEF, 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6,
    0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE,
    0x07F9
};
UINT16 luminance_ac_size_table[] = {
    0x0004, 0x0002, 0x0002, 0x0003, 0x0004, 0x0005, 0x0007, 0x0008, 0x000A,
    0x0010, 0x0010, 0x0004, 0x0005, 0x0007, 0x0009, 0x000B, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0005, 0x0008, 0x000A, 0x000C, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0006, 0x0009, 0x000C, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0006, 0x000A, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0007, 0x000B, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0007, 0x000C,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0008,
    0x000C, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0009, 0x000F, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0009, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0009, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x000A, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x000A, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x000B, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x000B
};
UINT16 chrominance_ac_code_table[] = {
    0x0000, 0x0001, 0x0004, 0x000A, 0x0018, 0x0019, 0x0038, 0x0078, 0x01F4,
    0x03F6, 0x0FF4, 0x000B, 0x0039, 0x00F6, 0x01F5, 0x07F6, 0x0FF5, 0xFF88,
    0xFF89, 0xFF8A, 0xFF8B, 0x001A, 0x00F7, 0x03F7, 0x0FF6, 0x7FC2, 0xFF8C,
    0xFF8D, 0xFF8E, 0xFF8F, 0xFF90, 0x001B, 0x00F8, 0x03F8, 0x0FF7, 0xFF91,
    0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0x003A, 0x01F6, 0xFF97, 0xFF98,
    0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0x003B, 0x03F9, 0xFF9F,
    0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0x0079, 0x07F7,
    0xFFA7, 0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0x007A,
    0x07F8, 0xFFAF, 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6,
    0x00F9, 0xFFB7, 0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE,
    0xFFBF, 0x01F7, 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6,
    0xFFC7, 0xFFC8, 0x01F8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE,
    0xFFCF, 0xFFD0, 0xFFD1, 0x01F9, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6,
    0xFFD7, 0xFFD8, 0xFFD9, 0xFFDA, 0x01FA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE,
    0xFFDF, 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0x07F9, 0xFFE4, 0xFFE5, 0xFFE6,
    0xFFE7, 0xFFE8, 0xFFE9, 0xFFEA, 0xFFEb, 0xFFEC, 0x3FE0, 0xFFED, 0xFFEE,
    0xFFEF, 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0x7FC3, 0xFFF6,
    0xFFF7, 0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE,
    0x03FA
};
UINT16 chrominance_ac_size_table[] = {
    0x0002, 0x0002, 0x0003, 0x0004, 0x0005, 0x0005, 0x0006, 0x0007, 0x0009,
    0x000A, 0x000C, 0x0004, 0x0006, 0x0008, 0x0009, 0x000B, 0x000C, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0005, 0x0008, 0x000A, 0x000C, 0x000F, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0005, 0x0008, 0x000A, 0x000C, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0006, 0x0009, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0006, 0x000A, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0007, 0x000B,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0007,
    0x000B, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0008, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0009, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0009, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0009, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0009, 0x0010, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x000B, 0x0010, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x000E, 0x0010, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x000F, 0x0010,
    0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
    0x000A 
};
UINT8 bitsize[] = {
    0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
    5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 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, 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, 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, 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, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
    8, 8
};
#if 0
#define PUTBITS	{ \
  bits_in_next_word = (INT16) (bitindex + numbits - 32); \
  if (bits_in_next_word < 0) \
    { \
    lcode = (lcode << numbits) | data; \
    bitindex += numbits; \
    } \
  else \
    { \
    lcode = (lcode << (32 - bitindex)) | (data >> bits_in_next_word); \
    if ((*output_ptr++ = (UINT8) (lcode >> 24)) == 0xff) \
    *output_ptr++ = 0; \
    if ((*output_ptr++ = (UINT8) (lcode >> 16)) == 0xff) \
    *output_ptr++ = 0; \
    if ((*output_ptr++ = (UINT8) (lcode >> 8)) == 0xff) \
    *output_ptr++ = 0; \
    if ((*output_ptr++ = (UINT8) lcode) == 0xff) \
    *output_ptr++ = 0; \
    lcode = data; \
    bitindex = bits_in_next_word; \
    } \
    }
#endif
UINT8 * huffman (JPEG_ENCODER_STRUCTURE * jpeg_encoder_structure,
		   UINT16 component, UINT8 * output_ptr) 
{
  UINT16 i;
  UINT16 * DcCodeTable, *DcSizeTable, *AcCodeTable, *AcSizeTable;
  INT16 * Temp_Ptr, Coeff, LastDc;
  UINT16 AbsCoeff, HuffCode, HuffSize, RunLength = 0, DataSize = 0, index;
  INT16 bits_in_next_word;
  UINT16 numbits;
  UINT32 data;
  Temp_Ptr = Temp;
  Coeff = *Temp_Ptr++;
  if (component == 1)
    
    {
      DcCodeTable = luminance_dc_code_table;
      DcSizeTable = luminance_dc_size_table;
      AcCodeTable = luminance_ac_code_table;
      AcSizeTable = luminance_ac_size_table;
      LastDc = jpeg_encoder_structure->ldc1;
      jpeg_encoder_structure->ldc1 = Coeff;
    }
  
  else
    
    {
      DcCodeTable = chrominance_dc_code_table;
      DcSizeTable = chrominance_dc_size_table;
      AcCodeTable = chrominance_ac_code_table;
      AcSizeTable = chrominance_ac_size_table;
      if (component == 2)
	
	{
	  LastDc = jpeg_encoder_structure->ldc2;
	  jpeg_encoder_structure->ldc2 = Coeff;
	}
      
      else
	
	{
	  LastDc = jpeg_encoder_structure->ldc3;
	  jpeg_encoder_structure->ldc3 = Coeff;
	}
    }
  Coeff -= LastDc;
  AbsCoeff = (Coeff < 0) ? -Coeff-- : Coeff;
  while (AbsCoeff != 0)
    
    {
      AbsCoeff >>= 1;
      DataSize++;
    }
  HuffCode = DcCodeTable[DataSize];
  HuffSize = DcSizeTable[DataSize];
  Coeff &= (1 << DataSize) - 1;
  data = (HuffCode << DataSize) | Coeff;
  numbits = HuffSize + DataSize;
  //PUTBITS
  { 
  bits_in_next_word = (INT16) (bitindex + numbits - 32); 
  if (bits_in_next_word < 0) 
    { 
    lcode = (lcode << numbits) | data; 
    bitindex += numbits; 
    } 
  else 
    { 
    lcode = (lcode << (32 - bitindex)) | (data >> bits_in_next_word); 
    if ((*output_ptr++ = (UINT8) (lcode >> 24)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) (lcode >> 16)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) (lcode >> 8)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) lcode) == 0xff) 
    *output_ptr++ = 0; 
    lcode = data; 
    bitindex = bits_in_next_word; 
    } 
    }  
  for (i = 63; i > 0; i--)
    
    {
      if ((Coeff = *Temp_Ptr++) != 0)
	
	{
	  while (RunLength > 15)
	    
	    {
	      RunLength -= 16;
	      data = AcCodeTable[161];
	      numbits = AcSizeTable[161];
	    //PUTBITS
	    { 
  bits_in_next_word = (INT16) (bitindex + numbits - 32); 
  if (bits_in_next_word < 0) 
    { 
    lcode = (lcode << numbits) | data; 
    bitindex += numbits; 
    } 
  else 
    { 
    lcode = (lcode << (32 - bitindex)) | (data >> bits_in_next_word); 
    if ((*output_ptr++ = (UINT8) (lcode >> 24)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) (lcode >> 16)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) (lcode >> 8)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) lcode) == 0xff) 
    *output_ptr++ = 0; 
    lcode = data; 
    bitindex = bits_in_next_word; 
    } 
    }    
	     }
	  AbsCoeff = (Coeff < 0) ? -Coeff-- : Coeff;
	  if (AbsCoeff >> 8 == 0)
	    DataSize = bitsize[AbsCoeff];
	  
	  else
	  DataSize = bitsize[AbsCoeff >> 8] + 8;
	  index = RunLength * 10 + DataSize;
	  HuffCode = AcCodeTable[index];
	  HuffSize = AcSizeTable[index];
	  Coeff &= (1 << DataSize) - 1;
	  data = (HuffCode << DataSize) | Coeff;
	  numbits = HuffSize + DataSize;
	 // PUTBITS
	   { 
  bits_in_next_word = (INT16) (bitindex + numbits - 32); 
  if (bits_in_next_word < 0) 
    { 
    lcode = (lcode << numbits) | data; 
    bitindex += numbits; 
    } 
  else 
    { 
    lcode = (lcode << (32 - bitindex)) | (data >> bits_in_next_word); 
    if ((*output_ptr++ = (UINT8) (lcode >> 24)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) (lcode >> 16)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) (lcode >> 8)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) lcode) == 0xff) 
    *output_ptr++ = 0; 
    lcode = data; 
    bitindex = bits_in_next_word; 
    } 
    }    
	  RunLength = 0;
	}
      
      else
	RunLength++;
    }
  if (RunLength != 0)
    
    {
      data = AcCodeTable[0];
      numbits = AcSizeTable[0];
    // PUTBITS 
     { 
  bits_in_next_word = (INT16) (bitindex + numbits - 32); 
  if (bits_in_next_word < 0) 
    { 
    lcode = (lcode << numbits) | data; 
    bitindex += numbits; 
    } 
  else 
    { 
    lcode = (lcode << (32 - bitindex)) | (data >> bits_in_next_word); 
    if ((*output_ptr++ = (UINT8) (lcode >> 24)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) (lcode >> 16)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) (lcode >> 8)) == 0xff) 
    *output_ptr++ = 0; 
    if ((*output_ptr++ = (UINT8) lcode) == 0xff) 
    *output_ptr++ = 0; 
    lcode = data; 
    bitindex = bits_in_next_word; 
    } 
    }  
    }
  return output_ptr;
}


/* For bit Stuffing and EOI marker */ 
  UINT8 * close_bitstream (UINT8 * output_ptr) 
{
  UINT16 i, count;
  UINT8 * ptr;
  if (bitindex > 0)
    
    {
      lcode <<= (32 - bitindex);
      count = (bitindex + 7) >> 3;
      ptr = (UINT8 *) & lcode + 3;
      for (i = count; i > 0; i--)
	
	{
	  if ((*output_ptr++ = *ptr--) == 0xff)
	    *output_ptr++ = 0;
	}
    }
  
    // End of image marker
    *output_ptr++ = 0xFF;
  *output_ptr++ = 0xD9;
  return output_ptr;
}


