/******************************************************************************
 * program:     rasimg library                                                *
 * function:    Library for saving/loading pictures                           *
 * modul:       ras_img.cc                                                    *
 * licency:     GPL or LGPL                                                   *
 ******************************************************************************/
#include <stddef.h>
#include <stdio.h>

#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#if defined(_MSC_VER) || defined(__CYGWIN32__) || defined(__APPLE__)
 #define MAXLONG     0x7FFFFFFF
#else
 #include <values.h>
#endif
#ifndef M_PI
 #define M_PI        3.14159265358979323846
#endif
#include <time.h>

#include "types.h"
#include "common.h"
#include "raster.h"
#include "ras_prot.h"

#ifndef __UNIX__
 #include <io.h>
#endif

#include "matrix.h"

//Support flags 0 undefined - no support
//		1 typedefs only
//		2 load format only
//		3 save format only
//	      >=4 both load and save
// These support flags could be predefined externally.

#ifndef SupportART
  #define SupportART  10
#endif
#ifndef SupportBMP
  #define SupportBMP  10
#endif
#ifndef SupportCSV
  #define SupportCSV  10
#endif
#ifndef SupportCUT
  #define SupportCUT  10
#endif
#ifndef SupportEPS
  #define SupportEPS  10
#endif
#ifndef SupportFITS
  #define SupportFITS 10
#endif
#ifndef SupportGIF
  #define SupportGIF  10
#endif
#ifndef SupportHRZ
  #define SupportHRZ  2
#endif
#ifndef SupportICO
  #define SupportICO  10
#endif
#ifndef SupportMAC
  #define SupportMAC  2
#endif
#ifndef SupportMAT
  #define SupportMAT  10
#endif
#ifndef SupportOKO
  #define SupportOKO  10
#endif
#ifndef SupportPBM
  #define SupportPBM  2
#endif
#ifndef SupportPCX
  #define SupportPCX  10
#endif
#ifndef SupportRAS
  #define SupportRAS  10
#endif
#ifndef SupportRAS_SUN
  #define SupportRAS_SUN  10
#endif
#ifndef SupportRAW
  #define SupportRAW  10
#endif
#ifndef SupportTGA
  #define SupportTGA 10
#endif
#ifndef SupportTIFF
  #define SupportTIFF 10
#endif
#ifndef SupportTXT
  #define SupportTXT 10
#endif
#ifndef SupportTXTgm
  #define SupportTXTgm 10
#endif
#ifndef SupportWMF
  #define SupportWMF  2
#endif
#ifndef SupportWPG
  #define SupportWPG  10
#endif


#define Rd_word(f,w) RdWORD_LoEnd(w,f);
#define Rd_dword(f,d) RdDWORD_LoEnd(d,f);
#define Wr_word(f,w) WrWORD_LoEnd(w,f);
#define Wr_dword(f,d) WrDWORD_LoEnd(d,f);

#ifndef SEEK_SET
 #define SEEK_SET 0
#endif

#ifndef __Have_stricmp
 #ifdef __Have_strcasecmp
  #define stricmp strcasecmp
 #endif
 #ifndef stricmp        //already fixed?
  #define stricmp strcmp
 #endif
#endif

extern "C" {
int loadstruct(FILE *F,const char *description, ...);

int savestruct(FILE *F,const char *description, ...);

int RdWORD_LoEnd( WORD *num, FILE *f );
int RdDWORD_LoEnd( DWORD *num, FILE *f );
int RdWORD_HiEnd( WORD *num, FILE *f );
int RdDWORD_HiEnd( DWORD *num, FILE *f );

int WrWORD_LoEnd( WORD num, FILE *f );
int WrDWORD_LoEnd( DWORD num, FILE *f );
int WrWORD_HiEnd( WORD num, FILE *f );
int WrDWORD_HiEnd( DWORD num, FILE *f );
}

const char *UnitName="Rasters";

#ifndef false
 #define  false          0
#endif
#ifndef true
 #define  true           1
#endif


#ifdef _MSC_VER  
  #pragma warning(disable: 4244)
#endif


static void RGB_BGR(char *Data,int size)
{
char c;
while(size-->0)
	{
	c=Data[2];
	Data[2]=*Data;
	*Data=c;
	Data+=3;
	}
}

static void NotR(char *R, int size)	//R1:=not(R1)
{
  while(size-->0)
    {
    *R = ~*R;
    R++;
    }
}


#if FileSize==1
 #undef FileSize
#endif

#ifndef FileSize
static long FileSize(FILE *f)
{
#ifdef __UNIX__
  long pos,len;
  if((pos=ftell(f))<0) return(0);
  fseek(f,0,SEEK_END);
  len=ftell(f);
  fseek(f,pos,SEEK_SET);
  return(len);
#else
  return(filelength(fileno(f)));
#endif
}
#endif


/** This function reads integer value from a file stream. */
static long ReadInt(FILE *F, char *pch=NULL)
{
char ch;
long n;

  n=0;
  if(pch) ch=*pch;
     else ch=' ';

  while(isspace(ch)||ch==0)
     {
     ch=fgetc(F);
     if(feof(F)) return(0);
     }

  while(isdigit(ch))
	{
	n=10*n+(ch-'0');
	ch=fgetc(F);
	if(feof(F)) return(n);
	}

 if(pch) *pch=ch;
     else ungetc(ch,F);

return(n);
}


static double ReadDouble(FILE *F, char *pch=NULL)
{
  int i;
  char ch, arr[32];

  i = 0;

  if(pch!=NULL)
    {
    ch = arr[0] = *pch;
    i++;
    }


  while(i<(sizeof(arr)-1) && !feof(F))
  {
    ch = fgetc(F);
    if(isdigit(ch) || ch=='.' || ch=='e' || ch=='E' || ch=='+' || ch=='-')
    {
      arr[i] = ch;
      i++;
      continue;
    }
    break;
  }

 if(pch) *pch=ch;
     else ungetc(ch,F);

 if(i>0)
 {
   arr[i] = 0;
   return atof(arr);
 } 
 return 0;
}


/** Reads one textual word from file. */
static void ReadWord(FILE *F, char *data, int SizeLimit, char *pch=NULL)
{
unsigned char ch;
long n;

  if(data==NULL) return;
  n=0;
  if(pch) ch=*pch;
     else ch=' ';

  while(isspace(ch) || ch==0)
     {
     ch=fgetc(F);
     if(feof(F)) goto EndOfFile;
     }

  while(!isspace(ch))
	{
	if(n>=SizeLimit) break;
	data[n]=ch;
	n++;
	ch=fgetc(F);
	if(feof(F)) break;
	}

  if(pch) *pch=ch;
    else ungetc(ch,F);

EndOfFile:
  if(n<SizeLimit) data[n]=0;
return;
}


/** Reads up to end of line. */
static void readln(FILE *f, char *pch=NULL)
{
char ch=0;
  if(pch) ch=*pch;
     else ch=' ';
  while(ch!=10 && ch!=13 && !feof(f))
    {
    ch=fgetc(f);
    }
  if(pch) *pch=ch;
}


//------------------ART--------------------------
#ifdef SupportART

#if SupportART>=4 || SupportART==2
Image LoadPictureART(const char *Name)
{
FILE  *f;
WORD ldblk;
WORD k,width,height;
WORD i;
long dummy;
Raster2DAbstract *Raster=NULL;
Image Img;

 if((f=fopen(Name,"rb"))==NULL) return(Img);

 RdWORD_LoEnd(&k,f);
 RdWORD_LoEnd(&width,f);
 RdWORD_LoEnd(&k,f);
 RdWORD_LoEnd(&height,f);

 ldblk = (width+7)/8;
 k = (-ldblk) & 1;

 if(FileSize(f)!=8+((long)ldblk+k)*height)
	{
	goto ENDPROC;
	}
 Raster = CreateRaster2D(width,height,1);
 if(Raster==NULL) goto ENDPROC;
// if AlineProc<>nil then AlineProc^.InitPassing(p.y,'Loading ART');

 for(i=0;i<Raster->Size2D;i++)
	{
	if(fread(Raster->GetRow(i),ldblk,1,f)!=1) {goto ENDPROC;}

	fread(&dummy,k,1,f);			//read till end of line
 //	AlineProc(i,p);
	}


ENDPROC:
 fclose(f);
 Img.AttachRaster(Raster); 
 return(Img);
}

#endif


#if SupportART>=3

int SavePictureART(const char *Name,const Image &Img)
{
FILE *f;
WORD ldblk;
WORD i,dummy;
char k;
Raster1D_1Bit TempData;
//    Formater:PFormStruct;

  if(Img.Raster==NULL) return(-10);

  if((f=fopen(Name,"wb"))==NULL) return(-1);

  WrWORD_LoEnd(0,f);
  WrWORD_LoEnd(Img.Raster->GetSize1D(),f);
  WrWORD_LoEnd(0,f);
  WrWORD_LoEnd(Img.Raster->Size2D,f);

  ldblk = (Img.Raster->GetSize1D()+7)/8;
  k = (-ldblk) & 1;

  if(Img.Raster->GetPlanes()!=1)
    {
    TempData.Allocate1D(Img.Raster->GetSize1D());
    }

  for(i=0;i<Img.Raster->Size2D;i++)
	{
	if(TempData.Data1D)
	  {
	  TempData.Set(*Img.Raster->GetRowRaster(i));
	  fwrite(TempData.Data1D,ldblk,1,f);
	  }
	else
	  fwrite(Img.Raster->GetRow(i),ldblk,1,f);
	fwrite(&dummy,k,1,f);			//write till end of line
	// if AlineProc<>nil then AlineProc^.NextLine;
	}

  if(TempData.Data1D) TempData.Erase();
  fclose(f);
  return(0);
}
#endif


TImageFileHandler ART_H(".ART",
#if SupportART>=4 || SupportART==2
	LoadPictureART,
#else
	NULL,
#endif
#if SupportART>=3
	SavePictureART);
#else
	NULL);
#endif


#endif
//-------------------End of ART routines------------------


//--------------------------BMP---------------------------
#ifdef SupportBMP

typedef enum
{
  BI_RGB = 0,	//An uncompressed format.
  BI_RLE8,	//A run-length encoded (RLE) format for bitmaps with 8 bpp. 
		//The compression format is a 2-byte format consisting of a count byte followed by a byte containing a color index.
  BI_RLE4,	//An RLE format for bitmaps with 4 bpp. The compression format is a 2-byte format consisting of a count byte followed by two word-length color indexes.
  BI_BITFIELDS, //Specifies that the bitmap is not compressed. The members bV4RedMask, bV4GreenMask, and bV4BlueMask specify the red, green, and blue components for each pixel. This is valid when used with 16- and 32-bpp bitmaps.
  BI_JPEG,	//Specifies that the image is compressed using the JPEG file interchange format. JPEG compression trades off compression against loss.
  BI_PNG	//Specifies that the image is compressed using the PNG file interchange format.
} BmpCompression;

typedef SDWORD FXPT2DOT30;

typedef struct {
  FXPT2DOT30 ciexyzX;
  FXPT2DOT30 ciexyzY;
  FXPT2DOT30 ciexyzZ;
} CIEXYZ;

typedef struct
{
  CIEXYZ ciexyzRed;
  CIEXYZ ciexyzGreen;
  CIEXYZ ciexyzBlue;
} CIEXYZTRIPLE;

typedef struct
	{
	BYTE    bfType[2]	PACKED;
	DWORD   bfSize		PACKED;
	WORD    bfReserved1	PACKED;
	WORD    bfReserved2	PACKED;
	DWORD   bfOffBits	PACKED;
	} BMPHeader;

struct	BitmapInfoHeader
	{
	DWORD  biSize		PACKED;
	DWORD  biWidth		PACKED;
	DWORD  biHeight		PACKED;
	WORD   biPlanes		PACKED;
	WORD   biBitCount	PACKED;
	DWORD  biCompression	PACKED;
	DWORD  biSizeImage	PACKED;
	SDWORD biXPelsPerMeter	PACKED;
	SDWORD biYPelsPerMeter	PACKED;
	DWORD  biClrUsed	PACKED;
	DWORD  biClrImportant	PACKED;
	};
typedef struct
	{
	DWORD	bV4Size;
	SDWORD	bV4Width;
	SDWORD	bV4Height;
	WORD	bV4Planes;
	WORD	bV4BitCount;
	DWORD	bV4V4Compression;
	DWORD	bV4SizeImage;
	SDWORD	bV4XPelsPerMeter;
	SDWORD	bV4YPelsPerMeter;
	DWORD	bV4ClrUsed;
	DWORD	bV4ClrImportant;   // <-- same as BitmapInfoHeader to this point.
	DWORD	bV4RedMask;
	DWORD	bV4GreenMask;
	DWORD	bV4BlueMask;
	DWORD	bV4AlphaMask;
	DWORD	bV4CSType;
	CIEXYZTRIPLE bV4Endpoints;
	DWORD	bV4GammaRed;
	DWORD	bV4GammaGreen;
	DWORD	bV4GammaBlue;
} BitmapV4Header;

typedef struct BitmapV5Header
{
	DWORD	bV5Size;
	SDWORD	bV5Width;
	SDWORD  bV5Height;
	WORD	bV5Planes;
	WORD	bV5BitCount;
	DWORD	bV5Compression;
	DWORD	bV5SizeImage;
	SDWORD	bV5XPelsPerMeter;
	SDWORD	bV5YPelsPerMeter;
	DWORD	bV5ClrUsed;
	DWORD	bV5ClrImportant;
	DWORD	bV5RedMask;
	DWORD	bV5GreenMask;
	DWORD	bV5BlueMask;
	DWORD	bV5AlphaMask;
	DWORD	bV5CSType;
	CIEXYZTRIPLE bV5Endpoints;
	DWORD	bV5GammaRed;
	DWORD	bV5GammaGreen;
	DWORD	bV5GammaBlue;
	DWORD	bV5Intent;
	DWORD	bV5ProfileData;
	DWORD	bV5ProfileSize;
	DWORD	bV5Reserved;
} BitmapV5Header;

typedef struct
	{
	DWORD bcSize		PACKED;
	WORD  bcWidth		PACKED;
	WORD  bcHeight		PACKED;
	WORD  bcPlanes		PACKED;
	WORD  bcBitCount	PACKED;
	} BitmapCoreInfoHeader;


union BMPInfo_Coreinfo
	{
	BitmapInfoHeader     BIH;
	BitmapV4Header	     BIHv4;
	BitmapV5Header       BIHv5;
	BitmapCoreInfoHeader BCIH;
	};

struct BMP_RGBQuad
	{
	BYTE rgbBlue;
	BYTE rgbGreen;
	BYTE rgbRed;
	BYTE rgbReserved;
	};

#if SupportBMP>=4 || SupportBMP==2


inline long LoadPartBmpCoreInfHdr(FILE *f, BitmapCoreInfoHeader &SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU.bcWidth,1,sizeof(SU)-4,f));
#else
 return(loadstruct(f,"wwww",
	 &SU.bcWidth,&SU.bcHeight,&SU.bcPlanes,&SU.bcBitCount));
#endif
}

inline long LoadPartBmpInfHdr(FILE *f, BitmapInfoHeader &SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU.biWidth,1,sizeof(SU)-4,f));
#else
 return(loadstruct(f,"ddwwdddddd",
	 &SU.biWidth, &SU.biHeight, &SU.biPlanes,
	 &SU.biBitCount, &SU.biCompression, &SU.biSizeImage, &SU.biXPelsPerMeter,
	 &SU.biYPelsPerMeter, &SU.biClrUsed, &SU.biClrImportant));
#endif
}

inline long LoadBmpHeader(FILE *f, BMPHeader &SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU,1,sizeof(SU),f));
#else
 return(loadstruct(f,"a2dwwd",
	 &SU.bfType, &SU.bfSize, &SU.bfReserved1,
	 &SU.bfReserved2, &SU.bfOffBits));
#endif
}

void LoadBmpStream(Image &Img,FILE *f, DWORD Header_bfOffBits);

Image LoadPictureBMP(const char *Name)
{
Image Img;
FILE *f;
BMPHeader Header;

 if((f=fopen(Name,"rb"))==NULL) return(Img);

 if(LoadBmpHeader(f,Header)!=14) goto ENDPROC;
 if((Header.bfType[0]!='B')||(Header.bfType[1]!='M')) goto ENDPROC;

 LoadBmpStream(Img,f,Header.bfOffBits);

ENDPROC:
 fclose(f);
 return(Img);
}


/** This procedure loads BMP without a header. It is usefull e.g. for reading WMF.*/
void LoadBmpStream(Image &Img,FILE *f, DWORD Header_bfOffBits)
{
WORD ldblk;
unsigned i;
BMPInfo_Coreinfo Info;
BMP_RGBQuad PalItem;
long       w;
BYTE	   k;
Raster2DAbstract *Raster=NULL;
APalette *Palette=NULL;
char Compression=0;

 if(RdDWORD_LoEnd(&Info.BIH.biSize,f)!=4) return;

 switch(Info.BIH.biSize)
	{
	case 12:	//OS/2 V1  BITMAPCOREHEADER  OS/2 and also all Windows versions since Windows 3.0
	   {
	   if(LoadPartBmpCoreInfHdr(f,Info.BCIH) != (12-4)) goto ENDPROC;
	   if(Info.BCIH.bcPlanes!=1) return;
	   Raster=CreateRaster2D(Info.BCIH.bcWidth,Info.BCIH.bcHeight,
				 Info.BCIH.bcPlanes*Info.BCIH.bcBitCount);
	   k=3;			//RGB Triple
	   break;
	   }
	case 40:	//Windows V3  BITMAPINFOHEADER  all Windows versions since Windows 3.0
	   {
Try40:	   if(LoadPartBmpInfHdr(f,Info.BIH) != (40-4)) goto ENDPROC;
	   if(Info.BIH.biPlanes!=1) return;
	   Compression=Info.BIH.biCompression;
	   if(Info.BIH.biCompression>BI_BITFIELDS) 
		goto ENDPROC;; //unsupported compression mode
                
           k = Info.BIH.biPlanes*Info.BIH.biBitCount;
           if(k==32)
             {
             Compression = -1; //!!!
             k=24;
             }
	   Raster=CreateRaster2D(Info.BIH.biWidth,Info.BIH.biHeight,k);
	   k=4;			//RGB Quad
	   break;
	   }
	case 64:	//OS/2 V2  BITMAPCOREHEADER2
		goto ENDPROC;

	case 108:	//Windows V4 	BITMAPV4HEADER 	all Windows versions since Windows 95/NT4
        case 124:	//Windows V5 	BITMAPV5HEADER 	Windows 98/2000 and newer
	   goto Try40;  //but it sometimes occurs
           
	default: goto ENDPROC;
	}

 if(Raster==NULL) goto ENDPROC;				//unsupported format
 i=Raster->GetPlanes();
 if(!((i==1)||(i==4)||(i==8)||(i==24)))
	 {
ERASEEND:delete Raster;
	 Raster=NULL;
	 goto ENDPROC;
	 }

 if(i==8 || i==4) 				//load of the palette
	{
	Palette=BuildPalette(1<<i, 8);
	if(Palette!=NULL)
	  {
	  for(i=0;i<((unsigned)1 << Raster->GetPlanes()) /*p.palette^.Colors-1*/  ;i++)
	     {
	     fread(&PalItem,sizeof(PalItem),1,f);
	     Palette->R(i,PalItem.rgbRed);
	     Palette->G(i,PalItem.rgbGreen);
	     Palette->B(i,PalItem.rgbBlue);
	     }
	  if(GrayPalette(Palette,Raster->GetPlanes()))
	     {
	     delete Palette;
	     Palette=NULL;
	     }
	  }
	}

 if(Header_bfOffBits>0)
   fseek(f,Header_bfOffBits,SEEK_SET);
 ldblk = (Raster->GetPlanes()*Raster->GetSize1D()+7)/8;
 k = (-ldblk) & 0x3;

 switch(Compression)
   {
   case BI_RGB: i = Raster->Size2D;
                while(i-->0)                
		{
		  if(fread(Raster->GetRow(i),ldblk,1,f)!=1) {goto ERASEEND;}

		  fread(&w,k,1,f);			//read till end of line
 //		  AlineProc(i,p);
		}
	  break;
   case BI_RLE8:{
	  unsigned x,y;
	  unsigned char *ptrB;

	  y=Raster->Size2D;
	  x=0;
	  i=0;
	  while( y-->0 )
	    {
	    ptrB=(unsigned char *)Raster->GetRow(y);
	    if(!ptrB) goto End_of_bitmap;
	    while(!feof(f))
		{
		Rd_word(f,(WORD*)&i);
		if((i&0xFF)==0) 		//escape code
			{
			i = i>>8;
			if(i==0) {x=0;break;}
			if(i==1) goto End_of_bitmap;
			if(i==2)
			   {
			   Rd_word(f,(WORD*)&i);
			   x += i&0xFF;
			   y -= (i>>8)-1;
			   break;
			   }

			while( (i>0)&&(x<ldblk-1) )
			       {
			       Rd_word(f,(WORD*)&w);
			       *ptrB=w;
			       ptrB++;
			       x++;
			       i--;
			       if((x==ldblk-1)|| i==0 ) {i=0;break;}
			       *ptrB=w >> 8;
			       ptrB++;
			       x++;
			       i--;
			       }
			continue;
			};

		if( x>=ldblk )
			 continue;
		if((i&0xFF)>0)
			{
			k=ldblk-x;
			if(k>(i&0xFF)) k=i&0xFF;
			memset(ptrB,i>>8,k);
			ptrB+=k;
			x+=k;
			i-=k;
			}
		};
//	   if AlineProc<>nil then AlineProc^.NextLine;
	   if(feof(f)) goto End_of_bitmap;	//unexpected end
	   };
	break;
	}

   case BI_RLE4:{		//BI_RLE4
	 unsigned x,y;

	 y=Raster->Size2D;
	 x=0;
	 while(y-->0)
	   {
	   while(!(feof(f)))
		{
		Rd_word(f,(WORD*)&i);
		if((i&0xFF)==0)			//escape code
			{
			i=i>>8;
			if(i==0) {x=0;break;} 	//end of line
			if(i==1) goto End_of_bitmap;
			if(i==2)
			     {
			     Rd_word(f,(WORD*)&i);
			     x+=i&0xFF;
			     y-=(i>>8)-1;
			     break;
			     };

			k=0;
			ldblk=0;
			while( i>0 && x<Raster->GetSize1D() )
			    {
			    switch(k)
				{
				case 0:Rd_word(f,&ldblk);
				       Raster->SetValue2D(x,y,(ldblk >> 4)& 0xF);
				       break;
				case 1:Raster->SetValue2D(x,y,ldblk & 0xF);break;
				case 2:Raster->SetValue2D(x,y,ldblk >> 12);break;
				case 3:Raster->SetValue2D(x,y,(ldblk >> 8) & 0xF);break;
				};
			    x++;
			    i--;
			    k=(k+1) & 3;
			    }
			continue;
			}

		if((i&0xFF)>0)
			{
			ldblk=Raster->GetSize1D()-x;
			if(ldblk>(i&0xFF)) ldblk=(i&0xFF);
			k=i>>8;
			for(i=0;i<ldblk;i++)
				{
				if(i&1) Raster->SetValue2D(x,y,k & 0xF);
				   else Raster->SetValue2D(x,y,k >> 4);
				x++;
				}
			}
		}
//	   if AlineProc<>nil then AlineProc^.NextLine;
	   if(feof(f)) goto End_of_bitmap;	//unexpected end
	   }
     break;
     }

   case -1:
         {            //fake 32 bit mode RGB alfa
   	 unsigned x,y;
         for(y=Raster->Size2D;y>0;y--)   //fix for 32 bit planes
	   for(x=0;x<Raster->GetSize1D();x++)
             {
             if(fread(&PalItem,4,1,f)!=1) {goto ERASEEND;}
             Raster->SetValue2D(x,y,*(DWORD *)&PalItem);
             }
         break;
         }
   }

End_of_bitmap:

 if(Raster->GetPlanes()==24)
 {
   i = Raster->Size2D;
   while(i-->0)   
       RGB_BGR((char *)Raster->GetRow(i),Raster->GetSize1D());
 }

ENDPROC: 
 Img.AttachRaster(Raster);
 Img.AttachPalette(Palette); 
}
#endif


#if SupportBMP>=3

inline long SaveBmpHeader(FILE *f, BMPHeader &SU)
{
#if defined(__PackedStructures__)
  return(fwrite(&SU,1,sizeof(SU),f));
#else
  return(savestruct(f,"a2dwwd",
	 SU.bfType, SU.bfSize, SU.bfReserved1,
	 SU.bfReserved2, SU.bfOffBits));
#endif
}

inline long SaveBmpInfHdr(FILE *f, BitmapInfoHeader &SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU.biWidth,1,sizeof(SU),f));
#else
 return(savestruct(f,"dddwwdddddd", SU.biSize,
	 SU.biWidth, SU.biHeight, SU.biPlanes,
	 SU.biBitCount, SU.biCompression, SU.biSizeImage, SU.biXPelsPerMeter,
	 SU.biYPelsPerMeter, SU.biClrUsed, SU.biClrImportant));
#endif
}


int SavePictureBMP(const char *Name,const Image &Img)
{
FILE *f;
unsigned  ldblk;
BMPHeader Header;
BMPInfo_Coreinfo Info;
char k;
int i;
BMP_RGBQuad PalItem;
char StoredPlanes;
Raster1DAbstract *ConvertMe=NULL;

 if(Img.Raster==NULL) return(-10);

// if not(p.planes in [1,4,8,24]) then exit;    {nepodporovany format}

 if((f=fopen(Name,"wb"))==NULL) return(-1);

 StoredPlanes = Img.Raster->GetPlanes();
 if(Img.ImageType()==ImageGray)
   {
   if(StoredPlanes==16 || StoredPlanes==32)
     {
     StoredPlanes=8;	//16 bit Gray images needs to be scalled
     ConvertMe = CreateRaster1D(Img.Raster->GetSize1D(), StoredPlanes);
     }
   }

 if(Img.ImageType()==ImageTrueColor)
   {
   if(StoredPlanes==32 || StoredPlanes==64)
     {
     StoredPlanes = 24;
     ConvertMe = CreateRaster1DRGB(Img.Raster->GetSize1D(),8);
     }
   }

 ldblk=(StoredPlanes*Img.Raster->GetSize1D()+7)/8;

 memset(&Header,0,sizeof(Header));
 memmove(&Header.bfType,"BM",2);
#if defined(__PackedStructures__)
 Header.bfOffBits = sizeof(Header)+sizeof(Info);
#else
 Header.bfOffBits = 14 + 40;
#endif
 if (StoredPlanes==4 || StoredPlanes==8)
   Header.bfOffBits+=(1 << (StoredPlanes + 2));
 Header.bfSize = Header.bfOffBits + Img.Raster->Size2D*((ldblk+3) & 0xFFFC);

 memset(&Info,0,sizeof(Info));
 Info.BIH.biSize=40;
 Info.BIH.biWidth=Img.Raster->GetSize1D();
 Info.BIH.biHeight=Img.Raster->Size2D;
 Info.BIH.biPlanes=1;
 Info.BIH.biBitCount=StoredPlanes;
 Info.BIH.biCompression=0;                      //I don't allow compression
 Info.BIH.biSizeImage=Header.bfSize-Header.bfOffBits;
 if(StoredPlanes==4 || StoredPlanes==8) Info.BIH.biClrUsed=1 << (StoredPlanes);

 SaveBmpHeader(f,Header);
 SaveBmpInfHdr(f,Info.BIH);

 if ((StoredPlanes==4)||(StoredPlanes==8))
       {                                        //palette
//       gray=p.palette==NULL;
//     if(gray) CreatePalette(p.palette,p.planes);
       PalItem.rgbReserved=0;

       if(Img.Palette==NULL)
	 {
	 k=1;
	 if(StoredPlanes==4) k=16;
	 for(i=0;i<(1 << StoredPlanes) /*p.palette^.Colors-1*/  ;i++)
	   {
	   PalItem.rgbRed= k*i;   // p.palette^.pal[K].Red;
	   PalItem.rgbGreen=k*i;  // p.palette^.pal[K].Green;
	   PalItem.rgbBlue=k*i;   // p.palette^.pal[K].Blue;
	   fwrite(&PalItem,sizeof(PalItem),1,f);
	   }
//       if Gray then ErasePalette(p.palette);
	 }
       else
	 {
	 k=Img.Palette->GetPlanes()/3-8;
	 if(k<0) k=0;
	 for(i=0;i<(1 << StoredPlanes) /*p.palette^.Colors-1*/  ;i++)
	   {
	   PalItem.rgbRed = Img.Palette->R(i)>>k;    //  p.palette^.pal[K].Red;
	   PalItem.rgbGreen = Img.Palette->G(i)>>k;// p.palette^.pal[K].Green;
	   PalItem.rgbBlue = Img.Palette->B(i)>>k; // p.palette^.pal[K].Blue;
	   fwrite(&PalItem,sizeof(PalItem),1,f);
	   }
	 }
       }

 fseek(f,Header.bfOffBits,SEEK_SET);
 k=(-(int)ldblk)& 3;
 for(i=Img.Raster->Size2D-1;i>=0;i--)
	{
	if(ConvertMe!=NULL)
	  {
	  ConvertMe->Set(*Img.Raster->GetRowRaster(i));
	  fwrite(ConvertMe->Data1D,ldblk,1,f);
	  }
	else
	  {
	  if(StoredPlanes==24) RGB_BGR((char *)Img.Raster->GetRow(i),Img.Raster->GetSize1D());
	  fwrite(Img.Raster->GetRow(i),ldblk,1,f);
	  if(StoredPlanes==24) RGB_BGR((char *)Img.Raster->GetRow(i),Img.Raster->GetSize1D());
	  }
	fwrite(&Header.bfReserved1,k,1,f);      //write zeroes to end of line
//      AlineProc(i,p);
	}

 fclose(f);
 if(ConvertMe) {delete(ConvertMe);ConvertMe=NULL;}
 return(0);
}
#endif

