/****************************************************************************
	jpeg.c - read and write jpeg images using libjpeg routines
	Copyright (C) 2002 Hari Nair <hari@alumni.caltech.edu>

	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
****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <jpeglib.h>
#include "const.h"

int
read_jpeg(const char *filename, int *width, int *height, unsigned char **rgb)
{
	int ret = 0;
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;
	unsigned char *ptr = NULL;
	unsigned int i, ipos;

	FILE *infile = fopen(filename, "rb");
	if (infile == NULL) {
		fprintf(stderr, "Can not fopen file: %s\n",filename);
		return ret;
	}

	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_decompress(&cinfo);
	jpeg_stdio_src(&cinfo, infile);
	jpeg_read_header(&cinfo, TRUE);
	jpeg_start_decompress(&cinfo);

	/* Prevent against integer overflow */
	if(cinfo.output_width >= MAX_DIMENSION || cinfo.output_height >= MAX_DIMENSION) {
		fprintf(stderr, "Unreasonable dimension found in file: %s\n",filename);
		goto close_file;
	}

	*width = cinfo.output_width;
	*height = cinfo.output_height;

	rgb[0] = malloc(3 * cinfo.output_width * cinfo.output_height);
	if (rgb[0] == NULL) {
		fprintf(stderr, "Can't allocate memory for JPEG file.\n");
		goto close_file;
	}

	if (cinfo.output_components == 3) {
		ptr = rgb[0];
		while (cinfo.output_scanline < cinfo.output_height) {
			jpeg_read_scanlines(&cinfo, &ptr, 1);
			ptr += 3 * cinfo.output_width;
		}
	} else if (cinfo.output_components == 1) {
		ptr = malloc(cinfo.output_width);
		if (ptr == NULL) {
			fprintf(stderr, "Can't allocate memory for JPEG file.\n");
			goto rgb_free;
		}

		ipos = 0;
		while (cinfo.output_scanline < cinfo.output_height) {
			jpeg_read_scanlines(&cinfo, &ptr, 1);

			for (i = 0; i < cinfo.output_width; i++) {
				memset(rgb[0] + ipos, ptr[i], 3);
				ipos += 3;
			}
		}

		free(ptr);
	}

	jpeg_finish_decompress(&cinfo);

	ret = 1;
	goto close_file;

rgb_free:
	free(rgb[0]);

close_file:
	jpeg_destroy_decompress(&cinfo);
	fclose(infile);

	return(ret);
}
