// MPImage - Amiga Image Conversion
// Copyright (C) © 1996 Mark John Paddock
//
// 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
// 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.

// mark@topic.demon.co.uk
// mpaddock@cix.compulink.co.uk

// Preliminary Cyber Graphics support - Done cyber "24 bit ilbm", "DCTV"

#include "mpimage.h"

// Properties for IFF read
static LONG props[] = {	ID_ILBM,	ID_BMHD,
						ID_ILBM,	ID_CAMG,
						ID_ILBM, ID_CMAP,
						TAG_DONE };
static LONG stops[] = {	ID_ILBM,	ID_BODY,
						TAG_DONE };
static LONG nowt[] = { TAG_DONE };

static void RGBToScreen(UBYTE *red,UBYTE *green,UBYTE *blue,UWORD Height,UWORD Width,
						  UWORD maxcol,UBYTE *r,BOOL bit12);
static void RToScreen(UBYTE *red,UWORD Height,UWORD Width,
						  UWORD maxcol,UBYTE *r);
static void PaletteToScreen(struct ILBMInfo *ilbm,UWORD maxcol,
							UBYTE *r,UBYTE *r1,
							UBYTE *chunky);
static void PaletteToEGS(struct MPImage *MPi,
							struct ILBMInfo *ilbm, UBYTE *plane,
							UBYTE *r,
							UBYTE *chunky,ULONG modeid,UWORD maxcol);
static void PaletteToRGB(struct MPImage *MPi,
							struct ILBMInfo *ilbm, UBYTE *red,UBYTE *green,UBYTE *blue,
							UBYTE *r,
							UBYTE *chunky,ULONG modeid,UWORD maxcol);
static void PaletteRGBToGrey(struct MPImage *MPi,
							struct ILBMInfo *ilbm,
							UBYTE *r,
							UBYTE *chunky,ULONG modeid,UWORD maxcol, BOOL Linear);
static void RGBToGrey(UBYTE *red,UBYTE *green,UBYTE *blue,UWORD Height, UWORD Width, BOOL Linear);
static BOOL CheckNotHAM(ULONG modeid);
static void PaletteToGrey(struct MPImage *MPi,
							struct ILBMInfo *ilbm, UBYTE *red,
							UBYTE *r,
							UBYTE *chunky,ULONG modeid,UWORD maxcol);

static unsigned int ReadPBMInteger(FILE *infile,int maxval);
static int ReadPBMChar(FILE *infile);

struct MPImage * __asm __saveds LoadMPImage(register __a0 const char *filename,register __a1 struct Screen *screen,register __d0 ULONG Flags);

static int ReadPBMChar(FILE *infile) {
	int ch;
	ch = getc(infile);
	if (ch == '#') {
		do {
			ch = getc(infile);
		} while ((ch != '\n') && (ch != EOF));
	}
	return ch;
}

static unsigned int ReadPBMInteger(FILE *infile,int maxval) {
	int ch;
	unsigned int val;
	do {
		ch = ReadPBMChar(infile);
		if (ch == EOF) {
			return 0;
		}
	} while ((ch == ' ') || (ch == '\t') || (ch == '\n') || (ch == '\r'));
	if ((ch < '0') || (ch > '9')) {
		return 0;
	}
	val = (ch - '0');
	while (((ch = ReadPBMChar(infile)) >= '0') && (ch <= '9')) {
		val *= 10;
		val += (ch - '0');
	}
	if (255 == maxval) {
		return val;
	}
	else {
		return ((val * 255)/maxval);
	}
}

#define FORMAT_IFF	1
#define FORMAT_DT		2
#define FORMAT_PBM	3
#define FORMAT_JPEG	4
#define FORMAT_PNG	5