TImageFileHandler BMP_H(".BMP",
#if SupportBMP>=4 || SupportBMP==2
	LoadPictureBMP,
#else
	NULL,
#endif
#if SupportBMP>=3
	SavePictureBMP);
#else
	NULL);
#endif

TImageFileHandler RLE_H(".RLE",
#if SupportBMP>=4 || SupportBMP==2
	LoadPictureBMP,
#else
	NULL,
#endif
//#if SupportBMP>=3
//	SavePictureBMP);
//#else
	NULL);
//#endif

#endif
//-------------------End of BMP routines------------------

//----------------CSV-comma separated values---------------
#ifdef SupportCSV


#if SupportCSV>=4 || SupportCSV==2

Image LoadPictureCSV(const char *Name)
{
FILE *f;
WORD x,y,R_X;
unsigned char ch;
long max,i;
Raster2DAbstract *Raster=NULL;
Image Img;
bool Doubles = false;

  if((f=fopen(Name,"rt"))==NULL) return(Img);
  x=0;y=0;
  max=0;
  i=0;
  R_X=0;

  ch=0;
  while(!feof(f))	//auto detect sizes and num of planes
    {
    while(!(ch >= '0' && ch <= '9'))
	 {             //go to the begin of number
	 ch = fgetc(f);
	 if(feof(f)) goto EndReading;
	 if(ch==0 || ch>128 || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
		goto FINISH; 	//not a text data
	 }
    x=0;
    i=0;
    do {
       x++;
       if(!isdigit(ch) && ch!=0) ch=0;
       i=ReadInt(f,(char *)&ch);
       if(ch=='.') 
         {
         ch = 0;
         if(ReadInt(f,(char *)&ch)!=0)	//dummy read frac part
           Doubles = true;
         }
       if(i>max) max=i;
       if(feof(f)) break;
       while(ch==' ') ch = fgetc(f);		//read spaces to next number
       if(ch==',')				// gobble comma that separate values
         {
         ch = fgetc(f);
         while(ch==' ') ch = fgetc(f);	//read spaces to next number
         }
       } while(!(ch==0 || ch==10 || ch==13 || ch==';' || ch==':' || ch>128 ||
		(ch>='a' && ch<='z') || (ch>='A' && ch<='Z')) );

    if(!feof(f))
      {
      if(ch==';') readln(f);		//comment
      if(ch==0 || ch==':' || ch>128 || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
		goto FINISH; 		//not a text data
      }
    if(x>1)
	 {
	 y++;
	 if(x>R_X) R_X=x;
	 }
    }
EndReading:
//  if IOResult!=0  goto Konec;
  fseek(f,0,SEEK_SET);

  if(Doubles)
    {
    Raster = CreateRaster2D(R_X,y,-64);
    }
  else
    {
    i=1;
    if(max>=    2) i=2;
    if(max>=    4) i=4;
    if(max>=   16) i=8;
    if(max>=  256) i=16;
    if(max>=65536) i=32;

    Raster = CreateRaster2D(R_X,y,i);
    }
  if(Raster==NULL) goto FINISH;
//if(AlineProc!=nil) AlineProc^.InitPassing(p.y,'Loading CSV');

  y = 0;
  ch = 0;
  while(!feof(f)) 	//load picture data
    {
    x = 0;
    while(!(ch >= '0' && ch <= '9'))
	 {		//move to the beginning of number
	 if(feof(f)) goto FINISH;
	 ch = fgetc(f);
	 }
    do {
       if(Doubles)
         Raster->SetValue2D(x,y,ReadDouble(f,(char *)&ch));
       else
         Raster->SetValue2D(x,y,ReadInt(f,(char *)&ch));
       //if IOresult!=0  goto Konec;
       x++;
       if(ch=='.') ReadInt(f,(char *)&ch);	//dummy read frac part
       if(feof(f)) break;
       while(ch==' ') ch=fgetc(f);		//read spaces to next number
       if(ch==',')				// gobble comma that separate values
         {
         ch = fgetc(f);
         while(ch==' ') ch = fgetc(f);	//read spaces to next number
         }
       } while(!(ch==0 || ch==10 || ch==13 || ch==';' ||  ch>128 || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z')) );

    if(ch==';') readln(f);
    if(x>1) y++;
    }

FINISH:
  fclose(f);
  Img.AttachRaster(Raster);  
  return(Img);
}
#endif


#if SupportCSV>=3
int SavePictureCSV(const char *Name,const Image &Img)
{
FILE *f;
WORD i,j;

 if(Img.Raster==NULL) return(-10);

 if((f=fopen(Name,"wt"))==NULL) return(-1);
 //if AlineProc<>nil AlineProc^.InitPassing(p.y*p.planes,'Saving TXT');

 //printf("1D%d 2D%d",Img.Raster->GetSize1D(),Img.Raster->Size2D);
 for(i=0;i<Img.Raster->Size2D;i++)
   {
   if(Img.Raster->GetPlanes()>=0 && Img.Raster->GetPlanes()<=32)
     {
     fprintf(f,"%u",Img.GetPixel(0,i));
     for(j=1;j<Img.Raster->GetSize1D();j++)
	{
	fprintf(f,", %u",Img.GetPixel(j,i));
	}
     }
   else
     {
     fprintf(f,"%f",Img.Raster->GetValue2Dd(0,i));
     for(j=1;j<Img.Raster->GetSize1D();j++)
	{
	fprintf(f,", %f",Img.Raster->GetValue2Dd(j,i));
	}
     }
   fprintf(f,"\n");
   //if AlineProc<>nil then AlineProc^.NextLine;
   }

 fclose(f);
 return(0);
}
#endif


TImageFileHandler CSV_H(".CSV",
#if SupportCSV>=4 || SupportCSV==2
	LoadPictureCSV,
#else
	NULL,
#endif
#if SupportTXT>=3
	SavePictureCSV,
#else
	NULL,
#endif
	NULL);

#endif
//-------------------End of CSV routines------------------


//--------------------------CUT----------------------------
#ifdef SupportCUT

struct RGBWord
	{
	WORD rgbRed;
	WORD rgbGreen;
	WORD rgbBlue;
	};

struct CUTHeader	//Dr Hallo
	{
	WORD	width;
	WORD	height;
	WORD	Reserved;
	};

struct CUTPalHeader
	{
	char 	FileId[2];
	WORD	Version;
	WORD	Size;
	BYTE	FileType;
	BYTE	SubType;
	WORD	BoardID;
	WORD	GraphicsMode;
	WORD	MaxIndex;
	WORD	MaxRed;
	WORD	MaxGreen;
	WORD	MaxBlue;
	char 	PaletteId[20];
       };


#if SupportCUT>=4 || SupportCUT==2
Image LoadPictureCUT(const char *Name)
{
FILE *f;
long ldblk;
WORD i,j;
BYTE *ptrB;
CUTHeader Header;
CUTPalHeader PalHeader;
RGBWord Pal;
WORD EncodedByte;
BYTE RunCount,RunCountMasked,RunValue;
Raster2DAbstract *Raster=NULL;
APalette *Palette=NULL;
Image Img;

 if((f=fopen(Name,"rb"))==NULL) return(Img);

 if(fread(&Header,sizeof(Header),1,f)!=1)
   goto Finish;
 if(Header.Reserved!=0 || Header.height==0 || Header.width==0)
   goto Finish;
/*---This code checks first line of image---*/
 Rd_word(f,&EncodedByte);
 RunCount=fgetc(f);
 RunCountMasked=RunCount & 0x7F;
 ldblk=0;
 while(RunCountMasked>0)	/*end of line?*/
	{
	i=1;
	if(RunCount<0x80) i=RunCountMasked;
	fseek(f,i,SEEK_CUR);
	if(feof(f)) goto Finish;	/*wrong data*/
	EncodedByte-=i+1;
	ldblk+=RunCountMasked;

	RunCount=fgetc(f);
	if(feof(f)) goto Finish;	/*wrong data: unexpected eof in line*/
	RunCountMasked=RunCount & 0x7F;
	};
 if(EncodedByte!=1) goto Finish;		/*wrong data: size incorrect*/
 i=0;				/*guess a number of bit planes*/
 if(ldblk==Header.width)   i=8;
 if(2*ldblk==Header.width) i=4;
 if(8*ldblk==Header.width) i=1;
 if(i==0) goto Finish;			/*wrong data: size incorrect*/
/*-----End of check-----*/
 Raster=CreateRaster2D(Header.width,Header.height,i);
 if(Raster==NULL) goto Finish;

 //if(AlineProc!=NULL) AlineProc->InitPassing(p.y,'Loading CUT');

 fseek(f,sizeof(Header),SEEK_SET);	/*Ldblk was set in the check phase*/

 for(i=0;i<Header.height;i++)
	{
	Rd_word(f,&EncodedByte);

	ptrB=(BYTE *)Raster->GetRow(i);
	j=ldblk;

	RunCount=fgetc(f);
	RunCountMasked=RunCount & 0x7F;
	while(RunCountMasked>0)		/*end of line?*/
		{
		if(RunCountMasked>j)
		  {		/*Wrong Data*/
		  //asm int 3; end;
		  RunCountMasked=j;
		  if(j==0) break;
		  }

		if(RunCount>0x80)
		  {
		  RunValue=fgetc(f);
		  memset(ptrB,RunValue,RunCountMasked);
		  }
		else
		  if(fread(ptrB,RunCountMasked,1,f)!=1) {goto Finish;}

		ptrB+=RunCountMasked;
		j-=RunCountMasked;

		if(feof(f)) goto Finish;	/*wrong data: unexpected eof in line*/
		RunCount=fgetc(f);
		RunCountMasked = RunCount & 0x7F;
		}

	//if(AlineProc!=NULL)  AlineProc^.NextLine;
	}

/*Try to load a palette*/
 fclose(f); f=NULL;
 if(Raster!=NULL)		/*remains loading palette*/
	{
	char *NameBuffer;

	j=i=strlen(Name);
	NameBuffer=(char *)malloc(i+5);
	strcpy(NameBuffer,Name);

	while(--i>0)
	  {
	  if(Name[i]=='.') break;
	  if(Name[i]=='/' || Name[i]=='\\' || Name[i]==':')
	       {i=j;break;}
	  }
	strcpy(NameBuffer+i,".PAL");
	if((f=fopen(NameBuffer,"rb"))==NULL)
	     {
	     strcpy(NameBuffer+i,".pal");
	     if((f=fopen(NameBuffer,"rb"))==NULL)
		 {
		 NameBuffer[i]=0;
		 if((f=fopen(NameBuffer,"rb"))==NULL)
			goto PalFail;
		 }
	     }

	if(fread(&PalHeader,sizeof(PalHeader),1,f)!=1) /*introduction information*/
	  goto PalFail;
	if(PalHeader.FileId[0]!='A' || PalHeader.FileId[1]!='H')
	  goto PalFail;

	Palette = BuildPalette(1<<Raster->GetPlanes(),8); //depth 16 ??
	ldblk = (1<<Raster->GetPlanes()) - 1;
	if(PalHeader.MaxIndex<ldblk) ldblk=PalHeader.MaxIndex;
	for(i=0;i<ldblk;i++)
		{      /*this may be wrong- I don't know why is palette such strange*/
		j=ftell(f);
		if( (j%512)>512-sizeof(Pal) )
			{
			j=((j / 512)+1)*512;
			fseek(f,j,SEEK_SET);
			}
		fread(&Pal,sizeof(Pal),1,f);
		Palette->R(i,Pal.rgbRed);
		Palette->G(i,Pal.rgbGreen);
		Palette->B(i,Pal.rgbBlue);
		}

PalFail:
	if(f) {fclose(f);f=NULL;}
	if(Palette!=NULL)
	  if(GrayPalette(Palette,Raster->GetPlanes()))
		{
		delete Palette;
		Palette=NULL;
		}
	if(NameBuffer) {free(NameBuffer);NameBuffer=NULL;}
	}

Finish:
 if(f) {fclose(f);f=NULL;}
 Img.AttachRaster(Raster); 
 Img.AttachPalette(Palette);
 return(Img);
};  /*LoadCUT*/

#endif


TImageFileHandler CUT_H(".CUT",
#if SupportCUT>=4 || SupportCUT==2
	LoadPictureCUT,
#else
	NULL,
#endif
//#if SupportCUT>=3
//	SavePictureCUT);
//#else
	NULL);
//#endif


#endif
//-------------------End of CUT routines------------------



//--------------------------EPS----------------------------
#ifdef SupportEPS


#if SupportEPS>=4 || SupportEPS==2

BYTE ReadxByte(FILE *F)
{
char c;
BYTE B;
  do		// rewind to number beginning
    {
    if(feof(F)) return 0;
    c=toupper(fgetc(F));
    } while(!isxdigit(c));
  if(c>='A')
    B = (c- 'A' + 10) << 4;
  else
    B = (c-'0') << 4;;

  c=toupper(fgetc(F));
  c-='0';
  if(c>=10) c+= -'A'+'0' + 10;
  B |= c;
  return B;
}


Image LoadPictureEPS(const char *Name)
{
FILE *F;
WORD x,y,Class;
int planes;
char ch;
BYTE r,g,b;
unsigned long i;
char a[256];
BYTE *ptrB;
bool RLE_Compressed;
Raster2DAbstract *Raster=NULL;
APalette *Palette=NULL;
Image Img;

 if((F=fopen(Name,"rb"))==NULL) return(Img);

 RLE_Compressed=false;

 ReadWord(F,a,sizeof(a));
 if(strncmp(a,"%!PS",4)) goto FINISH;
 readln(F);

 ch=0;
 while(!feof(F)) 		//auto detect sizes and num of planes
   {
   ReadWord(F,a,sizeof(a),&ch);
   if(*a==0) continue;

   if(*a=='%')			//strip comments
     {
     if(ch!='\n' && ch!='\r') readln(F);
     continue;
     }

    if(*a=='/')		//ignore definition
      {
      if(!strcmp(a,"/cmap"))
	{
	i=ftell(F);
	planes=ReadInt(F,&ch);
	if(planes>0 && planes<=256)
	  {
	  Palette=BuildPalette(planes/3,8);
	  }
	fseek(F,i,SEEK_SET);
	}

      i=0;
      do
       {
       ch=fgetc(F);

       if(ch=='{') i++;
       if(ch=='}') i--;
       if(ch=='%') readln(F);
       if(feof(F)) goto FINISH;
       } while( !((i==0) && isalnum(ch)) );
      continue;
      }

      if(!strcmp(a,"cmap") && Palette!=NULL)
	{
	ReadWord(F,a,sizeof(a),&ch);
	if(!strcmp(a,"readhexstring"))
	  {
	  for(i=0;i<Palette->GetSize1D();i++)
	    {
	    r = ReadxByte(F);
	    g = ReadxByte(F);
	    b = ReadxByte(F);
	    Palette->R(i,r);
	    Palette->G(i,g);
	    Palette->B(i,b);
	    }
	  }
	  continue;
	}

      if(!strcmp(a,"DisplayImage"))
	{
	if(ReadInt(F,&ch)==0) continue;		//x translation
	if(ReadInt(F,&ch)==0) continue;		//y translation
	ReadWord(F,a,sizeof(a),&ch);		//x scale
	ReadWord(F,a,sizeof(a),&ch);		//y scale
	if(ReadInt(F,&ch)==0) continue;		//pointsize
			//read label !!!
	if((x=ReadInt(F,&ch))==0) continue;	//columns

	if((y=ReadInt(F,&ch))==0) continue;	//rows
	if((Class=ReadInt(F,&ch))==0) continue; //class type

	if((i=ReadInt(F,&ch))==0) continue;	//compression
	if(i!=1) continue;			//compressed?
	if(Class==0)
	  {
	  i=planes=24;
	  goto readRAS;
	  }
	ReadWord(F,a,sizeof(a),&ch);		//?????
	if((planes=ReadInt(F,&ch))==0) continue;//planes
	goto readRAS;
	}

      x = atol(a);		//readX
      if(x<=0) continue;

      y=ReadInt(F,&ch);
      if(x<=0) continue;

      planes=ReadInt(F,&ch);
      if(planes<=0) continue;

ctiZ: ReadWord(F,a,sizeof(a));
      if(*a=='%') {readln(F);goto ctiZ;}
      if(*a!='[') continue;
      readln(F);

ctiZ2:ReadWord(F,a,sizeof(a));
      if(*a=='%') {readln(F);goto ctiZ2;}
      if(!strcmp(a,"rlecmapimage"))
	{
	RLE_Compressed=true;
	i=8;
	goto readRAS;
	}

      if(*a!='{') continue;
      readln(F);

      ch=0;
      while(ch!=10 && ch!=13)
	{
	ReadWord(F,a,sizeof(a),&ch);
	if(!strcmp(a,"colorimage")) planes*=3;
	}

readRAS:
      Raster=CreateRaster2D(x,y,planes);
      if(Raster==NULL) goto FINISH;
/*
      if(planes>2*i)
		begin
		 p.typ:='C';
		 i:=3*i;
		end;
*/

      i = (planes*Raster->GetSize1D()+7)/8 - 1;
//    if(AlineProc!=NULL) AlineProc->InitPassing(p.y,'Loading PS');

      for(y=0;y<Raster->Size2D;y++)
	{
	ptrB=(BYTE *)Raster->GetRow(y);

	if(RLE_Compressed)
	  {
	  x=0;
	  while(x<=i)
	    {
	    r=ReadxByte(F);
	    if(r<=0x80)
	      {
	      g=ReadxByte(F);
	      while((r&0x80) == 0)
		{
		*ptrB++=g;
		x++;
		r--;
		}
	      }
	    else
	      {
	      while(r>=0x80)
		{
		*ptrB++=ReadxByte(F);
		x++;
		r--;
		}
	      }

	   }
          }
	else for(x=0;x<=i;x++)
	   {
	   *ptrB++ = ReadxByte(F);
	   if(feof(F)) goto FINISH;
	   }
//	if AlineProc<>nil then AlineProc^.NextLine;
	}

   break;
   }

FINISH:
 if(F) {fclose(F);F=NULL;}
 Img.AttachRaster(Raster);
 Img.AttachPalette(Palette); 
 return(Img);
}
#endif


#if SupportEPS>=3

static void UpdateBBox(float & MinX,float & MaxX,float & MinY,float & MaxY,
		float alpha,float x,float y,float dx,float dy)
{
if(fabs(alpha)<1e-6)
	{
	if(MinX>x) MinX=x;
	if(MinY>y) MinY=y;
	if(MaxX<x+dx) MaxX=x+dx;
	if(MaxY<y+dy) MaxY=y+dy;
	return;
	}

float_matrix m(3,3),corners(4,3,1.0);
float X0,Y0;
unsigned i;

  alpha = (M_PI*alpha)/180.0;	//calculate radians
  X0=x+dx/2;
  Y0=y+dy/2;
  m(0,0)=cos(alpha);
  m(1,0)=-sin(alpha);
  m(2,0)=X0*(1-cos(alpha))+Y0*sin(alpha);
  m(0,1)=sin(alpha);
  m(1,1)=cos(alpha);
  m(2,1)=Y0*(1-cos(alpha))-X0*sin(alpha);
  m(0,2)=0;  m(1,2)=0;  m(2,2)=1;

  corners(0,0)=x;	corners(0,1)=y;
  corners(1,0)=x+dx;	corners(1,1)=y;
  corners(2,0)=x+dx;	corners(2,1)=y+dy;
  corners(3,0)=x;	corners(3,1)=y+dy;

  corners=m*corners;
  for(i=0;i<corners.cols();i++)
      {
      if(MinX>corners(i,0)) MinX=corners(i,0);
      if(MaxX<corners(i,0)) MaxX=corners(i,0);
      if(MinY>corners(i,1)) MinY=corners(i,1);
      if(MaxY<corners(i,1)) MaxY=corners(i,1);
      }
}


/** This function returns true, when arg is close to zero. */
static int IsZero2p(double arg)
{
int argi;
  argi = (int)(arg + 0.5);
  arg = fabs(arg - argi);
return arg<0.005;
}


int SavePictureEPS(const char *Name,const Image &Img)
{
typedef enum
{
  EPS_DrawElipse =   1,
  EPS_colorimage =   2,
  EPS_rlecmapimage = 4,
} EPS_COMPONENTS;
FILE *f;
unsigned Y;
unsigned char *ptrb,b;
int ColorMode;
unsigned long X, BytesPerLine;
const Image *CurrImg=&Img;
float x1,y1,x2,y2;
BYTE MakeDict=0;
RGBQuad RGB;

  if(Img.Raster==NULL && Img.Comment==NULL) return(-10);

  if((f=fopen(Name,"wt"))==NULL) return(-1);

  CurrImg=&Img;		//computation of bounding box
  x2=x1=Img.x+Img.dx/2.0;
  y2=y1=Img.y+Img.dy/2.0;
  while(CurrImg!=NULL)
    {
    UpdateBBox(x1,x2,y1,y2,		CurrImg->RotAngle,
	       CurrImg->x,CurrImg->y,CurrImg->dx,CurrImg->dy);

    if(CurrImg->Raster==NULL && CurrImg->Comment!=NULL) MakeDict|=1;
    if(CurrImg->Palette!=NULL)
	{
	MakeDict |= EPS_colorimage;  //fake true color - should be fixed
        if(CurrImg->Palette->Channels()<=3)
	  if(CurrImg->Palette->GetPlanes()<=8*CurrImg->Palette->Channels())
		MakeDict |= EPS_rlecmapimage;
	}
    if(CurrImg->Raster)
	if(CurrImg->Raster->GetPlanes()==24 || CurrImg->Raster->Channels()>=3)
		MakeDict |= EPS_colorimage; //RGB true color image

    CurrImg=CurrImg->Next;
    }

  if(x2<=1e-6 || y2<=1e-6)
    {   	//If size information is not present, calculate it.
    x2=Img.Raster->GetSize1D();
    y2=Img.Raster->Size2D;
    if(y2<=1e-6) y2=1;

    double ratio = x2/y2;
    if(ratio >= 612.0/792.0)
      {		//x should be shortened
      ratio = 612.0*25.4/(71.0*x2);	//calculate in mm
      }
    else
      {		//y should be shortened
      ratio = 792.0*25.4/(71.0*y2);	//calculate in mm
      }
    x2*=ratio;
    y2*=ratio;
    x1=y1=0;
    }

  CurrImg=&Img;

  fprintf(f,
"%%!PS-Adobe-2.0 EPSF-2.0\n"
"%%%%Title: %s\n"					//%title
"%%%%Creator: %s - (c) 2000-2014 by Jaroslav Fojtik\n"	//%creator
"%%%%BoundingBox: ",
   Name,UnitName);

  fprintf(f,"%2.0f %2.0f %2.0f %2.0f",
      x1*71/25.4,y1*71/25.4,x2*71/25.4,y2*71/25.4);
  if(!(IsZero2p(x1*71/25.4) && IsZero2p(y1*71/25.4) && IsZero2p(x2*71/25.4) && IsZero2p(y2*71/25.4)))
  {
    fprintf(f,"\n%%%%HiResBoundingBox: %2.2f %2.2f %2.2f %2.2f",
      x1*71/25.4, y1*71/25.4, x2*71/25.4, y2*71/25.4);
  }

  fprintf(f,"\n"
"%%%%Pages: 1\n"
"%%%%DocumentFonts:\n"
"%%%%EndComments\n"
"%%%%EndProlog\n"
"\n"
"%%%%Page: 1 1");

  if(MakeDict)
	{
	fprintf(f,"\n"
		  "/$F2psDict 200 dict def\n"
		  "$F2psDict begin\n"
		  "$F2psDict /mtrx matrix put\n"
		  "\n");
	if(MakeDict & EPS_DrawElipse) fprintf(f,"\n"
		"/DrawEllipse {\n"
		"	/endangle exch def\n"
		"	/startangle exch def\n"
		"	/yrad exch def\n"
		"	/xrad exch def\n"
		"	/y exch def\n"
		"	/x exch def\n"
		"	/savematrix mtrx currentmatrix def\n"
		"	x y translate xrad yrad scale 0 0 1 startangle endangle arc\n"
		"	savematrix setmatrix\n"
		"	} def\n"
		"\n");
	if(MakeDict & EPS_colorimage) fprintf(f,
		"%% define 'colorimage' if it isn't defined\n"
		"%%   ('colortogray' and 'mergeprocs' come from xwd2ps\n"
		"%%     via xgrab)\n"
		"/colorimage where   %% do we know about 'colorimage'?\n"
		"  { pop }           %% yes: pop off the 'dict' returned\n"
		"  {                 %% no:  define one\n"
		"  /colortogray {  %% define an RGB->I function\n"
		"    /rgbdata exch store    %% call input 'rgbdata'\n"
		"    rgbdata length 3 idiv\n"
		"    /npixls exch store\n"
		"    /rgbindx 0 store\n"
		"    0 1 npixls 1 sub {\n"
		"      grays exch\n"
		"      rgbdata rgbindx       get 20 mul    %% Red\n"
		"      rgbdata rgbindx 1 add get 32 mul    %% Green\n"
		"      rgbdata rgbindx 2 add get 12 mul    %% Blue\n"
		"      add add 64 idiv      %% I = .5G + .31R + .18B\n"
		"      put\n"
		"      /rgbindx rgbindx 3 add store\n"
		"    } for\n"
		"    grays 0 npixls getinterval\n"
		"  } bind def\n"
		"\n"
		"%% Utility procedure for colorimage operator.\n"
		"%% This procedure takes two procedures off the\n"
		"%% stack and merges them into a single procedure.\n"
		"\n"
		"/mergeprocs { %% def\n"
		"  dup length\n"
		"  3 -1 roll\n"
		"  dup\n"
		"  length\n"
		"  dup\n"
		"  5 1 roll\n"
		"  3 -1 roll\n"
		"  add\n"
		"  array cvx\n"
		"  dup\n"
		"  3 -1 roll\n"
		"  0 exch\n"
		"  putinterval\n"
		"  dup\n"
		"  4 2 roll\n"
		"  putinterval\n"
		"} bind def\n"
		"/colorimage { %% def\n"
		"  pop pop     %% remove ""false 3"" operands\n"
		" {colortogray} mergeprocs\n"
		"image\n"
		"} bind def\n"
		"} ifelse          %% end of 'false' case\n"
		"\n");
	if(MakeDict & EPS_rlecmapimage) fprintf(f,
		"%% rlecmapimage expects to have 'w h bits matrix' on stack\n"
		"/rlecmapimage {\n"
		"  /buffer 1 string def\n"
		"  /rgbval 3 string def\n"
		"  /block  384 string def\n"
		"\n"
		"  %% proc to read a block from file, and return RGB data\n"
		"  { currentfile buffer readhexstring pop\n"
		"    /bcount exch 0 get store\n"
		"    bcount 128 ge\n"
		"    {  %% it's a non-run block\n"
		"      0 1 bcount 128 sub\n"
		"      { currentfile buffer readhexstring pop pop\n"
		"\n"
		"        %% look up value in color map\n"
		"	 /rgbval cmap buffer 0 get 3 mul 3 getinterval store\n"
		"\n"
		"	 %% and put it in position i*3 in block\n"
		"	 block exch 3 mul rgbval putinterval\n"
		"      } for\n"
		"      block  0  bcount 127 sub 3 mul  getinterval\n"
		"    }\n"
		"\n"
		"    { %% else it's a run block\n"
		"      currentfile buffer readhexstring pop pop\n"
		"\n"
		"      %% look up value in colormap\n"
		"      /rgbval cmap buffer 0 get 3 mul 3 getinterval store\n"
		"\n"
		"      0 1 bcount { block exch 3 mul rgbval putinterval } for\n"
		"\n"
		"      block 0 bcount 1 add 3 mul getinterval\n"
		"    } ifelse\n"
		"  } %% end of proc\n"
		"  false 3 colorimage\n"
		"} bind def\n");
	}

	/** Store all rasters to image here. */
  while(CurrImg!=NULL)
    {
    fprintf(f,"\n"
"%% remember original state\n"
"/origstate save def\n"
"\n"
"%% build a temporary dictionary\n"
"20 dict begin\n");
   if(CurrImg->Comment!=NULL)
	{
	fprintf(f,"%% %s\n",CurrImg->Comment);
	}

   if(CurrImg->Raster==NULL) goto LOOP_CONTINUE;

   ColorMode=Img.ImageType(); //0;
   if(ColorMode==ImagePalette)
     if(CurrImg->Palette->GetPlanes()<=8*CurrImg->Palette->Channels())
	ColorMode=12;

   if(ColorMode==12)
     {
     fprintf(f,
	"%% define the colormap\n"
	"/cmap %d string def\n"
	"%% load up the colormap\n"
	"currentfile cmap readhexstring", 3*CurrImg->Palette->GetSize1D());  //3x size of a palette
     for(X=0;X<CurrImg->Palette->GetSize1D();X++)
	{
	if(X % 16 == 0) fputc('\n',f);
	CurrImg->Palette->Get(X,&RGB);
	fprintf(f,"%.2X%.2X%.2X ",
	     (int)RGB.R, (int)RGB.G, (int)RGB.B);
	}
     fprintf(f,
	"\npop pop  %% lose return values from readhexstring\n");
     }


   fprintf(f,"\n"
"%% define string to hold a scanline's worth of data\n"
"/pix %d string def\n"
"\n"
"%% define space for color conversions\n"
"/grays %d string def  %% space for gray scale line\n"
"/npixls 0 def\n"
"/rgbindx 0 def\n",
       (ColorMode==ImagePalette || ColorMode==12)
	   ?CurrImg->Raster->GetSize1D()
	   :(CurrImg->Raster->GetSize1D()*CurrImg->Raster->GetPlanes()+7)/8,
       CurrImg->Raster->GetSize1D());

    if(CurrImg->RotAngle!=0)
	{
	float Xs,Ys;
	if(CurrImg->dx<1e-6) Xs=CurrImg->Raster->GetSize1D()*71.0/25.4;
			else Xs=(CurrImg->x+CurrImg->dx/2)*71/25.4;
	if(CurrImg->dy<1e-6) Ys=Xs=CurrImg->Raster->Size2D*71.0/25.4;
			else Ys=(CurrImg->y+CurrImg->dy/2)*71/25.4;
	fprintf(f,"\n%2.2f %2.2f translate\n%g rotate\n%2.2f %2.2f translate",
		Xs,Ys, CurrImg->RotAngle, -Xs,-Ys);
	}

    if(CurrImg->x!=0 || CurrImg->y!=0)
      {
      fprintf(f,"\n%% lower left corner\n");
      fprintf(f,"%2.2f %2.2f translate\n",
		 CurrImg->x*71/25.4,CurrImg->y*71/25.4);
      }

    x2=CurrImg->dx;
    y2=CurrImg->dy;
    if(x2<=1e-6 || y2<=1e-6)
      {   	//If size information is not present, calculate it.
      x2=CurrImg->Raster->GetSize1D();
      y2=CurrImg->Raster->Size2D;
      if(y2<=1e-6) y2=1;

      double ratio = x2/y2;
      if(ratio >= 612.0/792.0)
	ratio = 612.0*25.4/(71.0*x2); //x should be shortened; calculate in mm
      else
	ratio = 792.0*25.4/(71.0*y2); //y should be shortened; calculate in mm
      x2*=ratio;
      y2*=ratio;
      }
  fprintf(f,"\n"
       "%% size of image (on paper, in 1/72inch coords)\n"
       "%2.2f %2.2f scale\n\n", x2*71/25.4, y2*71/25.4);

  if((ColorMode==ImagePalette || ColorMode==12)) Y=8;
  else
    {
    Y = CurrImg->Raster->GetPlanes()/CurrImg->Raster->Channels();
    if(Y>=16) Y=8;      
    }
  fprintf(f,
     "%% dimensions of data\n"
     "%d %d %d\n"					//%SizeX %SizeY %Planes
     "\n"
     "%% mapping matrix\n"
     "[ %d 0 0 -%d 0 %d]\n\n",				//%SizeX %SizeY %SizeY
    CurrImg->Raster->GetSize1D(),CurrImg->Raster->Size2D,Y,
    CurrImg->Raster->GetSize1D(),CurrImg->Raster->Size2D,CurrImg->Raster->Size2D);

  if(ColorMode==12)
     {
     fprintf(f,"rlecmapimage\n");
     }
  else
    {
    fprintf(f,
       "{currentfile pix readhexstring pop}\n"
       "%simage\n",
      (ColorMode>ImageGray)?"false 3 color":"" );
    }

    BytesPerLine=((long)(CurrImg->Raster->GetPlanes())*CurrImg->Raster->GetSize1D()+7) / 8;

    for(Y=0;Y<CurrImg->Raster->Size2D;Y++)
      {
      switch(ColorMode)
	{
	case 12:		//palette images - less than 256 colors, RLE compressed.
	  {
	  Raster1DAbstract *RasLine=CurrImg->Raster->GetRowRaster(Y);
	  for(X=0;X<RasLine->GetSize1D();X++)
	    {
	    if(X%128 == 0)
	      {
	      if(RasLine->GetSize1D()-X > 128)
		fprintf(f,"%.2X", (128-1)|0x80);
	      else
		fprintf(f,"%.2X", (RasLine->GetSize1D()-X-1)|0x80);
	      }
	    fprintf(f,"%.2X", RasLine->GetValue1D(X));
	    }
	  break;
	  }
	case ImagePalette:
	  {
	  if(CurrImg->Raster->GetPlanes()==8)  //speedup trick for 8 planes
	    {
	    ptrb=(BYTE *)CurrImg->Raster->GetRow(Y);
	    for(X=0;X<BytesPerLine;X++)
		{
		CurrImg->Palette->Get(*ptrb++,&RGB);
		fprintf(f,"%.2X%.2X%.2X",
		     (int)RGB.R, (int)RGB.G, (int)RGB.B);
		}
	     }
	  else
	     {
	     Raster1DAbstract *RasLine = CurrImg->Raster->GetRowRaster(Y);
	     if(RasLine)
	       for(X=0;X<RasLine->GetSize1D();X++)
		  {
		  b=RasLine->GetValue1D(X);
		  CurrImg->Palette->Get(b,&RGB);
		  fprintf(f,"%.2X%.2X%.2X",
		     (int)RGB.R, (int)RGB.G, (int)RGB.B);
		  }
	      }
	break;
	}

       case ImageTrueColor:
	   if(CurrImg->Raster->GetPlanes()==24) goto FAST_COPY;
	   {
	     Raster1DAbstract *RasLine = CurrImg->Raster->GetRowRaster(Y);	  
	     if(RasLine)
	       {
	       DWORD w;
	       for(X=0;X<RasLine->GetSize1D();X++)
		 {
	         w = RasLine->GetValue1D(X);	      
	         fprintf(f,"%.2X%.2X%.2X", w&0xFF, (w>>8)&0xFF, (w>>16)&0xFF);
	         }               
               }
           }
	   break;

       default:
	{
	if(CurrImg->Raster->GetPlanes()==8 ||
	   CurrImg->Raster->GetPlanes()==4 ||
	   CurrImg->Raster->GetPlanes()==1)	//speedup trick for 8, 4 and 1 planes
	  {
FAST_COPY:ptrb=(BYTE *)CurrImg->Raster->GetRow(Y);
	  for(X=0;X<BytesPerLine;X++)
	     {
	     fprintf(f,"%.2X",(unsigned)*ptrb++);
	     }
	  }
	else	/* Expand other bit depths to 8 bits */
	  {
	  Raster1DAbstract *RasLine = CurrImg->Raster->GetRowRaster(Y);	  
	  if(RasLine)
	    {
	    int k = CurrImg->Raster->GetPlanes()-8;
	    DWORD w;
	    for(X=0;X<RasLine->GetSize1D();X++)
	      {
	      w = RasLine->GetValue1D(X);
	      if(k>0) w>>=k;
	      fprintf(f,"%.2X", w);
	      }
            }
	  }
	}
      }

      fputc('\n',f);
  //    if AlineProc<>nil then AlineProc^.NextLine;
    }

LOOP_CONTINUE:
    fprintf(f,
      "%% stop using temporary dictionary\n"
      "end\n"
      "\n"
      "%% restore original state\n"
      "origstate restore\n");

    CurrImg=CurrImg->Next;
    }

  if(MakeDict) fprintf(f,"\nend  %%finish global function dictionary");

  fprintf(f,
      "\n"
      "showpage\n"
      "\n"
      "%%%%Trailer");
  
  fclose(f);
  return(0);
}
#endif


TImageFileHandler EPS_H(".EPS",
#if SupportEPS>=4 || SupportEPS==2
	LoadPictureEPS,
#else
	NULL,
#endif
#if SupportEPS>=3
	SavePictureEPS);
#else
	NULL);
#endif

TImageFileHandler PS_H(".PS",
#if SupportEPS>=4 || SupportEPS==2
	LoadPictureEPS,
#else
	NULL,
#endif
#if SupportEPS>=3
	SavePictureEPS);
#else
	NULL);
#endif

#endif
//-------------------End of EPS routines------------------


//-------------------------FITS---------------------------
#ifdef SupportFITS

void swab64(BYTE *block, int octets)
{
BYTE tmp;

 if(block==NULL) return;
 while(octets-->0)
   {
   tmp = block[7]; block[7]=block[0]; block[0]=tmp;
   tmp = block[6]; block[6]=block[1]; block[1]=tmp;
   tmp = block[5]; block[5]=block[2]; block[2]=tmp;
   tmp = block[4]; block[4]=block[3]; block[3]=tmp;
   block+=8;
   }
}

void swab32(BYTE *block, int octets)
{
BYTE tmp;

 if(block==NULL) return;
 while(octets-->0)
   {
   tmp = block[3]; block[3]=block[0]; block[0]=tmp;
   tmp = block[2]; block[2]=block[1]; block[1]=tmp;
   block+=4;
   }
}

static void FixSignedMSBValues(unsigned char *data, int size, unsigned step)
{
  while(size-->0)
  {
    *data ^= 0x80;
    data += step;
  }
}

static void FixSignedLSBValues(unsigned char *data, int size, unsigned step)
{
  data += step - 1;
  while(size-->0)
  {
    *data ^= 0x80;
    data += step;
  }
}

#if SupportFITS>=4 || SupportFITS==2
/** States of FITS parser. */
typedef enum
{
  HeaderStart,
  HeaderContinue,
  HeaderEnd,
  ExtensionStart,
  ExtensionContinue,
  ExtensionEnd,
  ExtensionData,
  ExtensionBinData
} FITS_PARSE;

#define MAX_AXIS 4

/** This procedure process one separate fits file. */
Image LoadPictureFITS(const char *Name)
{
char HDU[36][80];
char identifier[80];
char value[80];
char comment[80];
char c;
char BitPix = 0;
char pos;
FILE *F;
unsigned j;
char Simple = 0;
bool ExtensionExists = false;
int Naxis;
int Axes[MAX_AXIS];
FITS_PARSE ParseStatus;
int Endian=1;			///< Default BIG endiann
Image Img;
Raster2DAbstract *Raster=NULL;
DWORD ldblk;

  if((F=fopen(Name,"rb"))==NULL) return(NULL);
  //LogMessage(LOG_INFO,_("Parsing file: %s"),FileName).Print();

  ParseStatus = HeaderStart;

NewChunk:
  memset(Axes,0,sizeof(Axes));
//  memset(&attr,0,sizeof(attr));
  Naxis = 0;
  memset(HDU,0,sizeof(HDU));

  while(!feof(F))
    {
    if(fread(HDU,sizeof(HDU),1,F)!=1)
      break;
      
    for(int i=0; i<36; i++)        // parse separate rows
      {
      *identifier = *value = *comment = 0;
	  // parse identifier
      pos=0; j=0;
      while(j<sizeof(identifier)-1)
	{
	c = HDU[i][j++];
	if(isspace((unsigned char)c)) continue;
	if(c=='=') break;
	if(c=='/') goto COMMENT;

	identifier[pos++] = c;
	identifier[pos] = 0;
	}

	  // parse value
      pos = 0;
      while(j<80)
        {
	c = HDU[i][j++];
        if(isspace((unsigned char)c) && *value==0) continue;
	if(c=='/') break;
	value[pos++] = c;
        value[pos] = 0;
        }
      if(pos>0) pos--;
      while(pos>0)        // remove leading spaces
        {
	if(!isspace((unsigned char)value[pos])) break;
        value[pos--] = 0;
        }

COMMENT:
      pos = 0;
      while(j<80)
	{
	c = HDU[i][j++];
        if(isspace((unsigned char)c) && *comment==0) continue;
        comment[pos++] = c;
	comment[pos] = 0;
        }
      if(pos>0) pos--;
      while(pos>0)        // remove leading spaces
	{
	if(!isspace((unsigned char)comment[pos])) break;
	comment[pos--] = 0;
	}

      if(*identifier==0 && *value==0 && *comment==0)
	continue;         // line is empty

	// parse separate keywords
      if(!strcmp(identifier,"BITPIX"))
	{
	BitPix = atoi(value);
	}

      if(!strcmp(identifier,"END"))
	{
	switch(ParseStatus)
	  {
	  case HeaderStart:
	  case HeaderContinue:   ParseStatus=HeaderEnd;
	  case HeaderEnd:        break;
	  case ExtensionStart:
	  case ExtensionContinue:ParseStatus=ExtensionEnd;
	  case ExtensionEnd:     break;
	  }
	}

      if(!strcmp(identifier,"EXTEND"))
	{
	if(*value=='T') ExtensionExists = true;
	if(*value=='F') ExtensionExists = false;
	}

      if(!strncmp(identifier,"NAXIS",5))
	{
	if(identifier[5]==0)
	  Naxis = atoi(value);
	else
	  {
	  int AxNumber;

	  AxNumber = atoi(identifier+5) - 1;
	  if(AxNumber<MAX_AXIS && AxNumber>=0)
	    {
	    Axes[AxNumber] = atoi(value);
	    }
	  }
	}

      if(!strcmp(identifier,"SIMPLE"))
	Simple = *value;

      if(!strcmp(identifier,"XENDIAN"))
	{
	if(!strcmp(value,"'BIG'") || !strcmp(value,"BIG"))
	  Endian = 1;
	else
	  Endian = 0;
	}

      //printf("%s = %s / %s\n", identifier, value, comment);
      }

//     {LogMessage(LOG_DEBUG,_("ParseStatus %d of file %s"),ParseStatus,FileName).Print();}

     switch(ParseStatus)
       {
       case HeaderStart:      if(Simple!='T') goto ExitPoint;
			      if(BitPix==0) goto ExitPoint;
			      ParseStatus=HeaderContinue; break;
       case HeaderContinue:   break;
       case ExtensionStart:   ParseStatus=ExtensionContinue; break;
       case ExtensionContinue:break;
       case HeaderEnd:        // continues, no break please
       case ExtensionEnd:
	      {        // data should be read just here
	      if(Naxis>0)
		{
		long len = (Axes[0]==0) ? 1 : Axes[0];

		for(int i=1;i<Naxis;i++)
		  if(Axes[i]>0)
		    len *= Axes[i];

		len = labs(len * BitPix) / 8;  //fix for a proper length in bytes

		//printf(" len = %d, Bitpix = %d, Naxis = %d ", len, BitPix, Naxis);

		long FilePos = ftell(F);

		if(Naxis==2)
		{
		  Raster=CreateRaster2D(Axes[0],Axes[1],BitPix);
		  if(Raster==NULL) goto ExitPoint;

		  ldblk = (labs(Raster->GetPlanes())*Raster->GetSize1D()+7)/8;
		  for(j=0;j<Raster->Size2D;j++)
		  {
		    if(fread(Raster->GetRow(Raster->Size2D-j-1),ldblk,1,F)!=1) {goto ExitPoint;}
		    if(Endian == 1)  //!!! chyba !!!
		    {
		      switch(BitPix)
		      {
			case  64: FixSignedMSBValues((BYTE*)Raster->GetRow(Raster->Size2D-j-1), Raster->GetSize1D(), 8);
			case -64: swab64((BYTE*)Raster->GetRow(Raster->Size2D-j-1),Raster->GetSize1D());
				  break;
			case  32: FixSignedMSBValues((BYTE*)Raster->GetRow(Raster->Size2D-j-1), Raster->GetSize1D(), 4);
			case -32: swab32((BYTE*)Raster->GetRow(Raster->Size2D-j-1),Raster->GetSize1D());
				  break;
		      }
		    }
                    else
                    {
                      if(BitPix==64)
			FixSignedLSBValues((BYTE*)Raster->GetRow(Raster->Size2D-j-1), Raster->GetSize1D(), 8);
		      if(BitPix==32)
			FixSignedLSBValues((BYTE*)Raster->GetRow(Raster->Size2D-j-1), Raster->GetSize1D(), 4);
                    }

		//	AlineProc(j,p);
		  }
		}

		Img.AttachRaster(Raster);

		len = (len+2879)/2880;  //amount of blocks
		fseek(F, FilePos+len*2880, SEEK_SET);

//	        LogMessage(LOG_DEBUG,_("Processed %d blocks"),len).Print();
		}

	      if(ExtensionExists)
		 {
		 ParseStatus=ExtensionStart;
		 goto NewChunk;
		 }
	      }
       }

    } // header loop

ExitPoint:
  if(F) {fclose(F);F=NULL;}

  if(Raster!=NULL && Raster->UsageCount==0) delete Raster;
  return(Img);
}
#endif


#if SupportFITS>=3
/** This functions inserts one row into a HDU. */
int InsertRowHDU(char *buffer, const char *data)
{
int len;

  if(data==NULL) return 0;
  len = strlen(data);

  if(len>80) len = 80;

  (void)strncpy(buffer,data,len);
  return len;
}


int SavePictureFITS(const char *Name, const Image &Img)
{
FILE *f;
char HDU[36][80];
char depth;
Raster1DAbstract *RPixels = NULL;
unsigned ldblk;
unsigned y;

 if(Img.Raster==NULL) return(-10);

	/* Open output image file. */
 if((f=fopen(Name,"wb"))==NULL) return(-1);

 if(Img.Raster->GetPlanes() > 8)
   {
   if(Img.Raster->GetPlanes() > 16)
     {
     if(Img.Raster->GetPlanes() > 32)
       depth=64;
     else
       depth=32;
     }
   else
     depth=16;
   }
 else
   depth=8;

  ldblk = Img.Raster->GetSize1D() * (depth/8);
  switch(Img.Raster->GetPlanes())
  {
    case -64:ldblk = Img.Raster->GetSize1D()*8; depth=-64; break;
    case -32:ldblk = Img.Raster->GetSize1D()*4; depth=-32; break;
    case 8:  break;
    case 16: break;
    case 32: break;
    case 64: break;     // no pixels intermediate buffer needed
    default: RPixels = CreateRaster1D(Img.Raster->GetSize1D(), depth);
	     if(RPixels->Data1D==NULL) goto FINISH;
  }

	/* Initialize image header. */
  memset(HDU,' ',sizeof(HDU));
  InsertRowHDU(HDU[0], "SIMPLE  =                    T");
  y=sprintf(HDU[1],    "BITPIX  =                    %d", (int)depth);
  HDU[1][y] = ' ';
  InsertRowHDU(HDU[2], "NAXIS   =                    2");
  y = sprintf(HDU[3],  "NAXIS1  =           %10lu",(unsigned long)Img.Raster->GetSize1D());
  HDU[3][y] = ' ';
  y = sprintf(HDU[4],  "NAXIS2  =           %10lu",(unsigned long)Img.Raster->Size2D);
  HDU[4][y] = ' ';

  {
  int row = 5;

  if(Img.Raster->GetPlanes()<0)
    {
    double val;
    double Min,Max;

    Min = Max = Img.Raster->GetValue2Dd(0,0);
    for(y=0;y<Img.Raster->Size2D;y++)
      for(unsigned x=0;x<Img.Raster->GetSize1D();x++)
	{
	val = Img.Raster->GetValue2Dd(x,y);
	if(val<Min) Min=val;
	if(val>Max) Max=val;
	}
    y = sprintf(HDU[row],  "DATAMIN =           %10f",Min);
    HDU[row++][y] = ' ';
    y = sprintf(HDU[row],  "DATAMAX =           %10f",Max);
    HDU[row++][y] = ' ';
    }
  else
    {
    y = sprintf(HDU[row],  "DATAMIN =           %10u",0);
    HDU[row++][y] = ' ';
    if(depth==64)
      y = sprintf(HDU[row],  "DATAMAX =  9223372036854775807");	// "DATAMAX =  %19llu",0x7FFFFFFFFFFFFFFFll);
    else
      y = sprintf(HDU[row],  "DATAMAX =           %10lu",(unsigned long)1<<Img.Raster->GetPlanes());

    HDU[row++][y] = ' ';
    }
  if(depth>8 && depth<64)
    {
    y = sprintf(HDU[row],"BZERO   =           %10u", (depth<=16) ? 32768U : 2147483648U);
    HDU[row++][y] = ' ';
    }
  InsertRowHDU(HDU[row++], "HISTORY Created by pictures.");
  InsertRowHDU(HDU[row],   "END");
  }
  fwrite((void *)HDU,1,sizeof(HDU),f);

	/* Convert image to fits scale PseudoColor class. */
  y = Img.Raster->Size2D;
  while(y-->0)
    {
    if(RPixels)
      {
      RPixels->Set(*Img.Raster->GetRowRaster(y));
      fwrite(RPixels->Data1D,ldblk,1,f);
      }
    else
      {
      if(depth==-64 || depth==64)
	swab64((BYTE *)Img.Raster->GetRow(y), Img.Raster->GetSize1D());
      if(depth==64)
	FixSignedMSBValues((BYTE *)Img.Raster->GetRow(y), Img.Raster->GetSize1D(), 8);
      if(depth==-32 || depth==32)
	swab32((BYTE *)Img.Raster->GetRow(y), Img.Raster->GetSize1D());
      if(depth==32)
	FixSignedMSBValues((BYTE *)Img.Raster->GetRow(y), Img.Raster->GetSize1D(), 4);
        
      fwrite(Img.Raster->GetRow(y),ldblk,1,f);
      
      if(depth==64)
	FixSignedMSBValues((BYTE *)Img.Raster->GetRow(y), Img.Raster->GetSize1D(), 8);
      if(depth==-64 || depth==64)
	swab64((BYTE *)Img.Raster->GetRow(y), Img.Raster->GetSize1D());
      if(depth==32)
	FixSignedMSBValues((BYTE *)Img.Raster->GetRow(y), Img.Raster->GetSize1D(), 4);
      if(depth==-32 || depth==32)
	swab32((BYTE *)Img.Raster->GetRow(y), Img.Raster->GetSize1D());
      }
  }

	/* Calculate of padding */
  y = 2880 - (Img.Raster->Size2D * (long)ldblk) % 2880;
  if(y>0)
  {
    memset(HDU, 0, y);
    fwrite(HDU,y,1,f);
  }

FINISH:
  if(RPixels) {delete RPixels; RPixels=NULL;}
  fclose(f);
  return(0);
}	//SaveFITS
#endif


TImageFileHandler FITS_H(".FITS",
#if SupportFITS>=4 || SupportFITS==2
	LoadPictureFITS,
#else
	NULL,
#endif
#if SupportFITS>=3
	SavePictureFITS);
#else
	NULL);
#endif

TImageFileHandler FTS_H(".FTS",
#if SupportFITS>=4 || SupportFITS==2
	LoadPictureFITS,
#else
	NULL,
#endif
#if SupportFITS>=3
	SavePictureFITS);
#else
	NULL);
