/*
 *   MediaMVP Server Library
 *
 *   (C) 2004 Dominic Morris
 *
 *   $Id: jpeg.c,v 1.1 2004/04/22 18:36:24 dom Exp $
 *   $Date: 2004/04/22 18:36:24 $
 *
 *
 *   Display a jpeg image on to a MVP surface - does some pretty primitive scaling
 */



#include "libmvp_internal.h"

#ifdef HAVE_LIBJPEG
#include <jpeglib.h>
#include <setjmp.h>

struct my_error_mgr {
    struct jpeg_error_mgr  pub;
    jmp_buf                setjmp_buffer;
};


static void mvp_jpeg_rgb_scanline(surface_t *sfc, int X0, int Y0, unsigned char *buf, int size,  int y);

static void my_error(j_common_ptr cinfo)
{
    struct my_error_mgr *myerr = (struct my_error_mgr *)cinfo->err;

    (*cinfo->err->output_message)(cinfo);

    longjmp(myerr->setjmp_buffer,1);
}

static int calc_ratio(int width, int height, int target_width, int target_height)
{
    if ( width / 8 > target_width || height / 8 > target_height )
        return 8;
    else if ( width / 4 > target_width || height / 4 > target_height )
        return 4;
    else if ( width / 2 > target_width || height / 2 > target_height )
        return 2;
    return 1;
}



/** \brief Display a jpeg onto the surface
 *
 *  \param filename File to load the jpeg from
 *  \param x0 Top left x coord, -1 to centre
 *  \param y0 Top left y coord, -1 to centre
 *  \param width Maximum width
 *  \param depth Maximum depth
 *
 *  \return 0 on success, -1 on failure
 */
int mvp_jpeg_display(surface_t *surface,char *filename, int x0, int y0, int width, int depth)
{
    struct jpeg_decompress_struct cinfo;
    struct my_error_mgr  mgr;
    FILE *infile;
    int row_stride;
    JSAMPARRAY buffer;
    int count;

    if ( ( infile = fopen(filename,"rb") ) == NULL ) {
        return -1;
    }
    
  
    cinfo.err = jpeg_std_error(&mgr.pub);
    mgr.pub.error_exit = my_error;

    if ( setjmp(mgr.setjmp_buffer) ) {
        /* If we get here an error occurred */
        jpeg_destroy_decompress(&cinfo);
        fclose(infile);
        return -1;
    }

    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, infile);

    jpeg_read_header(&cinfo, TRUE);


    cinfo.scale_num = 1;
    cinfo.scale_denom = calc_ratio(cinfo.image_width,cinfo.image_height,
                                   width, depth);
    cinfo.dct_method = JDCT_FLOAT;
    cinfo.do_fancy_upsampling = FALSE;


    jpeg_start_decompress(&cinfo);


    row_stride = cinfo.output_width * cinfo.output_components;


    buffer = (*cinfo.mem->alloc_sarray)
        ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

    if ( x0 == -1 ) {
        if ( cinfo.output_width < width ) {
            x0 = ( width - cinfo.output_width ) / 2;
        } else {
            x0 = 0;
        }
    }

    if ( y0 == -1 ) {
        if ( cinfo.output_height < depth ) {
            y0 = ( depth - cinfo.output_height ) / 2;
        } else {
            y0 = 0;
        }
    }

    count = 0;
    while (cinfo.output_scanline < cinfo.output_height ) {
        jpeg_read_scanlines(&cinfo, buffer, 1);
        mvp_jpeg_rgb_scanline(surface,x0,y0,buffer[0], row_stride, count);
        count++;
    }

    jpeg_finish_decompress(&cinfo);

    jpeg_destroy_decompress(&cinfo);

    fclose(infile);

    return 0;
}


static void mvp_jpeg_rgb_scanline(surface_t *sfc, int X0, int Y0,  unsigned char *buf, int size, int y)
{
    int        i;
    int        x = 0;


    if ( x < 0 || y < 0 ) 
        return;

    for ( i = 0; i < size; i+= 3 ) {
        surface_set_pixel(sfc,X0+x++,y + Y0,((buf[i] << 16) | (buf[i+1] << 8) | buf[i+2]) );
    }
}

#endif