/****** MPImage.library/LoadMPImage ***********************************
*
*   NAME   
*  LoadMPImage -- Load an image in various formats (V4)
*
*   SYNOPSIS
*  MPi = LoadMPImage( filename,screen,Flags )
*  D0                       A0       A1     D0
*
*  struct MPImage *LoadMPImage
*                  ( const char *,struct Screen *,ULONG);
*
*   FUNCTION
*  Load an image in BitMap, EGSBitMap or RGB format.
*
*   INPUTS
*  filename - name of file from which to load image
*           - -c or -cnumber for clipboard
*  screen   - screen on which BitMap is to be used. May be NULL.
*  Flags    - Flags to control image loading
*      Default is to remap to screen palette and return a bitmap in BitMap
*      Only way to free is to call FreeMPImage().
*
*      MPIF_EGS         - Return E_EBitMap rather than BitMap. 
*          Overrides MPIF_RGB
*      MPIF_CLONEBITMAP - You are free to zero BitMap/EGS_BitMap before
*          calling FreeMPImage(). You must then call FreeBitMap() or 
*          E_DisposeBitMap() yourself. Ignored for MPIF_RGB/GREY. If screen
*          supplied then clone is screen depth deep if possible.
*      MPIF_NOREMAP     - Don't remap to the current screen colors. Ignored
*          for MPIF_EGS/RGB/GREY. Returns error if 24 bit input.
*      MPIF_RGB         - return Red, Green, Blue instead of BitMap.
*      MPIF_GREY        - return Red, Green, Blue instead of BitMap. If
*          image is greyscale then Red, Green and Blue will be the same
*          and GreyScale will be TRUE
*      MPIF_FORCEGREY   - As MPIF_GREY except input will always be remapped
*          to greyscale.
*      MPIF_LINEARGREY  - Use linear (not colour based) mapping (V5.0)
*
*   RESULT
*  MPi - Pointer to an MPImage structure holding the image data.
*        NULL if an error occurs. Use MPImageErrorMessage() to get error.
*
*   EXAMPLE
*
*   NOTES
*  If file format is JPG and env/mpimage/djpeg is set (e.g. djpeg "%s" "%s")
*  and not loading a BitMap then djpeg is used.
*
*  If file format is PNG and env/mpimage/pngtopnm is set
*  (e.g. pngtopnm "%s" >"%s") and not loading a BitMap then pngtopnm is used.
*
*  Other fileformats are IBLM (depth 1 to 8 and 24, EHB, HAM6 and HAM8),
*  PBM (all types) and any picture datatype. With dctv.library(3) can also
*  load DCTV images.
*
*   BUGS
*  Waits 20 seconds for djpeg/pngtopnm to start then aborts.
*  Fails to set an error message if failure loading from clipboard.
*  Can also fail to set an error message in other (unknown) circumstances.
*
*   SEE ALSO
*  FreeMPImage(),MPImageErrorMessage,graphics.library/FreeBitMap(),
*  egs.library/E_DisposeBitMap(),MPImageErrorMessage().
*
*****************************************************************************
*
*/
struct MPImage * __asm __saveds
LoadMPImage(register __a0 const char *filename,register __a1 struct Screen *screen,register __d0 ULONG Flags) {
	UWORD					i,j;				// loop counters
	struct ILBMInfo ilbm = {0};		// ILBM stuff
	UBYTE r[256*3];						// rgb colors of screen (8 bit)
	UBYTE r1[256*3];						// rgb colors of image (8 bit)
	UWORD					maxcol;			// Number of colors
	UBYTE					*red;				// rgb planes
	UBYTE					*green=NULL;
	UBYTE					*blue;
	UBYTE					*rr,*gg,*bb;	// Work pointers to above
	struct BitMap		*bitmap;			// BitMap to return
	struct BitMap		BM;				// Work bitmap
	int error=0;
	struct c2pStruct c2p;
	struct p2cStruct p2c;
	ULONG	col[3];
	struct MPImage *MPi;
	FILE *fh;						// File handle
	UBYTE buffer[9]="\0\0\0\0\0\0\0\0";	// First 8 bytes of file for identification
	UBYTE FileFormat;
	Object *o;
	struct BitMapHeader *bmhd = NULL;
	ULONG modeid = (ULONG)INVALID_ID;
	struct DisplayInfo di;
	struct dtFrameBox dtf = {0};
	struct FrameInfo fri = {0};
	UBYTE					*plane;			// EGB bit map byte pointer
	struct ColorRegister *cr;
	BOOL EGS;
	BOOL Remap=FALSE;
	BOOL RGB=FALSE;
	BOOL Clone=FALSE;
	BOOL Grey=FALSE;
	BOOL ForceGrey = FALSE;
	BOOL LoadBit = FALSE;
	BOOL LinearGrey;
	char *msg;
	BOOL IsGrey = TRUE;
	BOOL Bit12 = FALSE;
	char jpegbuf[120];
	char jpegcom[256];
	char *jfilename;
	int currbit = 7;
	unsigned char c;
	struct DCTVCvtHandle *handle;

	strcpy(ErrorMessage,"");
	EGS = (Flags & MPIF_EGS);
	if (!EGS) {
		RGB = (Flags & MPIF_RGB);
		if (!RGB) {
			ForceGrey = (Flags & MPIF_FORCEGREY);
			if (!ForceGrey) {
				Grey = (Flags & MPIF_GREY);
				if (!Grey) {	// BitMap
					LoadBit = TRUE;
					Clone = (Flags & MPIF_CLONEBITMAP);
					Remap = !(Flags & MPIF_NOREMAP);
				}
			}
		}
	}
	LinearGrey = (Flags & MPIF_LINEARGREY);

	// Error check
	if (Remap && !screen) {
		msg = "Can't Remap without a screen";
		strcpy(ErrorMessage,msg);
		return NULL;
	}
	if (EGS) {
		if (!(EGSBase = OpenLibrary((char *)"egs.library",0))) {
			msg = "Can't open egs.library";
			strcpy(ErrorMessage,msg);
			return NULL;
		}
	}

	if (!LoadBit || Remap) {
		if (!SetupScreen()) {
			OpenProgressWindow();
		}
	}

	if ((*filename == '-') &&
		 (filename[1] == 'c')) {
		FileFormat = FORMAT_IFF;
	}
	else {
		// Try and open file and read 1st 4 bytes
		if (fh = fopen(filename,"rb")) {
			// Default to using DataTypes
			FileFormat = FORMAT_DT;
			AddMessage("Geting file format");
			fread(buffer,8,1,fh);
			// check if a sort of IFF file
			if (!strcmp(buffer,"LIST") ||
				 !strcmp(buffer,"CAT ") ||
				 !strcmp(buffer,"FORM")) {
				FileFormat = FORMAT_IFF;
			}
			else {
				// check if a PBM file
				if ((buffer[0] == 'P') &&
					 ((buffer[1] == '1') ||
					  (buffer[1] == '4') ||
					  (buffer[1] == '2') ||
					  (buffer[1] == '3') ||
					  (buffer[1] == '5') ||
					  (buffer[1] == '6'))) {
					FileFormat = FORMAT_PBM;
				}
				else {
					if (!LoadBit) {
						if ((buffer[0] == 0xFF) &&
							 (buffer[1] == 0xD8)) {
							if (GetVar("mpimage/djpeg",jpegbuf,119,0) > 0) {
								FileFormat = FORMAT_JPEG;
							}
						}
						else {
							if ((buffer[0] == 0x89) &&
								 (buffer[1] == 0x50) &&
								 (buffer[2] == 0x4E) &&
								 (buffer[3] == 0x47) &&
								 (buffer[4] == 0x0D) &&
								 (buffer[5] == 0x0A) &&
								 (buffer[6] == 0x1A) &&
								 (buffer[7] == 0x0A)) {
								if (GetVar("mpimage/pngtopnm",jpegbuf,119,0) > 0) {
									FileFormat = FORMAT_PNG;
								}
							}
						}
					}
				}
			}
			fclose(fh);
		}
		else {
			sprintf(ErrorMessage,"Error opening file '%s'",filename);
			CloseProgressWindow();
			CloseDownScreen();
			return NULL;
		}
	}

	if (MPi = AllocMem(sizeof(struct MPImage),MEMF_CLEAR)) {
		ULONG SDepth;
		if (screen) {
			SDepth = GetBitMapAttr(screen->RastPort.BitMap,BMA_DEPTH);
		}
		else {
			SDepth = 8;
		}
		switch (FileFormat) {
		case FORMAT_IFF:
			AddMessage("Loading IFF");
			if (Remap && (SDepth < 9)) {
				struct DisplayInfo di;

				AddMessage("Geting Screen Colours");
			  	maxcol = min(1<<screen->BitMap.Depth,256);
				for (i=0; i < maxcol; ++i) {
					GetRGB32(screen->ViewPort.ColorMap,i,1,col);
					r[i]=(col[0]>>24);
					r[i+256]=(col[1]>>24);
					r[i+512]=(col[2]>>24);
				}
				if (GetDisplayInfoData(NULL,(UBYTE *)&di,sizeof(di),DTAG_DISP,screen->ViewPort.ColorMap->VPModeID)) {
					if (di.RedBits < 5) {
						Bit12 = TRUE;
					}
				}
			}
			if (ilbm.ParseInfo.iff = AllocIFF()) {
				ilbm.ParseInfo.propchks = props;
				ilbm.ParseInfo.collectchks = nowt;
				ilbm.ParseInfo.stopchks = stops;
				AddMessage("Loading ILBM");
				if (loadbrush(&ilbm,(char *)filename)) {
					closeifile(&(ilbm.ParseInfo));
					unloadbrush(&ilbm);
					FreeIFF(ilbm.ParseInfo.iff);
					ilbm.ParseInfo.iff = NULL;
				}
				else {	// loadbrush
#ifdef CYBER
					if (screen) {
						if (CyberGfxBase) {
							if (IsCyberModeID(GetVPModeID(&(screen->ViewPort)))) {
								MPi->Cyber = TRUE;
							}
						}
					}
#endif
					closeifile(&(ilbm.ParseInfo));
					AddMessage("Allocating Memory");
					if (LoadBit) {
						if (!(bitmap = AllocBitMap(ilbm.Bmhd.w,ilbm.Bmhd.h,SDepth,
#ifdef CYBER
											BMF_DISPLAYABLE|(MPi->Cyber?BMF_MINPLANES:0),
											MPi->Cyber?screen->RastPort.BitMap:NULL))) {
#else
											BMF_DISPLAYABLE,
											NULL))) {
#endif
							error = 1;
							msg = "Can't Allocate BitMap";
						}
					}
					if (!error) {
						if (ilbm.Bmhd.nPlanes == 24) {
							AddMessage("24 Bit ILBM");
#ifdef CYBER
							if (!Remap && LoadBit && (!MPi->Cyber || SDepth < 9)) {
#else
							if (!Remap && LoadBit) {
#endif
								msg = "Can't not remap 24 bit IFF";
							}
							else {
								InitBitMap(&BM,8,ilbm.Bmhd.w,ilbm.Bmhd.h);
								if ((red = AllocVec((int)ilbm.Bmhd.w*ilbm.Bmhd.h,0)) &&
								    (green = AllocVec((int)ilbm.Bmhd.w*ilbm.Bmhd.h,0)) &&
								    (blue = AllocVec((int)ilbm.Bmhd.w*ilbm.Bmhd.h,0))) {
									p2c.bmap = &BM;
									p2c.startX = 0;
									p2c.startY = 0;
									p2c.width = ilbm.Bmhd.w;
									p2c.height = ilbm.Bmhd.h;
									p2c.chunkybuffer = red;
						  	   	BM.Planes[0] = ilbm.brbitmap->Planes[0];
							      BM.Planes[1] = ilbm.brbitmap->Planes[1];
							      BM.Planes[2] = ilbm.brbitmap->Planes[2];
							      BM.Planes[3] = ilbm.brbitmap->Planes[3];
							      BM.Planes[4] = ilbm.brbitmap->Planes[4];
							      BM.Planes[5] = ilbm.brbitmap->Planes[5];
							      BM.Planes[6] = ilbm.brbitmap->Planes[6];
							      BM.Planes[7] = ilbm.brbitmap->Planes[7];
									PlanarToChunky(&p2c);
									p2c.chunkybuffer = green;
							 	   BM.Planes[0] = ilbm.brbitmap->Planes[8];
							      BM.Planes[1] = ilbm.brbitmap->Planes[9];
							      BM.Planes[2] = ilbm.brbitmap->Planes[10];
							      BM.Planes[3] = ilbm.brbitmap->Planes[11];
							      BM.Planes[4] = ilbm.brbitmap->Planes[12];
							      BM.Planes[5] = ilbm.brbitmap->Planes[13];
							      BM.Planes[6] = ilbm.brbitmap->Planes[14];
						   	   BM.Planes[7] = ilbm.brbitmap->Planes[15];
									PlanarToChunky(&p2c);
									p2c.chunkybuffer = blue;
							      BM.Planes[0] = ilbm.brbitmap->Planes[16];
							      BM.Planes[1] = ilbm.brbitmap->Planes[17];
							      BM.Planes[2] = ilbm.brbitmap->Planes[18];
							      BM.Planes[3] = ilbm.brbitmap->Planes[19];
							      BM.Planes[4] = ilbm.brbitmap->Planes[20];
							      BM.Planes[5] = ilbm.brbitmap->Planes[21];
						   	   BM.Planes[6] = ilbm.brbitmap->Planes[22];
						      	BM.Planes[7] = ilbm.brbitmap->Planes[23];
									PlanarToChunky(&p2c);
									if (RGB || Grey) {	// RGB IFF24
										MPi->Width = ilbm.Bmhd.w;
										MPi->Height = ilbm.Bmhd.h;
										unloadbrush(&ilbm);
										FreeIFF(ilbm.ParseInfo.iff);
										MPi->Red = red;
										MPi->Green = green;
										MPi->Blue = blue;
										CloseProgressWindow();
										CloseDownScreen();
										return MPi;
									}	// !RGB || Grey
									if (EGS) {	// EGS IFF24
			  				    		// Convert to an EGS BitMap
										if (MPi->EGS_BitMap = E_AllocBitMap(ilbm.Bmhd.w,ilbm.Bmhd.h,24,E_PIXELMAP,E_EB_NOTSWAPABLE,NULL)) {
											plane = ((struct E_EBitMapFull *)(MPi->EGS_BitMap))->Typekey.PixelMap.Planes.Dest;
											AddMessage("Chunky to EGS");
											SetMax(ilbm.Bmhd.h);
											rr = red;
											gg = green;
											bb = blue;
											for (i = 0; i<ilbm.Bmhd.h; i++) {
												SetCur(i);
												for (j = 0; j<ilbm.Bmhd.w; j++) {
													*plane++ = *rr++;
													*plane++ = *gg++;
													*plane++ = *bb++;
													plane++;
												}
												plane += (MPi->EGS_BitMap->BytesPerRow - (4*ilbm.Bmhd.w));
											}
											FreeVec(red);
											FreeVec(green);
											FreeVec(blue);
											MPi->Width = ilbm.Bmhd.w;
											MPi->Height = ilbm.Bmhd.h;
											unloadbrush(&ilbm);
											FreeIFF(ilbm.ParseInfo.iff);
											CloseLibrary(EGSBase);
											CloseProgressWindow();
											CloseDownScreen();
											return MPi;
										}
										else { // E_AllocBitMap
											msg = "Can't Allocate EGS BitMap";
										}
									}
									else {	// !EGS
										if (ForceGrey) {
											RGBToGrey(red,green,blue,ilbm.Bmhd.h,ilbm.Bmhd.w,LinearGrey);
											FreeVec(green);
											FreeVec(blue);
											MPi->Width = ilbm.Bmhd.w;
											MPi->Height = ilbm.Bmhd.h;
											unloadbrush(&ilbm);
											FreeIFF(ilbm.ParseInfo.iff);
											MPi->Red = red;
											MPi->Green = red;
											MPi->Blue = red;
											MPi->GreyScale = TRUE;
											CloseProgressWindow();
											CloseDownScreen();
											return MPi;
										}	// !ForceGrey - BitMap
#ifdef CYBER
										if (MPi->Cyber) {
											UBYTE *buffer,*r,*g,*b,*t;
											int i,j;
											if (buffer = AllocVec((int)ilbm.Bmhd.w*ilbm.Bmhd.h*3,0)) {
												struct RastPort rastport;
												r = red;
												g = green;
												b = blue;
												t = buffer;
												for (i=0; i<ilbm.Bmhd.w; ++i) {
													for (j=0; j<ilbm.Bmhd.h; ++j) {
														*t++ = *r++;
														*t++ = *g++;
														*t++ = *b++;
													}
												}
												FreeVec(red);
												FreeVec(green);
												FreeVec(blue);
												InitRastPort(&rastport);
												rastport.BitMap = bitmap;
												WritePixelArray(buffer,0,0,ilbm.Bmhd.w,&rastport,0,0,
																	ilbm.Bmhd.w,ilbm.Bmhd.h,RECTFMT_RGB);
												FreeVec(buffer);
												MPi->BitMap = bitmap;
												MPi->Width = ilbm.Bmhd.w;
												MPi->Height = ilbm.Bmhd.h;
												unloadbrush(&ilbm);
												FreeIFF(ilbm.ParseInfo.iff);
												CloseProgressWindow();
												CloseDownScreen();
												return MPi;
											}
											else {
												msg = "Out of memory";
											}
										}
										else {
#endif
									    	// Convert to screen palette
											RGBToScreen(red,green,blue,ilbm.Bmhd.h,ilbm.Bmhd.w,maxcol,r,Bit12);
											c2p.bmap = bitmap;
											c2p.startX = 0;
											c2p.startY = 0;
											c2p.width = ilbm.Bmhd.w;
											c2p.height = ilbm.Bmhd.h;
											c2p.chunkybuffer = red;
											ChunkyToPlanar(&c2p);
											FreeVec(red);
											FreeVec(green);
											FreeVec(blue);
											MPi->BitMap = bitmap;
											MPi->Width = ilbm.Bmhd.w;
											MPi->Height = ilbm.Bmhd.h;
											unloadbrush(&ilbm);
											FreeIFF(ilbm.ParseInfo.iff);
											CloseProgressWindow();
											CloseDownScreen();
											return MPi;
#ifdef CYBER
										}
#endif
									}
								}
								else {	// AllocVec red,green,blue
									msg = "Out of memory";
								}
								if (red) FreeVec(red);
								if (green) FreeVec(green);
							}
						}
						else {	// Not 24bit
							if ((Remap || !LoadBit) && DCTVBase && TestDCTVSignature(ilbm.brbitmap)) {
								AddMessage("DCTV ILBM");
								if ((red = AllocVec((int)ilbm.Bmhd.w*ilbm.Bmhd.h,0)) &&
								    (green = AllocVec((int)ilbm.Bmhd.w*ilbm.Bmhd.h,0)) &&
								    (blue = AllocVec((int)ilbm.Bmhd.w*ilbm.Bmhd.h,0))) {
									if (handle = AllocDCTVCvtTags(ilbm.brbitmap,
																	DCTVCVTA_Type,		DCTVCVTT_DCTVtoRGB,
																	DCTVCVTA_Width,	ilbm.Bmhd.w,
																	DCTVCVTA_Height,	ilbm.Bmhd.h,
																	DCTVCVTA_Flags,	((ilbm.camg & LACE)?DCTVCVTF_Lace:0) |
																							DCTVCVTF_CustomRGBBuf,
																	DCTVCVTA_ColorTable,	ilbm.colortable,
																	TAG_END)) {
										handle->Red = red;
										handle->Green = green;
										handle->Blue = blue;
										SetMax(ilbm.Bmhd.h);
										while (handle->DstLineNum < handle->Height) {
											CvtDCTVLine(handle);
											if ((handle->DstLineNum > 0) &&
												 (handle->DstLineNum <= handle->Height)) {
											 	SetCur(handle->DstLineNum-1);
											}
											handle->Red += ilbm.Bmhd.w;
											handle->Green += ilbm.Bmhd.w;
											handle->Blue += ilbm.Bmhd.w;
										}
										FreeDCTVCvt(handle);
										if (RGB || Grey) {	// RGB DCTV
											MPi->Width = ilbm.Bmhd.w;
											MPi->Height = ilbm.Bmhd.h;
											unloadbrush(&ilbm);
											FreeIFF(ilbm.ParseInfo.iff);
											MPi->Red = red;
											MPi->Green = green;
											MPi->Blue = blue;
											CloseProgressWindow();
											CloseDownScreen();
											return MPi;
										}	// !RGB || Grey
										if (EGS) {	// EGS DCTV
				  				    		// Convert to an EGS BitMap
											if (MPi->EGS_BitMap = E_AllocBitMap(ilbm.Bmhd.w,ilbm.Bmhd.h,24,E_PIXELMAP,E_EB_NOTSWAPABLE,NULL)) {
												plane = ((struct E_EBitMapFull *)(MPi->EGS_BitMap))->Typekey.PixelMap.Planes.Dest;
												AddMessage("Chunky to EGS");
												SetMax(ilbm.Bmhd.h);
												rr = red;
												gg = green;
												bb = blue;
												for (i = 0; i<ilbm.Bmhd.h; i++) {
													SetCur(i);
													for (j = 0; j<ilbm.Bmhd.w; j++) {
														*plane++ = *rr++;
														*plane++ = *gg++;
														*plane++ = *bb++;
														plane++;
													}
													plane += (MPi->EGS_BitMap->BytesPerRow - (4*ilbm.Bmhd.w));
												}
												FreeVec(red);
												FreeVec(green);
												FreeVec(blue);
												MPi->Width = ilbm.Bmhd.w;
												MPi->Height = ilbm.Bmhd.h;
												unloadbrush(&ilbm);
												FreeIFF(ilbm.ParseInfo.iff);
												CloseLibrary(EGSBase);
												CloseProgressWindow();
												CloseDownScreen();
												return MPi;
											}
											else { // E_AllocBitMap
												msg = "Can't Allocate EGS BitMap";
											}
										}
										else {	// !EGS
											if (ForceGrey) {
												RGBToGrey(red,green,blue,ilbm.Bmhd.h,ilbm.Bmhd.w,LinearGrey);
												FreeVec(green);
												FreeVec(blue);
												MPi->Width = ilbm.Bmhd.w;
												MPi->Height = ilbm.Bmhd.h;
												unloadbrush(&ilbm);
												FreeIFF(ilbm.ParseInfo.iff);
												MPi->Red = red;
												MPi->Green = red;
												MPi->Blue = red;
												MPi->GreyScale = TRUE;
												CloseProgressWindow();
												CloseDownScreen();
												return MPi;
											}	// !ForceGrey - DCTV
#ifdef CYBER
											if (MPi->Cyber) {
												UBYTE *buffer,*r,*g,*b,*t;
												int i,j;
												if (buffer = AllocVec((int)ilbm.Bmhd.w*ilbm.Bmhd.h*3,0)) {
													struct RastPort rastport;
													r = red;
													g = green;
													b = blue;
													t = buffer;
													for (i=0; i<ilbm.Bmhd.w; ++i) {
														for (j=0; j<ilbm.Bmhd.h; ++j) {
															*t++ = *r++;
															*t++ = *g++;
															*t++ = *b++;
														}
													}
													FreeVec(red);
													FreeVec(green);
													FreeVec(blue);
													InitRastPort(&rastport);
													rastport.BitMap = bitmap;
													WritePixelArray(buffer,0,0,ilbm.Bmhd.w,&rastport,0,0,
																		ilbm.Bmhd.w,ilbm.Bmhd.h,RECTFMT_RGB);
													FreeVec(buffer);
													MPi->BitMap = bitmap;
													MPi->Width = ilbm.Bmhd.w;
													MPi->Height = ilbm.Bmhd.h;
													unloadbrush(&ilbm);
													FreeIFF(ilbm.ParseInfo.iff);
													CloseProgressWindow();
													CloseDownScreen();
													return MPi;
												}
												else {
													msg = "Out of memory";
												}
											}
											else {
#endif
									   	 	// Convert to screen palette
												RGBToScreen(red,green,blue,ilbm.Bmhd.h,ilbm.Bmhd.w,maxcol,r,Bit12);
												c2p.bmap = bitmap;
												c2p.startX = 0;
												c2p.startY = 0;
												c2p.width = ilbm.Bmhd.w;
												c2p.height = ilbm.Bmhd.h;
												c2p.chunkybuffer = red;
												ChunkyToPlanar(&c2p);
												FreeVec(red);
												FreeVec(green);
												FreeVec(blue);
												MPi->BitMap = bitmap;
												MPi->Width = ilbm.Bmhd.w;
												MPi->Height = ilbm.Bmhd.h;
												unloadbrush(&ilbm);
												FreeIFF(ilbm.ParseInfo.iff);
												CloseProgressWindow();
												CloseDownScreen();
												return MPi;
#ifdef CYBER
											}
#endif
										}
									}
									else {
										msg = "Can't Allocate DCTV handle";
									}
								}
								else {
									msg = "Out of memory";
								}
							}
							else {
								if (red = AllocVec(ilbm.Bmhd.w*ilbm.Bmhd.h,0)) {
									AddMessage("ILBM Not 24");
									p2c.bmap = ilbm.brbitmap;
									p2c.startX = 0;
									p2c.startY = 0;
									p2c.width = ilbm.Bmhd.w;
									p2c.height = ilbm.Bmhd.h;
									p2c.chunkybuffer = red;
									PlanarToChunky(&p2c);
									if (LoadBit && !Remap) {
										// Actual bit map is in fast ram so must copy to chip ram version
										// use p2c and c2p (horrible!!!!)
										c2p.bmap = bitmap;
										c2p.startX = 0;
										c2p.startY = 0;
										c2p.width = ilbm.Bmhd.w;
										c2p.height = ilbm.Bmhd.h;
										c2p.chunkybuffer = red;
										ChunkyToPlanar(&c2p);
										MPi->Width = ilbm.Bmhd.w;
										MPi->Height = ilbm.Bmhd.h;
										unloadbrush(&ilbm);
										FreeIFF(ilbm.ParseInfo.iff);
										FreeVec(red);
										MPi->BitMap = bitmap;
										CloseProgressWindow();
										CloseDownScreen();
										return MPi;
									}	// !remap
									AddMessage("Checking if Grey");
									for (i=0; i < ilbm.ncolors; ++i) {
										r1[i]=(ilbm.colortable32[i].r)>>24;
										r1[i+256]=(ilbm.colortable32[i].g)>>24;
										r1[i+512]=(ilbm.colortable32[i].b)>>24;
										if (Grey || ForceGrey) {
											if ((r1[i] != r1[i+256]) || (r1[i] != r1[i+512])) {
												IsGrey = FALSE;
											}
										}
									}
									if ((ForceGrey || Grey) && IsGrey) {
										IsGrey = CheckNotHAM(ilbm.camg);
									}
									else {
										IsGrey = FALSE;
									}
									if (IsGrey) {
										MPi->Width = ilbm.Bmhd.w;
										MPi->Height = ilbm.Bmhd.h;
										PaletteToGrey(MPi,&ilbm,red,r1,red,0,0);
										unloadbrush(&ilbm);
										FreeIFF(ilbm.ParseInfo.iff);
										MPi->Red = red;
										MPi->Green = red;
										MPi->Blue = red;
										MPi->GreyScale = TRUE;
										CloseProgressWindow();
										CloseDownScreen();
										return MPi;
									}
									if (ForceGrey) {
										MPi->Width = ilbm.Bmhd.w;
										MPi->Height = ilbm.Bmhd.h;
										PaletteRGBToGrey(MPi,&ilbm,r1,red,0,0,LinearGrey);
										unloadbrush(&ilbm);
										FreeIFF(ilbm.ParseInfo.iff);
										MPi->Red = red;
										MPi->Green = red;
										MPi->Blue = red;
										MPi->GreyScale = TRUE;
										CloseProgressWindow();
										CloseDownScreen();
										return MPi;
									}
									if (RGB || Grey) {
										if ((green = AllocVec((int)ilbm.Bmhd.w*ilbm.Bmhd.h,0)) &&
											 (blue = AllocVec((int)ilbm.Bmhd.w*ilbm.Bmhd.h,0))) {
											MPi->Width = ilbm.Bmhd.w;
											MPi->Height = ilbm.Bmhd.h;
											PaletteToRGB(MPi,&ilbm,red,green,blue,r1,red,0,0);
											unloadbrush(&ilbm);
											FreeIFF(ilbm.ParseInfo.iff);
											MPi->Red = red;
											MPi->Green = green;
											MPi->Blue = blue;
											CloseProgressWindow();
											CloseDownScreen();
											return MPi;
										}
										else {	// allocvec green,blue
											msg = "Out of memory";
										}
										if (green) {
											FreeVec(green);
										}
									}
									else { // !RGB || Grey
										if (EGS) {
				  				    		// Convert to an EGS BitMap
											if (MPi->EGS_BitMap = E_AllocBitMap(ilbm.Bmhd.w,ilbm.Bmhd.h,24,E_PIXELMAP,E_EB_NOTSWAPABLE,NULL)) {
												plane = ((struct E_EBitMapFull *)(MPi->EGS_BitMap))->Typekey.PixelMap.Planes.Dest;
												MPi->Width = ilbm.Bmhd.w;
												MPi->Height = ilbm.Bmhd.h;
												PaletteToEGS(MPi,&ilbm,plane,r1,red,0,0);
												unloadbrush(&ilbm);
												FreeIFF(ilbm.ParseInfo.iff);
												FreeVec(red);
												CloseLibrary(EGSBase);
												CloseProgressWindow();
												CloseDownScreen();
												return MPi;
											}
											else {	// E_AllocBitMap
												msg = "Can't Allocate EGS BitMap";
											}
										}
										else { // !EGS && !RGB && !Grey && Remap
											// Convert image planar to screen palette planar
											PaletteToScreen(&ilbm,maxcol,r,r1,red);
											c2p.bmap = bitmap;
											c2p.startX = 0;
											c2p.startY = 0;
											c2p.width = ilbm.Bmhd.w;
											c2p.height = ilbm.Bmhd.h;
											c2p.chunkybuffer = red;
											ChunkyToPlanar(&c2p);
											MPi->Width = ilbm.Bmhd.w;
											MPi->Height = ilbm.Bmhd.h;
											unloadbrush(&ilbm);
											FreeIFF(ilbm.ParseInfo.iff);
											FreeVec(red);
											MPi->BitMap = bitmap;
											CloseProgressWindow();
											CloseDownScreen();
											return MPi;
										}
									}
								}
								else {	// AllocVec red;
									msg = "Out of memory";
								}
							}
						}
					}
					if (bitmap) {
						FreeBitMap(bitmap);
					}
				}
				if (ilbm.ParseInfo.iff) {
					FreeIFF(ilbm.ParseInfo.iff);
				}
			}
			else {	// AllocIFF
				msg = "Can't Allocate IFF structure";
			}
			break;
		case FORMAT_PBM:
		case FORMAT_JPEG:
		case FORMAT_PNG:
			if (FileFormat == FORMAT_PBM) {
				AddMessage("Loading PBM");
				jfilename = filename;
			}
			else {
				LockSema();
				if (FileFormat == FORMAT_JPEG) {
					AddMessage("Loading JPEG");
				}
				else {
					AddMessage("Loading PNG");
				}
				sprintf(jpegpip,"%s%ld","PIPE:",MPi);
				AddMessage(jpegpip);
				sprintf(jpegcom,jpegbuf,filename,jpegpip);
				djpegflag = DJPEG_WAIT;
				CreateNewProcTags(NP_Entry,	(ULONG)djpegWaitTask,
									   NP_Name,		(FileFormat == FORMAT_JPEG) ?
									   				"MPImage DJPEG Wait task" :
									   				"MPImage PNGTOPNM Wait task",
									   TAG_END);
				SystemTags(jpegcom,
						SYS_Input,	NULL,
						SYS_Output,	NULL,
						SYS_Asynch,	TRUE,
						NP_StackSize,	16000,
						NP_Name,		(FileFormat == FORMAT_JPEG) ?
										"MPImage DJPEG task" :
										"MPImage PNGTOPNM task",
						TAG_END);
				jfilename = jpegpip;
				if (FileFormat == FORMAT_JPEG) {
					AddMessage("Waiting for DJPEG");
				}
				else {
					AddMessage("Waiting for PNGTOPNM");
				}
			}
			if (Remap) {
				AddMessage("Geting screen colours");
			  	maxcol = min(1<<screen->BitMap.Depth,256);
				for (i=0; i < maxcol; ++i) {
					GetRGB32(screen->ViewPort.ColorMap,i,1,col);
					r[i]=(col[0]>>24);
					r[i+256]=(col[1]>>24);
					r[i+512]=(col[2]>>24);
				}
			}
		 	if (fh = fopen(jfilename,"rb")) {
				unsigned int width,height,maxval,z;
				fread(buffer,2,1,fh);
				if (((FileFormat == FORMAT_JPEG) || (FileFormat == FORMAT_PNG))&&
					 (djpegflag == DJPEG_ABORT)) {
					if (FileFormat == FORMAT_JPEG) {
						msg = "djpeg failed to start";
					}
					else {
						msg = "pngtopnm failed to start";
					}
					UnlockSema();
				}
				else {
					if (FileFormat == FORMAT_JPEG) {
						AddMessage("DJPEG started");
						djpegflag = DJPEG_HAVE;
						UnlockSema();
					}
					else {
						if (FileFormat == FORMAT_PNG) {
							AddMessage("PNGTOPNM started");
							djpegflag = DJPEG_HAVE;
							UnlockSema();
						}
					}
					// Get width
					width = ReadPBMInteger(fh,255);
					height = ReadPBMInteger(fh,255);
					if (('1' == buffer[1]) || ('4' == buffer[1])) {
						maxval = 255;
					}
					else {
						maxval = ReadPBMInteger(fh,255);
					}
					if ((width == 0) || (height == 0) || (maxval == 0)) {
						msg = "Unsupported/Invalid PBM file";
					}
					else {
						if (!Remap && LoadBit) {
							msg = "Can't not remap PBM";
						}
						else {
							if (EGS) {
  					    		// Convert to an EGS BitMap
								if (MPi->EGS_BitMap = E_AllocBitMap(width,height,24,E_PIXELMAP,E_EB_NOTSWAPABLE,NULL)) {
									if ('4' == buffer[1]) {
										c = getc(fh);
									}
									plane = ((struct E_EBitMapFull *)(MPi->EGS_BitMap))->Typekey.PixelMap.Planes.Dest;
									SetMax(height);
									for (i = 0; i<height; i++) {
										SetCur(i);
										for (j = 0; j<width; j++) {
											switch (buffer[1])  {
											case '1':
												z = ReadPBMInteger(fh,255);
												if (z) {
													*plane++ = 0;
													*plane++ = 0;
													*plane++ = 0;
												}
												else {
													*plane++ = 255;
													*plane++ = 255;
													*plane++ = 255;
												}
												break;
											case '2':
												z = ReadPBMInteger(fh,maxval);
												*plane++ = z;
												*plane++ = z;
												*plane++ = z;
												break;
											case '3':
												*plane++ = ReadPBMInteger(fh,maxval);
												*plane++ = ReadPBMInteger(fh,maxval);
												*plane++ = ReadPBMInteger(fh,maxval);
												break;
											case '4':
												if ((c>>currbit) & 1) {
													*plane++ = 0;
													*plane++ = 0;
													*plane++ = 0;
												}
												else {
													*plane++ = 255;
													*plane++ = 255;
													*plane++ = 255;
												}
												if (!currbit) {
													currbit = 7;
													c = getc(fh);
												}
												else {
													--currbit;
												}
												break;
											case '5':
												z = getc(fh);
												if (255 == maxval) {
													*plane++ = z;
													*plane++ = z;
													*plane++ = z;
												}
												else {
													*plane++ = (z*255)/maxval;
													*plane++ = (z*255)/maxval;
													*plane++ = (z*255)/maxval;
												}
												break;
											case '6':
												if (255 == maxval) {
													*plane++ = getc(fh);
													*plane++ = getc(fh);
													*plane++ = getc(fh);
												}
												else {
													*plane++ = (getc(fh) * 255)/maxval;
													*plane++ = (getc(fh) * 255)/maxval;
													*plane++ = (getc(fh) * 255)/maxval;
												}
												break;
											}
											plane++;
										}
										plane += (MPi->EGS_BitMap->BytesPerRow - (4*(int)width));
									}
									fclose(fh);
									MPi->Width = width;
									MPi->Height = height;
									CloseLibrary(EGSBase);
									CloseProgressWindow();
									CloseDownScreen();
									return MPi;
								}
								else { // E_AllocBitMap
									msg = "Can't Allocate EGS BitMap";
								}
							}
							else {	// !EGS
								if (LoadBit) {
									if (!(bitmap = AllocBitMap(width,height,screen ? screen->BitMap.Depth : 8,BMF_DISPLAYABLE,NULL))) {
										error = 1;
										msg = "Can't Allocate BitMap";
									}
								}
								if (!error) {
									if (LoadBit && ((buffer[1] == '2') || (buffer[1] == '1') || (buffer[1] == '4') || (buffer[1] == '5'))) {	// Grey Scale Bit Map
										if (red = AllocVec((int)width*height,0)) {
											switch (buffer[1]) {
											case '5':
												if (255 == maxval) {
											   	fread(red,width,height,fh);
											   }
											   else {
												   rr = red;
												   SetMax(height);
													for (i = 0; i<height; i++) {
														SetCur(i);
														for (j = 0; j<width; j++) {
															z = getc(fh);
															*rr++ = (z*255)/maxval;
														}
													}
												}
										   	break;
										   case '2':
											   rr = red;
											   SetMax(height);
												for (i = 0; i<height; i++) {
													SetCur(i);
													for (j = 0; j<width; j++) {
														*rr++ = ReadPBMInteger(fh,maxval);
													}
												}
												break;
											case '1':
											   rr = red;
											   SetMax(height);
												for (i = 0; i<height; i++) {
													SetCur(i);
													for (j = 0; j<width; j++) {
														z = ReadPBMInteger(fh,255);
														if (z) {
															*rr++ = 0;
														}
														else {
															*rr++ = 255;
														}
													}
												}
												break;
											case '4':
												c = getc(fh);
											   rr = red;
											   SetMax(height);
												for (i = 0; i<height; i++) {
													SetCur(i);
													for (j = 0; j<width; j++) {
														if ((c>>currbit) & 1) {
															*rr++ = 0;
														}
														else {
															*rr++ = 255;
														}
														if (!currbit) {
															currbit = 7;
															c = getc(fh);
														}
														else {
															--currbit;
														}
													}
												}
												break;
											}
									    	// Convert to screen palette
								   	 	fclose(fh);
											RToScreen(red,height,width,maxcol,r);
											c2p.bmap = bitmap;
											c2p.startX = 0;
											c2p.startY = 0;
											c2p.width = width;
											c2p.height = height;
											c2p.chunkybuffer = red;
											ChunkyToPlanar(&c2p);
											FreeVec(red);
											MPi->BitMap = bitmap;
											MPi->Width = width;
											MPi->Height = height;
											CloseProgressWindow();
											CloseDownScreen();
											return MPi;
										}
										else {	// AllocVec red,green,blue
											msg = "Out of memory";
										}
									}
									else {	// RGB or Grey or P3 or P6
										if (Grey || ForceGrey) {
											if ((buffer[1] == '3') || (buffer[1] == '6')) {
												IsGrey = FALSE;
											}
										}
										else {
											IsGrey = FALSE;
										}
										if (IsGrey) {	// GreyScale
											if (red = AllocVec((int)width*height,0)) {
												switch (buffer[1]) {
												case '5':
													if (255 == maxval) {
												   	fread(red,width,height,fh);
												   }
												   else {
														rr = red;
														SetMax(height);
														for (i = 0; i<height; i++) {
															SetCur(i);
															for (j = 0; j<width; j++) {
																z = getc(fh);
																*rr++ = (z*255)/maxval;
															}
														}
													}
											   	break;
											   case '2':
												   rr = red;
												   SetMax(height);
													for (i = 0; i<height; i++) {
														SetCur(i);
														for (j = 0; j<width; j++) {
															*rr++ = ReadPBMInteger(fh,maxval);
														}
													}
													break;
												case '1':
												   rr = red;
												   SetMax(height);
													for (i = 0; i<height; i++) {
														SetCur(i);
														for (j = 0; j<width; j++) {
															z = ReadPBMInteger(fh,255);
															if (z) {
																*rr++ = 0;
															}
															else {
																*rr++ = 255;
															}
														}
													}
													break;
												case '4':
													c = getc(fh);
												   rr = red;
												   SetMax(height);
													for (i = 0; i<height; i++) {
														SetCur(i);
														for (j = 0; j<width; j++) {
															if ((c>>currbit) & 1) {
																*rr++ = 0;
															}
															else {
																*rr++ = 255;
															}
															if (!currbit) {
																currbit = 7;
																c = getc(fh);
															}
															else {
																--currbit;
															}
														}
													}
													break;
												}
												fclose(fh);
												MPi->Width = width;
												MPi->Height = height;
												MPi->Red = red;
												MPi->Green = red;
												MPi->Blue = red;
												MPi->GreyScale = TRUE;
												CloseProgressWindow();
												CloseDownScreen();
												return MPi;
											}
											else {	// AllocVec red
												msg = "Out of memory";
											}
										}
										else { // RGB || P3 || P6 || (Grey && !IsGrey)
											if (ForceGrey) {
												if (red = AllocVec((int)width*height,0)) {
												   rr = red;
												   SetMax(height);
												   if (LinearGrey) {
														for (i = 0; i<height; i++) {
															SetCur(i);
															for (j = 0; j<width; j++) {
																switch (buffer[1])  {
																case '3':
																	*rr++ = (ReadPBMInteger(fh,maxval)+ReadPBMInteger(fh,maxval)+ReadPBMInteger(fh,maxval))/3;
																	break;
																case '6':
																	if (255 == maxval) {
																		*rr++ = (getc(fh)+getc(fh)+getc(fh))/3;
																	}
																	else {
																		*rr++ = (((getc(fh)+getc(fh)+getc(fh))/3)*255)/maxval;
																	}
																	break;
																}
															}
														}
												   }
												   else {
														for (i = 0; i<height; i++) {
															SetCur(i);
															for (j = 0; j<width; j++) {
																switch (buffer[1])  {
																case '3':
																	*rr++ = ((ReadPBMInteger(fh,maxval)*77)+(ReadPBMInteger(fh,maxval)*151)+(ReadPBMInteger(fh,maxval)*28))>>8;
																	break;
																case '6':
																	if (255 == maxval) {
																		*rr++ = ((getc(fh)*77)+(getc(fh)*151)+(getc(fh)*28))>>8;
																	}
																	else {
																		*rr++ = ((((getc(fh)*77)+(getc(fh)*151)+(getc(fh)*28))>>8)*255)/maxval;
																	}
																	break;
																}
															}
														}
													}
													fclose(fh);
													MPi->Width = width;
													MPi->Height = height;
													MPi->Red = red;
													MPi->Green = red;
													MPi->Blue = red;
													MPi->GreyScale = TRUE;
													CloseProgressWindow();
													CloseDownScreen();
													return MPi;
												}
												else {	// AllocVec red
													msg = "Out of memory";
												}
											}
											else {
												if ((red = AllocVec((int)width*height,0)) &&
												    (green = AllocVec((int)width*height,0)) &&
												    (blue = AllocVec((int)width*height,0))) {
												   SetMax(height);
												   if (buffer[1] == '5') {
												   	if (maxval == 255) {
													   	fread(red,width,height,fh);
													   }
													   else {
														   rr = red;
														   SetMax(height);
															for (i = 0; i<height; i++) {
																SetCur(i);
																for (j = 0; j<width; j++) {
																	z = getc(fh);
																	*rr++ = (z*255)/maxval;
																}
															}
														}
												   	memcpy(green,red,width*height);
											   		memcpy(blue,red,width*height);
												   }
												   else {
														if ('4' == buffer[1]) {
															c = getc(fh);
														}
													   rr = red;
													   gg = green;
													   bb = blue;
														for (i = 0; i<height; i++) {
															SetCur(i);
															for (j = 0; j<width; j++) {
																switch (buffer[1])  {
																case '1':
																	z = ReadPBMInteger(fh,255);
																	if (z) {
																		*rr++ = 0;
																		*gg++ = 0;
																		*bb++ = 0;
																	}
																	else {
																		*rr++ = 255;
																		*gg++ = 255;
																		*bb++ = 255;
																	}
																	break;
																case '2':
																	*rr = ReadPBMInteger(fh,maxval);
																	*gg++ = *rr;
																	*bb++ = *rr++;
																	break;
																case '3':
																	*rr++ = ReadPBMInteger(fh,maxval);
																	*gg++ = ReadPBMInteger(fh,maxval);
																	*bb++ = ReadPBMInteger(fh,maxval);
																	break;
																case '4':
																	if ((c>>currbit) & 1) {
																		*plane++ = 0;
																		*plane++ = 0;
																		*plane++ = 0;
																	}
																	else {
																		*plane++ = 255;
																		*plane++ = 255;
																		*plane++ = 255;
																	}
																	if (!currbit) {
																		currbit = 7;
																		c = getc(fh);
																	}
																	else {
																		--currbit;
																	}
																	break;
																case '6':
																	if (255 == maxval) {
																		*rr++ = getc(fh);
																		*gg++ = getc(fh);
																		*bb++ = getc(fh);
																	}
																	else {
																		*rr++ = (getc(fh)*255)/maxval;
																		*gg++ = (getc(fh)*255)/maxval;
																		*bb++ = (getc(fh)*255)/maxval;
																	}
																	break;
																}
															}
														}
													}
													if (!LoadBit) {
														fclose(fh);
														MPi->Width = width;
														MPi->Height = height;
														MPi->Red = red;
														MPi->Green = green;
														MPi->Blue = blue;
														CloseProgressWindow();
														CloseDownScreen();
														return MPi;
													}
													else {	// !RGB && !Grey
												    	// Convert to screen palette
										   		 	fclose(fh);
														RGBToScreen(red,green,blue,height,width,maxcol,r,Bit12);
														c2p.bmap = bitmap;
														c2p.startX = 0;
														c2p.startY = 0;
														c2p.width = width;
														c2p.height = height;
														c2p.chunkybuffer = red;
														ChunkyToPlanar(&c2p);
														FreeVec(red);
														FreeVec(green);
														FreeVec(blue);
														MPi->BitMap = bitmap;
														MPi->Width = width;
														MPi->Height = height;
														CloseProgressWindow();
														CloseDownScreen();
														return MPi;
													}
												}
												else {	// AllocVec red,green,blue
													msg = "Out of memory";
												}
												if (red) FreeVec(red);
												if (green) FreeVec(green);
											}
										}
									}
								}
								if (bitmap) {
									FreeBitMap(bitmap);
								}
							}
						}
					}
				}
				fclose(fh);
			}
			else {
				sprintf(ErrorMessage,"Error opening file '%s'",filename);
			}
			break;
		case FORMAT_DT:
		default:
			AddMessage("Loading DataType");
			if (o = NewDTObject((char *)filename,
								DTA_GroupID, GID_PICTURE,
								OBP_Precision, PRECISION_IMAGE,
								PDTA_Remap, (LoadBit && Remap) ? TRUE : FALSE,
								(LoadBit && Remap) ? PDTA_Screen : TAG_IGNORE, screen,
								PDTA_FreeSourceBitMap, TRUE,
								TAG_END)) {
				GetDTAttrs(o,
							PDTA_BitMapHeader, &bmhd,
							TAG_END);
				if (bmhd) {
					if (screen) {
						modeid = GetVPModeID (&(screen->ViewPort));
						if (GetDisplayInfoData (NULL, (APTR) & di, sizeof (struct DisplayInfo), DTAG_DISP, modeid)) {
							fri.fri_PropertyFlags = di.PropertyFlags;
							fri.fri_Resolution = *(&di.Resolution);
							fri.fri_RedBits = di.RedBits;
							fri.fri_GreenBits = di.GreenBits;
							fri.fri_BlueBits = di.BlueBits;
							fri.fri_Dimensions.Depth = screen->BitMap.Depth;
							fri.fri_Screen = screen;
							fri.fri_ColorMap = screen->ViewPort.ColorMap;
						}
					}
					fri.fri_Dimensions.Width = bmhd->bmh_Width;
					fri.fri_Dimensions.Height = bmhd->bmh_Height;
					dtf.MethodID = DTM_FRAMEBOX;
					dtf.dtf_FrameInfo = &fri;
					dtf.dtf_ContentsInfo = &(fri);
					dtf.dtf_SizeFrameInfo = sizeof(struct FrameInfo);
					dtf.dtf_FrameFlags = FRAMEF_SPECIFY;
					AddMessage("Layout DataType");
					DoDTMethodA(o,NULL,NULL,(Msg)&dtf);
					DoDTMethod(o,NULL,NULL,DTM_PROCLAYOUT,NULL,1);
					if (EGS) {
						GetDTAttrs(o,
									PDTA_BitMapHeader, &bmhd,
									PDTA_DestBitMap, &bitmap,
									PDTA_ModeID, &modeid,
									PDTA_ColorRegisters, &cr,
									TAG_END);
						if (bmhd && bitmap && cr) {
							AddMessage("Geting Colours");
							maxcol = 1 << bmhd->bmh_Depth;
							for (i=0; i < maxcol; ++i) {
								r1[i]=cr[i].red;
								r1[i+256]=cr[i].green;
								r1[i+512]=cr[i].blue;
							}
							MPi->Width = bmhd->bmh_Width;
							MPi->Height = bmhd->bmh_Height;
							if (red = AllocVec((int)MPi->Width*MPi->Height,0)) {
								p2c.bmap = bitmap;
								p2c.startX = 0;
								p2c.startY = 0;
								p2c.width = MPi->Width;
								p2c.height = MPi->Height;
								p2c.chunkybuffer = red;
								PlanarToChunky(&p2c);
								if (MPi->EGS_BitMap = E_AllocBitMap(MPi->Width,MPi->Height,24,E_PIXELMAP,E_EB_NOTSWAPABLE,NULL)) {
									plane = ((struct E_EBitMapFull *)(MPi->EGS_BitMap))->Typekey.PixelMap.Planes.Dest;
									MPi->Width = bmhd->bmh_Width;
									MPi->Height = bmhd->bmh_Height;
									PaletteToEGS(MPi,NULL,plane,r1,red,modeid,maxcol);
									DisposeDTObject(o);
									FreeVec(red);
									CloseLibrary(EGSBase);
									CloseProgressWindow();
									CloseDownScreen();
									return MPi;
								}
								else {	// E_AllocBitMap
									msg = "Can't Allocate EGS BitMap";
								}
								FreeVec(red);
							}
							else { // Alloc red
								msg = "Out of memory";
							}
						}
						else {	// bmhd && bitmap && cr
							msg = "Error geting datatype BitMap";
						}
					}
					else {	// not EGS
						if (!LoadBit) {
							GetDTAttrs(o,
										PDTA_BitMapHeader, &bmhd,
										PDTA_DestBitMap, &bitmap,
										PDTA_ModeID, &modeid,
										PDTA_ColorRegisters, &cr,
										TAG_END);
							if (bmhd && bitmap && cr) {
								AddMessage("Geting Colours");
								maxcol = 1 << bmhd->bmh_Depth;
								for (i=0; i < maxcol; ++i) {
									r1[i]=cr[i].red;
									r1[i+256]=cr[i].green;
									r1[i+512]=cr[i].blue;
									if (Grey || ForceGrey) {
										if ((r1[i] != r1[i+256]) || (r1[i] != r1[i+512])) {
											IsGrey = FALSE;
										}
									}
								}
								MPi->Width = bmhd->bmh_Width;
								MPi->Height = bmhd->bmh_Height;
								if (red = AllocVec((int)MPi->Width*MPi->Height,0)) {
									p2c.bmap = bitmap;
									p2c.startX = 0;
									p2c.startY = 0;
									p2c.width = MPi->Width;
									p2c.height = MPi->Height;
									p2c.chunkybuffer = red;
									PlanarToChunky(&p2c);
									if ((ForceGrey || Grey) && IsGrey) {
										IsGrey = CheckNotHAM(modeid);
									}
									else {
										IsGrey = FALSE;
									}
									if (IsGrey) {
										MPi->Width = bmhd->bmh_Width;
										MPi->Height = bmhd->bmh_Height;
										PaletteToGrey(MPi,NULL,red,r1,red,modeid,maxcol);
										MPi->Red = red;
										MPi->Green = red;
										MPi->Blue = red;
										MPi->GreyScale = TRUE;
										DisposeDTObject(o);
										CloseProgressWindow();
										CloseDownScreen();
										return MPi;
									}
									if (ForceGrey) {
										MPi->Width = bmhd->bmh_Width;
										MPi->Height = bmhd->bmh_Height;
										PaletteRGBToGrey(MPi,NULL,r1,red,modeid,maxcol,LinearGrey);
										MPi->Red = red;
										MPi->Green = red;
										MPi->Blue = red;
										MPi->GreyScale = TRUE;
										DisposeDTObject(o);
										CloseProgressWindow();
										CloseDownScreen();
										return MPi;
									}
									if ((green = AllocVec((int)bmhd->bmh_Width*bmhd->bmh_Height,0)) &&
										 (blue = AllocVec((int)bmhd->bmh_Width*bmhd->bmh_Height,0))) {
										MPi->Width = bmhd->bmh_Width;
										MPi->Height = bmhd->bmh_Height;
										PaletteToRGB(MPi,NULL,red,green,blue,r1,red,modeid,maxcol);
										MPi->Red = red;
										MPi->Green = green;
										MPi->Blue = blue;
										DisposeDTObject(o);
										CloseProgressWindow();
										CloseDownScreen();
										return MPi;
									}
									else {	// AllocVec(blue);
										msg = "Out of memory";
									}
									if (green) {
										FreeVec(green);
									}
								}
								else {	// AllocVec red
									msg = "Out of memory";
								}
							}
							else { // bmhd && bitmap && cr
								msg = "Error geting datatype BitMap";
							}
						}
						else {	// LoadBit
							if (!Remap) {
								GetDTAttrs(o,
											PDTA_BitMapHeader, &bmhd,
											PDTA_DestBitMap, &bitmap,
											TAG_END);
								if (bmhd && bitmap) {
									if (!Clone) {
										MPi->Width = bmhd->bmh_Width;
										MPi->Height = bmhd->bmh_Height;
										MPi->Object = o;
										MPi->BitMap = bitmap;
										CloseProgressWindow();
										CloseDownScreen();
										return MPi;
									}
									else {
										MPi->Width = bmhd->bmh_Width;
										MPi->Height = bmhd->bmh_Height;
										if (MPi->BitMap = AllocBitMap(MPi->Width,MPi->Height,
																screen ? screen->BitMap.Depth : bmhd->bmh_Depth,
																BMF_DISPLAYABLE,bitmap)) {
											AddMessage("Copying DT to BitMap");
											BltBitMap(bitmap,0,0,MPi->BitMap,0,0,MPi->Width,MPi->Height,0xc0,0xff,NULL);
											WaitBlit();
											DisposeDTObject(o);
											CloseProgressWindow();
											CloseDownScreen();
											return MPi;
										}
										else {	// AllocBitMap
											msg = "Can't Allocate BitMap";
										}
									}
								}
								else {	// !bmhd || ! bitmap
									msg = "Error geting datatype BitMap";
								}
							}
							else { // remapping...
								GetDTAttrs(o,
										PDTA_DestBitMap, &bitmap,
										TAG_END);
								if (bitmap) {
									if (Clone) {
										MPi->Width = bmhd->bmh_Width;
										MPi->Height = bmhd->bmh_Height;
										if (MPi->BitMap = AllocBitMap(MPi->Width,MPi->Height,
																screen ? screen->BitMap.Depth : bmhd->bmh_Depth,
																BMF_DISPLAYABLE,bitmap)) {
											AddMessage("Copying DT to BitMap");
											BltBitMap(bitmap,0,0,MPi->BitMap,0,0,MPi->Width,MPi->Height,0xc0,0xff,NULL);
											WaitBlit();
											DisposeDTObject(o);
											CloseProgressWindow();
											CloseDownScreen();
											return MPi;
										}
										else {	// AllocBitMap
											msg = "Can't Allocate BitMap";
										}
									}
									else {
										MPi->BitMap = bitmap;
										MPi->Width = bmhd->bmh_Width;
										MPi->Height = bmhd->bmh_Height;
										MPi->Object = o;
										CloseProgressWindow();
										CloseDownScreen();
										return MPi;
									}
								}
								else {	// not bitmap
									msg = "Error geting datatype BitMap";
								}
							}
						}
					}
				}
				else {	// bmhd
					msg = "Error geting datatype BitMapHeader";
				}
				DisposeDTObject(MPi->Object);
			}
			else { // no object
				msg = "Error loading DataType";
			}
			break;
		}
		FreeMem(MPi,sizeof(struct MPImage));
	}
	else {	// Alloc MPImage
		msg = "Out of memory";
	}
	strcpy(ErrorMessage,msg);
	CloseProgressWindow();
	CloseDownScreen();
	return NULL;
}