#endif

#endif
//------------------End of FITS routines------------------


//--------------------------GIF---------------------------
#ifdef SupportGIF

typedef struct
	{
	char SignatureMain[3];
	char SignatureRelease[3];
	WORD Width,Height;
	BYTE Flag,BackGround,Nul;
	} TypeGIFHeader;
typedef struct
	{
	WORD Left,Top,Width,Height;
	BYTE Flag;
	} TypeGIFImageDescriptor;

inline long LoadGIFHeader(FILE *f,TypeGIFHeader &SU)
{
#if defined(__PackedStructures__)
return(fread(&SU,1,sizeof(SU),f));
#else
return(loadstruct(f,"a3a3wwbbb",
	 &SU.SignatureMain,&SU.SignatureRelease,
	 &SU.Width,&SU.Height,&SU.Flag,&SU.BackGround,&SU.Nul));
#endif
}

inline long LoadGIFImageDescriptor(FILE *f,TypeGIFImageDescriptor &SU)
{
#if defined(__PackedStructures__)
return(fread(&SU,1,sizeof(SU),f));
#else
return(loadstruct(f,"wwwwb",
	 &SU.Left,&SU.Top,&SU.Width,&SU.Height,&SU.Flag));
#endif
}

class ABitStream
	{
public: BYTE *ptr;
	BYTE *RealBufStart,*BufEnd;
	DWORD BitBuf;
	WORD BufSize;
	BYTE BitPos;

	long FileLeft;
	FILE *f;
	BYTE Flag;

	BYTE *_BufEnd;
	BYTE m;
	BYTE n;

	void InitBitStream(void *p,WORD NewBufSize,FILE *file,long fsize);
	WORD Read_N(BYTE BitCount);
	virtual void RdFromFile(void)=0;	// Load bits from GIF file
	};

//This procedure make initialization of the bit stream
void ABitStream::InitBitStream(void *p,WORD NewBufSize,FILE *file,long fsize)
{
//----------------------}
  m=0x01;
  _BufEnd=(BYTE *)p+BufSize-1;
  n=0;
//---------------------}
  FileLeft=fsize;
  BufSize=NewBufSize & ~(WORD)1;
  RealBufStart=(BYTE *)p;
  ptr=(BYTE *)p;
  *RealBufStart=0;
  BufEnd=RealBufStart;
  BitPos=32;
  Flag=0;

  f=file;
}

/*This procedure read n bits from the bit stream*/
WORD ABitStream::Read_N(BYTE BitCount)
{
static const WORD bmsk[17]={0x0,0x1,0x3,0x7,0xF,0x1F,0x3F,0x7F,0xFF,
		     0x1FF,0x3FF,0x7FF,0xFFF,0x1FFF,0x3FFF,0x7FFF,0xFFFF};
WORD u;

 if(BitPos>=16)
	{
	BitBuf=BitBuf >> 16;
	BitPos-=16;
	if(ptr>=BufEnd) RdFromFile();
	BitBuf=BitBuf | ( (long)(*(WORD *)ptr) << 16 );
	ptr+=2;
	}
 u=BitBuf >> BitPos;
 BitPos+=BitCount;
 return(u & bmsk[BitCount]);
}

class GIFBitStream:public ABitStream
	{
public: virtual void RdFromFile(void);	// Load bits from GIF file
	};

void GIFBitStream::RdFromFile(void)		// Load bits from GIF file
{
BYTE len;
WORD ReadedB;

ReadedB=0;
if(Flag==1) *(RealBufStart)=*(BufEnd);

if(FileLeft>0)
	{
	ReadedB=fread(&len,1,1,f);
	if(len==0) len=255;
	if(ReadedB!=1) len=0;

	ptr=RealBufStart;
	if(Flag==1) ptr++;
	ReadedB=fread(ptr,1,len,f);
	FileLeft-=ReadedB;
	}

 if(ReadedB==0) FileLeft=0;		//EOF
 ptr=RealBufStart;
 BufEnd=RealBufStart;
 if(Flag==1) ReadedB++;
 if(ReadedB&1) {Flag=1;ReadedB--;}
	  else Flag=0;
 BufEnd+=ReadedB;

// if IOResult<>0 then FileLeft:=-1; {error}
}


void Add2Pixel(Raster2DAbstract *Raster,WORD Value,WORD &x,WORD &y,int &Interlace)
{
 if(!Raster) return;
 Raster->SetValue2D(x,y,Value);
 x++;
 if(x<Raster->GetSize1D()) return;
 x=0;
// if AlineProc!=NULL   AlineProc^.NextLine;

 if(Interlace<0)
	{
	y++;
	return;
	}

 switch(Interlace)
     {
     case 0:y+=8;
	    if(y>=Raster->Size2D)
	      {
	      Interlace++;
	      y=4;
	      }
	    break;
     case 1:y+=8;
	   if(y>=Raster->Size2D)
	      {
	      Interlace++;
	      y=2;
	      }
	   break;
     case 2:y+=4;
	    if(y>=Raster->Size2D)
	      {
	      Interlace++;
	      y=1;
	      }
	    break;
     case 3:y+=2;
	    break;
     }
}   //..Add2Pixel..}


