/*
    ORPP Client

    (C) 2005 Jason Hunt

    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.

    Contact: huntjas2@msu.edu

    FILE: decompress.cpp
    
    You have to wrap jpeglib.h in extern "C" { } 
    
    Code based on libjpeg
*/

#include <windows.h>
#include <stdio.h>
#include <jpeglib.h>
#include <jconfig.h>
#include <jerror.h>

#pragma hdrstop

#include "display.h"
#include "decompress.h"


typedef struct {
    struct jpeg_source_mgr pub;	

    unsigned int data_size;
    JOCTET * buffer;
    char *source_buffer;

} my_source_mgr;

typedef my_source_mgr * my_src_ptr;


/* not needed */
METHODDEF(void) camera_init_source (j_decompress_ptr cinfo) {}
METHODDEF(void) camera_term_source (j_decompress_ptr cinfo) {}


/* setup for data fill */
METHODDEF(boolean) camera_fill_input_buffer (j_decompress_ptr cinfo)
{
    my_src_ptr src = (my_src_ptr) cinfo->src;

    src->pub.next_input_byte = (JOCTET *) src->source_buffer;
    src->pub.bytes_in_buffer = src->data_size;

    return TRUE;
}
/* end of  camera_fill_input_buffer */


/* hop ofer some data in the buffer */
METHODDEF(void) camera_skip_input_data (j_decompress_ptr cinfo, long num_bytes)
{
    my_src_ptr src = (my_src_ptr) cinfo->src;
    src->pub.next_input_byte += num_bytes;
    src->pub.bytes_in_buffer -= num_bytes;
}
/* end of  camera_skip_input_data  */



/* init a buffer as a source */
GLOBAL(void) camera_jpeg_src (j_decompress_ptr cinfo, char *data, unsigned int size)
{
    my_src_ptr src;

    if (cinfo->src == NULL) 
    {
        cinfo->src = (struct jpeg_source_mgr *)
                   (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr));

        src = (my_src_ptr) cinfo->src;
        src->buffer = NULL;
    }

    src->source_buffer = data;
    src->data_size = size;
    
    src = (my_src_ptr) cinfo->src;
    src->pub.init_source = camera_init_source;
    src->pub.fill_input_buffer = camera_fill_input_buffer;
    src->pub.skip_input_data = camera_skip_input_data;
    src->pub.resync_to_restart = jpeg_resync_to_restart;
    src->pub.term_source = camera_term_source;
    src->pub.bytes_in_buffer = 0;
    src->pub.next_input_byte = NULL;
}
/* end of camera_jpeg_src */


/* decomepress the image in [compressed_image] */
//void decompress_image(char * compressed_image, color_type *out_buff, unsigned int compressed_size)
void decompress_image(char *compressed_image, unsigned int compressed_size, 
                      color_type *out_buff, unsigned int out_x, unsigned int out_y)
{
    struct jpeg_decompress_struct cinfo;

    jpeg_error_mgr jerr;
    JSAMPARRAY buffer;	

    cinfo.err = jpeg_std_error(&jerr);
  
    jpeg_create_decompress(&cinfo);
    camera_jpeg_src(&cinfo, compressed_image, compressed_size);
    jpeg_read_header(&cinfo, TRUE);
    jpeg_start_decompress(&cinfo);
    
    int row_stride = cinfo.output_width * cinfo.output_components;
    
    buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

    if (cinfo.output_height > out_y) return;


    while (cinfo.output_scanline < cinfo.output_height) 
    {
        jpeg_read_scanlines(&cinfo, buffer, 1);

        // decode the scan_line
        unsigned int index = (cinfo.output_height - cinfo.output_scanline) * out_x;
        unsigned int bi = 0;

        if (cinfo.output_components == 1) // grayscale decode
        {
            for (unsigned int i = 0; i < out_x; i++)
            {
                unsigned char color = buffer[0][bi++];
                out_buff[index].r = color;
                out_buff[index].g = color;
                out_buff[index++].b = color;
            }   
        } else
        {  // color decode
            for (unsigned int i = 0; i < out_x; i++)
            {
                out_buff[index].b =   buffer[0][bi++];
                out_buff[index].g =   buffer[0][bi++];
                out_buff[index++].r = buffer[0][bi++];     
            }
        }

     }

    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
}
/* end of decompress_image */
 



  