#define RGB6(r,g,b) (UWORD)((((b)&~15)<<4)|((g)&~15)|((r)>>4))
#define RED6(x)     ((((x)&15)<<4)|((x)&15))
#define GREEN6(x)   (((((x)>>4)&15)<<4)|((((x)>>4)&15)))
#define BLUE6(x)    (((((x)>>8)&15)<<4)|((((x)>>8)&15)))

/* RGB to screen palette
 * red,green,blue : chunky pointers - result is pallete mapped chunky in red
 * Height,Width   : image size
 * maxcol         : number of colours
 * r              : r,g,b palette
 */
static void
RGBToScreen(UBYTE *red,UBYTE *green,UBYTE *blue,UWORD Height,UWORD Width,
						  UWORD maxcol,UBYTE *r,BOOL bit12) {
	UWORD i,j,k;
	ULONG maxdiff;
	ULONG diff;
	LONG 	t;
	UWORD index;
	UBYTE *InvMap;
	int ir,ig,ib;

	AddMessage("RGB to Screen");
	if (bit12 && (InvMap = AllocVec(4096,MEMF_ANY))) {
		AddMessage("Calculating 12bit Map");
		for (i = 0; i < 4096; ++i) {
			ir = RED6(i);
			ig = GREEN6(i);
			ib = BLUE6(i);
			// Find closest color
			maxdiff = 0x7FFFFFFF;
			for (k = 0;
				  k < maxcol;
				  ++k) {
				t = ir - r[k];
				diff = t*t*2;
				t = ig - r[k+256];
				diff += (t*t*4);
				t = ib - r[k+512];
				diff += (t*t);
				if (diff < maxdiff) {
					maxdiff = diff;
					index = k;
				}
			}
			InvMap[i] = index;
		}
		AddMessage("Remapping");
		SetMax(Height);
		for (j = 0;
			  j < Height;
			  ++j) {
			SetCur(j);
   		// for each pixel
			for (i = 0;
				  i < Width;
				  ++i) {
				*red = InvMap[RGB6(*red,*green,*blue)];
				++red;
				++green;
				++blue;
			}
		}
	}
	else {
		AddMessage("Remapping");
		SetMax(Height);
		// for each line
		for (j = 0;
			  j < Height;
			  ++j) {
			SetCur(j);
   		// for each pixel
			for (i = 0;
				  i < Width;
				  ++i) {
				// Find closest color based on:
				// red_difference*sqrt(3)+green_difference*srqt(6)+blue_difference
				// (some sort of logic in the figures somewhere)
				maxdiff = 0x7FFFFFFF;
				for (k = 0;
					  k < maxcol;
					  ++k) {
					t = (int)*red - r[k];
					diff = t*t*2;
					t = (int)*green - r[k+256];
					diff += (t*t*4);
					t = (int)*blue - r[k+512];
					diff += (t*t);
					if (diff < maxdiff) {
						maxdiff = diff;
						index = k;
					}
				}
				// Store index to color
				*red = index;
				++red;
				++green;
				++blue;
			}
		}
	}
}