Image LoadPictureGIF(const char *Name)
{
BYTE *OutCode=NULL;
WORD *Prefix=NULL,*Suffix=NULL;
WORD Nacteno;
FILE *f;
Image Img,*CurrImg;
WORD InCode,OldCode,CurCode,Code,ClearCode,OutCount,FirstFree,FreeCode,EOFCode,MaxCode;
BYTE FinChar,BitMask,CodeSize,InitCodeSize;
WORD X,Y;
int Interlace;
TypeGIFHeader GIFHeader;
TypeGIFImageDescriptor GIFImageDescriptor;
GIFBitStream bit;
void *CompBuffer;
Raster2DAbstract *Raster=NULL;
APalette *Palette=NULL,*LocalPalette=NULL;
const int GIFBufSize=512;
int I;

  CompBuffer=NULL;
  CurrImg=&Img;

  if((f=fopen(Name,"rb"))==NULL) return(NULL);

  if((X=LoadGIFHeader(f,GIFHeader))<13) goto FINISH;
  if(strncmp(GIFHeader.SignatureMain,"GIF",3)) goto FINISH;

  if(GIFHeader.Width==0||GIFHeader.Height==0) goto FINISH;
// if AlineProc!=NULL AlineProc^.InitPassing(Obr.y,'Loading GIF');

//  seek(soubor,Sizeof(GIFHeader));

  if((GIFHeader.Flag & 0x80)>0)  	/*Global Color Map*/
	{
	X=(unsigned)2 << (GIFHeader.Flag & 7);
	Palette=BuildPalette(X,8);
	if(Palette==NULL) goto FINISH;
	if(Palette->Data1D==NULL) goto FINISH;
	X*=3;
	Nacteno=fread(Palette->Data1D,1,X,f);
	if(Nacteno<X) goto FINISH;
	}
  /*?-Global Color Map*/

  if( (OutCode=(BYTE *)malloc(4096))==NULL) goto FINISH;
  if( (CompBuffer=(BYTE *)malloc(GIFBufSize))==NULL) goto FINISH;
  if( (Prefix=(WORD *)calloc(4096,sizeof(WORD)))==NULL) goto FINISH;

  if( (Suffix=(WORD *)calloc(4096,sizeof(WORD)))==NULL) goto FINISH;

  while(!feof(f))
    {
    I=fgetc(f);
//fpos_t pos;fgetpos(f,&pos);printf("%lX,%X\n",pos,I);
    switch(I)
       {
       case EOF:goto FINISH;	//Next Byte

       case 0x21:			   	/*?-Extended Bloks*/
	  if(fread(OutCode,1,2,f)!=2) goto FINISH;
	   //      WriteLn('Extension block type: ',Outcode^[0]);}
	  CodeSize=OutCode[1];
	  while(CodeSize>0)
	     {
	     Nacteno=fread(OutCode,1,CodeSize+1,f);
	     if(Nacteno!=CodeSize+1) goto FINISH;
	     CodeSize=OutCode[CodeSize];
	    }
	  break;

       case 0x2C:
	  if(LoadGIFImageDescriptor(f,GIFImageDescriptor)!=9) goto FINISH;
	  Interlace=-1;
	  if((GIFImageDescriptor.Flag & 64)>0) Interlace=0;
	  /*?-Image Descriptor*/

	  Raster=CreateRaster2D(GIFImageDescriptor.Width,GIFImageDescriptor.Height,
		NearAvailPlanes((((GIFImageDescriptor.Flag & 0x80)?GIFImageDescriptor.Flag:GIFHeader.Flag) & 7) + 1));
	  if(Raster==NULL) goto FINISH;

	  if(GIFImageDescriptor.Flag & 0x80) /*Local Color Map*/
		 {
		 X=(unsigned)2 << (GIFImageDescriptor.Flag & 7);
		 LocalPalette=BuildPalette(X,8);
		 if(LocalPalette==NULL) goto FINISH;
		 if(LocalPalette->Data1D==NULL) goto FINISH;
		 X*=3;
		 Nacteno=fread(LocalPalette->Data1D,1,X,f);
		 if(Nacteno<X) goto FINISH;
		 }

	  X=Y=0;
	  CodeSize=fgetc(f);
	  ClearCode=1 << CodeSize;
	  if(CodeSize==0) goto FINISH;			//GIF error

	  EOFCode = ClearCode+1;
	  FirstFree = ClearCode+2;
	  FreeCode = FirstFree;

	  CodeSize++;
	  InitCodeSize=CodeSize;

	  MaxCode=1 << CodeSize;

	  BitMask = GIFImageDescriptor.Flag & 7;  // Prefer bit depth in descriptor
	  if(BitMask==0) BitMask = GIFHeader.Flag & 7;	  // get it from header if not available
	  BitMask = (2<<BitMask) - 1;

	  OutCount=0;

	  bit.InitBitStream(CompBuffer,GIFBufSize,f,MAXLONG);

	  do {				// Decompress GIF raster
	     if(bit.FileLeft<0)
		 {			// Load error
		 goto FINISH;
		 }
	     Code=bit.Read_N(CodeSize);

	     if(Code!=EOFCode)
		{
		if(Code==ClearCode)
		   {
		   CodeSize=InitCodeSize;
		   MaxCode=1 << CodeSize;
		   FreeCode=FirstFree;

		   Code = bit.Read_N(CodeSize);

		   CurCode = Code;
		   OldCode = Code;
		   FinChar = Code & BitMask;
		   Add2Pixel (Raster,FinChar,X,Y,Interlace);
		   }
	       else
		   {
		   CurCode=Code;
		   InCode=Code;
		   if(Code>=FreeCode)
			{
			 CurCode=OldCode;
			 OutCode[OutCount]=FinChar;
			 OutCount++;
			 if(Code>FreeCode)
			     {
			     break;		//Compression Error
			     }
			 }
		   while(CurCode>=ClearCode)    //first vocambulary item
		        {
			OutCode[OutCount]=Suffix[CurCode];
			OutCount++;
			CurCode=Prefix[CurCode];
		        }
		   FinChar=CurCode & BitMask;
		   OutCode[OutCount]=FinChar;
		   OutCount++;
		   for(I=OutCount-1;I>=0;I--)
			       Add2Pixel(Raster,OutCode[I],X,Y,Interlace);
		   OutCount=0;
		   Prefix[FreeCode]=OldCode;
		   Suffix[FreeCode]=FinChar;
		   OldCode=InCode;
		   FreeCode++;
		   if(FreeCode>=MaxCode)
			{
			 if(CodeSize<12)
			    {
			    CodeSize++;
			    MaxCode=MaxCode*2;
			    }
			 else FreeCode=FirstFree;
			 }
		    }
		  }
	   } while(Code!=EOFCode);

	if(Img.Raster!=NULL)
		{
		CurrImg->Next=new Image;
		CurrImg=CurrImg->Next;
		}
	CurrImg->x=GIFImageDescriptor.Left/5.0;
//	CurrImg->y=(GIFHeader.Height-GIFImageDescriptor.Top-GIFImageDescriptor.Height)/5.0;
	CurrImg->y=(GIFImageDescriptor.Height)/5.0;
	CurrImg->dx=GIFImageDescriptor.Width/5.0;
	CurrImg->dy=GIFImageDescriptor.Height/5.0;
	if(Raster!=NULL) {CurrImg->AttachRaster(Raster);Raster=NULL;}
	if(LocalPalette) {CurrImg->AttachPalette(LocalPalette);LocalPalette=NULL;}
		    else if(Palette!=NULL){CurrImg->AttachPalette(Palette);}

	I=fgetc(f);
	if(I==EOF) goto FINISH;
	if(I!=0) ungetc(I,f);
	break;

     default:goto FINISH;
     }
  }

FINISH:
 if(f) fclose(f);

 if(CompBuffer!=NULL) free(CompBuffer);
 if(OutCode!=NULL) free(OutCode);
 if(Prefix!=NULL) free(Prefix);
 if(Suffix!=NULL) free(Suffix);

 if(Raster!=NULL && Raster->UsageCount==0) delete Raster;
 if(Palette!=NULL && Palette->UsageCount==0) delete Palette;
 if(LocalPalette!=NULL && LocalPalette->UsageCount==0) delete LocalPalette;
 return(Img);
} //LoadGIF


TImageFileHandler GIF_H(".GIF",
#if SupportGIF>=4 || SupportGIF==2
	LoadPictureGIF,
#else
	NULL,
#endif
//#if SupportGIF>=3
//	SavePictureGIF);
//#else
	NULL);
//#endif

#endif
//-------------------End of GIF routines------------------


//------------------HRZ--------------------------
#ifdef SupportHRZ

#if SupportHRZ>=4 || SupportHRZ==2
Image LoadPictureHRZ(const char *Name)
{
FILE  *f;
WORD y,x;
BYTE *pByte;
long ldblk;
Raster2DAbstract *Raster=NULL;
Image Img;

 if((f=fopen(Name,"rb"))==NULL) return(Img);

 if(FileSize(f)!=184320)
	{
	goto ENDPROC;
	}
 Raster=CreateRaster2D(256,240,24);
 if(Raster==NULL) goto ENDPROC;
// if AlineProc<>nil then AlineProc^.InitPassing(p.y,'Loading HRZ');

 ldblk = 3*Raster->GetSize1D();
 for(y=0;y<Raster->Size2D;y++)
   {
   pByte = (BYTE *)Raster->GetRow(y);
   if(fread(pByte,ldblk,1,f)!=1) {goto ENDPROC;}
   for(x=0;x<ldblk;x++)
      *pByte++ <<= 2;
 //	AlineProc(i,p);
   }

ENDPROC:
 fclose(f);
 Img.AttachRaster(Raster); 
 return(Img);
}

#endif


#if SupportHRZ>=3

/*
int SavePictureHRZ(const char *Name,const Image &Img)
{
FILE *f;
WORD ldblk;
WORD i,dummy;
char k;
//    Formater:PFormStruct;
char *TempData=NULL;

  if(Img.Raster==NULL) return(-10);

  if((f=fopen(Name,"wb"))==NULL) return(-1);

  if(Img.Raster->GetPlanes()!=24)
    {
    TempData = (char *)malloc(Raster->GetSize1D()*3);
    }

  for(i=0;i<Img.Raster->Size2D;i++)
	{
	if(TempData)
	  {
	  Img.Raster->GetRowRaster(i)->Get1Bit(TempData);
	  fwrite(TempData,ldblk,1,f);
	  }
	else
	  fwrite(Img.Raster->GetRow(i),ldblk,1,f);
	fwrite(&dummy,k,1,f);			//write till end of line
	// if AlineProc<>nil then AlineProc^.NextLine;
	}

FINISH:
  if(TempData) free(TempData);
  fclose(f);
  return(0);
}
*/
#endif


TImageFileHandler HRZ_H(".HRZ",
#if SupportHRZ>=4 || SupportHRZ==2
	LoadPictureHRZ,
#else
	NULL,
#endif
#if SupportHRZ>=3
	SavePictureHRZ);
#else
	NULL);
#endif


#endif
//-------------------End of HRZ routines------------------


//--------------------------ICO---------------------------
#ifdef SupportICO

typedef struct
	{
	WORD idReserved;
	WORD idType;
	WORD idCount;
	}IconHeader;
typedef struct
	{
	BYTE  bWidth;
	BYTE  bHeight;
	BYTE  bColorCount;
	BYTE  bReserved;
	WORD  wPlanes;
	WORD  wBitCount;
	DWORD dwBytesInRes;
	DWORD dwImageOffset;
	} IconDirectoryEntry;


#if SupportICO>=4 || SupportICO==2
Image LoadPictureICO(const char *Name)
{
FILE  *f;
WORD ldblk;
WORD i;
Raster2DAbstract *Raster=NULL;
APalette *Palette=NULL;
Image Img;
IconHeader Header;
IconDirectoryEntry Entry;
BMPInfo_Coreinfo Info;
BMP_RGBQuad RGB;

  if((f=fopen(Name,"rb"))==NULL) return(Img);
  if(fread(&Header,sizeof(Header),1,f)!=1) goto ENDPROC;

  if (Header.idReserved!=0 || Header.idType!=1 || Header.idCount<1)
	{
//	LoadPictureICO:=ErrAnother;
	goto ENDPROC;
	}

  if(fread(&Entry,sizeof(Entry),1,f)!=1) goto ENDPROC;
  fseek(f,Entry.dwImageOffset,SEEK_SET);
  if(fread(&Info,sizeof(Info),1,f)!=1) goto ENDPROC;

  if(Info.BIH.biWidth!=Entry.bWidth) // then {or(Info.biHeight<>Entry.bHeight)}
	{
//	LoadPictureICO:=ErrAnother;
	goto ENDPROC;
	}

 if(Entry.bColorCount==0) Entry.bColorCount=255;
 i = (int)(log((float)Entry.bColorCount)/log(2.0));
 if(i==2) i=4;
 if(i==7) i=8;

 Raster=CreateRaster2D(Entry.bWidth,Entry.bHeight,i);
 if(Raster==NULL) goto ENDPROC;
// if AlineProc<>nil then AlineProc^.InitPassing(p.y,'Loading ICO');

 Palette=BuildPalette(Entry.bColorCount,8);
 if(Palette!=NULL)
    {
    if(Entry.bColorCount<255) Entry.bColorCount--;
    if(Entry.bColorCount>2 && Entry.bColorCount<15) Entry.bColorCount=15;
    for(i=0;i<=Entry.bColorCount;i++)
	{
	fread(&RGB,sizeof(RGB),1,f);
	Palette->R(i,RGB.rgbRed);
	Palette->G(i,RGB.rgbGreen);
	Palette->B(i,RGB.rgbBlue);
	}
    if(GrayPalette(Palette,Raster->GetPlanes()))
	{
	delete Palette;
	Palette=NULL;
	}
    }

  ldblk=(Raster->GetPlanes()*Raster->GetSize1D()+7)/8; //XOR part
  for(i=Raster->Size2D;i>0;i--)
	{
	if(fread(Raster->GetRow(i-1),ldblk,1,f)!=1) {goto ENDPROC;}
 //	AlineProc(i,p);
	}

	//!!!!!!!!!!!		{AND part is omitted!}
ENDPROC:
 fclose(f);
 Img.AttachRaster(Raster);
 Img.AttachPalette(Palette); 
 return(Img);
}
#endif


#if SupportICO>=3
int SavePictureICO(const char *Name, const Image &Img)
{
FILE *f;
WORD Ldblk1,Ldblk;
int i,k;
IconHeader Header;
IconDirectoryEntry Entry;
BMPInfo_Coreinfo Info;
BMP_RGBQuad RGB;
void *Dummy;
APalette *Palette=NULL;

 if(Img.Raster==NULL) return(-10);
 if(Img.Raster->GetPlanes()>8 || Img.Raster->GetSize1D()>255 || Img.Raster->Size2D>255)
	return(-9); //image is too big to fit into the icon

 if((f=fopen(Name,"wb"))==NULL) return(-1);

 Header.idReserved=0;
 Header.idType=1;
 Header.idCount=1;

 if(fwrite(&Header,sizeof(Header),1,f)!=1) goto FINISH;

 Ldblk=((long)Img.Raster->GetPlanes()*Img.Raster->GetSize1D()+7) / 8;
 Ldblk1=((long)Img.Raster->GetSize1D()+7) / 8;

 Entry.bWidth=Img.Raster->GetSize1D();
 Entry.bHeight=Img.Raster->Size2D;
 Entry.bColorCount = 1 << Img.Raster->GetPlanes();
 if(Img.Raster->GetPlanes()==8) Entry.bColorCount=255;
 Entry.bReserved=0;
 Entry.wPlanes=0;
 Entry.wBitCount=0;
 Entry.dwImageOffset=sizeof(Entry) + sizeof(Header);
 Entry.dwBytesInRes=Entry.bHeight*(Ldblk+Ldblk1) + (1 << Img.Raster->GetPlanes())*sizeof(RGB) + sizeof(Info);

 Info.BIH.biSize=40;
 Info.BIH.biWidth=Img.Raster->GetSize1D();
 Info.BIH.biHeight=2*Img.Raster->Size2D;
 Info.BIH.biPlanes=1;
 Info.BIH.biBitCount=Img.Raster->GetPlanes();
 Info.BIH.biCompression=0;
 Info.BIH.biSizeImage=Img.Raster->GetSize1D()*(Ldblk+Ldblk1);
 Info.BIH.biXPelsPerMeter=0;
 Info.BIH.biYPelsPerMeter=0;
 Info.BIH.biClrUsed=0;
 Info.BIH.biClrImportant=0;

 if(fwrite(&Entry,sizeof(Entry),1,f)!=1) goto FINISH;
 if(fwrite(&Info,sizeof(Info),1,f)!=1) goto FINISH;

// if AlineProc<>nil then AlineProc^.InitPassing(2*p.y,'Saving ICO');

 Palette = Img.Palette;
 if(Palette==NULL) Palette = BuildPalette(1<<Img.Raster->GetPlanes(),8);
 k=Palette->GetPlanes()-8;
 if(k<0) k=0;
 for(i=0;i<(1 << Img.Raster->GetPlanes());i++)
	   {
	   RGB.rgbRed = Img.Palette->R(i)>>k;	//  p.palette^.pal[K].Red;
	   RGB.rgbGreen = Img.Palette->G(i)>>k;	// p.palette^.pal[K].Green;
	   RGB.rgbBlue = Img.Palette->B(i)>>k;	// p.palette^.pal[K].Blue;
	   fwrite(&RGB,sizeof(RGB),1,f);
	   }
 if(Palette!=Img.Palette) delete Palette;
 Palette=NULL;

 for(i=Entry.bHeight-1;i>=0;i--)	//XOR part
	{
	fwrite(Img.Raster->GetRow(i),Ldblk,1,f);
	// if AlineProc<>nil then AlineProc^.NextLine;
	}

 Dummy=malloc(Ldblk1);
 memset(Dummy,0,Ldblk1);
 for(i=Entry.bHeight-1;i>=0;i--)	//AND part is empty
	{
	fwrite(Dummy,Ldblk1,1,f);
	//if AlineProc<>nil then AlineProc^.NextLine;
	}
 free(Dummy);

FINISH:
  fclose(f);
  return(0);
}	//SaveICO
#endif


TImageFileHandler ICO_H(".ICO",
#if SupportICO>=4 || SupportICO==2
	LoadPictureICO,
#else
	NULL,
#endif
#if SupportICO>=3
	SavePictureICO);
#else
	NULL);
#endif

#endif
//-------------------End of ICO routines------------------


//----------------------- Load MAC ----------------------
#ifdef SupportMAC

Image LoadPictureMAC(const char *Name)
{
FILE  *f;
WORD x8,y;
BYTE rep,b;
BYTE *DataPtr;
WORD ldblk;
Raster2DAbstract *Raster = NULL;
Image Img;

 if((f=fopen(Name,"rb"))==NULL) return(Img);

 RdWORD_LoEnd(&ldblk,f);
 if((ldblk & 0xFF)!=0)
	{
//	LoadPictureMAC=ErrAnother;
	goto FINISH;
	}

 if(ldblk==0)		//???? don't know why
   fseek(f,0x200,SEEK_SET);
 else
   fseek(f,0x280,SEEK_SET);

 Raster = CreateRaster2D(576,720,1);
 if(Raster==NULL) goto FINISH;
// if AlineProc!=nil then
//	AlineProc^.InitPassing(p.y,'Loading MAC');

 ldblk = (Raster->GetPlanes()*Raster->GetSize1D()) /8;

 x8=0; y=0;
 DataPtr = (BYTE *)Raster->GetRow(0);
 while(y<Raster->Size2D)
   {
   rep = fgetc(f);
   if(feof(f)) break;

   if( rep>=128 || rep<=0)
     {
     b = ~fgetc(f);

     rep = ~rep + 2;
     while(rep>0)
       {
       *DataPtr++ = b;
       x8++;
       rep--;
       if(x8>=ldblk)
	 {
	 x8=0;
	 y++;
	 if(y>=Raster->Size2D)
	   {
           delete Raster;
           Raster = NULL;
           goto FINISH;
           }
	 DataPtr = (BYTE *)Raster->GetRow(y);
	   //if AlineProc!=nil then AlineProc^.NextLine;
	 }
       }
      }
   else
     {
     rep++;
     while(rep>0)
       {
       b = ~fgetc(f);
       *DataPtr++ = b;
       x8++;
       rep--;
       if(x8>=ldblk)
	 {
	 x8=0;
	 y++;
	 if(y>=Raster->Size2D)
	   {
           delete Raster;
           Raster = NULL;
           goto FINISH;
           }
	 DataPtr = (BYTE *)Raster->GetRow(y);
	   //if AlineProc!=nil then AlineProc^.NextLine;	 
	 }
       }
     }
   }

FINISH:
 fclose(f);
 //if IOResult!=0 then LoadPictureMACErrRdDisk;
 Img.AttachRaster(Raster); 
 return Img;
}  //LoadMAC


TImageFileHandler MAC_H(".MAC",
#if SupportMAC>=4 || SupportMAC==2
	LoadPictureMAC,
#else
	NULL,
#endif
#if SupportMAC>=3
	SavePictureMAC);
#else
	NULL);
#endif

#endif
//------------------End of - Load MAC --------------------


//--------------------------MAT---------------------------
#ifdef SupportMAT


typedef struct {
	char identific[124];
	WORD ff_version;
	char idx[2];
	DWORD DataType;
	DWORD ObjectSize;
	DWORD unknown1;
	DWORD unknown2;

	DWORD StructureFlagClass;
	DWORD unknown3;
	DWORD unknown4;
	DWORD DimFlag;

	DWORD SizeX;
	DWORD SizeY;
	//Size Z optionally
	DWORD Unknown5;		//only for 3D matrix (RGB)
	WORD Flag1;
	WORD NameFlag;
	} MATHeader;

typedef enum
  {
    miINT8 = 1,			/* 8 bit signed */
    miUINT8,			/* 8 bit unsigned */
    miINT16,			/* 16 bit signed */
    miUINT16,			/* 16 bit unsigned */
    miINT32,			/* 32 bit signed */
    miUINT32,			/* 32 bit unsigned */
    miSINGLE,			/* IEEE 754 single precision float */
    miRESERVE1,
    miDOUBLE,			/* IEEE 754 double precision float */
    miRESERVE2,
    miRESERVE3,
    miINT64,			/* 64 bit signed */
    miUINT64,			/* 64 bit unsigned */
    miMATRIX,		        /* MATLAB array */
    miCOMPRESSED,	        /* Compressed Data */
    miUTF8,		        /* Unicode UTF-8 Encoded Character Data */
    miUTF16,		        /* Unicode UTF-16 Encoded Character Data */
    miUTF32			/* Unicode UTF-32 Encoded Character Data */
  } mat5_data_type;

typedef enum
  {
    mxCELL_CLASS = 1,		/* cell array */
    mxSTRUCT_CLASS,		/* structure */
    mxOBJECT_CLASS,		/* object */
    mxCHAR_CLASS,		/* character array */
    mxSPARSE_CLASS,		/* sparse array */
    mxDOUBLE_CLASS,		/* double precision array */
    mxSINGLE_CLASS,		/* single precision floating point */
    mxINT8_CLASS,		/* 8 bit signed integer */
    mxUINT8_CLASS,		/* 8 bit unsigned integer */
    mxINT16_CLASS,		/* 16 bit signed integer */
    mxUINT16_CLASS,		/* 16 bit unsigned integer */
    mxINT32_CLASS,		/* 32 bit signed integer */
    mxUINT32_CLASS,		/* 32 bit unsigned integer */
    mxINT64_CLASS,		/* 64 bit signed integer */
    mxUINT64_CLASS,		/* 64 bit unsigned integer */
    mxFUNCTION_CLASS            /* Function handle */
  } arrayclasstype;

#define FLAG_COMPLEX 0x800
#define FLAG_GLOBAL  0x400
#define FLAG_LOGICAL 0x200

#define STRUCTURE_CLASS(x) ((x.StructureFlagClass)&0xFF)
#define STRUCTURE_FLAG(x) ((x.StructureFlagClass>>8)&0xFF)

/**This procedure loads 2D data from MATLAB MAT file*/
#if SupportMAT>=4 || SupportMAT==2

Image LoadPictureMAT(const char *Name)
{
SBYTE Depth;
WORD iy, ix;
MATHeader MATLAB_HDR;
DWORD size;
Image Img;
Raster2DAbstract *Raster=NULL;
FILE *f;
Raster1D_8Bit RBit8;


DWORD CellType,ldblk,z;
int (*RdWORD_xxEnd)( WORD *num, FILE *f );
int (*RdDWORD_xxEnd)( DWORD *num, FILE *f );

  if((f=fopen(Name,"rb"))==NULL) return(Img);

  fread(&MATLAB_HDR,1,124+2+2,f);
  if (strncmp(MATLAB_HDR.identific,"MATLAB",6)) goto FINISH;
  if (!strncmp(MATLAB_HDR.idx,"IM",2))
    {
    RdWORD_xxEnd = RdWORD_LoEnd;
    RdDWORD_xxEnd = RdDWORD_LoEnd;
    }
  else if(!strncmp(MATLAB_HDR.idx,"MI",2))
    {
    RdWORD_xxEnd = RdWORD_HiEnd;
    RdDWORD_xxEnd = RdDWORD_HiEnd;
    }
  else goto FINISH;	//unsupported endian

  loadstruct(f,(MATLAB_HDR.idx[0]=='M')?"DDDDDDDDDD":"dddddddddd",
	 &MATLAB_HDR.DataType,	&MATLAB_HDR.ObjectSize,
	 &MATLAB_HDR.unknown1,	&MATLAB_HDR.unknown2,
	 &MATLAB_HDR.StructureFlagClass,&MATLAB_HDR.unknown3,
	 &MATLAB_HDR.unknown4,  &MATLAB_HDR.DimFlag,
	 &MATLAB_HDR.SizeX,	&MATLAB_HDR.SizeY);

  if(MATLAB_HDR.DataType!=miMATRIX) goto FINISH;
  switch(MATLAB_HDR.DimFlag)
    {
    case  8: z=1; break;	  //2D matrix
    case 12: RdDWORD_xxEnd(&z,f); //3D matrix RGB
	     RdDWORD_xxEnd(&MATLAB_HDR.Unknown5,f);
	     if(z!=3) goto FINISH;
	     break;
    default: goto FINISH;
    }
  RdWORD_xxEnd(&MATLAB_HDR.Flag1,f);
  RdWORD_xxEnd(&MATLAB_HDR.NameFlag,f);

  if(STRUCTURE_CLASS(MATLAB_HDR) != mxDOUBLE_CLASS &&
     STRUCTURE_CLASS(MATLAB_HDR) != mxSINGLE_CLASS &&
     STRUCTURE_CLASS(MATLAB_HDR) != mxUINT8_CLASS &&	//uint8 + 3D
     STRUCTURE_CLASS(MATLAB_HDR) != mxUINT16_CLASS &&	//uint16 + 3D
     STRUCTURE_CLASS(MATLAB_HDR) != mxUINT32_CLASS	//uint16 + 3D
     ) goto FINISH;

  switch(MATLAB_HDR.NameFlag)
    {
    case 0:RdDWORD_xxEnd(&size,f);	/*Object name string size*/
	   size=4*(long)((size+3+1)/4);
	   fseek(f,size,SEEK_CUR);
    case 1:
    case 2:
    case 3:
    case 4:fread(&size,1,4,f);		/*Object name string*/
	   break;
    default:goto FINISH;
    }

   RdDWORD_xxEnd(&CellType,f);	/*Additional object type*/
/*fprintf(stdout,"Cell type:%ld\n",CellType);*/

   RdDWORD_xxEnd(&size,f);	/*data size*/
//  if(size!=2) goto FINISH;

   Depth=0;
   switch(CellType)
      {
      case miUINT8:
	     if(MATLAB_HDR.StructureFlagClass & FLAG_LOGICAL)
		Depth=1;		   /*Byte type cell*/
	     else
		Depth=8;		   /*Byte type cell*/
	     ldblk=(long) MATLAB_HDR.SizeX;
	     if(MATLAB_HDR.StructureFlagClass & FLAG_COMPLEX) goto FINISH; //MATLAB_KO;
	     break;
      case miUINT16:
	     Depth=16;		  /*Word type cell*/
	     ldblk=(long) (2*MATLAB_HDR.SizeX);
	     // BUG! endians must be swapped
	     if(MATLAB_HDR.StructureFlagClass & FLAG_COMPLEX) goto FINISH; //MATLAB_KO;
	     break;
      case miUINT32:
	     Depth=32;		  /*DWord type cell*/
	     ldblk=(long) (4*MATLAB_HDR.SizeX);
	     // BUG! endians must be swapped
	     if(MATLAB_HDR.StructureFlagClass & FLAG_COMPLEX) goto FINISH; //MATLAB_KO;
	     break;
      case miSINGLE:Depth=-32;	//float type cell
	     if(sizeof(float)!=4) goto FINISH;
	     if(MATLAB_HDR.StructureFlagClass & FLAG_COMPLEX)
		  {      	//complex double type cell
		  goto FINISH; //MATLAB_KO;
		  }
	     if(z>=3) goto FINISH; //MATLAB_KO;
	     ldblk = (long)4*MATLAB_HDR.SizeX;
	     break;
      case miDOUBLE:Depth=-64;	//double type cell
	     if(sizeof(double)!=8) goto FINISH;
	     if(MATLAB_HDR.StructureFlagClass & FLAG_COMPLEX)
		  {      	//complex double type cell
		  goto FINISH; //MATLAB_KO;
		  }
	     if(z>=3) goto FINISH; //MATLAB_KO;
	     ldblk = (long)8*MATLAB_HDR.SizeX;
	     break;
      default:goto FINISH;
      }

  if(MATLAB_HDR.SizeX==0 || MATLAB_HDR.SizeY==0 || Depth==0)
	goto FINISH;

  if(z==3)
    Raster = CreateRaster2D(MATLAB_HDR.SizeY,MATLAB_HDR.SizeX,24);
  else
    Raster = CreateRaster2D(MATLAB_HDR.SizeY,MATLAB_HDR.SizeX,Depth);
  if(Raster==NULL) goto FINISH;

  if(z==3)
    {
    Raster1DAbstract *Ras=NULL;
    RBit8.Allocate1D(MATLAB_HDR.SizeX);
    if(RBit8.Data1D==NULL) goto FINISH;
    if(Depth!=8)
      {
      Ras=CreateRaster1D(MATLAB_HDR.SizeX,Depth);
      if(Ras==NULL) goto FINISH_LOOP;
      }

    while(z>0)
      {
      for(iy=0;iy<MATLAB_HDR.SizeY;iy++)
	{
	if(Depth==8)
	  {if(fread(RBit8.Data1D,MATLAB_HDR.SizeX,1,f)!=1) goto FINISH_LOOP;}
	else
	  {
	  if(fread(Ras->Data1D,ldblk,1,f)!=1) goto FINISH_LOOP;
	  Ras->Get(RBit8);
	  }

	  /* Rotate image data by 90 degs */
	int shift = Raster->GetPlanes()-8*z;
	DWORD mask = ~(0xFF<<shift);
	for(ix=0;ix<MATLAB_HDR.SizeX;ix++)
	  {
	  Raster->SetValue2D(iy,ix, (Raster->GetValue2D(iy,ix)&mask)|(DWORD)(RBit8.GetValue1D(ix))<<shift);
	  }
	}
      z--;
      }
FINISH_LOOP:
    if(Ras) delete(Ras);
    }
  else
    {
    RBit8.Allocate1D(ldblk);
    if(RBit8.Data1D==NULL) goto FINISH;

    for(iy=0;iy<MATLAB_HDR.SizeY;iy++)
      {
      if(fread(RBit8.Data1D,ldblk,1,f)!=1)
		goto FINISH;
	/* Rotate image data by 90 degs */
      for(ix=0;ix<MATLAB_HDR.SizeX;ix++)
	{
	switch(Depth)
	  {
	  case 1:  Raster->SetValue2D(iy,ix,((BYTE *)(RBit8.Data1D))[ix]?1:0); break;
	  case 8:  Raster->SetValue2D(iy,ix,((BYTE *)(RBit8.Data1D))[ix]); break;
	  case 16: Raster->SetValue2D(iy,ix,((WORD *)(RBit8.Data1D))[ix]); break;
	  case 32: Raster->SetValue2D(iy,ix,((DWORD *)(RBit8.Data1D))[ix]); break;
	  case -32:Raster->SetValue2Dd(iy,ix,((float *)(RBit8.Data1D))[ix]); break;
	  case -64:Raster->SetValue2Dd(iy,ix,((double *)(RBit8.Data1D))[ix]); break;
	  }
	}
      }
    }

FINISH:
  if(RBit8.Data1D) RBit8.Erase();;

  fclose(f);
  Img.AttachRaster(Raster);  
  return(Img);
}
#endif


#if SupportMAT>=3

