/*
 * Copyright 1996, Torsten Martinsen
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* $Id: writejpg.c,v 1.1 2003/09/08 02:50:46 jch Exp $ */

#include <stdio.h>
#include <stdlib.h>
#include <setjmp.h>
#include <jpeglib.h>
#include "image.h"
//#include "rwTable.h"

//extern void *xmalloc(size_t n);
#define xmalloc malloc


struct error_mgr {
    struct jpeg_error_mgr pub;	/* "public" fields */
    jmp_buf setjmp_buffer;	/* for return to caller */
};

static struct error_mgr jerr;

typedef struct error_mgr *error_ptr;

/*
 * Here's the routine that will replace the standard error_exit method:
 */
static void error_exit(j_common_ptr cinfo)
{
    /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
    error_ptr err = (error_ptr) cinfo->err;

    //    trace_message(cinfo);

    /* Return control to the setjmp point */
    longjmp(err->setjmp_buffer, 1);
}

int WriteJPEG(char *file, int quality, Image * outImage)
{
    struct jpeg_compress_struct jpegInfo;
    FILE *output_file;
    int w, i, row_stride;
    JSAMPROW scanline[1];
    unsigned char *p, *d, *theline;


    if ((output_file = fopen(file, "w")) == NULL)
	return 1;

    w = outImage->width;
    jpegInfo.err = jpeg_std_error(&jerr.pub);
    jerr.pub.error_exit = error_exit;

    if (setjmp(jerr.setjmp_buffer)) {
	/* If we get here, the JPEG code has signaled an error.
	 * We need to clean up the JPEG object, close the output file,
	 * and return.
	 */
	jpeg_destroy_compress(&jpegInfo);
	fclose(output_file);
	return 1;
    }
    jpeg_create_compress(&jpegInfo);
    jpeg_stdio_dest(&jpegInfo, output_file);

    jpegInfo.image_height = outImage->height;
    jpegInfo.image_width = w;
    if (outImage->isGrey) {
	jpegInfo.in_color_space = JCS_GRAYSCALE;
	jpegInfo.input_components = 1;
    } else {
	jpegInfo.in_color_space = JCS_RGB;
	jpegInfo.input_components = 3;
	theline = xmalloc(w * 3);
    }

    jpeg_set_defaults(&jpegInfo);
    jpeg_set_quality(&jpegInfo, quality, TRUE);
    jpeg_start_compress(&jpegInfo, TRUE);
    row_stride = w * jpegInfo.input_components;

    while (jpegInfo.next_scanline < jpegInfo.image_height) {
	/*
	 * If we have a greyscale or TrueColor image, just feed
	 * the raw data to the JPEG routine. Otherwise, we must
	 * build an array of RGB triples in 'theline'.
	 */
	if (outImage->isGrey || (outImage->cmapSize == 0))
	    scanline[0] = (JSAMPROW) outImage->data +
		jpegInfo.next_scanline * row_stride;
	else {
	  printf("life sucks!!!\n"); exit(0);
	  /*
	    d = theline;
	    for (i = 0; i < w; ++i) {
		p = ImagePixel(outImage, i, jpegInfo.next_scanline);
		*d++ = *p++;
		*d++ = *p++;
		*d++ = *p;
	    }
	    scanline[0] = theline;
	  */
	}
	jpeg_write_scanlines(&jpegInfo, scanline, (JDIMENSION) 1);
    }
    jpeg_finish_compress(&jpegInfo);
    jpeg_destroy_compress(&jpegInfo);

    fclose(output_file);
    if (!outImage->isGrey)
	free(theline);

    if (jerr.pub.num_warnings > 0) {	/* XXX */
	printf("JPEG warning, image may be corrupted");
	longjmp(jerr.setjmp_buffer, 1);
    }
    return 0;
}