/* BW to screen palette
 * red				: chunky pointers - result is pallete mapped chunky in red
 * Height,Width   : image size
 * maxcol         : number of colours
 * r              : r,g,b palette
 */
static void
RToScreen(UBYTE *red,UWORD Height,UWORD Width,
						  UWORD maxcol,UBYTE *r) {
	UWORD i,j,k;
	ULONG maxdiff;
	ULONG diff;
	LONG 	t;
	UBYTE NewPen[256];	// New pens for input pens

	AddMessage("Grey to Screen");
	AddMessage("Calculating Map");
	for (i = 0;
		(i < 256);
		i++) {
		maxdiff = 0x7FFFFFFF;
		for (k = 0;
			  k < maxcol;
			  ++k) {
			t = i - (int)r[k];
			diff = (t*t*2);
			t = i - (int)r[k+256];
			diff += (t*t*4);
			t = i - (int)r[k+512];
			diff += (t*t);
			if (diff < maxdiff) {
				maxdiff = diff;
				NewPen[i] = k;
			}
		}
	}

	AddMessage("Remapping");
	SetMax(Height);
	// for each line
	for (j = 0;
		  j < Height;
		  ++j) {
		SetCur(j);
   	// for each pixel
		for (i = 0;
			  i < Width;
			  ++i) {
			// Store index to color
			*red = NewPen[*red];
			red++;
		}
	}
}