static const char *MonthsTab[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
static const char *DayOfWTab[7]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
#if defined(_WIN32) || defined(__WIN32__) || defined(__DOS__) || defined(__DJGPP__)
 static const char *OsDesc="PCWIN";
#else
 static const char *OsDesc="LNX86";
#endif

/** This procedure fills common stuff into the matlab header. */
static void BuildMAT_TXT(char *Header)
{
  const struct tm *t;
  time_t current_time;

  current_time=time((time_t *) NULL);
  t=localtime(&current_time);
  sprintf(Header,"MATLAB 5.0 MAT-file, Platform: %s, Created on: %s %s %2d %2d:%2d:%2d %d",
    OsDesc,
    DayOfWTab[t->tm_wday],
    MonthsTab[t->tm_mon],
    t->tm_mday,
    t->tm_hour,t->tm_min,t->tm_sec,
    t->tm_year+1900);
  Header[0x7D]=1;
  Header[0x7E]='I';
  Header[0x7F]='M';
}


/**This procedure saves image data into MATLAB MAT file*/
int SavePictureMAT(const char *Name, const Image &Img)
{
FILE *f;
WORD iy;
SBYTE padding=0;
int IsColor=0;

  if(Img.Raster==NULL) return(-10);
  if((f=fopen(Name,"wb"))==NULL) return(-1);

  IsColor = Img.Raster->GetPlanes()==24;

  char MATLAB_HDR[184];
  DWORD DataSize;

  DataSize=(DWORD)Img.Raster->GetSize1D() * (DWORD)Img.Raster->Size2D;

  memset(MATLAB_HDR,' ',124);
  memset(MATLAB_HDR+124,0,sizeof(MATLAB_HDR)-124);

  BuildMAT_TXT(MATLAB_HDR);

  *(DWORD *)&(MATLAB_HDR[0x80])=miMATRIX;
  MATLAB_HDR[0x88]=0x6;
  MATLAB_HDR[0x8C]=mxUINT8_CLASS;
  MATLAB_HDR[0x90]=0x6;
  MATLAB_HDR[0x98]=0x5;
  MATLAB_HDR[0x9C] = IsColor?12:0x8;         //DimFlag
  *(DWORD *)&(MATLAB_HDR[0xA0])=Img.Raster->Size2D;  //Rotate image 90 degs
  *(DWORD *)&(MATLAB_HDR[0xA4])=Img.Raster->GetSize1D();  //Rotate image 90 degs
  MATLAB_HDR[0xA8]=1;
  MATLAB_HDR[0xAA]=1;   		//NameFlag
  MATLAB_HDR[0xAC]='M';                 //matrix name
  if(IsColor)
    {
    MATLAB_HDR[0xB0]=miUINT8;	//BYTE
    DataSize *= 3;
    }
  else
    {
    switch(Img.Raster->GetPlanes())
      {
      case  1:
      case  2:
      case  4:
      case  8: MATLAB_HDR[0xB0]=miUINT8;
	       MATLAB_HDR[0x8C]=mxUINT8_CLASS;
	       break;					//BYTE
      case 16: MATLAB_HDR[0xB0]=miUINT16;
	       MATLAB_HDR[0x8C]=mxUINT16_CLASS;
	       DataSize *= 2;
	       break;					//WORD
      case 24:
      case 32: MATLAB_HDR[0xB0]=miUINT32;
	       MATLAB_HDR[0x8C]=mxUINT32_CLASS;
	       DataSize *= 4;
	       break;					//DWORD
      case -32:MATLAB_HDR[0xB0]=miSINGLE;
	       MATLAB_HDR[0x8C]=mxSINGLE_CLASS;
	       DataSize *= 4;
	       break;
      case -64:MATLAB_HDR[0xB0]=miDOUBLE;
	       MATLAB_HDR[0x8C]=mxDOUBLE_CLASS;
	       DataSize *= 8;
	       break;
      default: goto FINISH;
      }
    }

  padding=((BYTE)(DataSize-1) & 0x7) ^ 0x7;
  *(DWORD *)&(MATLAB_HDR[0x84]) = DataSize + 56l + (DWORD)padding;

  *(DWORD *)&(MATLAB_HDR[0xB4])=DataSize;

  unsigned ix;
  if(IsColor)
    {
    fwrite(MATLAB_HDR,1,sizeof(MATLAB_HDR)-16,f);
    DataSize = 3;       //z order
    Wr_dword(f,DataSize);
    DataSize = 0;       //Unknown 5
    Wr_dword(f,DataSize);
    fwrite(MATLAB_HDR+sizeof(MATLAB_HDR)-16,1,16,f); // co to je????? !!!!

    BYTE *ptrLineX;
    ptrLineX = (BYTE *)malloc(Img.Raster->Size2D);  // traverse by y

    for(IsColor=0;IsColor<=16;IsColor+=8)
      {
      for(ix=0; ix<Img.Raster->GetSize1D();ix++)
	{
	for(iy=0;iy<Img.Raster->Size2D;iy++)
	  {
	  ptrLineX[iy] = ((DWORD)Img.GetPixel(ix,iy)>>IsColor) & 0xFF;
	  }
	fwrite(ptrLineX,Img.Raster->Size2D,1,f);
	}
      }
    if(ptrLineX) {free(ptrLineX);ptrLineX=NULL;}
    }
  else
    {
    fwrite(MATLAB_HDR,1,sizeof(MATLAB_HDR),f);

    switch(MATLAB_HDR[0xB0])
    {
      case miUINT8:
	{
	BYTE *ptrLineX;
	ptrLineX = (BYTE *)malloc(Img.Raster->Size2D);   // traverse by y
	if(ptrLineX==NULL) break;
	for(ix=0; ix<Img.Raster->GetSize1D();ix++)
	  {
	  for(iy=0;iy<Img.Raster->Size2D;iy++)
	    {
	    ptrLineX[iy] = Img.GetPixel(ix,iy); //Gray image 8 bit, rotated 90 degs
	    }
	  fwrite(ptrLineX,Img.Raster->Size2D,1,f);
	  }
	if(ptrLineX) {free(ptrLineX);ptrLineX=NULL;}
	break;
	}
      case miUINT16:
	{
	WORD *ptrLineX;

	ptrLineX = (WORD *)malloc(2*Img.Raster->Size2D);
	if(ptrLineX==NULL) break;
	for(ix=0; ix<Img.Raster->GetSize1D();ix++)
	  {
	  for(iy=0;iy<Img.Raster->Size2D;iy++)
	    {
	    ptrLineX[iy] = Img.GetPixel(ix,iy); //Gray image 16 bit, rotated 90 degs
	    }

	  fwrite(ptrLineX,2*Img.Raster->Size2D,1,f);
	  }
	if(ptrLineX) {free(ptrLineX);ptrLineX=NULL;}
	break;
	}
      case miSINGLE:
	{
	float *ptrLineX;

	ptrLineX = (float *)malloc(sizeof(float)*Img.Raster->Size2D);
	if(ptrLineX==NULL) break;
	for(ix=0; ix<Img.Raster->GetSize1D();ix++)
	  {
	  for(iy=0;iy<Img.Raster->Size2D;iy++)
	    {
	    ptrLineX[iy] = Img.Raster->GetValue2Dd(ix,iy); //float image 32 bit, rotated 90 degs
	    }

	  fwrite(ptrLineX,sizeof(float)*Img.Raster->Size2D,1,f);
	  }
	if(ptrLineX) {free(ptrLineX);ptrLineX=NULL;}
	break;
	}
      case miDOUBLE:
	{
	double *ptrLineX;

	ptrLineX = (double *)malloc(sizeof(double)*Img.Raster->Size2D);
	if(ptrLineX==NULL) break;
	for(ix=0; ix<Img.Raster->GetSize1D();ix++)
	  {
	  for(iy=0;iy<Img.Raster->Size2D;iy++)
	    {
	    ptrLineX[iy] = Img.Raster->GetValue2Dd(ix,iy); //double image 64 bits, rotated 90 degs
	    }

	  fwrite(ptrLineX,sizeof(double)*Img.Raster->Size2D,1,f);
	  }
	if(ptrLineX) {free(ptrLineX);ptrLineX=NULL;}
	break;
	}
      }
    }

  while(padding-->0) fputc(0,f);
FINISH:
  fclose(f);
  return(0);
}
#endif


TImageFileHandler MAT_H(".MAT",
#if SupportMAT>=4 || SupportMAT==2
	LoadPictureMAT,
#else
	NULL,
#endif
#if SupportMAT>=3
	SavePictureMAT);
#else
	NULL);
#endif

#endif
//-------------------End of MAT routines------------------


//--------------------------OKO---------------------------
#ifdef SupportOKO

typedef struct
	{
	char  identific[80];
	WORD  ver;
	WORD  modif;
	WORD  Histogram;
	WORD  Text;
	WORD  rows;
	WORD  cols;
	WORD  levels;
	WORD  identif;
	char dummy[416];
	}OkoHeader;


#if SupportOKO>=4 || SupportOKO==2
Image LoadPictureOKO(const char *Name)
{
FILE  *f;
WORD ldblk;
WORD i;
Raster2DAbstract *Raster=NULL;
Image Img;
OkoHeader Header;

  if((f=fopen(Name,"rb"))==NULL) return(Img);

  if(fread(&Header,sizeof(Header),1,f)!=1) goto ENDPROC;
  if(strncmp(Header.identific,"OBR2 Image File",15)) goto ENDPROC;

  if(Header.levels==0) goto ENDPROC;	//wrong image
  //printf(" %d %f \n\r",Header.levels,(log((float)(Header.levels+1))/log(2.0))+1e-3);
  Raster=CreateRaster2D(Header.rows,Header.cols,(int)(log((float)(Header.levels+1))/log(2.0)+1e-3));
  if(Raster==NULL) goto ENDPROC;

// if AlineProc<>nil then AlineProc^.InitPassing(p.y,'Loading OKO');
  fseek(f,0x200,SEEK_SET);

  ldblk=(Raster->GetPlanes()*Raster->GetSize1D()+7)/8;
  for(i=0;i<Raster->Size2D;i++)
	{
	if(fread(Raster->GetRow(i),ldblk,1,f)!=1) {goto ENDPROC;}
 //	AlineProc(i,p);
	}

ENDPROC:
 fclose(f);
 Img.AttachRaster(Raster); 
 return(Img);
}
#endif


#if SupportOKO>=3
int SavePictureOKO(const char *Name, const Image &Img)
{
FILE *f;
WORD ldblk;
WORD i;
OkoHeader Header;
Raster1DAbstract *ConvertMe=NULL;

  if(Img.Raster==NULL) return(-10);

  memset(&Header,sizeof(Header),0);

  Header.rows=Img.Raster->GetSize1D();
  Header.cols=Img.Raster->Size2D;
  Header.ver=3;
  Header.modif=5;
  if(Img.Raster->GetPlanes()>=16 || Img.Raster->GetPlanes()<0)
    {
    Header.levels = 0xFFFF;
    ldblk = Header.rows * 2l;
    if(Img.Raster->GetPlanes()>16 ||  	//OKO cannot store more than 16bits
       Img.Raster->GetPlanes()<0 )      //OKO cannot store float values
	 ConvertMe = CreateRaster1D(Img.Raster->GetSize1D(),16);
    }
  else
    {
    Header.levels = 1 << Img.Raster->GetPlanes();
    ldblk=((long)Img.Raster->GetPlanes()*Header.rows+7) / 8;
    }
  strcpy(Header.identific,"OBR2 Image File v3.05");

  if((f=fopen(Name,"wb"))==NULL) return(-1);

  if(fwrite(&Header,sizeof(Header),1,f)!=1) goto FINISH;

  for(i=0;i<Header.cols;i++)
	{
	if(ConvertMe!=NULL)
	  {
	  ConvertMe->Set(*Img.Raster->GetRowRaster(i));
	  fwrite(ConvertMe->Data1D,ldblk,1,f);
	  }
	else
	  fwrite(Img.Raster->GetRow(i),ldblk,1,f);
	// if AlineProc<>nil then AlineProc^.NextLine;
	}

FINISH:
  fclose(f);
  if(ConvertMe) {delete ConvertMe; ConvertMe=NULL;}
  return(0);
}
#endif


TImageFileHandler OKO_H(".OKO",
#if SupportOKO>=4 || SupportOKO==2
	LoadPictureOKO,
#else
	NULL,
#endif
#if SupportOKO>=3
	SavePictureOKO);
#else
	NULL);
#endif

#endif
//-------------------End of OKO routines------------------


//-----------------------PBM------------------------------
#ifdef SupportPBM

#if SupportPBM>=4 || SupportPBM==2

Image LoadPicturePBM(const char *Name)
{
FILE *f;
WORD x,y;
char ch;
char a[255];
int binary;
long i;
Raster2DAbstract *Raster=NULL;
Image Img;

 if((f=fopen(Name,"rb"))==NULL) return(Img);

 ch=' ';
 ReadWord(f,a,sizeof(a),&ch);

 if(*a!='P') goto ENDPROC;
 if(strlen(a)!=2) goto ENDPROC;
 i=a[1]-'0';

 do
   {
   ReadWord(f,a,sizeof(a),&ch);
   if(a[0]=='#') readln(f);
   if(feof(f)) goto ENDPROC;
   } while(a[0]=='#');
 if(*a==0) goto ENDPROC;

 switch(i)
   {
   case 1: x=atol(a);
	   y=ReadInt(f,&ch);
	   if(x<=0) goto ENDPROC;
	   Raster=CreateRaster2D(x,y,1);
	   binary=0;
	   break;
   case 2: x=atol(a);
	   y=ReadInt(f,&ch);
	   i=NearAvailPlanes(ReadInt(f,&ch));
	   if(x<=0) goto ENDPROC;
	   Raster=CreateRaster2D(x,y,i);
	   binary=0;
	   break;
   case 3: x=atol(a);		//true color text
	   y=ReadInt(f,&ch);
	   i=ReadInt(f,&ch);
	   Raster=CreateRaster2D(x,y,24);
	   //p.typ:='C';
	   //p.planes:=8;
	   //p.x:=p.x * 3;
	   binary=0;
	   break;
   case 4: x=atol(a);
	   y=ReadInt(f,&ch);
	   if(x<=0) goto ENDPROC;
	   Raster=CreateRaster2D(x,y,1);
	   binary=1;
	   break;
   case 5: x=atol(a);		//gray level
	   y=ReadInt(f,&ch);
	   if(x<=0) goto ENDPROC;
	   i=ReadInt(f,&ch);
	   if(i!=255) goto ENDPROC;
	   Raster=CreateRaster2D(x,y,8);
	   binary=1;
	   break;
   case 6: x=atol(a);		//binary true color 24bit format
	   y=ReadInt(f,&ch);
	   i=ReadInt(f,&ch);
	   if(i!=255) goto ENDPROC;
	   if(x<=0) goto ENDPROC;
	   Raster=CreateRaster2D(x,y,24);
	   binary=1;
	   //p.typ='C';
	   break;
   default: goto ENDPROC;
   }

 if(Raster==NULL) goto ENDPROC;

 //if AlineProc<>nil then
 // 	AlineProc^.InitPassing(p.y,'Loading PBM');

 y=0;
 x=0;
 if(binary!=0)		//Binary modification
	{
	i=(long)(Raster->GetPlanes()*Raster->GetSize1D()+7) / 8;
	for(y=0;y<Raster->Size2D;y++)
	  {
	  if(fread(Raster->GetRow(y),i,1,f)!=1) goto ENDPROC;
	  if(Raster->GetPlanes()==1)
	    NotR((char *)Raster->GetRow(y),i);
 //	  if(AlineProc) AlineProc(i,p);
	  }
	}
   else {		//Text modification
	ch=' ';
	while(!feof(f)) 	//load picture data
	  {
	  if(ch=='#') {readln(f);ch='\13';continue;}
	  if(isspace(ch)) {ch=fgetc(f);continue;}
	  if(isalpha(ch)) break;	//unexpected character occured

	  i=ReadInt(f,&ch);
	  if(ch=='.') ReadInt(f,&ch);	//dummy read frac part
	  if(Raster->GetPlanes()==24)
	    {
	    i+=256*ReadInt(f,&ch);
	    if(ch=='.') ReadInt(f,&ch);	//dummy read frac part
	    i+=65536*ReadInt(f,&ch);
	    if(ch=='.') ReadInt(f,&ch);	//dummy read frac part
	    }

	  Raster->SetValue2D(x,y,i);
	  x++;
	  if(x>=Raster->GetSize1D())
	    {
	    x=0;
	    if(Raster->GetPlanes()==1)  //binary images are inverted
	      NotR((char *)Raster->GetRow(y),(Raster->GetSize1D()+7)/8);
	    y++;
	    if(y>=Raster->Size2D) break;
	    }
	  }
	}
/*
KONEC:
 if (p.typ='C') then
   begin
   if(binary=0) then
	begin
	p.planes:=24;
	p.x:=p.x div 3;
	end
   end;
*/

ENDPROC:
  fclose(f);
  Img.AttachRaster(Raster);  
  return(Img);
}  //LoadPBM
#endif


TImageFileHandler PBM_H(".PBM",
#if SupportPBM>=4 || SupportPBM==2
	LoadPicturePBM,
#else
	NULL,
#endif
#if SupportPBM>=3
	SavePicturePBM);
#else
	NULL);
#endif

TImageFileHandler PPM_H(".PPM",
#if SupportPBM>=4 || SupportPBM==2
	LoadPicturePBM,
#else
	NULL,
#endif
#if SupportPBM>=3
	SavePicturePBM);
#else
	NULL);
#endif

#endif
//-------------------End of PBM routines------------------


//-----------------------PCX------------------------------
#ifdef SupportPCX
struct RGBColor
       {
	BYTE Red,Green,Blue;
       };

struct PCXHeader{
       BYTE Id0;
       BYTE Version;
       BYTE encoding;
       BYTE BitPerPix;
       WORD x0,y0;
       WORD x1,y1;
       WORD horizontal;
       WORD vertical;
       RGBColor ColorMap[16];
       BYTE reserved;
       BYTE NumPlanes;
       WORD BytesPerLine;
       WORD PaletteInfo;
       BYTE user[58];
       };


#if SupportPCX>=4 || SupportPCX==2
Image LoadPicturePCX(const char *Name)
{
const int Mask=0xC0;
//const int MaxCnt=63;
FILE *f;
WORD X,Y;
BYTE C,Cnt;
PCXHeader Header;
BYTE *adata,*data;
int Aplane;
Raster1DAbstract *pbuf=NULL;
APalette *Palette=NULL;
Raster2DAbstract *Raster=NULL;
Image Img;
long ldblk;

  if((f=fopen(Name,"rb"))==NULL) return(Img);
  data=NULL;

  if(fread(&Header,128,1,f)!=1) {fclose(f);return(Img);};
  if(Header.Id0!=10) goto ENDPROC;	/*incorrect identifier*/

  Raster=CreateRaster2D(Header.x1-Header.x0+1,Header.y1-Header.y0+1,
			Header.BitPerPix*Header.NumPlanes);
  if(Raster==NULL) goto ENDPROC;

  ldblk = ((long)Raster->GetPlanes()*Raster->GetSize1D()+7)/8;

//  p.typ='G';
// if(p.planes=24) p.typ='C';
//  if(AlineProc!=NULL) AlineProc->InitPassing(Raster->Size2D,'Loading PCX');

  Aplane=Header.NumPlanes;

  if(Header.NumPlanes!=1)
    {
    pbuf=CreateRaster1D(Raster->GetSize1D(),Header.BitPerPix);
    data=(BYTE *)pbuf->Data1D;
    }

  Y=0;
  Cnt=0;
  while(Y<Raster->Size2D)
    {
    Aplane=Header.NumPlanes;
    if(Header.NumPlanes==1) data=(BYTE *)Raster->GetRow(Y);

    do {
       adata=data;
       X=0;

       if(Cnt>0) goto RestOfLast;
       while(X<Header.BytesPerLine)
	  {
	  fread(&C,1,1,f);
	  Cnt=1;
	  if((C & Mask)==Mask)	/*the prefix was added*/
		  {
		  Cnt=C & 0x3F;
		  fread(&C,1,1,f);
		  };
RestOfLast:
	  while(Cnt>0)
	     {
	     if(X>=Header.BytesPerLine) break;  /*repeater overflows over a line*/
	     if(X<ldblk)
	       *adata++ = C;		/* some PCX image have longer rows with garbage data */
	     X++;
	     Cnt--;
	     }
	  }
       if(X!=Header.BytesPerLine)
		{		/*load error*/
		delete Raster;
		Raster=NULL;
		goto ENDPROC;
		}

					/*adding a next bit plane*/
       if(Header.NumPlanes!=1)
	 {
	 if(Header.BitPerPix==1)
	    {
	    Raster->GetRowRaster(Y)->Join1Bit(data,Raster->GetPlanes()-Aplane);
	    }
	 if((Header.BitPerPix==8)&&(Raster->GetPlanes()==24))
	    {		/*RGB image*/
//	    if not aplane in [1,2,3]  asm int 3; };
	    Raster->GetRowRaster(Y)->Join8Bit(data,Raster->GetPlanes()-8*Aplane);
	    }
	  }

      Aplane--;		/*loop for bit rows*/
      } while(Aplane>=1);

//  if(AlineProc!=NULL) AlineProc->NextLine();
  Y++;
  if(Cnt>0) 	//repeater overflows over line}
	{		/*load error*/
	delete Raster;
	Raster=NULL;
	goto ENDPROC;
	}
   }

 if(Header.BitPerPix==8)   //loading of palette
     {
     C=0;
     fread(&C,1,1,f);
     if (C!=12) goto ENDPROC;
     Palette=BuildPalette(256,8);
     if(Palette!=NULL)
	fread(Palette->Data1D,(7+Palette->GetSize1D()*Palette->GetPlanes())/8,1,f);
     if(GrayPalette(Palette,Raster->GetPlanes()))
		{
		delete Palette;
		Palette=NULL;
		}
     }
  else if (Raster->GetPlanes()==4 || Raster->GetPlanes()==2)  /*move palette from header*/
	{
	Palette=BuildPalette(1<<Raster->GetPlanes(),8);
	if(Palette!=NULL)
	  memcpy(Palette->Data1D,Header.ColorMap,(7+Palette->Size1D*Palette->GetPlanes())/8);
	if(GrayPalette(Palette,Raster->GetPlanes()))
		{
		delete Palette;
		Palette=NULL;
		}
	}

ENDPROC:
  if(pbuf) delete pbuf;
  fclose(f);
  Img.AttachRaster(Raster);
  Img.AttachPalette(Palette);  
  return(Img);
}  //LoadPCX
#endif


#if SupportPCX>=3
int SavePicturePCX(const char *Name,const Image &Img)
{
const int Mask=0xC0;
const int MaxCnt=63;
FILE *F;
WORD X,Y,OC,C,Cnt;
PCXHeader PCXFile;
BYTE *data;
BYTE *ptrb;
WORD datapos;
//int gray;
BYTE *bbuf;
BYTE Aplane;
APalette *Palette=NULL;
int k;

  if(Img.Raster==NULL) return(-10);

  bbuf=NULL;

  memset(&PCXFile,0,sizeof(PCXFile));
  PCXFile.Id0 = 10;
  PCXFile.Version = 5;
  PCXFile.encoding = 1;
  PCXFile.BitPerPix = 1;
  PCXFile.x0 = 0;
  PCXFile.y0 = 0;
  PCXFile.x1 = Img.Raster->GetSize1D()-1;
  PCXFile.y1 = Img.Raster->Size2D-1;
  PCXFile.NumPlanes = Img.Raster->GetPlanes();
  PCXFile.BytesPerLine = PCXFile.x1-PCXFile.x0+1;
  PCXFile.PaletteInfo=1;

  switch(Img.Raster->GetPlanes())
   {
   case 1:PCXFile.BytesPerLine=(PCXFile.BytesPerLine+7) >> 3;
	  break;
   case 2:C=3*4;
	  goto InternalPalette;
   case 4:C=3*16;
InternalPalette:
	  Palette = Img.Palette;
	  if(Palette==NULL) Palette = BuildPalette(1<<Img.Raster->GetPlanes(),8);
	  memcpy(&PCXFile.ColorMap,Palette->Data1D,C);
	  if(Palette!=Img.Palette) delete Palette;
	  Palette=NULL;
	  bbuf=(BYTE *)malloc((Img.Raster->GetSize1D()+7) >> 3);
	  PCXFile.BytesPerLine=(PCXFile.BytesPerLine+7) >> 3;
	  break;
   case 8:PCXFile.BitPerPix=8;
	  PCXFile.NumPlanes=1;
	  break;
   case 24:PCXFile.BitPerPix=8;
	  PCXFile.NumPlanes=3;
	  bbuf=(BYTE *)malloc(Img.Raster->GetSize1D());
	  break;
   default:return(-2);
  }

  if((F=fopen(Name,"wb"))==NULL) return(-1);

  if(fwrite(&PCXFile,sizeof(PCXFile),1,F)!=1) goto FINISH;

  data=(BYTE *)malloc(2*PCXFile.BytesPerLine);


  for(Y=0;Y<Img.Raster->Size2D;Y++)
    {
    for(Aplane=0;Aplane<PCXFile.NumPlanes;Aplane++)
	{
	datapos = 0;
	Cnt = 0;
	ptrb = (BYTE *)Img.Raster->GetRow(Y);

	if(PCXFile.NumPlanes!=1)
	   {
	   if(PCXFile.BitPerPix==1)
	     Img.Raster->GetRowRaster(Y)->Peel1Bit(bbuf,Aplane);
	   if(PCXFile.BitPerPix==8)
	     Img.Raster->GetRowRaster(Y)->Peel8Bit(bbuf,8*Aplane);
	   ptrb=bbuf;
	   }

	for(X=0;X<PCXFile.BytesPerLine;X++)
	  {
	  C=*ptrb;
	  ptrb++;

	  if( (Cnt!=0) && ((OC!=C)||(Cnt==MaxCnt)) )
	    {
	    if( (Cnt!=1) || ((OC & Mask)==Mask) ) //add a prefix
		{
		data[datapos]=Cnt | Mask;
		datapos++;
		}
	    data[datapos]=OC;
	    datapos++;
	    Cnt=0;
	    }
	  OC=C;
	  Cnt++;
	  }

       if(Cnt!=0) 	//end of line
	   {
	   if( (Cnt!=1) || ((OC & Mask)==Mask) ) //Add prefix
		{
		data[datapos]=Cnt | Mask;
		datapos++;
		}
	   data[datapos]=OC;
	   datapos++;
	   Cnt=0;
	   }
       fwrite(data,datapos,1,F);
       }
//  if AlineProc<>nil then AlineProc^.NextLine;
    }

  if(data) {free(data);data=NULL;}

  if(Img.Raster->GetPlanes()==8)
    {
    Palette = Img.Palette;
    if(Palette==NULL)
	{
	Palette = BuildPalette(256,8);
	if(Palette==NULL)		// Error creating palette
	  {
	  printf("Memory exhausted.");
	  goto FINISH;
	  }
	FillGray(Palette,8);
	}

    k = Palette->GetPlanes()/3 - 8;
    if(k<0) k = 0;

    fputc(12,F);	//{paleta}

    for(X=0;X<=255;X++)
      {
      fputc(Palette->R(X)>>k,F);	//Red;
      fputc(Palette->G(X)>>k,F);	//Green;
      fputc(Palette->B(X)>>k,F);	//Blue;
      }

    if(Palette!=Img.Palette) delete Palette;
    Palette = NULL;
    }

FINISH:
  if(bbuf!=NULL) {free(bbuf);bbuf=NULL;}
  fclose(F);
return(0);
}
#endif


TImageFileHandler PCX_H(".PCX",
#if SupportPCX>=4 || SupportPCX==2
	LoadPicturePCX,
#else
	NULL,
#endif
#if SupportPCX>=3
	SavePicturePCX);
#else
	NULL);
#endif

#endif
//-------------------End of PCX routines------------------


//-------------------------RAS-TopoL-----------------------
#ifdef SupportRAS

struct RasHeader
	{
	char Name[20];
	SWORD Rows;
	SWORD Cols;
	SWORD TypSou; // 0-binarni, 1-8 bitu,2-8 bitu+PAL,3-4 bity,
		      // 4-4 bity+PAL, 5-24 bite,6-16 bite,7- 32 bite}
	SDWORD Zoom;
	SWORD Verze;
	SWORD Komprese;	// {0 - nekomprimovano}	 {od Verze 1}
	SWORD Stav;
	double xRasMin;
	double yRasMin;
	double xRasMax;
	double yRasMax;
	double Scale;	//from release 2
	WORD TileWidth;	      // tilt width in pixels
	WORD TileHeight;      // tile height in pixels
	SDWORD TileOffsets;   // offset na pole longintu, ktere jsou adresami tilu v rastru (adresy se pocitaji od 0)}
	SDWORD TileByteCounts;/* offset na pole wordu, ktere obsahuji pocet bytu ulozenych v
				 v jednotlivych tilech velikost tilu se muze lisit v zavislosti
				 na hodnote TileCompression*/
	BYTE TileCompression; //0 - nekomprimovano, 1 - varianta TIFF Packbits, 2 - CCITT G3

	BYTE Dummy[423];
	};

struct paletteRAS
   {
   BYTE Flag;
   BYTE Red;
   BYTE Green;
   BYTE Blue;
   };


inline long LoadTopolHeader(FILE *f, RasHeader &SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU,1,sizeof(SU),f));
#else
 return(loadstruct(f,"a20wwwdwwwqqqqqwwddba423",
	 &SU.Name,&SU.Rows,&SU.Cols,&SU.TypSou,&SU.Zoom,&SU.Verze,
         &SU.Komprese,&SU.Stav,
         &SU.xRasMin,&SU.yRasMin,&SU.xRasMax,&SU.yRasMax,&SU.Scale,	//from release 2
	 &SU.TileWidth,&SU.TileHeight,&SU.TileOffsets,&SU.TileByteCounts,
         &SU.TileCompression,&SU.Dummy));
#endif
}

