/**********************************************************/
/* Copyright   ©1999 Wolf-Juergen Faust                   */
/* Am Dorfgarten 10                                       */
/* 60435 Frankfurt      EXAMPLE2.c                        */
/* Germany                                                */
/* Tel: +(49) 69 5486556                                  */
/* Fax: +(49) 69 95409598                                 */
/* email: wfaust@stud.uni-frankfurt.de                    */
/*                                                        */
/*                                                        */
/* This piece of source code is part of the current       */
/* ICSConvert version and shows how to call ICS.          */
/* See the included comments and ICS.doc for more         */
/* info when adding ICS support to your software          */
/*                                                        */
/* Unlike Example.c this file corrects multiple pixels    */
/* with a single call to TranslateColors().               */
/*                                                        */
/**********************************************************/

#include	<proto/ics.h>

struct Library *ICSBase=NULL;

/*** VARS ***/

UWORD LoadPic(struct Window *, UBYTE *inputfile, UBYTE *outputfile, BOOL nosetup, BOOL nostatus, BOOL nocolor, PSTR prefsfile);
UWORD LoadPic(struct Window *win2, UBYTE *inputfile, UBYTE *outputfile, BOOL nosetup, BOOL nostatus, BOOL nocolor, PSTR prefsfile)
#endif