/* Palette to screen palette
 * ilbm  : ILBMInfo *
 * maxcol: number of colours
 * r     : r,g,b palette
 * r1    : r,g,b image palette
 * chunky: Chunky data
 */
static void
PaletteToScreen(struct ILBMInfo *ilbm,UWORD maxcol,
							UBYTE *r,UBYTE *r1,
							UBYTE *chunky) {

	UWORD	i,j,k;			// loop counters
	LONG	penno;
	UBYTE	rr,gg,bb;
	ULONG maxdiff;
	ULONG diff;
	UWORD index;
	int	t;					// temp diff
	BOOL isHAM6 = FALSE;
	BOOL isHAM8 = FALSE;
	BOOL isEHB = FALSE;
	struct DisplayInfo queryinfo;
	DisplayInfoHandle handle;
	UBYTE *arrayp;
	UBYTE NewPen[256];	// New pens for input pens

	AddMessage("Palette To Screen");
	// based on CAMG chunk determine special type of image
	if ((handle = FindDisplayInfo(ilbm->camg)) &&
		 (GetDisplayInfoData(handle,(UBYTE *)&queryinfo,sizeof(queryinfo),DTAG_DISP,NULL))) {
		// 6 plane HAM
		if ((ilbm->Bmhd.nPlanes == 6) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
			isHAM6 = TRUE;
		}
		else {
			// 8 plane HAM
			if ((ilbm->Bmhd.nPlanes == 8) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
				isHAM8 = TRUE;
			}
			else {
				// 6 plane EHB
	  			if ((ilbm->Bmhd.nPlanes == 6) && (queryinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE)) {
	  				isEHB = TRUE;
	  			}
	  		}
		}
	}
	else {	// Unknown mode on this machine check somehow else
		if ((ilbm->Bmhd.nPlanes == 6) && (ilbm->camg & HAM)) {
			isHAM6 = TRUE;
		}
		else {
			if ((ilbm->Bmhd.nPlanes == 8) && (ilbm->camg & HAM)) {
				isHAM8 = TRUE;
			}
			else {
				if ((ilbm->Bmhd.nPlanes == 6) && (ilbm->camg & EXTRA_HALFBRITE)) {
					isEHB = TRUE;
				}
			}
		}
	}
	if (isHAM6) {
		AddMessage("Computing HAM6 Map");
		for (i = 0;
			  (i < 16);
			  i++) {
			maxdiff = 0x7FFFFFFF;
			for (k = 0;
				  k < maxcol;
				  ++k) {
				t = (int)r1[i] - r[k];
				diff = (t*t*2);
				t = (int)r1[i+256] - r[k+256];
				diff += (t*t*4);
				t = (int)r1[i+512] - r[k+512];
				diff += (t*t);
				if (diff < maxdiff) {
					maxdiff = diff;
					NewPen[i] = k;
				}
			}
		}
	}
	else {
		if (isHAM8) {
			AddMessage("Computing HAM8 Map");
			for (i = 0;
				  (i < 64);
				  i++) {
				maxdiff = 0x7FFFFFFF;
				for (k = 0;
					  k < maxcol;
					  ++k) {
					t = (int)r1[i] - r[k];
					diff = (t*t*2);
					t = (int)r1[i+256] - r[k+256];
					diff += (t*t*4);
					t = (int)r1[i+512] - r[k+512];
					diff += (t*t);
					if (diff < maxdiff) {
						maxdiff = diff;
						NewPen[i] = k;
					}
				}
			}
		}
		else {
			if (isEHB) {
	  			AddMessage("Computing EHB Map");
				for (i = 0;
					  (i < 32);
					  i++) {
					maxdiff = 0x7FFFFFFF;
					for (k = 0;
						  k < maxcol;
						  ++k) {
						t = (int)r1[i] - r[k];
						diff = (t*t*2);
						t = (int)r1[i+256] - r[k+256];
						diff += (t*t*4);
						t = (int)r1[i+512] - r[k+512];
						diff += (t*t);
						if (diff < maxdiff) {
							maxdiff = diff;
							NewPen[i] = k;
						}
					}
				}
				for (i = 32;
					  (i < 64);
					  i++) {
					maxdiff = 0x7FFFFFFF;
					for (k = 0;
						  k < maxcol;
						  ++k) {
						t = (int)(r1[i]>>1) - r[k];
						diff = t*t*2;
						t = (int)(r1[i+256]>>1) - r[k+256];
						diff += (t*t*4);
						t = (int)(r1[i+512]>>1) - r[k+512];
						diff += (t*t);
						if (diff < maxdiff) {
							maxdiff = diff;
							NewPen[i] = k;
						}
					}
				}
	  		}
	  		else { // standard ILBM
				AddMessage("Computing Colour Map");
				for (i = 0;
					(i < ilbm->ncolors);
					i++) {
					maxdiff = 0x7FFFFFFF;
					for (k = 0;
						  k < maxcol;
						  ++k) {
						t = (int)r1[i] - r[k];
						diff = t*t*2;
						t = (int)r1[i+256] - r[k+256];
						diff += (t*t*4);
						t = (int)r1[i+512] - r[k+512];
						diff += (t*t);
						if (diff < maxdiff) {
							maxdiff = diff;
							NewPen[i] = k;
						}
					}
				}
			}
		}
	}
  	arrayp = chunky;
	AddMessage("Remapping");
	SetMax(ilbm->Bmhd.h);
	// for each line
	for (j = 0;
		 j < ilbm->Bmhd.h;
		 ++j) {
		SetCur(j);
	  	// for each pixel depending on mode convert line to screen palette (like palette to screen)
		if (isHAM6) {
			// rgb = 0 at start of line
	  		rr = r1[0];
	  		gg = r1[256];
	  		bb = r1[512];
	   	for (i = 0;
		  		  i < ilbm->Bmhd.w;
	   		  ++i) {
	   		penno = *arrayp;
	   		if (!(penno & 0x30)) {	// Normal pen
		   		rr = r1[penno];
		   		gg = r1[penno+256];
	   			bb = r1[penno+512];
	   			*arrayp++ = NewPen[penno];
	   		}
	   		else {
		   		switch (penno & 0x30) {	// HAM selection
		   		case 0x10:
	   				bb = (penno&0xf)|((penno&0xf)<<4);
	   				break;
	   			case 0x20:
		   			rr = (penno&0xf)|((penno&0xf)<<4);
		   			break;
	   			case 0x30:
	   				gg = (penno&0xf)|((penno&0xf)<<4);
	   				break;
		   		}
					// Find closest color
					maxdiff = 0x7FFFFFFF;
					for (k = 0;
						  k < maxcol;
						  ++k) {
						t = (int)rr - r[k];
						diff = t*t*2;
						t = (int)gg - r[k+256];
						diff += (t*t*4);
						t = (int)bb - r[k+512];
						diff += (t*t);
						if (diff < maxdiff) {
							maxdiff = diff;
							index = k;
						}
					}
					*arrayp++ = index;
				}
			}
	  	}
	  	else {
	  		if (isHAM8) {
	  			// very similar to HAM6
				rr = r1[0];
				gg = r1[256];
				bb = r1[512];
		   	for (i = 0;
			  		  i < ilbm->Bmhd.w;
		   		  ++i) {
		   		penno = *arrayp;
		   		if (!(penno & 0xc0)) {	// Normal pen
			   		rr = r1[penno];
		   			gg = r1[penno+256];
	   				bb = r1[penno+512];
	   				*arrayp++ = NewPen[penno];
		   		}
		   		else {
			   		switch (penno & 0xc0) {	// HAM selection
			   		case 0x40:
			   			bb = (penno&0x3f)<<2;
	   					break;
	   				case 0x80:
	   					rr = (penno&0x3f)<<2;
	   					break;
			   		case 0xc0:
			   			gg = (penno&0x3f)<<2;
	   					break;
	   				}
						// Find closest color
						maxdiff = 0x7FFFFFFF;
						for (k = 0;
							  k < maxcol;
							  ++k) {
							t = (int)rr - r[k];
							diff = (t*t*2);
							t = (int)gg - r[k+256];
							diff += (t*t*4);
							t = (int)bb - r[k+512];
							diff += (t*t);
							if (diff < maxdiff) {
								maxdiff = diff;
								index = k;
							}
						}
						*arrayp++ = index;
					}
				}
	  		}
	  		else {	// EHB or standard
	  			// simple palette remap
		   	for (i = 0;
			  		  i < ilbm->Bmhd.w;
		   		  ++i) {
		   		penno = *arrayp;
					*arrayp++ = NewPen[penno];
				}
			}
   	}
	}
}