#if SupportRAS>=4 || SupportRAS==2
Image LoadPictureRAS(const char *Name)
{
FILE *f;
WORD Ldblk;
WORD j,i,k;
RasHeader Header;
Image Img;
Raster2DAbstract *Raster=NULL;
APalette *Palette=NULL;
char *NameBuffer=NULL;
DWORD *Offsets=NULL;
WORD TilesAcross,TilesDown;
WORD TilX,TilY;

  if((f=fopen(Name,"rb"))==NULL) return(Img);

  memset(&Header,0,sizeof(Header));
  LoadTopolHeader(f,Header);

  for(i=0;i<sizeof(Header.Name);i++)
    {
    if(Header.Name[i]<' ') goto FINISH;
    }
  if(Header.Komprese!=0) goto FINISH;
  if(Header.Rows==0 || Header.Cols==0 ) goto FINISH;
  if(Header.Verze>2)  goto FINISH;		//unknown version

  switch(Header.TypSou)
    {
    case 0: i=1;  break;
    case 1:
    case 2: i=8;  break;
    case 3:
    case 4: i=4;  break;
    case 5: i=24; break;  //if( Header.TypSou = 5 p.typ='C';	{True Color}
    case 6: i=16; break;
    case 7: i=32; break;
    default: goto FINISH;
    }
  Raster = CreateRaster2D(Header.Cols,Header.Rows,i);
  if(Raster==NULL) goto FINISH;
  // if(AlineProc!=NULL) AlineProc^.InitPassing(p.y,'Loading RAS');

  switch(Header.Verze)
   {
   case 0:
   case 1:fseek(f,0x200,SEEK_SET);
	  Ldblk=((long)Raster->GetPlanes()*Header.Cols+7) / 8;

	  for(i=0;i<Header.Rows;i++)
	     {
	     if(fread(Raster->GetRow(i),Ldblk,1,f)!=1) goto FINISH;
	     //if( AlineProc!=NULL  AlineProc^.NextLine;
	     }

	 break;

   case 2:
       TilesAcross = (Header.Cols+Header.TileWidth-1) / Header.TileWidth;
       TilesDown   = (Header.Rows+Header.TileHeight-1) / Header.TileHeight;

       if(Header.TileCompression!=0)
		{
TileFailed:	delete Raster; Raster=NULL;
		goto FINISH;
		}
       //dlazdice.create(Header.TileWidth,Header.TileHeight,p.Planes);
       Offsets=(DWORD *)malloc(TilesAcross*TilesDown*sizeof(DWORD));
       if(Offsets==NULL) goto TileFailed;

       fseek(f,Header.TileOffsets,SEEK_SET);
       fread(Offsets,TilesAcross*TilesDown,sizeof(DWORD),f);

       for(TilY=0;TilY<Header.Rows;TilY+=Header.TileHeight)
	 for(TilX=0;TilX<TilesAcross;TilX++)
	   {
	   Ldblk = Raster->GetSize1D() - TilX*Header.TileWidth;
	   if(Ldblk>Header.TileWidth) Ldblk=Header.TileWidth;
	   long SkipBlk = ((long)Raster->GetPlanes() * (Header.TileWidth-Ldblk)+7) / 8;
	   Ldblk = ((long)Raster->GetPlanes()*Ldblk+7) / 8;

	   fseek(f,Offsets[(TilY/Header.TileHeight)*TilesAcross+TilX],SEEK_SET);
	   j = TilX * (Ldblk+SkipBlk);
	   for(i=0;i<Header.TileHeight;i++)
		{
		BYTE *Data = (BYTE *)Raster->GetRow(i+TilY);
		if(Data)
		   {
		   if(fread(Data+j,Ldblk,1,f)!=1) goto FINISH;
		   if(SkipBlk>0) fseek(f,SkipBlk,SEEK_CUR);
		   }
		    //if(AlineProc!=NULL)  AlineProc^.NextLine;
		}
	    }

       if(Offsets) {free(Offsets);Offsets=NULL;}
       break;

    }

 fclose(f); f=NULL;

 if( Raster!=NULL && (Header.TypSou==2 || Header.TypSou==4) ) //the palette should be loaded
	{
	j=i=strlen(Name);
	NameBuffer=(char *)malloc(i+5);
	strcpy(NameBuffer,Name);

	while(--i>0)
	  {
	  if(Name[i]=='.') break;
	  if(Name[i]=='/' || Name[i]=='\\' || Name[i]==':')
	       {i=j;break;}
	  }
	strcpy(NameBuffer+i,".PAL");
	if((f=fopen(NameBuffer,"rb"))==NULL)
	     {
	     strcpy(NameBuffer+i,".pal");
	     if((f=fopen(NameBuffer,"rb"))==NULL)
		 {
		 NameBuffer[i]=0;
		 if((f=fopen(NameBuffer,"rb"))==NULL)
			goto PalSkip;
		 }
	     }

	Ldblk=fgetc(f);		//startup info
	if(Ldblk==EOF) goto PalFail;
	Ldblk++;

	Palette=BuildPalette(1 << Raster->GetPlanes(),8);

	i=1<<Raster->GetPlanes();
	if(i<Ldblk) Ldblk=i;
	for(i=0;i<Ldblk;i++)
		{
		if( (j=fgetc(f))==EOF ) goto PalFail;
		Palette->R(j,fgetc(f));	//Red
		Palette->G(j,fgetc(f));	//Green
		Palette->B(j,fgetc(f));	//Blue
		}
PalFail:
	if(f) {fclose(f);f=NULL;}
	if(GrayPalette(Palette,Raster->GetPlanes()))
		{
		delete Palette;
		Palette=NULL;
		}
	}
PalSkip:        

			//the mez file should be loaded now
  if( Raster!=NULL && Header.TypSou>=1 && Header.TypSou<=4 )
	{
	j=i=strlen(Name);
	if(NameBuffer==NULL) NameBuffer=(char *)malloc(i+5);
	strcpy(NameBuffer,Name);

	while(--i>0)
	  {
	  if(Name[i]=='.') break;
	  if(Name[i]=='/' || Name[i]=='\\' || Name[i]==':')
	       {i=j;break;}
	  }
	strcpy(NameBuffer+i,".MEZ");
	if((f=fopen(NameBuffer,"rb"))==NULL)
	     {
	     strcpy(NameBuffer+i,".mez");
	     if((f=fopen(NameBuffer,"rb"))==NULL)
		 goto MezFail;
	     }

	BYTE Mez[256];
	Ldblk=fread(Mez,1,sizeof(Mez),f);
	if(Ldblk==0) goto MezFail;

	for(i=0;i<Raster->Size2D;i++)
	  for(j=0;j<Raster->GetSize1D();j++)
	    {
	    k=Raster->GetValue2D(j,i);
	    if(k<Ldblk) Raster->SetValue2D(j,i,Mez[k]);
	    }
	//Operation1(p,ReTabB,addr(Mez),nil);
	}
MezFail:


FINISH:
  if(f) fclose(f);
  if(NameBuffer) {free(NameBuffer);NameBuffer=NULL;}
  Img.AttachRaster(Raster);
  Img.AttachPalette(Palette);  
return(Img);
}
#endif


#if SupportRAS>=3
int SavePictureRAS(const char *Name,const Image &Img)
{
FILE *f;
WORD Ldblk;
WORD i;
RasHeader Header;
paletteRAS pal;
char *PalName=NULL;

  if(Img.Raster==NULL) return(-10);

  memset(&Header,0,sizeof(Header));
  memset(&Header.Name,' ',sizeof(Header.Name));
  Header.Cols=Img.Raster->GetSize1D();
  Header.Rows=Img.Raster->Size2D;
  switch(Img.Raster->GetPlanes())
	{
	case 1:Header.TypSou=0;
	       break;
	case 4:if(Img.Palette==NULL) Header.TypSou=3;
				else Header.TypSou=4;
	       break;
	case 8:if(Img.Palette==NULL) Header.TypSou=1;
				else Header.TypSou=2;
	       break;
	case 16:Header.TypSou=6;
		break;
	case 24:Header.TypSou=5;
		break;
	default:return(-2);
	}

  if((f=fopen(Name,"wb"))==NULL) return(-1);

  fwrite(&Header,sizeof(Header),1,f);

  fseek(f,0x200,SEEK_SET);
  Ldblk=((long)Img.Raster->GetPlanes()*Img.Raster->GetSize1D()+7) / 8;
  for(i=0;i<Header.Rows;i++)
	{
	fwrite(Img.Raster->GetRow(i),Ldblk,1,f);
	// if AlineProc<>nil then AlineProc^.NextLine;
	}

  fclose(f);

  if( Img.Palette!=NULL && (Header.TypSou==2 || Header.TypSou==4)) //now remains storing of palette
	{
	i=strlen(Name);
	PalName=(char *)malloc(i+4);

	memcpy(PalName,Name,i+1);
	memcpy(PalName+i-3,"PAL",3);

	if((f=fopen(PalName,"wb"))==NULL)
		{
		free(PalName);
		return(-1);
		}
	free(PalName);

	i=(1 << Img.Raster->GetPlanes())-1;
	fputc(i,f);

	for(i=0;i<(1 << Img.Raster->GetPlanes());i++)
		{
		pal.Flag=i;
		pal.Red=  Img.Palette->R(i);	//Red;
		pal.Green=Img.Palette->G(i);	//Green;
		pal.Blue= Img.Palette->B(i);	//Blue;

		if(fwrite(&pal,sizeof(pal),1,f)!=1) goto PalFail;
		}
PalFail:fclose(f);
	}

return(0);
}
#endif


TImageFileHandler RAS_TopoL_H(".RAS",
#if SupportRAS>=4 || SupportRAS==2
	LoadPictureRAS,
#else
	NULL,
#endif
#if SupportRAS>=3
	SavePictureRAS);
#else
	NULL);
#endif

#endif
//-----------------End of RAS-TopoL routines----------------


//-------------------------RAS-SUN-------------------------
#ifdef SupportRAS_SUN

struct SUNRASHeader
	{
	DWORD ras_magic;
	DWORD ras_width;
	DWORD ras_height;
	DWORD ras_depth;
	DWORD ras_length;
	DWORD ras_type;
	DWORD ras_maptype;
	DWORD ras_maplength;
	};


#if SupportRAS_SUN>=4 || SupportRAS_SUN==2

inline long LoadSUNRASHeader(FILE *f,SUNRASHeader &SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU,1,sizeof(SU),f));
#else
 return(loadstruct(f,"DDDDDDDD",
	 &SU.ras_magic,&SU.ras_width,&SU.ras_height,
	 &SU.ras_depth,&SU.ras_length,&SU.ras_type,
	 &SU.ras_maptype,&SU.ras_maplength));
#endif
}

Image LoadPictureRAS_SUN(const char *Name)
{
FILE *f;
WORD Ldblk;
WORD k,w,i;
SUNRASHeader Header;
Image Img;
Raster2DAbstract *Raster=NULL;
APalette *Palette=NULL;

  if((f=fopen(Name,"rb"))==NULL) return(Img);

  memset(&Header,0,sizeof(Header));
  LoadSUNRASHeader(f,Header);

  if(Header.ras_magic != 0x59A66A95)
		 {
		 //LoadPictureSUNRAS=ErrAnother;
		 goto FINISH;		//incorrect identifier
		 }

  Raster=CreateRaster2D(Header.ras_width,Header.ras_height,Header.ras_depth);
  if(Raster==NULL) goto FINISH;
//if(AlineProc!=NULL) AlineProc^.InitPassing(p.y,'Loading SUNRAS');

  if(Header.ras_maptype!=0 && Header.ras_maplength!=0)
	 {
	 Palette=BuildPalette(1<<Header.ras_depth,8);
	 w=(Header.ras_maplength / 3) - 1;
	 if( w < (1<<Header.ras_depth) )
	    {
	    for(i=0;i<=w;i++) Palette->R(i,fgetc(f));	//Red
	    for(i=0;i<=w;i++) Palette->G(i,fgetc(f));	//Green
	    for(i=0;i<=w;i++) Palette->B(i,fgetc(f));	//Blue
	    };
	 if(GrayPalette(Palette,Raster->GetPlanes()))
		{
		delete Palette;
		Palette=NULL;
		}

	 fseek(f,sizeof(Header)+Header.ras_maplength,SEEK_SET);
	 };

  Ldblk=((long)Header.ras_depth*Header.ras_width+7) / 8;
  k=(-Ldblk) & 1;
  for(i=0;i<Header.ras_height;i++)
	 {
	 if(fread(Raster->GetRow(i),Ldblk,1,f)!=1) goto FINISH;
	 if(i<Header.ras_height-1) fseek(f,k,SEEK_CUR);	//docteni do konce radku
	 //if InOutRes!=0 then goto KONEC;
	 //if AlineProc!=NULL then AlineProc^.NextLine;
	 }

  if(Header.ras_depth==24)
	for(i=0;i<Raster->Size2D;i++)
		RGB_BGR((char *)Raster->GetRow(i),Raster->GetSize1D());

FINISH:
  fclose(f);
  Img.AttachRaster(Raster);
  Img.AttachPalette(Palette);  
  return(Img);
}
#endif


TImageFileHandler RAS_SUN_H(".RAS",
#if SupportRAS_SUN>=4 || SupportRAS_SUN==2
	LoadPictureRAS_SUN,
#else
	NULL,
#endif
//#if SupportRAS_SUN>=3
//	SavePictureRAS_SUN);
//#else
	NULL);
//#endif

#endif
//-----------------End of RAS-SUN routines---------------



//-------------------------RAW----------------------------
#ifdef SupportRAW

#if SupportRAW>=3
int SavePictureRAW(const char *Name, const Image &Img)
{
FILE *f;
WORD ldblk;
WORD i;

  if(Img.Raster==NULL) return(-10);

  if((f=fopen(Name,"wb"))==NULL) return(-1);

  ldblk=((long)labs(Img.Raster->GetPlanes())*Img.Raster->GetSize1D()+7) / 8;
  for(i=0;i<Img.Raster->Size2D;i++)
    {
    if(fwrite(Img.Raster->GetRow(i),ldblk,1,f)!=1)
      {
      fclose(f);
      return -1;
      }
    // if AlineProc<>nil then AlineProc^.NextLine;
    }

  fclose(f);
  return 0;
}
#endif


TImageFileHandler RAW_H(".RAW",
//#if SupportRAW>=4 || SupportRAW==2
//	LoadPictureRAW,
//#else
	NULL,
//#endif
#if SupportRAW>=3
	SavePictureRAW);
#else
	NULL);
#endif

#endif
//-------------------End of RAW routines------------------


//-------------------------TIFF----------------------------
#ifdef SupportTIFF

struct TIFHeader
	{
	BYTE CharId[2];
	WORD CharV;
	DWORD Pos;
	};

struct TIFDirectory
	{
	WORD Tag,Field;
	DWORD Long2,Value;
	};


Image LoadPictureTIFF(const char *Name)
{
DWORD *StripsPtrs;
FILE *f;
WORD Ldblk;
int i;
TIFHeader Header;
TIFDirectory IFD;
WORD EntryCount,SizeX,SizeY;
/*    :^StripArray;*/
DWORD  PalettePos,NextPtr;
WORD BitsPerSample,SamplesPerPixel;
WORD Compression;
DWORD StripOffsets;
WORD StripCount;
WORD RowsPerStrip,PlanarCfg;
int (*RdWORD_TIFF)( WORD *num, FILE *f );
int (*RdDWORD_TIFF)( DWORD *num, FILE *f );
const char *IFD_Marshall = NULL;
Raster2DAbstract *Raster = NULL;
APalette *Palette = NULL;
Image Img;

StripsPtrs=NULL;
PalettePos=0;
BitsPerSample=1;
SamplesPerPixel=1;
Compression=1;
StripOffsets=0;
StripCount=0;
PlanarCfg=0;
RowsPerStrip=65535;

 if((f=fopen(Name,"rb"))==NULL) return(Img);
// Pbuf.Init;
//  p.Erase;
 if(fread(&Header,2,1,f)!=1) {fclose(f);return(Img);};

 RdWORD_TIFF=NULL;RdDWORD_TIFF=NULL;
 if(Header.CharId[0]=='I' && Header.CharId[1]=='I')
	{
	RdWORD_TIFF=RdWORD_LoEnd;
	RdDWORD_TIFF=RdDWORD_LoEnd;
	IFD_Marshall="wwdd";
	}
 if(Header.CharId[0]=='M' && Header.CharId[1]=='M')
	{
	RdWORD_TIFF=RdWORD_HiEnd;
	RdDWORD_TIFF=RdDWORD_HiEnd;
	IFD_Marshall="WWDD";
	}

 if(RdWORD_TIFF==NULL || RdDWORD_TIFF==NULL ) goto FINISH;
 RdWORD_TIFF(&Header.CharV,f);
 RdDWORD_TIFF(&Header.Pos,f);

 if (Header.CharV!=42) goto FINISH; /*check of version*/
 fseek(f,Header.Pos,SEEK_SET);

 RdWORD_TIFF(&EntryCount,f);
 for(i=1;i<=EntryCount;i++)
	{
	loadstruct(f,IFD_Marshall,&IFD.Tag,&IFD.Field,&IFD.Long2,&IFD.Value);

	if (IFD.Field==3 && Header.CharId[0]=='M')
		{
		if(IFD.Long2>=65536) IFD.Long2=IFD.Long2 >> 16;
		if(IFD.Value>=65536) IFD.Value=IFD.Value >> 16;
		}

	switch(IFD.Tag)
	   {
//		255:;				{SubFileType}
	   case 256:SizeX=IFD.Value;break;	//ImageWidth   $0100
	   case	257:SizeY=IFD.Value;break;	//ImageLength  $0101
	   case	258:BitsPerSample=IFD.Value;break; // $102
	   case	259:Compression=IFD.Value;break; //Compression  $0103
//		262:;				{PhotometricInterpretation}
//		266:;				{FillOrder}
	   case	273:StripOffsets=IFD.Value;	//StripOffsets $111
		    StripCount=IFD.Long2;
		    break;
//		274:;				//Orientation
	   case	277:SamplesPerPixel=IFD.Value;break;//SamplesPerPixel
	   case	278:RowsPerStrip=IFD.Value;break;//RowsPerStrip
//		280:;				{MinSampleValue
//		281:;				{MaxSampleValue
//		282:;				{XResolution}
//		283:;				{YResolution}
	   case	284:PlanarCfg=IFD.Value;break;	//PlanarConfiguration
	   case	320:PalettePos=IFD.Value;break; //Palette-color map
	   }
	}

 RdDWORD_TIFF(&NextPtr,f);
 if(StripOffsets==0 || RowsPerStrip==0) goto FINISH;
 if(((SizeY-1) / RowsPerStrip)+1 != StripCount) goto FINISH;

 if(SamplesPerPixel==3)
	{	/*it is a big hack but I really don't know what to do with wrong? BitsPerSample*/
	BitsPerSample=24;
//	asm int 3;
	}

 Raster=CreateRaster2D(SizeX,SizeY,BitsPerSample);
 if(Raster==NULL) goto FINISH;
/* if(AlineProc<>nil)AlineProc^.InitPassing(Raster->Size2D,'Loading TIF');*/

 if( (StripsPtrs=(DWORD *)calloc(StripCount,sizeof(DWORD)))==NULL ) goto FINISH;
 if(StripCount>1)		/*more strips*/
	{
	fseek(f,StripOffsets,SEEK_SET);
	for(i=0;i<StripCount-1;i++)
		RdDWORD_TIFF(&StripsPtrs[i],f);
	fseek(f,StripsPtrs[0],SEEK_SET);
	}
   else {
	if(StripsPtrs) StripsPtrs[0]=StripOffsets;
	fseek(f,StripOffsets,SEEK_SET);
	}


 Ldblk=((long)BitsPerSample*SizeX+7) / 8;
 for(i=0;i<SizeY-1;i++)
	{
	if(i % RowsPerStrip == 0)
		fseek(f,StripsPtrs[i/RowsPerStrip],SEEK_SET);
	if(fread(Raster->GetRow(i),Ldblk,1,f)!=1) {goto FINISH;}
//	if AlineProc<>nil then AlineProc^.NextLine;
	if(feof(f)) break;
	}

 if(PalettePos!=0)		/*load of the palette*/
	{
	fseek(f,PalettePos,SEEK_SET);
	Ldblk=(1 << BitsPerSample);
	Palette=BuildPalette(Ldblk,16);
	for(i=0;i<Ldblk;i++)
		{
		RdWORD_TIFF(&Compression,f);
		Palette->R(i,Compression);
		}
	for(i=0;i<Ldblk;i++)
		{
		RdWORD_TIFF(&Compression,f);
		Palette->G(i,Compression);
		}
	for(i=0;i<Ldblk;i++)
		{
		RdWORD_TIFF(&Compression,f);
		Palette->B(i,Compression);
		}

	if(GrayPalette(Palette,Raster->GetPlanes()))
		{
		delete Palette;
		Palette=NULL;
		}
	}

FINISH:
 if(f) fclose(f);
 if(StripsPtrs!=NULL) free(StripsPtrs);

 Img.AttachRaster(Raster);
 Img.AttachPalette(Palette); 
 return(Img);
}  /*LoadTIF*/


TImageFileHandler TIF_H(".TIF",
#if SupportTIFF>=4 || SupportTIFF==2
	LoadPictureTIFF,
#else
	NULL,
#endif
//#if SupportTIFF>=3
//	SavePictureTIFF);
//#else
	NULL);
//#endif

TImageFileHandler TIFF_H(".TIFF",
#if SupportTIFF>=4 || SupportTIFF==2
	LoadPictureTIFF,
#else
	NULL,
#endif
//#if SupportTIFF>=3
//	SavePictureTIFF);
//#else
	NULL);
//#endif

#endif
//-------------------End of TIFF routines------------------


//--------------------------TGA----------------------------
#ifdef SupportTGA

struct TGAHeader
	{
	BYTE IdentifLen;
	BYTE ColorMapType;
	BYTE ImageCodeType;

	WORD CMapOrigin;
	WORD CMapLength;
	BYTE CMapEntrySize;

	WORD XOrigin;
	WORD YOrigin;
	WORD Width;
	WORD Height;
	BYTE ImagePixSize;
	BYTE ImageDescByte;
	};


#if SupportTGA>=4 || SupportTGA==2

inline long LoadTgaHeader(FILE *f, TGAHeader &SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU,1,sizeof(SU),f));
#else
 return(loadstruct(f,"bbbwwbwwwwbb",
	&SU.IdentifLen, &SU.ColorMapType, &SU.ImageCodeType,
	&SU.CMapOrigin, &SU.CMapLength, &SU.CMapEntrySize,
	&SU.XOrigin, &SU.YOrigin, &SU.Width, &SU.Height,
	&SU.ImagePixSize, &SU.ImageDescByte));
#endif
}


Image LoadPictureTGA(const char *Name)
{
FILE  *f;
WORD ldblk;
unsigned i;
Raster2DAbstract *Raster=NULL;
APalette *Palette=NULL;
Image Img;
TGAHeader Header;

  if((f=fopen(Name,"rb"))==NULL) return(Img);
  if(LoadTgaHeader(f,Header)!=18) goto ENDPROC;

  if((Header.ImageCodeType<1 || Header.ImageCodeType>3) ||
     (Header.ColorMapType>=2))
		{  //LoadPictureTGA:=ErrAnother;
		goto ENDPROC;
		}

  Raster=CreateRaster2D(Header.Width,Header.Height,Header.ImagePixSize);
  if(Raster==NULL) goto ENDPROC;

  fseek(f,18+Header.IdentifLen,SEEK_SET);

// if AlineProc<>nil then AlineProc^.InitPassing(p.y,'Loading TGA');
  if(Header.ColorMapType==1)
    {
    Palette=BuildPalette(1 << Header.ImagePixSize,8);
    if(Header.CMapEntrySize == 24)
	{		// Pozor Muze se zhroutit pri spatne tabulce
	fread((char *)Palette->Data1D + 3*Header.CMapOrigin,
			  3*Header.CMapLength,1,f);
	RGB_BGR((char *)Palette->Data1D + 3*Header.CMapOrigin,Header.CMapLength);
	};
    fseek(f,18+Header.IdentifLen + (Header.CMapEntrySize / 8)*Header.CMapLength,SEEK_SET);
    };

//  if(Header.ImageCodeType==ImagePalette) ColorMode=ImagePalette;
  ldblk=(Raster->GetPlanes()*Raster->GetSize1D()+7)/8;
  if(Header.ImageDescByte==32)
    for(i=0; i<Raster->Size2D; i++)
	{
	if(fread(Raster->GetRow(i),ldblk,1,f)!=1) {goto ENDPROC;}
	if(Header.ImageCodeType==2) RGB_BGR((char *)Raster->GetRow(i),Raster->GetSize1D());
/*	if AlineProc<>nil then AlineProc^.NextLine;*/
	}
  else
    for(i=Raster->Size2D-1;i>=0;i--)
	{
	if(fread(Raster->GetRow(i),ldblk,1,f)!=1) {goto ENDPROC;}
	if(Header.ImageCodeType==2) RGB_BGR((char *)Raster->GetRow(i),Raster->GetSize1D());
/*	if AlineProc<>nil then AlineProc^.NextLine;*/
	}

ENDPROC:
 fclose(f);
 Img.AttachRaster(Raster);
 Img.AttachPalette(Palette); 
 return(Img);
}
#endif


#if SupportTGA>=3

inline long SaveTgaHeader(FILE *f, TGAHeader &SU)
{
#if defined(__PackedStructures__)
 return(fwrite(&SU,1,sizeof(SU),f));
#else
 return(savestruct(f,"bbbwwbwwwwbb",
	SU.IdentifLen, SU.ColorMapType, SU.ImageCodeType,
	SU.CMapOrigin, SU.CMapLength, SU.CMapEntrySize,
	SU.XOrigin, SU.YOrigin, SU.Width, SU.Height,
	SU.ImagePixSize, SU.ImageDescByte));
#endif
}


int SavePictureTGA(const char *Name,const Image &Img)
{
FILE *f;
TGAHeader Header;
char ImageID[256] = "";		//???
//char Author[41] = "";
//char SoftwareID[41] = "";
WORD x, y;

 if(Img.Raster==NULL) return(-10);
 if((f=fopen(Name,"wb"))==NULL) return(-1);

 Header.IdentifLen=strlen(ImageID); //??? Start with the lenght of the Image ID string. ??
 if(Img.Raster->GetPlanes()==8 && Img.Palette!=NULL)
   {
   Header.ColorMapType = 1;	    // Then the Color Map Type.
   Header.ImageCodeType = 1;
   Header.ImagePixSize = Img.Raster->GetPlanes();

   Header.CMapLength = 1 << Header.ImagePixSize;
   Header.CMapEntrySize = 24;
   }
 else
   {
   Header.ColorMapType = 0;  //There's no color map here (0).
   if(Img.Raster->GetPlanes()==1)
     {
     Header.ImageCodeType = 3; //And then the Image Type. Uncompressed Monochromatic.
     Header.ImagePixSize = 1;
     }
   else
     {
     Header.ImageCodeType = 2; //Uncompressed True Color (2).
     Header.ImagePixSize = 24;
     }
   Header.CMapLength = 0;
   Header.CMapEntrySize = 0;
   }
 Header.CMapOrigin = 0;

 Header.XOrigin = Header.YOrigin = 0;
		    /*  Now we should output the image specification. The last byte
		     *  written (32) indicates that the first pixel is upper left on
		     *  the screen. */
 Header.Width = Img.Raster->GetSize1D();
 Header.Height = Img.Raster->Size2D;
 Header.ImageDescByte = 32;

 SaveTgaHeader(f,Header);

 /* Now we write the Image ID string. */
 if (fwrite(ImageID,strlen(ImageID),1,f) != 1) return -1;

 /* This is where the color map should go if this was not True Color. */
  if(Header.ImageCodeType==1)
    {
    for(x=0; x<Header.CMapLength ;x++)
      {
      fputc(Img.Palette->B(x),f);
      fputc(Img.Palette->G(x),f);
      fputc(Img.Palette->R(x),f);
      }
    }

  for(y=0; y<Header.Height;y++)
    {
    switch(Img.Raster->GetPlanes())
      {
      case 24:
	{
	char *row = (char *)Img.Raster->GetRow(y);
	RGB_BGR(row,Img.Raster->GetSize1D());
	fwrite(row,3*Header.Width,1,f);
	RGB_BGR(row,Img.Raster->GetSize1D());
	}
	break;

     case 1:
	fwrite(Img.Raster->GetRow(y),(Header.Width+7)/8,1,f);
	break;

     default:
      if(Header.ImageCodeType==1)   //palette image
	fwrite(Img.Raster->GetRow(y),Header.Width,1,f);
      else
	for(x=0; x<Header.Width; x++)
	  {
	  DWORD pix = Img.GetPixel(x,y);
	  if(Img.Palette)
	    {
	    fputc(Img.Palette->B(pix),f);
	    fputc(Img.Palette->G(pix),f);
	    fputc(Img.Palette->R(pix),f);
	    }
	  else
	    {
	    fputc(pix,f);  /*b*/ fputc(pix,f);  /*g*/ fputc(pix,f); /*r*/
	    }
	  }
      }
    }

 fclose(f);
 return(0);
}

#endif


TImageFileHandler TGA_H(".TGA",
#if SupportTGA>=4 || SupportTGA==2
	LoadPictureTGA,
#else
	NULL,
#endif
#if SupportTGA>=3
	SavePictureTGA);
#else
	NULL);
#endif

#endif
//-------------------End of TGA routines------------------


//-------------------------TXT-plain----------------------
#ifdef SupportTXT


#if SupportTXT>=4 || SupportTXT==2

