/*

			Slide Show Screen Saver for Windows

					JPEG Image Loader

*/

#include "screensv.h"

#include <setjmp.h>

jmp_buf JPEG_bailout;

//  LOADJPEGIMAGE  --  Load JPEG image into memory

int loadJPEGimage(FILE *input_file, HGLOBAL *LimageBitmap,
				   int *LsizeX, int *LsizeY)
{
	int i;
	LPBITMAPINFOHEADER bh;
	DWORD bmpsize;
	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;
	JSAMPARRAY colormap;
	LPBYTE pix, px;
	int linewid;
	int pixbytes;
	static LPBYTE sl = NULL;
	static HGLOBAL imageBitmap = NULL;		// In-memory bitmap

	sl = NULL;
	imageBitmap = NULL;
	if (setjmp(JPEG_bailout) != 0) {
		/*	Since we arrive here via longjmp() from
			parts unknown, we may have allocated
			the line buffer or bitmap prior to bailing
			out.  If they've been allocated, release them.  */

		if (sl != NULL) {
			GlobalFree(sl);
			sl = NULL;
		}
		if (imageBitmap != NULL) {
			GlobalFree(imageBitmap);
			imageBitmap = NULL;
		}
		return FALSE;
	}
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_decompress(&cinfo);
	jpeg_stdio_src(&cinfo, input_file);
	jpeg_read_header(&cinfo, TRUE);
	cinfo.desired_number_of_colors = 254;
	cinfo.quantize_colors = usePalette;
	jpeg_start_decompress(&cinfo);

	pixbytes = (usePalette ? 1 : 3);
	sl = GlobalAlloc(GMEM_FIXED, cinfo.output_width * pixbytes);
	if (sl == NULL) {
		loadError = "Cannot allocate JPEG decoder row buffer";
		return FALSE;
	}

	linewid = ((((cinfo.output_width * pixbytes) + (sizeof(LONG) - 1)) / sizeof(LONG)) * sizeof(LONG));
	bmpsize = sizeof(BITMAPINFOHEADER) +
		(usePalette ? (256 * sizeof(RGBQUAD)) : 0) +
		(linewid * cinfo.output_height);

	imageBitmap = GlobalAlloc(GMEM_FIXED, bmpsize);
	if (imageBitmap == NULL) {
		loadError = "Cannot allocate bitmap for decoded JPEG image";
		GlobalFree(sl);
		return FALSE;
	}

	//	Plug in header fields with information from cinfo

	bh = (LPBITMAPINFOHEADER) imageBitmap;
	pix = ((LPBYTE) imageBitmap) + sizeof(BITMAPINFOHEADER) +
			(usePalette ? (256 * sizeof(RGBQUAD)) : 0);
	bh->biSize = sizeof(BITMAPINFOHEADER);
	bh->biWidth = cinfo.output_width;
	bh->biHeight = cinfo.output_height;
	bh->biPlanes = 1;
	bh->biBitCount = usePalette ? 8 : 24;
	bh->biCompression = BI_RGB;
	bh->biSizeImage = 0;
	bh->biXPelsPerMeter = bh->biYPelsPerMeter = 2835;
	bh->biClrUsed = 0;
	bh->biClrImportant = 0;

	/*	Construct the palette from the colour map optimised
		for the JPEG file.  */

	if (usePalette) {
		colormap = cinfo.colormap;
		for (i = 0; i < cinfo.actual_number_of_colors; i++) {
			((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbRed = GETJSAMPLE(colormap[0][i]);
			((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbGreen = GETJSAMPLE(colormap[1][i]);
			((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbBlue = GETJSAMPLE(colormap[2][i]);
			((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[i])->rgbReserved = 0;
		}

		/*	Plug black and our text colour in the last two slots
			of the palette so we canbe sure they're available.  */
	
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[254])->rgbRed = 0;
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[254])->rgbGreen = 0;
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[254])->rgbBlue = 0;
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[254])->rgbReserved = 0;

		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[255])->rgbRed = GetRValue(skycolour);
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[255])->rgbGreen = GetGValue(skycolour);
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[255])->rgbBlue = GetBValue(skycolour);
		((LPRGBQUAD) &((LPBITMAPINFO) bh)->bmiColors[255])->rgbReserved = 0;
	}

	//	Return scan lines and transfer to the pixel array

	px = pix + (linewid * (bh->biHeight - 1));
	for (i = 0; i < (int) cinfo.output_height; i++) {
		unsigned char *slp[1] = { sl };
		jpeg_read_scanlines(&cinfo, slp, 1);
		if (usePalette) {
			memcpy(px, sl, cinfo.output_width);
		} else {
			int j, k;

			for (j = k = 0; j < (int) cinfo.output_width; j++, k += 3) {
				px[k] = sl[k + 2];
				px[k + 1] = sl[k + 1];
				px[k + 2] = sl[k];
			}
		}
		px -= linewid;
	}

	GlobalFree(sl);
	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);

#ifdef SNAP_BMP
{
	FILE *o_file = fopen("d:/slidescr/snap.bmp", "wb");

	BITMAPFILEHEADER bf;

	memcpy(&bf.bfType , "BM", 2);
	bf.bfSize = (sizeof bf) + bmpsize;
	bf.bfReserved1 = bf.bfReserved2 = 0;
	bf.bfOffBits = (sizeof bf) + sizeof(BITMAPINFOHEADER) + (usePalette * 256 * sizeof(RGBQUAD));
	fwrite(&bf, sizeof bf, 1, o_file);
	fwrite(bh, bmpsize, 1, o_file);
	fclose(o_file);
}
#endif
	 
	*LsizeX = (int) bh->biWidth;
	*LsizeY = (int) bh->biHeight;
	*LimageBitmap = imageBitmap;
	return TRUE;
}