/*
 * ilbm  : ILBMInfo *
 * plane : EGS plane
 * r     : r,g,b palette
 * r1    : r,g,b image palette
 * chunky: Chunky data
 * modeid: set if ilbm==NULL
 * maxcol: set if ilbm==NULL
 */
static void
PaletteToEGS(struct MPImage *MPi,
				struct ILBMInfo *ilbm, UBYTE *plane,
							UBYTE *r,
							UBYTE *chunky,ULONG modeid,UWORD maxcol) {
	UWORD	i,j;			// loop counters
	LONG	penno;
	UBYTE	rr,gg,bb;
	UWORD EHB;
	BOOL isHAM6 = FALSE;
	BOOL isHAM8 = FALSE;
	BOOL isEHB = FALSE;
	struct DisplayInfo queryinfo;
	DisplayInfoHandle handle;
	UBYTE *arrayp,*planep;

	AddMessage("Palette to EGS");
	if (ilbm) {
		modeid = ilbm->camg;
	}
	// based on CAMG chunk determine special type of image
	if ((handle = FindDisplayInfo(modeid)) &&
		 (GetDisplayInfoData(handle,(UBYTE *)&queryinfo,sizeof(queryinfo),DTAG_DISP,NULL))) {
		// 8 plane HAM
		if (((ilbm && (ilbm->Bmhd.nPlanes == 8)) || (maxcol >= 64)) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
			isHAM8 = TRUE;
		}
		else {
			// 8 plane HAM
			if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >=16)) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
				isHAM6 = TRUE;
			}
			else {
				// 6 plane EHB
	  			if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >=32)) && (queryinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE)) {
	  				isEHB = TRUE;
	  			}
	  		}
		}
	}
	else {	// Unknown mode on this machine check somehow else
		if (((ilbm && (ilbm->Bmhd.nPlanes == 8)) || (maxcol >= 64)) && (modeid & HAM)) {
			isHAM8 = TRUE;
		}
		else {
			if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >= 16)) && (modeid & HAM)) {
				isHAM6 = TRUE;
			}
			else {
				if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >= 32)) && (modeid & EXTRA_HALFBRITE)) {
					isEHB = TRUE;
				}
			}
		}
	}
  	arrayp = chunky;
  	planep = plane;
	AddMessage("Remapping");
	SetMax(MPi->Height);
	// for each line
	for (j = 0;
		 j < MPi->Height;
		 ++j) {
		SetCur(j);
	  	// for each pixel depending on mode convert to EGS
		if (isHAM6) {
			// rgb = 0 at start of line
	  		rr = r[0];
	  		gg = r[256];
	  		bb = r[512];
	   	for (i = 0;
		  		  i < MPi->Width;
	   		  ++i) {
	   		penno = *arrayp;
	   		switch (penno & 0x30) {	// HAM selection
	   		case 0:
		   		rr = r[penno];
		   		gg = r[penno+256];
	   			bb = r[penno+512];
	   			break;
	   		case 0x10:
	   			bb = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		case 0x20:
	   			rr = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		case 0x30:
	   			gg = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		}
	   		*planep++ = rr;
	   		*planep++ = gg;
	   		*planep++ = bb;
	   		planep++;
	   		arrayp++;
			}
	  	}
	  	else {
	  		if (isHAM8) {
	  			// very similar to HAM6
				rr = r[0];
				gg = r[256];
				bb = r[512];
		   	for (i = 0;
			  		  i < MPi->Width;
		   		  ++i) {
		   		penno = *arrayp;
		   		switch (penno & 0xc0) {
		   		case 0:
			   		rr = r[penno];
		   			gg = r[penno+256];
	   				bb = r[penno+512];
	   				break;
		   		case 0x40:
		   			bb = (penno&0x3f)<<2;
	   				break;
	   			case 0x80:
	   				rr = (penno&0x3f)<<2;
	   				break;
		   		case 0xc0:
		   			gg = (penno&0x3f)<<2;
	   				break;
	   			}
		   		*planep++ = rr;
		   		*planep++ = gg;
	   			*planep++ = bb;
	   			planep++;
		   		arrayp++;
				}
	  		}
	  		else {
	  			if (isEHB) {
	  				// simple - just check highest plane and divide by two if required
			   	for (i = 0;
				  		  i < MPi->Width;
			   		  ++i) {
			   		penno = *arrayp;
			   		EHB = (penno & 0x20)?1:0;
			   		penno &= 0x1f;
			   		*planep++ = r[penno]>>EHB;
			   		*planep++ = r[penno+256]>>EHB;
			   		*planep++ = r[penno+512]>>EHB;
	   				planep++;
			   		arrayp++;
					}
		  		}
		  		else {
		  			// simple palette remap
			   	for (i = 0;
				  		  i < MPi->Width;
			   		  ++i) {
			   		penno = *arrayp;
			   		*planep++ = r[penno];
			   		*planep++ = r[penno+256];
			   		*planep++ = r[penno+512];
	   				planep++;
			   		arrayp++;
					}
				}
			}
   	}
		planep += (MPi->EGS_BitMap->BytesPerRow - (4*MPi->Width));
	}
}