/*** MAIN ***/
{
	UWORD ret = 1;

	UWORD wi;
	ULONG x,y, li;
	ULONG size;
	struct IFFHandle *iffhandle;
	UBYTE *temp;
	static void *idc=NULL;
	static void *idctrans=NULL;
	UBYTE *r,*g,*b;
	LONG ifferr;
	struct MyHandle *ilbm;
	struct URGBCOLOR *rgb;
	struct UGRAYCOLOR *gray;
	void *linebuffer;
	COLORTYPE savemode;

	if(!inputfile) // signal we want to free all allocated handles?
	{
		if(idctrans)
		{
			DeleteIDCTransform(idctrans);
			idctrans = NULL;
		}
		if(idc)
		{
			DeleteIDC(idc);
			idc = NULL;
		}
		return(0);
	}
	if(!idc) // create a device context if not already present (idc is 
	{
		if(!(idc = CreateIDC(                // create ICS device context object
			ICS_APPNAME, PRGMNAME,           // name of this application
			ICS_APPNAMEVERSION, NUMVERSION,  // version of this application
			ICS_APPICSVERSION, 2,            // version of ICS library this application was made for/with
			ICS_PREFSFILE, prefsfile,
			TAG_DONE)))
		{
			ErrMes(win2, MSG_ICSERR_NOCONTEXT); // Error: Can't create device context using ics.library\n      Maybe not enough memory?
			return(0);
		}
	}
	if(!nosetup) // Does calling function want a setup?
	{
		if(idctrans) // delete any old transformation before new setup.
		{
			DeleteIDCTransform(idctrans);
			idctrans = NULL;
		}
		if(SetupIDCColorMatching(idc, dscreen, TAG_DONE)<=1)  // display ICS preference window. Note: ICSConvert currently does not offer any GUI. So I abort if the user selects cancel...   - returns 0=err, 1=user cancel
		{
			temp = ICSFault(idc, MyGetString(MSG_ICSERR_MSGHEADER)); // Error while running ICSConvert.
			if(!temp) temp = MyGetString(MSG_ICSERR_NOPREFS); // "Error: Can't open ICS preferences.";
			if(ICSErr(idc)>ICS_ERRMSGLIMIT) Mes(temp, win2);
			return(0);
		}
	}
	if(idctrans) ICSStatusWin(idctrans, ICS_StatusText,  MyGetString(MSG_ICSSTATUS_OPENSRCFILE), TAG_DONE);  // change title and text of status window created by ICS library during CreateIDCTransform(): "Opening image file..."
	sprintf(tempstr, PRGMNAME": %s", FilePart(inputfile)); // Generate window title of ICS status window
	if(strlen(tempstr) > 35) sprintf(tempstr, "ICS: %s", FilePart(inputfile));
	if(strlen(tempstr) > 35) stccpy(tempstr, MyGetString(MSG_ICSSTATUS_TITLE), 35);
	if(!idctrans) // Is there a transformation function available from a previous call - if not, make one now
	{
		if(!(idctrans = CreateIDCTransform(idc,
			ICS_TransferDevices, ICS_INPUT_DEVICE,        // We want to convert from input to display device (not printer device)
			((nostatus) ? TAG_DONE: ICS_StatusOpen), dscreen,                      // Screen to use for status window or NULL for default public screen
			ICS_StatusTitle, tempstr, //  Overwrite status window title with our own: "ICS Image Conversion"
			//ICS_StatusActivate, TRUE,                     // Activate status window
			ICS_StatusKeep, TRUE,                         // keep status window open as we use the ics status window during conversion of image data later
			// ICS_StatusDisableAbort, TRUE,                 // use this to disable Abort/Stop button
			TAG_DONE))) // create input (scanner) to device (display/monitor) color corretion and show status window while processing.. leave status window open for user below...
		{
			temp = ICSFault(idc, MyGetString(MSG_ICSERR_MSGHEADER)); // Error while running ICSConvert.
			if(!temp) temp = MyGetString(MSG_ICSERR_CREATETRANSFORM); // Error: Can't create color transformation using ics.library.
			if(ICSErr(idc)>ICS_ERRMSGLIMIT) Mes(temp, win2);
			return(0);
		}
	} else
	{
		ICSStatusWin(idctrans, ICS_StatusTitle, tempstr, ICS_StatusText,  MyGetString(MSG_ICSSTATUS_OPENSRCFILE), TAG_DONE);  // change status window for new file
	}
	if(ret)
	{
		if(ICSStatusWin(idctrans, ICS_StatusCheck,  0, TAG_DONE))
		{
			ret = 0;
		}
	}
	if(ilbm = (struct MyHandle *) AllocVec(sizeof(struct MyHandle), MEMF_PUBLIC|MEMF_CLEAR))
	{
		stccpy(ilbm->prtfile, inputfile, PATH);
		stccpy(ilbm->savefile, outputfile, PATH);

		if(insema = (struct SignalSemaphore *) AllocVec(sizeof(struct SignalSemaphore),MEMF_PUBLIC|MEMF_CLEAR)) // Semaphore used by the image reading routine GetMain()
		{
			InitSemaphore(insema);

			if(ret)
			{
				ilbm->memory = 2;    // Reading routine may use more memory...
				ilbm->landscape=0;   // No landscape rotation wanted of input
				if (GetMain(ilbm, POPEN, win2, 0))  // open source image file for conversion
				{
					ilbm->savemode = ilbm->destmode; // set var indicating the output file type: 1=gray 0=color depending on input ("destmode" is the input file mode),
					if(nocolor) ilbm->savemode = 1;  // user asked for grayscale only output?
					if (GetMain(ilbm, PREADINIT, win2, 0))  // init read routines for file
					{
						size = ilbm->wssize * ( (ilbm->destmode)  ? sizeof(struct UGRAYCOLOR) : sizeof(struct URGBCOLOR) );
						if(linebuffer = AllocVec(size, MEMF_CLEAR))
						{
							ICSStatusWin(idctrans, ICS_StatusText,  MyGetString(MSG_ICSSTATUS_OPENDESTFILE), TAG_DONE);  // "Opening destination file"
							if(iffhandle = OPENMYFILE(ilbm, win2)) // open destination image file for color corrected image
							{
								if(ifferr = PushChunk(iffhandle,ID_ILBM,ID_BODY,IFFSIZE_UNKNOWN)) // Start writing the main body of destination image file
								{
									ErrMes(win2, MSG_IFFERR_WRITECHUNK, ifferr, "BODY", ( (strlen(ilbm->savefile)>60) ? FilePart(ilbm->savefile) : ilbm->savefile )); // Error (Type %ld): Can't write '%s' chunk of\ndestination file: '%s'.
									ret = 0;
								} else
								{
									if (SetSignal(0,0) & SIGBREAKF_CTRL_C) ret=0; // check if user aborted ICSConvert...
									for(ret=1,y=0; (ret) && (y<ilbm->hssize); y++)  // loop for number of lines in image
									{
										// Display progress status and check for user abort...
										sprintf(tempstr, MyGetString(MSG_ICSSTATUS_COMPLETE), (y*100)/ilbm->hssize); // Converting Image  -  %ld%% complete
										 // change status text and update progress bar. Also check if user wants to abort...
										if(ICSStatusWin(idctrans, ICS_StatusText,  tempstr, ICS_StatusProgress, (y*100)/ilbm->hssize, ICS_StatusCheck,  0, TAG_DONE))
										{
											ret = 0;
											break;
										}
										// read a single image line into buffer.
										if(temp = (UBYTE *)GetMain(ilbm, PREADLINE, win2, y))
										{
											if(ilbm->destmode) // is source a grayscale image?  Note: white=255  gray=0
											{
												for(x=0, gray=linebuffer; (ret) && (x<ilbm->wssize); x++, gray++)  // loop for number of pixels in line
												{
													gray->gray = (temp[x]<<8) | temp[x];  // convert 8 bit to 16 bit unsigned graylevel. IMPORTANT: Black=0   White=65535
												}
												if(!(TranslateColors(idctrans, linebuffer, ilbm->wssize, COLOR_UGRAY, linebuffer, COLOR_UGRAY)))
												{
													temp = ICSFault(idc, MyGetString(MSG_ICSERR_CONVERT)); // Error while converting color using ICS.
													if(!temp) temp = MyGetString(MSG_ICSERR_CONVERT);
													if(ICSErr(idc)>ICS_ERRMSGLIMIT) Mes(temp, win2);
													ret = 0;
													break;
												}
												r = temp;
												for(x=0, gray=linebuffer; (ret) && (x<ilbm->wssize); x++, gray++)  // loop for number of pixels in line
												{
													*r++ = gray->gray >> 8;
												}
											} else
											{
												r = temp;
												g = r + ilbm->wssize;
												b = g + ilbm->wssize;
	
												for(x=0, rgb=linebuffer; (ret) && (x<ilbm->wssize); x++, rgb++)  // loop for number of pixels in line
												{
													rgb->red   = (r[x]<<8) | r[x];  // convert 8 bit to 16 bit unsigned RGB color
													rgb->green = (g[x]<<8) | g[x];
													rgb->blue  = (b[x]<<8) | b[x];
												}
												savemode = ((ilbm->savemode) ? COLOR_UGRAY : COLOR_URGB); // note: linebuffer is used as input and output but input maybe URGB while output is UGRAY. This only works because UGRAY is smaller than URGB.
												if(!(TranslateColors(idctrans, linebuffer, ilbm->wssize, COLOR_URGB, linebuffer, savemode)))
												{
													temp = ICSFault(idc, MyGetString(MSG_ICSERR_CONVERT)); // Error while converting color using ICS.
													if(!temp) temp = MyGetString(MSG_ICSERR_CONVERT);
													if(ICSErr(idc)>ICS_ERRMSGLIMIT) Mes(temp, win2);
													ret = 0;
													break;
												}
												if(ilbm->savemode) // is the output gray or color?
												{
													r = temp;
													for(x=0, gray=linebuffer; (ret) && (x<ilbm->wssize); x++, gray++)  // loop for number of pixels in line
													{
														*r++ = gray->gray >> 8;
													}
												} else
												{
													r = temp;
													g = r + ilbm->wssize;
													b = g + ilbm->wssize;
													for(x=0, rgb=linebuffer; (ret) && (x<ilbm->wssize); x++, rgb++)  // loop for number of pixels in line
													{
														*r++ = rgb->red >> 8;      // Convert 16 to 8 Bit - Correct would be to devide by 65535/255=257 and not 256... but we ignore the invisible fault introduced...
														*g++ = rgb->green >> 8;
														*b++ = rgb->blue >> 8;
														//KPrintF("x %ld  %ld %ld %ld\n",r[x],g[x],b[x]);
													}
												}
											}
											if(!(WRITEMYLINE(ilbm, win2, iffhandle, temp)))
											{
												ret = 0;
												break;
											}
										} else
										{
											ret = 0;
											break;
										}
										if (SetSignal(0,0) & SIGBREAKF_CTRL_C) ret=0;
									}
									if(ret)
									{
										if(ifferr = PopChunk(iffhandle))
										{
											ErrMes(win2, MSG_IFFERR_WRITECHUNK, ifferr, "BODY", ( (strlen(ilbm->savefile)>60) ? FilePart(ilbm->savefile) : ilbm->savefile )); // Error (Type %ld): Can't write '%s' chunk of\ndestination file: '%s'.
											ret = 0;
										}
									}
								}
								ICSStatusWin(idctrans, ICS_StatusText,  MyGetString(MSG_ICSSTATUS_CLOSING), TAG_DONE);  // Closing source and destination file
								CLOSEMYFILE(iffhandle);
								if( (!ret) && (iffhandle) ) // Delete written file after error
								{
									DeleteFile(ilbm->savefile);
								}
							}
							FreeVec(linebuffer);
						} else
						{
							ErrMes(NULL, MSG_ERR_MEMORY, size); // Not enough free memory.\nFailed to get %ld bytes.
						}
						GetMain(ilbm, PREADEND, win2, 0);
					} else
					{
						ret = 0;
					}
					GetMain(ilbm, PCLOSE, win2, 0);
					ICSStatusWin(idctrans, ICS_StatusText,  MyGetString(MSG_ICSSTATUS_FINISH), TAG_DONE);  // Finished processing of file
				} else
				{
					ret = 0;
				}
			}
			FreeVec(insema);
		} else
		{
			ErrMes(win2, MSG_ERR_MEMORY, sizeof(struct SignalSemaphore)); // Not enough free memory.\nFailed to get %ld bytes.
			ret = 0;
		}
		FreeVec(ilbm);
	} else
	{
		ErrMes(NULL, MSG_ERR_MEMORY, sizeof(struct MyHandle)); // Not enough free memory.\nFailed to get %ld bytes.
	}
	return(ret);
}