Image LoadPictureTXT(const char *Name)
{
FILE *f;
WORD x,y,R_X;
unsigned char ch;
long max,i;
Raster2DAbstract *Raster=NULL;
Image Img;
bool Doubles = false;

  if((f=fopen(Name,"rt"))==NULL) return(Img);

  x=0;y=0;
  max=0;
  i=0;
  R_X=0;

  ch=0;
  while(!feof(f))	//auto detect sizes and num of planes
    {
    while(!(ch >= '0' && ch <= '9'))
	 {             //go to the begin of number
	 ch=fgetc(f);
	 if(feof(f)) goto EndReading;
	 if(ch==0 || ch>128 || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
		goto FINISH; 	//not a text data
	 }
    x=0;
    i=0;
    do {
       x++;
       if(!isdigit(ch) && ch!=0) ch=0;
       i=ReadInt(f,(char *)&ch);
       if(ch=='.')
         {
         ch = 0;
         if(ReadInt(f,(char *)&ch)!=0)	//dummy read frac part
           Doubles = true;
         }
       if(i>max) max=i;
       if(feof(f)) break;
       while(ch==' ') ch=fgetc(f);	//read spaces to next number
       } while(!(ch==0 || ch==10 || ch==13 || ch==';' || ch==':' || ch>128 ||
		(ch>='a' && ch<='z') || (ch>='A' && ch<='Z')) );

    if(!feof(f))
      {
      if(ch==';') readln(f);		//comment
      if(ch==0 || ch==':' || ch>128 || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
		goto FINISH; 		//not a text data
      }
    if(x>1)
	 {
	 y++;
	 if(x>R_X) R_X=x;
	 }
    }
EndReading:
//  if IOResult!=0  goto Konec;
  fseek(f,0,SEEK_SET);

  if(Doubles)
    {
    Raster = CreateRaster2D(R_X,y,-64);
    }
  else
    {
    i=1;
    if(max>=    2) i=2;
    if(max>=    4) i=4;
    if(max>=   16) i=8;
    if(max>=  256) i=16;
    if(max>=65536) i=32;

    Raster = CreateRaster2D(R_X,y,i);
    }

  if(Raster==NULL) goto FINISH;
//if(AlineProc!=nil) AlineProc^.InitPassing(p.y,'Loading TXT');

  y=0;
  ch=0;
  while(!feof(f)) 	//load picture data
    {
    x=0;
    while(!(ch >= '0' && ch <= '9'))
	 {		//move to the beginning of number
	 if(feof(f)) goto FINISH;
	 ch=fgetc(f);
	 }
    do {
       if(Doubles)
         Raster->SetValue2Dd(x, y, ReadDouble(f,(char *)&ch));
       else
         Raster->SetValue2D(x, y, ReadInt(f,(char *)&ch));
       //if IOresult!=0  goto Konec;
       x++;
       if(ch=='.') ReadInt(f,(char *)&ch);	//dummy read frac part
       if(feof(f)) break;
       while(ch==' ') ch=fgetc(f);	//read spaces to next number
       } while(!(ch==0 || ch==10 || ch==13 || ch==';' ||  ch>128 || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z')) );

    if(ch==';') readln(f);
    if(x>1) y++;
    }

FINISH:
  fclose(f);
  Img.AttachRaster(Raster);  
  return(Img);
}
#endif


#if SupportTXT>=3
int SavePictureTXT(const char *Name,const Image &Img)
{
FILE *f;
WORD i,j;

 if(Img.Raster==NULL) return(-10);

 if((f=fopen(Name,"wt"))==NULL) return(-1);
 //if AlineProc<>nil AlineProc^.InitPassing(p.y*p.planes,'Saving TXT');

 //printf("1D%d 2D%d",Img.Raster->GetSize1D(),Img.Raster->Size2D);
 for(i=0;i<Img.Raster->Size2D;i++)
   {
   if(Img.Raster->GetPlanes()>=0 && Img.Raster->GetPlanes()<=32)
     for(j=0;j<Img.Raster->GetSize1D();j++)
	{
	fprintf(f,"%u ",Img.GetPixel(j,i));
	}
   else
     for(j=0;j<Img.Raster->GetSize1D();j++)
	{
	fprintf(f,"%f ",Img.Raster->GetValue2Dd(j,i));
	}
   fprintf(f,"\n");
   //if AlineProc<>nil then AlineProc^.NextLine;
   }

 fclose(f);
 return(0);
}
#endif


TImageFileHandler TXT_H(".TXT",
#if SupportTXT>=4 || SupportTXT==2
	LoadPictureTXT,
#else
	NULL,
#endif
#if SupportTXT>=3
	SavePictureTXT,
#else
	NULL,
#endif
	"plain");

#endif


//-------------------------TXT-gm----------------------
#ifdef SupportTXTgm


#if SupportTXTgm>=4 || SupportTXTgm==2

Image LoadPictureTXTgm(const char *Name)
{
FILE *f;
WORD x,y;
unsigned char ch;
long max,i;
Raster2DAbstractRGB *Raster=NULL;
Image Img;

  if((f=fopen(Name,"rt"))==NULL) return(Img);

  x=0; y=0;
  max=0;

  ch=0;
  while(!feof(f))	//auto detect sizes and num of planes
    {
    while(!(ch>='0' && ch<='9'))
	 {             //go to the begin of number
	 ch=fgetc(f);
	 if(feof(f)) goto EndReading;
	 if(ch=='#') {readln(f,(char *)&ch);continue;}  //comment
	 if(ch==0 || ch>128 || (ch>='a' && ch<='z') || (ch>='A' && ch<='Z'))
		goto FINISH; 	//not a text data
	 }
					// x,y: (R,G,B)
   i=ReadInt(f,(char *)&ch);		// x
   if(i>x) x=i;

   while(ch!=',')
     {ch=fgetc(f);
      if(ch==10 || ch==13) goto FINISH;
      if(feof(f)) break;}
   ch=0;
   i=ReadInt(f,(char *)&ch);		// y
   if(i>y) y=i;

   while(ch!=':')
     {ch=fgetc(f);
      if(ch==10 || ch==13) goto FINISH;
      if(feof(f)) break;}
   while(ch!='(')
     {ch=fgetc(f);
      if(ch==10 || ch==13) goto FINISH;
      if(feof(f)) break;}
   ch=0;
   i = ReadInt(f,(char *)&ch);		// R
   if(i>max) max=i;

   while(ch!=',')
     {ch=fgetc(f);
      if(ch==10 || ch==13) goto FINISH;
      if(feof(f)) break;}
   ch=0;
   i=ReadInt(f,(char *)&ch);		//G
   if(i>max) max=i;

   while(ch!=',')
     {ch=fgetc(f);
      if(ch==10 || ch==13) goto FINISH;
      if(feof(f)) break;}
   ch=0;
   i=ReadInt(f,(char *)&ch);		//B
   if(i>max) max=i;

   while(ch!=')')
     {ch=fgetc(f);
      if(ch==10 || ch==13) goto FINISH;
      if(feof(f)) break;}

   readln(f,(char *)&ch);
   }

EndReading:
  i=1;
//  if(max>=    2) i=2;
//  if(max>=    4) i=4;
//  if(max>=   16) i=8;
  if(max>=  256) i=16;
  if(max>=65536) goto FINISH; //!!! Cannot read 48 bits R(16)G(16)B(16)

  Raster = CreateRaster2DRGB(x+1, y+1, (i<=8)?8:16);

  // printf("Creating raster %d %d",x,y);

  if(Raster==NULL) goto FINISH;
//if(AlineProc!=nil) AlineProc^.InitPassing(p.y,'Loading TXT');

  fseek(f,0,SEEK_SET);

  while(!feof(f)) 	//load picture data
    {
    x=0;
    while(!(ch >= '0' && ch <= '9'))
	 {		//move to the beginning of number
	 if(feof(f)) goto FINISH;
	 ch=fgetc(f);
	 }
    x = ReadInt(f,(char *)&ch);		// x

    while(ch!=',')
      {ch=fgetc(f);
       if(feof(f)) break;}
    ch=0;
    y = ReadInt(f,(char *)&ch);		// y

    while(ch!=':')
      {ch=fgetc(f);
       if(feof(f)) break;}
    while(ch!='(')
      {ch=fgetc(f);
       if(feof(f)) break;}
    ch=0;
    i = ReadInt(f,(char *)&ch);		// R
    Raster->R(x,y,i);

    while(ch!=',')
      {ch=fgetc(f);
       if(feof(f)) break;}
    ch=0;
    i = ReadInt(f,(char *)&ch);		//G
    Raster->G(x,y,i);

    while(ch!=',')
      {ch=fgetc(f);
       if(feof(f)) break;}
    ch=0;
    i = ReadInt(f,(char *)&ch);		//B
    Raster->B(x,y,i);

    while(ch!=')')
      {ch=fgetc(f);
       if(feof(f)) break;}

    readln(f,(char *)&ch);
    }

FINISH:
  fclose(f);
  Img.AttachRaster(Raster);  
  return(Img);
}
#endif


#if SupportTXTgm>=3
int SavePictureTXTgm(const char *Name, const Image &Img)
{
FILE *f;
WORD i,j;
DWORD pix;
BYTE *Buffer24Bit;

 if(Img.Raster==NULL) return(-10);

 Buffer24Bit = (BYTE*)calloc(Img.Raster->GetSize1D(),3);
 if(Buffer24Bit==NULL) return(-11);

 if((f=fopen(Name,"wt"))==NULL) return(-1);
 //if AlineProc<>nil AlineProc^.InitPassing(p.y*p.planes,'Saving TXT gm');

 for(i=0;i<Img.Raster->Size2D;i++)
   {
     if((Img.ImageType() & 0xFF00) == ImagePalette)
     {
       for(j=0;j<Img.Raster->GetSize1D();j++)
	 {	  //0,0: (175,160,148) #865F58
	 pix = Img.Raster->GetValue2D(j,i);
	 pix = Img.Palette->GetValue1D(pix);
	 fprintf(f,"%d,%d: (%d,%d,%d) #%6.6lX\n", j, i,
		(int)(pix & 0xFF), (int)((pix>>8)&0xFF), (int)(pix>>16),
		pix);
	 }
     }
     else
     {
       if(Img.Raster->GetPlanes()>8 && Img.Raster->GetPlanes()<=16)
	 {	/* Slow 16 bit processing. */
	 for(j=0;j<Img.Raster->GetSize1D();j++)
	   {	  //0,0: (175,160,148) #86005F005800
	   pix = Img.Raster->GetValue2D(j,i);
	   fprintf(f,"%d,%d: (%d,%d,%d) #%4X%4X%4X\n", j, i,
		pix, pix, pix,
		pix, pix, pix);
	    }
	 }
       else
	 {
	 Img.Raster->GetRowRaster(i)->Get24BitRGB(Buffer24Bit);
	 for(j=0;j<Img.Raster->GetSize1D();j++)
	   {	  //0,0: (175,160,148) #865F58
	   fprintf(f,"%d,%d: (%d,%d,%d) #%2X%2X%2X\n", j, i,
		Buffer24Bit[3*j], Buffer24Bit[3*j+1], Buffer24Bit[3*j+2],
		Buffer24Bit[3*j], Buffer24Bit[3*j+1], Buffer24Bit[3*j+2] );
	   }
	 }
      }

   fprintf(f,"\n");
   //if AlineProc<>nil then AlineProc^.NextLine;
   }

 if(Buffer24Bit!=NULL) {free(Buffer24Bit);Buffer24Bit=NULL;}

 fclose(f);
 return(0);
}
#endif


TImageFileHandler TXTgm_H(".TXT",
#if SupportTXTgm>=4 || SupportTXTgm==2
	LoadPictureTXTgm,
#else
	NULL,
#endif
#if SupportTXTgm>=3
	SavePictureTXTgm,
#else
	NULL,
#endif
	"gm");

#endif

//-------------------End of TXT routines------------------


//--------------------------WMF----------------------------
#if SupportWMF>0

struct STRETCHDIB_PARAMS
   {
   DWORD bmp_draw_type; 		//0,1
   WORD  dummy;				//2
   WORD bmp_draw_crop_h;		//3
   WORD bmp_draw_crop_w;		//4
   WORD bmp_draw_crop_y;		//5
   WORD bmp_draw_crop_x;		//6
   WORD par_U16_h;			//7
   WORD par_U16_w;			//8
   WORD par_U16_y;			//9
   WORD par_U16_x;			//10
   };

typedef struct _WindowsMetaHeader
{
  WORD  FileType;       /* Type of metafile (0=memory, 1=disk) */
  WORD  HeaderSize;     /* Size of header in WORDS (always 9) */
  WORD  Version;        /* Version of Microsoft Windows used */
  DWORD FileSize;       /* Total size of the metafile in WORDs */
  WORD  NumOfObjects;   /* Number of objects in the file */
  DWORD MaxRecordSize;  /* The size of largest record in WORDs */
  WORD  NumOfParams;    /* Not Used (always 0) */
} WMFHEAD;


typedef struct _StandardMetaRecord
{
    DWORD Size;          /* Total size of the record in WORDs */
    WORD  Function;      /* Function number (defined in WINDOWS.H) */
    DWORD ParamFilePos;
    //WORD  Parameters[];  /* Parameter values passed to function */
} WMFRECORD;


static inline long LoadWMFHeader(FILE *f, _WindowsMetaHeader & SU)
{
#if defined(__PackedStructures__)
return(fread(&SU,1,sizeof(_WindowsMetaHeader),f));
#else
return(loadstruct(f,"wwwdwdw",&SU.FileType,&SU.HeaderSize,
	&SU.Version,&SU.FileSize,&SU.NumOfObjects,&SU.MaxRecordSize,&SU.NumOfParams));
#endif
}


static inline _StandardMetaRecord *LoadWmfRecord(FILE *f)
{
DWORD Size;
_StandardMetaRecord *WmfRec;

  Rd_dword(f,&Size);
  if(Size<3 || feof(f)) return NULL;
  WmfRec=(_StandardMetaRecord *)malloc(sizeof(_StandardMetaRecord));
  WmfRec->Size=Size;
  Rd_word(f,&WmfRec->Function);
  WmfRec->ParamFilePos = ftell(f);
/*
  for(Size=0;Size<WmfRec->Size-3;Size++)
    {
    Rd_word(f,&WmfRec->Parameters[Size]);
    }
*/
  return(WmfRec);
}


typedef struct _EnhancedMetaHeader
{
    DWORD   RecordType;       /* Record type */
    DWORD   RecordSize;       /* Size of the record in bytes */
    SDWORD  BoundsLeft;       /* Left inclusive bounds */
    SDWORD  BoundsRight;      /* Right inclusive bounds */
    SDWORD  BoundsTop;        /* Top inclusive bounds */
    SDWORD  BoundsBottom;     /* Bottom inclusive bounds */
    SDWORD  FrameLeft;        /* Left side of inclusive picture frame */
    SDWORD  FrameRight;       /* Right side of inclusive picture frame */
    SDWORD  FrameTop;         /* Top side of inclusive picture frame */
    SDWORD  FrameBottom;      /* Bottom side of inclusive picture frame */
    DWORD   Signature;        /* Signature ID (always 0x464D4520) */
    DWORD   Version;          /* Version of the metafile */
    DWORD   Size;             /* Size of the metafile in bytes */
    DWORD   NumOfRecords;     /* Number of records in the metafile */
    WORD    NumOfHandles;     /* Number of handles in the handle table */
    WORD    Reserved;         /* Not used (always 0) */
    DWORD   SizeOfDescrip;    /* Size of description string in WORDs */
    DWORD   OffsOfDescrip;    /* Offset of description string in metafile */
    DWORD   NumPalEntries;    /* Number of color palette entries */
    SDWORD  WidthDevPixels;   /* Width of reference device in pixels */
    SDWORD  HeightDevPixels;  /* Height of reference device in pixels */
    SDWORD  WidthDevMM;       /* Width of reference device in millimeters */
    SDWORD  HeightDevMM;      /* Height of reference device in millimeters */
} ENHANCEDMETAHEADER;


static inline long LoadWMF_DIB_PARAMS(FILE *f, STRETCHDIB_PARAMS & params)
{
#if defined(__PackedStructures__)
return(fread(&params,1,sizeof(STRETCHDIB_PARAMS),f));
#else
return(loadstruct(f,"dwwwwwwwww",
	 &params.bmp_draw_type,
	 &params.dummy,
	 &params.bmp_draw_crop_h, &params.bmp_draw_crop_w,
	 &params.bmp_draw_crop_y, &params.bmp_draw_crop_x,
	 &params.par_U16_h, &params.par_U16_w,
	 &params.par_U16_y, &params.par_U16_x));
#endif
}


/** This function extracts bitmap from a WMF stream */
void WMF_STRETCHDIB(Image &Img, FILE *f, DWORD ParamFilePos)
{
STRETCHDIB_PARAMS params;
BitmapInfoHeader BIH;

  fseek(f,ParamFilePos,SEEK_SET);
  LoadWMF_DIB_PARAMS(f,params);

  if(RdDWORD_LoEnd(&BIH.biSize,f)!=4) return;

  if(BIH.biSize==40)
    {
    if(LoadPartBmpInfHdr(f,BIH) != (40-4)) return;

    fseek(f,ParamFilePos+2*11,SEEK_SET);
    if(BIH.biPlanes*BIH.biBitCount == 1)
      LoadBmpStream(Img,f,ParamFilePos+2*11+BIH.biSize+8); //skip 8bit palette for monochromatic images
    else
      LoadBmpStream(Img,f,0);
    }
  else	// don't know
    {
    fseek(f,ParamFilePos+2*11,SEEK_SET);
    LoadBmpStream(Img,f,0);
    }
}

#if SupportWMF>=4 || SupportWMF==2
Image LoadPictureWMF(const char *Name)
{
_WindowsMetaHeader WmfHead;
_StandardMetaRecord *WmfRec;
int Rec;
DWORD NewPos, ActualPos;
FILE *f;
Image Img;

  if((f=fopen(Name,"rb"))==NULL) return(Img);

  if(LoadWMFHeader(f,WmfHead)!=18) return(Img);
  if(WmfHead.HeaderSize!=9) return(Img);

  //perc.Init(ftell(wpd), fsize,_("First pass WMF:") );

  ActualPos=ftell(f);
  Rec=0;
  while(!feof(f))
    {
    WmfRec=LoadWmfRecord(f);
    if(WmfRec!=NULL)
      {
      NewPos=0;

      switch(WmfRec->Function)
	{
/*
	case 0x0000: strcpy(ObjType,"WMF End"); break;

	case 0x001E: strcpy(ObjType,"!SaveDC"); break;

	case 0x0035: strcpy(ObjType,"!RealizePalette"); break;
	case 0x0037: strcpy(ObjType,"!SetPalEntries"); break;

	case 0x004F: strcpy(ObjType,"!StartPage"); break;
        case 0x0050: strcpy(ObjType,"!EndPage"); break;

	case 0x0052: strcpy(ObjType,"!AbortDoc"); break;
        case 0x005E: strcpy(ObjType,"!EndDoc"); break;

	case 0x00F7: strcpy(ObjType,"!CreatePalette"); break;
	case 0x00F8: strcpy(ObjType,"!CreateBrush"); break;

	case 0x0102: strcpy(ObjType,"!SetBkMode"); break;
	case 0x0103: strcpy(ObjType,"!SetMapMode"); break;
	case 0x0104: strcpy(ObjType,"!SetROP2"); break;
	case 0x0105: strcpy(ObjType,"!SetRelabs"); break;
	case 0x0106: strcpy(ObjType,"!SetPolyFillMode"); break;
	case 0x0107: strcpy(ObjType,"!SetStretchBltMode"); break;
	case 0x0108: strcpy(ObjType,"!SetTextCharExtra"); break;

	case 0x0127: strcpy(ObjType,"!RestoreDC"); break;
	case 0x012A: strcpy(ObjType,"!InvertRegion"); break;
	case 0x012B: strcpy(ObjType,"!PaintRegion"); break;
	case 0x012C: strcpy(ObjType,"!SelectClipRegion"); break;
	case 0x012D: strcpy(ObjType,"!SelectObject"); break;
	case 0x012E: strcpy(ObjType,"!SetTextAlign"); break;

	case 0x0139: strcpy(ObjType,"!ResizePalette"); break;

	case 0x0142: strcpy(ObjType,"!DibCreatePatternBrush"); break;

	case 0x014C: strcpy(ObjType,"!ResetDc"); break;
	case 0x014D: strcpy(ObjType,"!StartDoc"); break;

	case 0x01F0: strcpy(ObjType,"!DeleteObject"); break;

	case 0x01F9: strcpy(ObjType,"!CreatePatternBrush"); break;

	case 0x0201: strcpy(ObjType,"!SetBkColor"); break;

	case 0x0209: strcpy(ObjType,"!SetTextColor"); break;
	case 0x020A: strcpy(ObjType,"!SetTextJustification"); break;
	case 0x020B: strcpy(ObjType,"!SetWindowOrg"); break;
	case 0x020C: strcpy(ObjType,"!SetWindowExt"); break;
	case 0x020D: strcpy(ObjType,"!SetViewportOrg"); break;
	case 0x020E: strcpy(ObjType,"!SetViewportExt"); break;
	case 0x020F: strcpy(ObjType,"!OffsetWindowOrg"); break;

	case 0x0211: strcpy(ObjType,"!OffsetViewportOrg"); break;
	case 0x0213: strcpy(ObjType,"!LineTo"); break;
	case 0x0214: strcpy(ObjType,"!MoveTo"); break;

	case 0x0220: strcpy(ObjType,"!OffsetClipRgn"); break;

	case 0x0228: strcpy(ObjType,"!FillRegion"); break;

	case 0x0231: strcpy(ObjType,"!SetMapperFlags"); break;

	case 0x0234: strcpy(ObjType,"!SelectPalette"); break;

	case 0x02FA: strcpy(ObjType,"!CreatePenIndirect"); break;
	case 0x02FB: strcpy(ObjType,"!CreateFontIndirect"); break;
	case 0x02FC: strcpy(ObjType,"!CreateBrushIndirect"); break;
	case 0x02FD: strcpy(ObjType,"!CreateBitmapIndirect"); break;

	case 0x0324: strcpy(ObjType,"!Polygon"); break;
	case 0x0325: strcpy(ObjType,"!Polyline"); break;

	case 0x0410: strcpy(ObjType,"!ScaleWindowExt"); break;

	case 0x0412: strcpy(ObjType,"!ScaleViewportExt"); break;

	case 0x0415: strcpy(ObjType,"!ExcludeClipRect"); break;
	case 0x0416: strcpy(ObjType,"!IntersectClipRect"); break;

	case 0x0418: strcpy(ObjType,"!Ellipse"); break;
	case 0x0419: strcpy(ObjType,"!FloodFill"); break;

	case 0x041B: strcpy(ObjType,"!Rectangle"); break;

	case 0x041F: strcpy(ObjType,"!SetPixel"); break;

	case 0x0429: strcpy(ObjType,"!FrameRegion"); break;

	case 0x0436: strcpy(ObjType,"!AnimatePalette"); break;

	case 0x0521: strcpy(ObjType,"!TextOut"); break;

	case 0x0538: strcpy(ObjType,"!PolyPolygon"); break;

	case 0x0548: strcpy(ObjType,"!ExtFloodFill"); break;

	case 0x626:  strcpy(ObjType,"Escape");break;

	case 0x061C: strcpy(ObjType,"!RoundRect"); break;
	case 0x061D: strcpy(ObjType,"!PatBlt"); break;

	case 0x062F: strcpy(ObjType,"!DrawText"); break;

	case 0x06FE: strcpy(ObjType,"!CreateBitmap"); break;
	case 0x06FF: strcpy(ObjType,"!CreateRegion"); break;

        case 0x0817: strcpy(ObjType,"!Arc"); break;

	case 0x081A: strcpy(ObjType,"!Pie"); break;

 	case 0x0830: strcpy(ObjType,"!Chord"); break;

	case 0x0922: strcpy(ObjType,"!BitBlt"); break;

	case 0x0940: strcpy(ObjType,"!DibBitblt"); break;

	case 0x0A32: strcpy(ObjType,"!ExtTextOut"); break;

	case 0x0B23: strcpy(ObjType,"!StretchBlt"); break;

	case 0x0B41: strcpy(ObjType,"!DibStretchBlt"); break;

	case 0x0d33: strcpy(ObjType,"!SetDibToDev"); break;
*/
	case 0x0F43: WMF_STRETCHDIB(Img, f, WmfRec->ParamFilePos);
//		     strcpy(ObjType,"StretchDIBits");
		     break;
	}


      if(NewPos!=0) ActualPos=NewPos;
	       else ActualPos+=2*WmfRec->Size;
      free(WmfRec); WmfRec=NULL;

      fseek(f,ActualPos,SEEK_SET);
      }
    else
      ActualPos=ftell(f);

    Rec++;
    }

  return(Img);
}
#endif


TImageFileHandler WMF_H(".WMF",
#if SupportWMF>=4 || SupportWMF==2
	LoadPictureWMF,
#else
	NULL,
#endif
#if SupportWMF>=3
	SavePictureWMF);
#else
	NULL);
#endif

#endif
//-------------------End of WMF routines------------------


//--------------------------WPG----------------------------
#if SupportWPG>0
struct WPGHeader
	{
	DWORD FileId;
	DWORD DataOffset;
	WORD ProductType;
	WORD FileType;
	BYTE MajorVersion;
	BYTE MinorVersion;
	WORD EncryptKey;
	WORD Reserved;
	};
//structures for WPG level 1
struct WPGRecord
	{
	BYTE	RecType;
	DWORD   RecordLength;
	};

struct WPGCurve
	{
	WORD Count;
	DWORD something;
	SWORD x;
	SWORD y;
	};

struct WPGBitmapType1
	{
	WORD Width;
	WORD Height;
	WORD Depth;
	WORD HorzRes;
	WORD VertRes;
	};
struct WPGBitmapType2
	{
	WORD RotAngle;
	WORD LowLeftX;
	WORD LowLeftY;
	WORD UpRightX;
	WORD UpRightY;
	WORD Width;
	WORD Height;
	WORD Depth;
	WORD HorzRes;
	WORD VertRes;
	};
struct WPGColorMapRec
	{
	WORD StartIndex;
	WORD NumOfEntries;
	};
struct WPGTextL2
	{
	BYTE Unknown[4];
	WORD RotAngle;
	BYTE Unknown2[2];
	SWORD LowLeftX;
	SWORD LowLeftY;
	SWORD UpRightX;
	SWORD UpRightY;
	BYTE Unknown3[4];
	};
struct WPGEllipse
	{
	WORD Sx;
	WORD Sy;
	WORD rx;
	WORD ry;
	WORD RotAngle;
	WORD bAngle;
	WORD eAngle;
	BYTE style;
	};

//structures for WPG level 2
struct WPG2Record
	{
	BYTE	Class;
	BYTE    Type;
	DWORD   Extension;
	DWORD   RecordLength;
	};

struct WPG2BitmapData
	{
	WORD Width;
	WORD Height;
	BYTE Depth;
	BYTE Compression;
	};
struct WPG2BitmapRectangle
	{
	//WORD Flags;
	WORD LowLeftX;
	WORD LowLeftY;
	WORD UpRightX;
	WORD UpRightY;
	WORD HorzRes;
	WORD VertRes;
	};
struct WPG2DblBitmapRectangle
	{
	//WORD Flags;
	DWORD LowLeftX;
	DWORD LowLeftY;
	DWORD UpRightX;
	DWORD UpRightY;
	DWORD HorzRes;
	DWORD VertRes;
	};
struct WPG2Start
	{
	WORD	HorizontalUnits;
	WORD	VerticalUnits;
	BYTE    PosSizePrecision;
	};
struct WPG2Arc
	{
	//WORD Flags;
	SWORD Sx;
	SWORD Sy;
	SWORD rx;
	SWORD ry;
	SWORD Xi,Yi;
	SWORD Xt,Yt;
	BYTE aFlags;
	};
struct WPG2Rectangle
	{
	//WORD Flags;
	SWORD X_ll;
	SWORD Y_ll;
	SWORD X_ur;
	SWORD Y_ur;
	SWORD H_radius;
	SWORD V_radius;
	};
struct WPG2TextLine
	{
	//WORD Flags;
	WORD TxtFlags;
	SWORD Xref;
	SWORD Yref;
	BYTE HAlign,VAlign;
	DWORD Angle;
	};


union WPG_records
	{
	WPGBitmapType1       BitmapType1;
	WPGBitmapType2       BitmapType2;
	WPGColorMapRec       ColorMapRec;
	WPGCurve	     Curve;
	WPGTextL2	     TextL2;
	WPGEllipse	     Ellipse;

	WPG2BitmapData      _2BitmapData;
	WPG2BitmapRectangle _2BitmapRectangle;
	WPG2DblBitmapRectangle _2DblBitmapRectangle;
	WPG2Arc		    _2Arc;
	WPG2Rectangle	    _2Rect;
	WPG2TextLine	    _2TxtLine;
	};

RGB_Record WPG2_Palette[256]={
{0,   0,   0},
{0xFF,0xFF,0xFF},
{0x7F,0x7F,0x7F},
{0xBF,0xBF,0xBF},
{0x00,0x00,0x7F},
{0x00,0x7F,0x00},
{0x00,0x7F,0x7F},
{0x7F,0x00,0x00},
{0x7F,0x00,0x7F},
{0x7F,0x7F,0x00},
{0x00,0x00,0xFF},
{0x00,0xFF,0x00},
{0x00,0xFF,0xFF},
{0xFF,0x00,0x00},
{0xFF,0x00,0xFF},
{0xFF,0xFF,0x00}   };


RGB_Record WPG_Palette[256]={
{  0,  0,  0},		{  0,  0,168},  //Original 16 items of palette
{  0,168,  0},		{  0,168,168},
{168,  0,  0},		{168,  0,168},
{168, 84,  0},		{168,168,168},
{ 84, 84, 84},		{ 84, 84,252},
{ 84,252, 84},		{ 84,252,252},
{252, 84, 84},		{252, 84,252},
{252,252, 84},		{252,252,252},  //16

/*
{  0,  0,  0},		{  0,  0,127},	//Strong 16 items of palette
{  0,127,  0},		{  0,127,127},
{127,  0,  0},		{127,  0,127},
{127, 63,  0},		{127,127,127},
{192,192,192},		{  0,  0,255},
{  0,255,  0},		{255,  0,  0},
{255,  0,  0},		{255,  0,255},
{255,255,  0},		{255,255,255},  //16
*/
{  0,  0,  0},		{ 20, 20, 20},
{ 32, 32, 32},		{ 44, 44, 44},
{ 56, 56, 56},		{ 68, 68, 68},
{ 80, 80, 80},		{ 96, 96, 96},
{112,112,112},		{128,128,128},
{144,144,144},		{160,160,160},
{180,180,180},		{200,200,200},
{224,224,224},		{252,252,252},  //32
{  0,  0,252},		{ 64,  0,252},
{124,  0,252},		{188,  0,252},
{252,  0,252},		{252,  0,188},
{252,  0,124},		{252,  0, 64},
{252,  0,  0},		{252, 64,  0},
{252,124,  0},		{252,188,  0},
{252,252,  0},		{188,252,  0},
{124,252,  0},		{ 64,252,  0},	//48
{  0,252,  0},		{  0,252, 64},
{  0,252,124},		{  0,252,188},
{  0,252,252},		{  0,188,252},
{  0,124,252},		{  0, 64,252},
{124,124,252},		{156,124,252},
{188,124,252},		{220,124,252},
{252,124,252},		{252,124,220},
{252,124,188},		{252,124,156},	//64
{252,124,124},		{252,156,124},
{252,188,124},		{252,220,124},
{252,252,124},		{220,252,124},
{188,252,124},		{156,252,124},
{124,252,124},		{124,252,156},
{124,252,188},		{124,252,220},
{124,252,252},		{124,220,252},
{124,188,252},		{124,156,252},	//80
{180,180,252},		{196,180,252},
{216,180,252},		{232,180,252},
{252,180,252},		{252,180,232},
{252,180,216},		{252,180,196},
{252,180,180},		{252,196,180},
{252,216,180},		{252,232,180},
{252,252,180},		{232,252,180},
{216,252,180},		{196,252,180},	//96
{180,220,180},		{180,252,196},
{180,252,216},		{180,252,232},
{180,252,252},		{180,232,252},
{180,216,252},		{180,196,252},
{0,0,112},		{28,0,112},
{56,0,112},		{84,0,112},
{112,0,112},		{112,0,84},
{112,0,56},		{112,0,28},	//112
{112,0,0},		{112,28,0},
{112,56,0},		{112,84,0},
{112,112,0},		{84,112,0},
{56,112,0},		{28,112,0},
{0,112,0},		{0,112,28},
{0,112,56},		{0,112,84},
{0,112,112},		{0,84,112},
{0,56,112},		{0,28,112}, 	//128
{56,56,112},		{68,56,112},
{84,56,112},		{96,56,112},
{112,56,112},		{112,56,96},
{112,56,84},		{112,56,68},
{112,56,56},		{112,68,56},
{112,84,56},		{112,96,56},
{112,112,56},		{96,112,56},
{84,112,56},		{68,112,56},	//144
{56,112,56},		{56,112,69},
{56,112,84},		{56,112,96},
{56,112,112},		{56,96,112},
{56,84,112},		{56,68,112},
{80,80,112},		{88,80,112},
{96,80,112},		{104,80,112},
{112,80,112},		{112,80,104},
{112,80,96},		{112,80,88},	//160
{112,80,80},		{112,88,80},
{112,96,80},		{112,104,80},
{112,112,80},		{104,112,80},
{96,112,80},		{88,112,80},
{80,112,80},		{80,112,88},
{80,112,96},		{80,112,104},
{80,112,112},		{80,114,112},
{80,96,112},		{80,88,112},	//176
{0,0,64},		{16,0,64},
{32,0,64},		{48,0,64},
{64,0,64},		{64,0,48},
{64,0,32},		{64,0,16},
{64,0,0},		{64,16,0},
{64,32,0},		{64,48,0},
{64,64,0},		{48,64,0},
{32,64,0},		{16,64,0},	//192
{0,64,0},		{0,64,16},
{0,64,32},		{0,64,48},
{0,64,64},		{0,48,64},
{0,32,64},		{0,16,64},
{32,32,64},		{40,32,64},
{48,32,64},		{56,32,64},
{64,32,64},		{64,32,56},
{64,32,48},		{64,32,40},	//208
{64,32,32},		{64,40,32},
{64,48,32},		{64,56,32},
{64,64,32},		{56,64,32},
{48,64,32},		{40,64,32},
{32,64,32},		{32,64,40},
{32,64,48},		{32,64,56},
{32,64,64},		{32,56,64},
{32,48,64},		{32,40,64},	//224
{44,44,64},		{48,44,64},
{52,44,64},		{60,44,64},
{64,44,64},		{64,44,60},
{64,44,52},		{64,44,48},
{64,44,44},		{64,48,44},
{64,52,44},		{64,60,44},
{64,64,44},		{60,64,44},
{52,64,44},		{48,64,44},	//240
{44,64,44},		{44,64,48},
{44,64,52},		{44,64,60},
{44,64,64},		{44,60,64},
{44,55,64},		{44,48,64},
{0,0,0},		{0,0,0},
{0,0,0},		{0,0,0},
{0,0,0},		{0,0,0},
{0,0,0},		{0,0,0}		//256
};


inline long LoadWPGHeader(FILE *f,WPGHeader & SU)
{
#if defined(__PackedStructures__)
return(fread(&SU,1,sizeof(WPGHeader),f));
#else
return(loadstruct(f,"ddwwbbww",&SU.FileId,&SU.DataOffset,
	&SU.ProductType,&SU.FileType,&SU.MajorVersion,&SU.MinorVersion,&SU.EncryptKey,&SU.Reserved));
#endif
}

inline long LoadWPGBitmapType1(FILE *f,WPGBitmapType1 & SU)
{
#if defined(__PackedStructures__)
return(fread(&SU,sizeof(WPGBitmapType1),1,f));
#else
return(loadstruct(f,"wwwww",&SU.Width,&SU.Height,&SU.Depth,&SU.HorzRes,&SU.VertRes));
#endif
}

inline long LoadWPG2BitmapData(FILE *f,WPG2BitmapData & SU)
{
#if defined(__PackedStructures__)
return(fread(&SU,sizeof(WPG2BitmapData),1,f));
#else
return(loadstruct(f,"wwbb",&SU.Width,&SU.Height,&SU.Depth,&SU.Compression));
#endif
}

inline long LoadWPG2BitmapRectangle(FILE *f,WPG2BitmapRectangle & SU)
{
#if defined(__PackedStructures__)
return(fread(&SU,sizeof(WPG2BitmapRectangle),1,f));
#else
return(loadstruct(f,"wwwwww",&SU.LowLeftX,&SU.LowLeftY,&SU.UpRightX,&SU.UpRightY,
	&SU.HorzRes,&SU.VertRes));
#endif
}

inline long LoadWPG2DblBitmapRectangle(FILE *f,WPG2DblBitmapRectangle & SU)
{
#if defined(__PackedStructures__)
return(fread(&SU,sizeof(WPG2DblBitmapRectangle),1,f));
#else
return(loadstruct(f,"dddddd",&SU.LowLeftX,&SU.LowLeftY,&SU.UpRightX,&SU.UpRightY,
	&SU.HorzRes,&SU.VertRes));
#endif
}

inline long LoadWPGBitmapType2(FILE *f,WPGBitmapType2 & SU)
{
#if defined(__PackedStructures__)
return(fread(&SU,sizeof(WPGBitmapType2),1,f));
#else
return(loadstruct(f,"wwwwwwwwww",&SU.RotAngle,&SU.LowLeftX,&SU.LowLeftY,&SU.UpRightX,&SU.UpRightY,
	&SU.Width,&SU.Height,&SU.Depth,&SU.HorzRes,&SU.VertRes));
#endif
}

inline long LoadWPGColormap(FILE *f,WPGColorMapRec & SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU,1,sizeof(WPGColorMapRec),f));
#else
 return(loadstruct(f,"ww",&SU.StartIndex,&SU.NumOfEntries));
#endif
}

inline long LoadWPG2Start(FILE *f,WPG2Start & SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU,1,sizeof(WPG2Start),f));
#else
 return(loadstruct(f,"wwb",&SU.HorizontalUnits,&SU.VerticalUnits,&SU.PosSizePrecision));