/* Convert RGB input to Grey output
 *
 * output is stored in red.
 */
static void
RGBToGrey(UBYTE *red,UBYTE *green,UBYTE *blue,UWORD Height, UWORD Width, BOOL Linear) {
	UWORD i,j;
	UBYTE *r,*g,*b;
	AddMessage("RGB to Grey");
	r = red;
	g = green;
	b = blue;
  	SetMax(Height);
  	if (Linear) {
		// for each line
		for (j = 0;
			 j < Height;
			 ++j) {
			SetCur(j);
	  		// for each pixel convert to grey
	   	for (i = 0;
		  		  i < Width;
   			  ++i) {
   			*r = ((int)*r + (int)*g++ + (int)*b++)/3;
	   		++r;
	   	}
   	}
   }
   else {
		// for each line
		for (j = 0;
			 j < Height;
			 ++j) {
			SetCur(j);
	  		// for each pixel convert to grey
	   	for (i = 0;
		  		  i < Width;
   			  ++i) {
   			*r = ((77 * (int)*r) + (151 * (int)*g++) + (28 * (int)*b++))>>8;
	   		++r;
	   	}
   	}
   }
}

/* modeid
 *
 * returns TRUE if not a HAM mode
 *
*/
static BOOL
CheckNotHAM(ULONG modeid) {
	struct DisplayInfo queryinfo;
	DisplayInfoHandle handle;

	AddMessage("Checking if HAM");
	// based on CAMG chunk determine special type of image
	if ((handle = FindDisplayInfo(modeid)) &&
		 (GetDisplayInfoData(handle,(UBYTE *)&queryinfo,sizeof(queryinfo),DTAG_DISP,NULL))) {
		if (queryinfo.PropertyFlags & DIPF_IS_HAM) {
			return FALSE;
		}
	}
	else {	// unknown mode on this machine
		if (modeid & HAM) {
			return FALSE;
		}
	}
	return TRUE;
}

/*
 * ilbm  : ILBMInfo *
 * r     : r,g,b palette
 * red,green,blue: Chunky data
 * Chunky: Chunky buffer
 * modeid: set if ilbm==NULL
 * maxcol: set if ilbm==NULL
 */