#endif
}

inline long LoadWPG2Rectangle(FILE *f,WPG2Rectangle & SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU,1,sizeof(WPG2Rectangle),f));
#else
 return(loadstruct(f,"wwwwww",&SU.X_ll,&SU.Y_ll,&SU.X_ur,&SU.Y_ur,
			      &SU.H_radius,&SU.V_radius));
#endif
}

inline long LoadWPG2Arc(FILE *f,WPG2Arc & SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU,1,sizeof(WPG2Arc),f));
#else
 return(loadstruct(f,"wwwwwwwwb",&SU.Sx,&SU.Sy,&SU.rx,&SU.ry,
				 &SU.Xi,&SU.Yi,&SU.Xt,&SU.Yt,&SU.aFlags));
#endif
}

inline long LoadWPG2TextLine(FILE *f,WPG2TextLine & SU)
{
#if defined(__PackedStructures__)
 return(fread(&SU,1,sizeof(WPG2TextLine),f));
#else
 return(loadstruct(f,"wwwbbd",&SU.TxtFlags,&SU.Xref,&SU.Yref,&SU.HAlign,&SU.VAlign,
			      &SU.Angle));
#endif
}


#define InsertByte(b) \
{\
 *BObrPos = b;BObrPos++;\
 x++;\
 if(x>=ldblk)\
    {\
    x=0;y++;\
    BObrPos=(BYTE *)Raster->GetRow(y>=Raster->Size2D?0:y);\
	/*if(AlineProc) AlineProc->NextLine;*/\
    }\
}


#define InsertByte6(b) \
{\
 if(BObrUpPos)\
   {*BObrPos = b ^ *BObrUpPos; BObrUpPos++;}\
 else\
   *BObrPos = b;\
 BObrPos++;\
 x++;\
 if(x>=ldblk)\
    {\
    x=0;y++;\
    BObrPos=(BYTE *)Raster->GetRow(y>=Raster->Size2D?0:y);\
    BObrUpPos=NULL;\
	/*if(AlineProc) AlineProc->NextLine;*/\
    }\
}


static void Rd_WP_DWORD(FILE *f, DWORD *d)
{
   unsigned char b;

   fread(&b, sizeof(unsigned char), 1, f);
   *d = b;
   if(b<0xFF) return;

   fread(&b, sizeof(unsigned char), 1, f);
   *d = (DWORD)b ;
   fread(&b, sizeof(unsigned char), 1, f);
   *d += (DWORD)b * 256;
   if(*d<0x8000) return;

   *d = (*d & 0x7FFF) << 16;
   fread(&b, sizeof(unsigned char), 1, f);
   *d += (DWORD)b;
   fread(&b, sizeof(unsigned char), 1, f);
   *d += (DWORD)b * 256l;
   return;
}


int UnpackWPGRaster(Raster2DAbstract *Raster,FILE *f)
{
unsigned x,y,i;
BYTE bbuf,*BObrPos,RunCount;
unsigned long ldblk;

if(Raster==NULL) return(-1);  //Not Enough memory
//	     if AlineProc<>nil then AlineProc^.InitPassing(Raster->Size2D,'Loading WPG');

 x=0;
 y=0;
 BObrPos=(BYTE *)Raster->GetRow(0);
 ldblk=((long)Raster->GetPlanes()*Raster->GetSize1D()+7)/8;

 while(y<Raster->Size2D)
     {
     if(fread(&bbuf,1,1,f)!=1)
	{
	Raster->Erase();
	return(-2);
	}

     RunCount=bbuf & 0x7F;
     if(bbuf & 0x80)
	{
	if(RunCount)	// repeat next byte runcount *
		{
		fread(&bbuf,1,1,f);
		for(i=0;i<RunCount;i++) InsertByte(bbuf);
		}
	   else {	//read next byte as RunCount; repeat 0xFF runcount*
		fread(&RunCount,1,1,f);
		for(i=0;i<RunCount;i++) InsertByte(0xFF);
		}
	}
   else {
	if(RunCount)   // next runcount byte are readed directly
		{
		for(i=0;i<RunCount;i++)
			{
			fread(&bbuf,1,1,f);
			InsertByte(bbuf);
			};
		}
	   else {	// repeat previous line runcount*
		fread(&RunCount,1,1,f);
		if(x) {
		      return(-3);  // missing code	  asm int 3; }; { not finished !!!!!!!!}
		      }
		for(i=0;i<RunCount;i++)
			{
			x=0;
			y++;
			if(y>=Raster->Size2D) BObrPos=(BYTE *)Raster->GetRow(0);
					      BObrPos=(BYTE *)Raster->GetRow(y);
//			if AlineProc<>nil then AlineProc^.NextLine;
				if(y<2) continue;
			if(y>Raster->Size2D) return(-4);
			memmove(Raster->GetRow(y-1),Raster->GetRow(y-2),ldblk);
			}
                }
        }
   }
 return(0);
}


/** This procedure binds non-gray palette to image. */
void AssignPalette(Image *Img, APalette *Palette)
{
  if(Img==NULL) return;
  Img->AttachPalette(NULL);

  if(Palette==NULL) return;
  if(GrayPalette(Palette,Img->Raster->GetPlanes())) return;

  if(Img->Raster->GetPlanes()==1)   //palete empty check
    {
    if(Palette->GetValue1D(0)==0 && Palette->GetValue1D(1)==0)
           return;    		   //reject crippled monochrome palette
    }

  Img->AttachPalette(Palette);
}


int UnpackWPG2Raster(Raster2DAbstract *Raster,FILE *f)
{
unsigned x,y,i;
BYTE bbuf,RunCount;
BYTE *BObrPos,*BObrUpPos;
unsigned long ldblk;
unsigned char SampleBuffer[8];
unsigned char SampleSize = 1;

if(Raster==NULL) return(-1);  //Not Enough memory
//	     if AlineProc<>nil then AlineProc^.InitPassing(Raster->Size2D,'Loading WPG');

 x=0;
 y=0;
 BObrPos = (BYTE *)Raster->GetRow(0);
 BObrUpPos = NULL;
 ldblk = ((unsigned long)Raster->GetPlanes()*Raster->GetSize1D()+7)/8;

 while(y<Raster->Size2D)
     {
     if(fread(&bbuf,1,1,f)!=1)
	{
	Raster->Erase();
	return(-2);
	}

     switch(bbuf)
       {
       case 0x7D:fread(&SampleSize,1,1,f); 		// DSZ
		 if(SampleSize>8) return(-2);
		 if(SampleSize<1) return(-2);
		 break;
       case 0x7E:if(y==0)				// XOR
		   fprintf(stderr,"\nWPG token XOR on the first line is not supported, please report!");
		 else
		   BObrUpPos = (BYTE *)Raster->GetRow(y>Raster->Size2D?0:y-1) + x;
		 break;
       case 0x7F:fread(&RunCount,1,1,f);		// BLK
		 for(i=0;i<SampleSize*((unsigned)RunCount+1);i++)
		   InsertByte6(0);
		 break;
       case 0xFD:fread(&RunCount,1,1,f);                                // EXT
		 for(i=0;i<=(unsigned)RunCount;i++)
		    for(bbuf=0;bbuf<SampleSize;bbuf++)
			InsertByte6(SampleBuffer[bbuf]);   //extend previous REP or another EXT token
		 break;
       case 0xFE:fread(&RunCount,1,1,f);				// RST
		 if(x!=0)
			{
			fprintf(stderr,"\nUnsupported WPG2 unaligned token RST x=%d, please report!\n",x);
			return(-3);
			}
		 for(i=0;i<=RunCount;i++)
			{
			x=0;
			y++;
			if(y>=Raster->Size2D) BObrPos=(BYTE *)Raster->GetRow(0);
					      BObrPos=(BYTE *)Raster->GetRow(y);
//			if AlineProc<>nil then AlineProc^.NextLine;
			if(y<2) continue;
			if(y>Raster->Size2D) return(-4);
			memmove(Raster->GetRow(y-1),Raster->GetRow(y-2),ldblk);
			}
		 break;
       case 0xFF:fread(&RunCount,1,1,f);		// WHT
		 for(i=0;i<SampleSize*((unsigned)RunCount+1);i++)//read next byte as RunCount; repeat 0xFF runcount*
			{
			InsertByte6(0xFF);
			}
		 break;
       default:
	  RunCount=bbuf & 0x7F;

	  if(bbuf & 0x80)                               //REP
		{	// repeat next byte runcount *
		for(i=0;i<SampleSize;i++)
			fread(&SampleBuffer[i],1,1,f);
		for(i=0;i<=(unsigned)RunCount;i++)
		    for(bbuf=0;bbuf<SampleSize;bbuf++)
			InsertByte6(SampleBuffer[bbuf]);
		}
	   else {                                       //NRP
		for(i=0;i<SampleSize*((unsigned)RunCount+1);i++)
			{
			fread(&bbuf,1,1,f);
			InsertByte6(bbuf);
			}
		}
	  }
   }
 return(0);
}


WORD LoadWPG2Flags(FILE *F,float_matrix &CTM,char Precision=0,float *Angle=NULL)
{
const BYTE TPR=1,TRN=2,SKW=4,SCL=8,ROT=0x10,OID=0x20,LCK=0x80;
SDWORD x;
WORD xW,DenX;
WORD Flags;

//x=ftell(F);
 CTM.erase();
 CTM.resize(3,3);
 CTM.member(0,0)=1;
 CTM.member(1,1)=1;
 CTM.member(2,2)=1;

 Rd_word(F,&Flags);
 if(Flags & LCK) Rd_dword(F,(DWORD *)&x);	//Edit lock
 if(Flags & OID)
	{
	if(Precision==0)
	  {Rd_word(F,(WORD *)&x);}	//ObjectID
	else
	  {Rd_dword(F,(DWORD *)&x);}		//ObjectID (Double precision)
	}
 if(Flags & ROT)
	{
	Rd_dword(F,(DWORD *)&x);		//Rot Angle
	if(Angle) *Angle=x/65536.0;
	}
 if(Flags & (ROT|SCL))
	{
	Rd_dword(F,(DWORD *)&x);		//Sx*cos()
	CTM.member(0,0) = (float)x/0x10000;
	Rd_dword(F,(DWORD *)&x);		//Sy*cos()
	CTM.member(1,1) = (float)x/0x10000;
	}
 if(Flags & (ROT|SKW))
	{
	Rd_dword(F,(DWORD *)&x);		//Kx*sin()
	CTM.member(1,0) = (float)x/0x10000;
	Rd_dword(F,(DWORD *)&x);		//Ky*sin()
	CTM.member(0,1) = (float)x/0x10000;
	}
 if(Flags & TRN)
	{
	Rd_dword(F,(DWORD *)&x); Rd_word(F,&DenX); //Tx
        if(x>=0) CTM.member(0,2)=(float)x+(float)DenX/0x10000;
           else CTM.member(0,2)=(float)x-(float)DenX/0x10000;
	Rd_dword(F,(DWORD *)&x); Rd_word(F,&DenX); //Ty
        if(x>=0) CTM.member(1,2)=(float)x+(float)DenX/0x10000;
           else CTM.member(1,2)=(float)x-(float)DenX/0x10000;
	}
 if(Flags & TPR)
	{
	Rd_word(F,&xW);Rd_word(F,&DenX);	//Px
	CTM.member(2,0)=xW+(float)DenX/0x10000;
	Rd_word(F,&xW);Rd_word(F,&DenX);	//Py
	CTM.member(2,1)=xW+(float)DenX/0x10000;
	}
 return(Flags);
}


#if SupportWPG>=4 || SupportWPG==2
Image LoadPictureWPG(const char *Name)
{
FILE *f;
long len,ldblk;
unsigned i;
WPGHeader  Header;
WPGRecord  Rec;
WPG2Record  Rec2;
WPG_records WPG;
WPG2Start StartWPG;
WPGColorMapRec wpPal;
Raster2DAbstract *Raster=NULL;
APalette *Palette=NULL;
Image Img,*CurrImg;
float RotAngle,x,y,dx,dy;

 CurrImg=&Img;

 if((f=fopen(Name,"rb"))==NULL) return(NULL);

 len=LoadWPGHeader(f,Header);
 if(Header.FileId!=0x435057FF || len!=18 ||
    (Header.ProductType>>8)!=0x16 || Header.EncryptKey!=0 )
	 {fclose(f);return(NULL);}

 RotAngle=x=y=dx=dy=0;
 switch(Header.FileType)
   {
   case 1:
     while(!feof(f))
       {
       fseek(f,Header.DataOffset,SEEK_SET);
       if(feof(f)) break;

       Rec.RecType=fgetc(f);
       Rd_WP_DWORD(f,&Rec.RecordLength);

       Header.DataOffset=ftell(f)+Rec.RecordLength;

       //!!!!!!The internal palette should be loaded right here

       switch(Rec.RecType)
	 {
	 case 0x0B:	// bitmap type 1
		 LoadWPGBitmapType1(f,WPG.BitmapType1);
		 if(Raster!=NULL) break;
		 Raster=CreateRaster2D(WPG.BitmapType1.Width,WPG.BitmapType1.Height,WPG.BitmapType1.Depth);
		 if(Raster)
		   {
		   if(UnpackWPGRaster(Raster,f)<0) Raster->Erase();
LoadRaster:	   if(Img.Raster!=NULL)
		     {
		     CurrImg->Next=new Image;
		     CurrImg=CurrImg->Next;
		     }
		   RotAngle-=360*((long)RotAngle/360);
		   CurrImg->x=x;
		   CurrImg->y=y;
		   CurrImg->dx=dx;
		   CurrImg->dy=dy;
		   CurrImg->RotAngle=RotAngle;
		   RotAngle=x=y=dx=dy=0;

		   CurrImg->AttachRaster(Raster);		   
		   if(Raster->GetPlanes()>1)		// Assign palette for non monochrome images.
		     AssignPalette(CurrImg,Palette);
		   Raster=NULL;
		   }
		 break;
	 case 0x0E:	// color palette
		 LoadWPGColormap(f,wpPal);
		 if(Palette!=NULL && Palette->UsageCount==0) delete Palette;
		 Palette=BuildPalette(wpPal.NumOfEntries+wpPal.StartIndex,8);
		 if(Palette!=NULL)
		    {
		    fread((char *)Palette->Data1D + 3*wpPal.StartIndex,
			  3*wpPal.NumOfEntries,1,f);
		    }
		 break;

	 case 0x14:	// bitmap type 2
		 LoadWPGBitmapType2(f,WPG.BitmapType2);
		 if(Raster!=NULL) break;
		 Raster=CreateRaster2D(WPG.BitmapType2.Width,WPG.BitmapType2.Height,WPG.BitmapType2.Depth);
		 if(Raster==NULL) break;
		 x = WPG.BitmapType2.LowLeftX/47.0;
		 y = WPG.BitmapType2.LowLeftY/47.0;
		 dx= (WPG.BitmapType2.UpRightX-WPG.BitmapType2.LowLeftX)/47.0;
		 dy= (WPG.BitmapType2.UpRightY-WPG.BitmapType2.LowLeftY)/47.0;
		 RotAngle=WPG.BitmapType2.RotAngle & 0x0FFF;
		 if(UnpackWPGRaster(Raster,f)<0)
					{delete Raster;Raster=NULL;break;}
		 if(WPG.BitmapType2.RotAngle & 0x8000)
				   {Flip1D(Raster);RotAngle=360-RotAngle;}
		 if(WPG.BitmapType2.RotAngle & 0x2000)
				   {
				   Flip2D(Raster);
				   if((WPG.BitmapType2.RotAngle & 0x8000)==0)
					RotAngle=360-RotAngle;
				   }
		 goto LoadRaster;
	 }
      }
     break;
   case 2:
     float_matrix CTM(3,3);
     StartWPG.PosSizePrecision=0;
     while(!feof(f))
       {
       fseek(f,Header.DataOffset,SEEK_SET);
       if(feof(f)) break;

       Rec2.Class=fgetc(f);
       Rec2.Type=fgetc(f);
       Rd_WP_DWORD(f,&Rec2.Extension);
       Rd_WP_DWORD(f,&Rec2.RecordLength);

       Header.DataOffset=ftell(f)+Rec2.RecordLength;

       switch(Rec2.Type)
	 {
	 case 0x01:LoadWPG2Start(f,StartWPG);
		   break;
	 case 0x0C:	// color palette
		 LoadWPGColormap(f,wpPal);
		 if(Palette!=NULL && Palette->UsageCount==0) delete Palette;
		 Palette=BuildPalette(wpPal.NumOfEntries+wpPal.StartIndex,8);
		 if(Palette!=NULL)
		    {
		    for(i=wpPal.StartIndex;i<wpPal.NumOfEntries;i++)
			{
			Palette->R(i,fgetc(f));
			Palette->G(i,fgetc(f));
			Palette->B(i,fgetc(f));
			fgetc(f);
			}
		    }
		 break;

	 case 0x0E:	//raster data
	     LoadWPG2BitmapData(f,WPG._2BitmapData);
	     if(WPG._2BitmapData.Compression>1) goto Skip_WP_BMP;
	     switch(WPG._2BitmapData.Depth)
	       {
	       case 1:i=1;break;
	       case 2:i=2;break;
	       case 3:i=4;break;
	       case 4:i=8;break;
	       case 8:i=24;break;
	       default:continue;  /*Ignore raster with unknown depth*/
	       }
	     Raster=CreateRaster2D(WPG._2BitmapData.Width,WPG._2BitmapData.Height,i);
	     if(Raster==NULL) continue;

	     if(WPG._2BitmapData.Compression==1)
		   {
		   if(UnpackWPG2Raster(Raster,f)<0)
				  Raster->Erase();
		   }
	     if(WPG._2BitmapData.Compression==0)
		{
		ldblk=(Raster->GetPlanes()*Raster->GetSize1D()+7)/8;
		for(i=0;i<Raster->Size2D;i++)
		   {
		   if(fread(Raster->GetRow(i),ldblk,1,f)!=1) {goto FINISH;}
	//	   AlineProc(i,p);
		   }
		}
	     if(Img.Raster!=NULL)
		   {
		   CurrImg->Next=new Image;
		   CurrImg=CurrImg->Next;
		   }
	     CurrImg->x=x;
	     CurrImg->y=y;
	     CurrImg->dx=dx;
	     CurrImg->dy=dy;
	     x=y=dx=dy=0;
             if(Raster!=NULL)
		{
		if(CTM.member(0,0)<0)
		  {
		  Flip1D(Raster); //?? RotAngle=360-RotAngle;
			/* Try to change CTM according to Flip - I am not sure, must be checked. */
		  float_matrix Tx(3,3);
		  Tx(0,0)=-1;      Tx(1,0)=0;   Tx(2,0)=0;
		  Tx(0,1)= 0;      Tx(1,1)=1;   Tx(2,1)=0;
		  Tx(0,2)=(WPG._2Rect.X_ur+WPG._2Rect.X_ll);
		                   Tx(1,2)=0;   Tx(2,2)=1;
                  CTM *= Tx;
                  }
		if(CTM.member(1,1)<0)
		  {
		  Flip2D(Raster); //?? RotAngle=360-RotAngle;
			  /* Try to change CTM according to Flip - I am not sure, must be checked. */
		  float_matrix Tx(3,3);
		  Tx(0,0)= 1;   Tx(1,0)= 0;   Tx(2,0)=0;
		  Tx(0,1)= 0;   Tx(1,1)=-1;   Tx(2,1)=0;
		  Tx(0,2)= 0;   Tx(1,2)=(WPG._2Rect.Y_ur+WPG._2Rect.Y_ll);
					      Tx(2,2)=1;
		  CTM *= Tx;
		  }
		CurrImg->AttachRaster(Raster);
		Raster=NULL;
		}
	     AssignPalette(CurrImg,Palette);
	     break;
	 case 0x1B:	//bitmap rectangle
             WORD Flags;

	     Flags=LoadWPG2Flags(f,CTM,StartWPG.PosSizePrecision,&RotAngle);
	     if(StartWPG.PosSizePrecision==0)
			{
			LoadWPG2BitmapRectangle(f,WPG._2BitmapRectangle);
			x=WPG._2BitmapRectangle.LowLeftX/47.0;
			y=WPG._2BitmapRectangle.LowLeftY/47.0;
			dx=(WPG._2BitmapRectangle.UpRightX-WPG._2BitmapRectangle.LowLeftX)/47.0;
			dy=(WPG._2BitmapRectangle.UpRightY-WPG._2BitmapRectangle.LowLeftY)/47.0;
			break;
			}
	     if(StartWPG.PosSizePrecision==1)
			{
			LoadWPG2DblBitmapRectangle(f,WPG._2DblBitmapRectangle);
			x=WPG._2DblBitmapRectangle.LowLeftX/(47.0*0xFFFF);
			y=WPG._2DblBitmapRectangle.LowLeftY/(47.0*0xFFFF);
			dx=(WPG._2DblBitmapRectangle.UpRightX-WPG._2DblBitmapRectangle.LowLeftX)/(47.0*0xFFFF);
			dy=(WPG._2DblBitmapRectangle.UpRightY-WPG._2DblBitmapRectangle.LowLeftY)/(47.0*0xFFFF);
			break;

		}
	     break;
	 }
Skip_WP_BMP: {}
       }
     break;
   }

FINISH:
 if(f) fclose(f);
 if(Palette!=NULL && Palette->UsageCount==0) delete Palette;
 return(Img);
}
#endif


#if SupportWPG>=2
 TImageFileHandler WPG_H(".WPG",
 #if SupportWPG>=4 || SupportWPG==2
	LoadPictureWPG,
 #else
	NULL,
 #endif
 //#if SupportWPG>=3
 //	SavePictureWPG);
 //#else
	NULL);
 //#endif
#endif

#endif //SupportWPG
//-------------------End of WPG routines------------------