static void
PaletteToRGB(struct MPImage *MPi,
				struct ILBMInfo *ilbm, UBYTE *red, UBYTE *green, UBYTE *blue,
							UBYTE *r,
							UBYTE *chunky,ULONG modeid,UWORD maxcol) {
	UWORD	i,j;			// loop counters
	LONG	penno;
	UBYTE	rr,gg,bb;
	UWORD EHB;
	BOOL isHAM6 = FALSE;
	BOOL isHAM8 = FALSE;
	BOOL isEHB = FALSE;
	struct DisplayInfo queryinfo;
	DisplayInfoHandle handle;
	UBYTE *arrayr,*arrayg,*arrayb,*arrayp;

	AddMessage("Palette to RGB");
	if (ilbm) {
		modeid = ilbm->camg;
	}
	// based on CAMG chunk determine special type of image
	if ((handle = FindDisplayInfo(modeid)) &&
		 (GetDisplayInfoData(handle,(UBYTE *)&queryinfo,sizeof(queryinfo),DTAG_DISP,NULL))) {
		// 8 plane HAM
		if (((ilbm && (ilbm->Bmhd.nPlanes == 8)) || (maxcol >= 64)) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
			isHAM8 = TRUE;
		}
		else {
			// 8 plane HAM
			if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >=16)) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
				isHAM6 = TRUE;
			}
			else {
				// 6 plane EHB
	  			if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >=32)) && (queryinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE)) {
	  				isEHB = TRUE;
	  			}
	  		}
		}
	}
	else {	// Unknown mode on this machine check somehow else
		if (((ilbm && (ilbm->Bmhd.nPlanes == 8)) || (maxcol >= 64)) && (modeid & HAM)) {
			isHAM8 = TRUE;
		}
		else {
			if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >= 16)) && (modeid & HAM)) {
				isHAM6 = TRUE;
			}
			else {
				if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >= 32)) && (modeid & EXTRA_HALFBRITE)) {
					isEHB = TRUE;
				}
			}
		}
	}
  	arrayr = red;
  	arrayg = green;
  	arrayb = blue;
  	arrayp = chunky;
  	SetMax(MPi->Height);
	// for each line
	for (j = 0;
		 j < MPi->Height;
		 ++j) {
		SetCur(j);
	  	// for each pixel depending on mode convert to RGB
		if (isHAM6) {
			// rgb = [0] at start of line
	  		rr = r[0];
	  		gg = r[256];
	  		bb = r[512];
	   	for (i = 0;
		  		  i < MPi->Width;
	   		  ++i) {
	   		penno = *arrayp;
	   		switch (penno & 0x30) {	// HAM selection
	   		case 0:
		   		rr = r[penno];
		   		gg = r[penno+256];
	   			bb = r[penno+512];
	   			break;
	   		case 0x10:
	   			bb = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		case 0x20:
	   			rr = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		case 0x30:
	   			gg = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		}
	   		*arrayr++ = rr;
	   		*arrayg++ = gg;
	   		*arrayb++ = bb;
	   		arrayp++;
			}
	  	}
	  	else {
	  		if (isHAM8) {
	  			// very similar to HAM6
				rr = r[0];
				gg = r[256];
				bb = r[512];
		   	for (i = 0;
			  		  i < MPi->Width;
		   		  ++i) {
		   		penno = *arrayp;
		   		switch (penno & 0xc0) {
		   		case 0:
			   		rr = r[penno];
		   			gg = r[penno+256];
	   				bb = r[penno+512];
	   				break;
		   		case 0x40:
		   			bb = (penno&0x3f)<<2;
	   				break;
	   			case 0x80:
	   				rr = (penno&0x3f)<<2;
	   				break;
		   		case 0xc0:
		   			gg = (penno&0x3f)<<2;
	   				break;
	   			}
		   		*arrayr++ = rr;
		   		*arrayg++ = gg;
	   			*arrayb++ = bb;
		   		arrayp++;
				}
	  		}
	  		else {
	  			if (isEHB) {
	  				// simple - just check highest plane and divide by two if required
			   	for (i = 0;
				  		  i < MPi->Width;
			   		  ++i) {
			   		penno = *arrayp;
			   		EHB = (penno & 0x20)?1:0;
			   		penno &= 0x1f;
			   		*arrayr++ = r[penno]>>EHB;
			   		*arrayg++ = r[penno+256]>>EHB;
			   		*arrayb++ = r[penno+512]>>EHB;
			   		arrayp++;
					}
		  		}
		  		else {
		  			// simple palette remap
			   	for (i = 0;
				  		  i < MPi->Width;
			   		  ++i) {
			   		penno = *arrayp;
			   		*arrayr++ = r[penno];
			   		*arrayg++ = r[penno+256];
			   		*arrayb++ = r[penno+512];
			   		arrayp++;
					}
				}
			}
   	}
	}
}

/*
 * ilbm  : ILBMInfo *
 * r     : r,g,b palette
 * Chunky: Chunky buffer
 * modeid: set if ilbm==NULL
 * maxcol: set if ilbm==NULL
 */
static void
PaletteRGBToGrey(struct MPImage *MPi,
				struct ILBMInfo *ilbm,
							UBYTE *r,
							UBYTE *chunky,ULONG modeid,UWORD maxcol,BOOL Linear) {
	UWORD	i,j;			// loop counters
	LONG	penno;
	UBYTE	rr,gg,bb;
	UWORD EHB;
	BOOL isHAM6 = FALSE;
	BOOL isHAM8 = FALSE;
	BOOL isEHB = FALSE;
	struct DisplayInfo queryinfo;
	DisplayInfoHandle handle;
	UBYTE *arrayp;

	AddMessage("Palette to RGB");
	if (ilbm) {
		modeid = ilbm->camg;
	}
	// based on CAMG chunk determine special type of image
	if ((handle = FindDisplayInfo(modeid)) &&
		 (GetDisplayInfoData(handle,(UBYTE *)&queryinfo,sizeof(queryinfo),DTAG_DISP,NULL))) {
		// 8 plane HAM
		if (((ilbm && (ilbm->Bmhd.nPlanes == 8)) || (maxcol >= 64)) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
			isHAM8 = TRUE;
		}
		else {
			// 8 plane HAM
			if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >=16)) && (queryinfo.PropertyFlags & DIPF_IS_HAM)) {
				isHAM6 = TRUE;
			}
			else {
				// 6 plane EHB
	  			if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >=32)) && (queryinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE)) {
	  				isEHB = TRUE;
	  			}
	  		}
		}
	}
	else {	// Unknown mode on this machine check somehow else
		if (((ilbm && (ilbm->Bmhd.nPlanes == 8)) || (maxcol >= 64)) && (modeid & HAM)) {
			isHAM8 = TRUE;
		}
		else {
			if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >= 16)) && (modeid & HAM)) {
				isHAM6 = TRUE;
			}
			else {
				if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >= 32)) && (modeid & EXTRA_HALFBRITE)) {
					isEHB = TRUE;
				}
			}
		}
	}
  	arrayp = chunky;
  	SetMax(MPi->Height);
	// for each line
	for (j = 0;
		 j < MPi->Height;
		 ++j) {
		SetCur(j);
	  	// for each pixel depending on mode convert to RGB
		if (isHAM6) {
			// rgb = [0] at start of line
	  		rr = r[0];
	  		gg = r[256];
	  		bb = r[512];
	   	for (i = 0;
		  		  i < MPi->Width;
	   		  ++i) {
	   		penno = *arrayp;
	   		switch (penno & 0x30) {	// HAM selection
	   		case 0:
		   		rr = r[penno];
		   		gg = r[penno+256];
	   			bb = r[penno+512];
	   			break;
	   		case 0x10:
	   			bb = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		case 0x20:
	   			rr = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		case 0x30:
	   			gg = (penno&0xf)|((penno&0xf)<<4);
	   			break;
	   		}
	   		if (Linear) {
		   		*arrayp++ = ((int)rr + (int)gg + (int)bb)/3;
		   	}
		   	else {
		   		*arrayp++ = ((77 * (int)rr) + (151 * (int)gg) + (28 * (int)bb))>>8;
		   	}
			}
	  	}
	  	else {
	  		if (isHAM8) {
	  			// very similar to HAM6
				rr = r[0];
				gg = r[256];
				bb = r[512];
		   	for (i = 0;
			  		  i < MPi->Width;
		   		  ++i) {
		   		penno = *arrayp;
		   		switch (penno & 0xc0) {
		   		case 0:
			   		rr = r[penno];
		   			gg = r[penno+256];
	   				bb = r[penno+512];
	   				break;
		   		case 0x40:
		   			bb = (penno&0x3f)<<2;
	   				break;
	   			case 0x80:
	   				rr = (penno&0x3f)<<2;
	   				break;
		   		case 0xc0:
		   			gg = (penno&0x3f)<<2;
	   				break;
	   			}
	   			if (Linear) {
			   		*arrayp++ = ((int)rr + (int)gg + (int)bb)/3;
			   	}
			   	else {
			   		*arrayp++ = ((77 * (int)rr) + (151 * (int)gg) + (28 * (int)bb))>>8;
			   	}
				}
	  		}
	  		else {
	  			if (isEHB) {
	  				// simple - just check highest plane and divide by two if required
			   	for (i = 0;
				  		  i < MPi->Width;
			   		  ++i) {
			   		penno = *arrayp;
			   		EHB = (penno & 0x20)?1:0;
			   		penno &= 0x1f;
			   		if (Linear) {
				   		*arrayp++ = ((int)(r[penno]>>EHB) + (int)(r[penno+256]>>EHB) + (int)(r[penno+512]>>EHB))/3;
				   	}
				   	else {
				   		*arrayp++ = ((77 * (int)(r[penno]>>EHB)) + (151 * (int)(r[penno+256]>>EHB)) + (28 * (int)(r[penno+512]>>EHB)))>>8;
				   	}
					}
		  		}
		  		else {
		  			// simple palette remap
		  			if (Linear) {
				   	for (i = 0;
					  		  i < MPi->Width;
				   		  ++i) {
				   		penno = *arrayp;
				   		*arrayp++ = ((int)r[penno] + (int)r[penno+256] + (int)r[penno+512])/3;
				   	}
					}
					else {
				   	for (i = 0;
					  		  i < MPi->Width;
				   		  ++i) {
				   		penno = *arrayp;
				   		*arrayp++ = ((77 * (int)r[penno]) + (151 * (int)r[penno+256]) + (28 * (int)r[penno+512]))>>8;
				   	}
					}
				}
			}
   	}
	}
}

static void
PaletteToGrey(struct MPImage *MPi,
				struct ILBMInfo *ilbm, UBYTE *red,
							UBYTE *r,
							UBYTE *chunky,ULONG modeid,UWORD maxcol) {
	UWORD	i,j;			// loop counters
	LONG	penno;
	UWORD EHB;
	BOOL isEHB = FALSE;
	struct DisplayInfo queryinfo;
	DisplayInfoHandle handle;
	UBYTE *arrayr,*arrayp;

	AddMessage("Palette to Grey");
	if (ilbm) {
		modeid = ilbm->camg;
	}
	// based on CAMG chunk determine special type of image
	if ((handle = FindDisplayInfo(modeid)) &&
		 (GetDisplayInfoData(handle,(UBYTE *)&queryinfo,sizeof(queryinfo),DTAG_DISP,NULL))) {
		// 6 plane EHB
  		if (((ilbm && (ilbm->Bmhd.nPlanes == 6)) || (maxcol >= 32)) &&
  			 (queryinfo.PropertyFlags & DIPF_IS_EXTRAHALFBRITE)) {
  			isEHB = TRUE;
  		}
  		else {
  			// standard ILBM
		}
	}
	else {
		if (modeid & EXTRA_HALFBRITE) {
			isEHB = TRUE;
		}
	}
  	arrayr = red;
  	arrayp = chunky;
  	SetMax(MPi->Height);
	// for each line
	for (j = 0;
		 j < MPi->Height;
		 ++j) {
		SetCur(j);
	  	// for each pixel depending on mode convert to Grey
		if (isEHB) {
			// simple - just check highest plane and divide by two if required
	   	for (i = 0;
	  		  i < MPi->Width;
   		  ++i) {
	   		penno = *arrayp;
	   		EHB = (penno & 0x20)?1:0;
	   		penno &= 0x1f;
	   		*arrayr++ = r[penno]>>EHB;
	   		arrayp++;
			}
  		}
  		else {
  			// simple palette remap
	   	for (i = 0;
		  		  i < MPi->Width;
	   		  ++i) {
	   		penno = *arrayp;
	   		*arrayr++ = r[penno];
	   		arrayp++;
			}
   	}
	}
}
