/******************************************************************************
 * program:     wp2latex                                                      *
 * function:    Convert WordPerfect files into LaTeX.			      *
 * modul:       pass1wmf.cc                                                   *
 * description: Opens Windows MetaFile and Enhanced Windows Metafile	      *
 * licency:     GPL		                                              *
 ******************************************************************************/
// See https://en.wikipedia.org/wiki/Windows_Metafile
//     http://www.fileformat.info/format/wmf/egff.htm
// for WMF description.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifndef M_PI
 #define M_PI        3.14159265358979323846
#endif

#ifndef MAX
 #define MAX(value1,value2) ((value1 > value2) ? value1 : value2)
#endif


//Atoms library
#include "stringa.h"
#include "struct.h"

#include "wp2latex.h"
#include "images/raster.h"
#include "images/vecimage.h"
#include "images.h"
#include "cp_lib/cptran.h"


void WMF_STRETCHDIB(Image &Img, FILE *f, DWORD ParamFilePos);
void WMF_DIBSTRETCHBLT(Image &Img, FILE *f, DWORD ParamFilePos);
void LoadBmpStream(Image &Img,FILE *f, DWORD Header_bfOffBits);
int SavePictureEPS(const char *Name, const Image &Img);

extern string wpd_filename;


/// WMF codepages: see this https://docs.microsoft.com/en-us/previous-versions/aa915041(v=msdn.10)?redirectedfrom=MSDN
typedef  enum  
{ 
  ANSI_CHARSET = 0x00000000,		///< 1252 FS_LATIN1 
  DEFAULT_CHARSET = 0x00000001,
  SYMBOL_CHARSET = 0x00000002, 
  MAC_CHARSET = 0x0000004D, 
  SHIFTJIS_CHARSET = 0x00000080,	///< cp932 FS_JISJAPAN
  HANGUL_CHARSET = 0x00000081,		///< cp949 FS_WANSUNG
  JOHAB_CHARSET = 0x00000082,		///< 1361 FS_JOHAB
  GB2312_CHARSET = 0x00000086,		///< 936 FS_CHINESESIMP 
  CHINESEBIG5_CHARSET = 0x00000088,	///< 950 FS_CHINESETRAD
  GREEK_CHARSET = 0x000000A1,		///< 1253 FS_GREEK
  TURKISH_CHARSET = 0x000000A2,		///< 1254 FS_TURKISH
  VIETNAMESE_CHARSET = 0x000000A3, 
  HEBREW_CHARSET = 0x000000B1,		///< cp1255 FS_HEBREW
  ARABIC_CHARSET = 0x000000B2,		///< cp1256 FS_ARABIC
  BALTIC_CHARSET = 0x000000BA,		///< cp1257 FS_BALTIC 
  RUSSIAN_CHARSET = 0x000000CC,		///< cp1251 FS_CYRILLIC
  THAI_CHARSET = 0x000000DE,		///< cp874 FS_THAI
  EASTEUROPE_CHARSET = 0x000000EE,	///< cp1250 FS_LATIN2
  OEM_CHARSET = 0x000000FF 
} TCharacterSet;


typedef  enum  
{ 
  PS_COSMETIC = 0x0000, 
  PS_ENDCAP_ROUND = 0x0000, 
  PS_JOIN_ROUND = 0x0000, 
  PS_SOLID = 0x0000, 
  PS_DASH = 0x0001, 
  PS_DOT = 0x0002, 
  PS_DASHDOT = 0x0003, 
  PS_DASHDOTDOT = 0x0004, 
  PS_NULL = 0x0005, 
  PS_INSIDEFRAME = 0x0006, 
  PS_USERSTYLE = 0x0007, 
  PS_ALTERNATE = 0x0008, 
  PS_ENDCAP_SQUARE = 0x0100, 
  PS_ENDCAP_FLAT = 0x0200, 
  PS_JOIN_BEVEL = 0x1000,
  PS_JOIN_MITER = 0x2000,
#if !defined(__BORLANDC__)
  PS_GEOMETRIC = 0x00010000	// used in EMF
#endif
} TPenStyle;


typedef  enum  
{ 
  BS_SOLID = 0x0000, 
  BS_NULL = 0x0001, 
  BS_HATCHED = 0x0002, 
  BS_PATTERN = 0x0003, 
  BS_INDEXED = 0x0004, 
  BS_DIBPATTERN = 0x0005, 
  BS_DIBPATTERNPT = 0x0006, 
  BS_PATTERN8X8 = 0x0007, 
  BS_DIBPATTERN8X8 = 0x0008, 
  BS_MONOPATTERN = 0x0009 
} TBrushStyle;

typedef  enum 
{ 
  HS_HORIZONTAL = 0x0000, 
  HS_VERTICAL = 0x0001, 
  HS_FDIAGONAL = 0x0002, 
  HS_BDIAGONAL = 0x0003, 
  HS_CROSS = 0x0004, 
  HS_DIAGCROSS = 0x0005 
} HatchStyle; 


typedef  enum  
{ 
  MM_TEXT = 0x0001, 
  MM_LOMETRIC = 0x0002, 
  MM_HIMETRIC = 0x0003, 
  MM_LOENGLISH = 0x0004, 
  MM_HIENGLISH = 0x0005, 
  MM_TWIPS = 0x0006, 
  MM_ISOTROPIC = 0x0007, 
  MM_ANISOTROPIC = 0x0008 
} TMapMode;

/// Get scalling factor for a given map mode.
/// @return	Scalling factor.
float GetScale2PSU(const TMapMode MapM)
{
  switch(MapM)
  {
    case MM_TEXT:	return 1; 
    case MM_LOMETRIC:   return mm2PSu(0.1f);
    case MM_HIMETRIC:   return mm2PSu(0.01f);
    case MM_LOENGLISH:  return mm2PSu(0.254f);
    case MM_HIENGLISH:  return mm2PSu(0.0254f);
    case MM_TWIPS:	return mm2PSu(0.017638889f);
    case MM_ISOTROPIC:
    case MM_ANISOTROPIC: break;
  }
  return 1;
}


/** This functor class is used for flipping image data. */
class vFlip: public AbstractTransformXY
{
public:
  vFlip(float Top, float Bottom) {TopPBottom=Top+Bottom;}

  virtual void ApplyTransform(float &x, float &y) const {y = -y+TopPBottom;}

  float TopPBottom;
};



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;


class ObjectTable
{
public:
  VectorAttribute **Attributes;
  unsigned Count;

  ObjectTable() {Count=0; Attributes=NULL;}  
  ~ObjectTable();

  void AddObject(VectorAttribute *NewAttr);
  void DeleteObject(unsigned ObjectIndex);
  const VectorAttribute *GetObjectAt(unsigned ObjectIndex) const;
};


ObjectTable::~ObjectTable()
{
  if(Count>0)
  {
    if(Attributes!=NULL)
    {
      for(unsigned i=0; i<Count; i++)
      {
        delete Attributes[i]; 
        Attributes[i] = NULL;
      }
      free(Attributes);
      Attributes = NULL;
    }
    Count = 0;
  }
}


void ObjectTable::AddObject(VectorAttribute *NewAttr)
{
  if(NewAttr==NULL) return;

  if(Attributes==NULL || Count<=0)
  {
    Attributes = (VectorAttribute**)malloc(sizeof(VectorAttribute*));
    if(Attributes==NULL)
    {
      delete NewAttr;
      return;
    }
    Attributes[0] = NewAttr;
    Count = 1;
    return;
  }

  for(unsigned i=0; i<Count; i++)
  {
    if(Attributes[i]==NULL)
    {
      Attributes[i] = NewAttr;
      return;
    }
  }

  Count++;
  VectorAttribute **tmp = (VectorAttribute**)realloc(Attributes, Count*sizeof(VectorAttribute*));
  if(tmp==NULL)		// memory exhausted, but Attributes contains original array.
    {ReportNoMemory();return;}
  Attributes = tmp;
  Attributes[Count-1] = NewAttr;
}


void ObjectTable::DeleteObject(unsigned ObjectIndex)
{
  if(ObjectIndex>=Count || Attributes==NULL) return;
  delete Attributes[ObjectIndex];
  Attributes[ObjectIndex] = NULL;
}


const VectorAttribute *ObjectTable::GetObjectAt(unsigned ObjectIndex) const
{
  if(ObjectIndex>=Count || Attributes==NULL) return NULL;
  return Attributes[ObjectIndex];
}


////////////////////////////////////////////////

class TconvertedPass1_xMF: public TconvertedPass1
{
protected:
     int NoConvertImage;

public:
     TconvertedPass1_xMF(void);
     void PutImageIncluder(const char *NewFilename);
     void PleaseReport(const char *Feature) {TconvertedPass1::PleaseReport(Feature,"WMF");}

     SWORD YOffset, XOffset;
     SWORD YExtent, XExtent;
     
     Image Img;     
     WORD MapMode;
     char MixMode;
     FloatBBox bbx;
     PS_State PSS;
     string PSData;
     ObjectTable ObjTab;
     CpTranslator *PsNativeCP;
     CpTranslator *PsNativeSym;     
};


TconvertedPass1_xMF::TconvertedPass1_xMF(void)
{
  MixMode = 1;		// Transparent
  NoConvertImage = 0;  
  YOffset = XOffset = 0;
  YExtent = XExtent = 0;
  InitBBox(bbx);
	// PSS has its own CTOR.
  PSS.FillPattern = FILL_SOLID;
  PSS.FontSizeW = PSS.FontSize = 1100/2.66;		// Default font size [mm]
  MapMode = MM_ANISOTROPIC;
  PsNativeCP = GetTranslator("internalTOcp1276");
  PsNativeSym = GetTranslator("internalTOsymbol");
}


void TconvertedPass1_xMF::PutImageIncluder(const char *NewFilename)
{
  if(InputPS & IMG_graphicx)	//graphicx.sty
    {
    fprintf(strip," \\begin{center}");
    fprintf(strip,"\\includegraphics");
    fprintf(strip,"[width=\\textwidth]");
    fprintf(strip,"{\\FigDir/%s.eps}",NewFilename);
    fprintf(strip," \\end{center}");
    putc('\n',strip);  rownum++;
  }
  else if(InputPS & IMG_epsfig)	//epsfig.sty
    {
    fprintf(strip," \\begin{center}");
    fprintf(strip,"\\epsfig{file=\\FigDir/%s.eps,",NewFilename);
    fprintf(strip,"width=\\textwidth");
    putc('}',strip);
    fprintf(strip," \\end{center}");
    putc('\n',strip);  rownum++;
    }
  else if(InputPS & IMG_graphics)	//graphics.sty
    {
    fprintf(strip," \\begin{center}");
    fprintf(strip,"\\includegraphics");
    fprintf(strip,"{\\FigDir/%s.eps}",NewFilename);
    fprintf(strip," \\end{center}");
    putc('\n',strip);  rownum++;
    }
  else			//InputPS.sty
    {
    fprintf(strip,"\\begin{forcewidth}");
    fprintf(strip,"{\\textwidth}\n"); rownum++;
    fprintf(strip," \\begin{center}");
    fprintf(strip,"\\InputPS{\\FigDir/%s.eps}",NewFilename);
    putc('\n',strip);  rownum++;
    fprintf(strip," \\end{center}");
    putc('\n',strip);  rownum++;
    fprintf(strip,"\\end{forcewidth}\n");  rownum++;
    }
}


////////////////////////////////////////////////

class TconvertedPass1_WMF: public TconvertedPass1_xMF
     {
public:
     TconvertedPass1_WMF(void) {PositionX=PositionY=0;}

     virtual int Convert_first_pass(void);
     virtual int Dispatch(int FuncNo, const void *arg);

     SWORD PositionX, PositionY;
     _StandardMetaRecord WmfRec;

protected:
     bool CheckWmfRecSz(WORD WSizeRequest);
     void ReportCorruptedObj(const char *ObjName);

     void parse_Arc(VectorList &VectList);
     void parse_CreateBrushIndirect(void);
     void parse_CreatePalette(void);
     void parse_CreatePenIndirect(void);     
     void parse_DeleteObject(void);
     void parse_DibCreatePatternBrush(void);
     void parse_DibStretchBlt(void );
     void parse_Ellipse(VectorList &VectList);
     void parse_FontIndirect(void);
     void parse_Chord(void);
     void parse_LineTo(VectorList &VectList);
     void parse_MoveTo(void);
     void parse_SetPolyFillMode(void);
     void parse_Pie(VectorList &VectList);
     void parse_Polygon(VectorList &VectList);
     void parse_PolyPolygon(VectorList &VectList);
     void parse_PolyLine(VectorList &VectList);
     void wmf_ESCAPE(void);
     void parse_ExtTextOut(VectorList &VectList);
     void parse_Rectangle(VectorList &VectList);
     void parse_RoundRect(VectorList &VectList);
     void parse_SelectObject(void);
     void parse_SelectPalette(void);
     void parse_SetPixel(VectorList &VectList);
     void parse_SetTextAlign(void);
     void parse_SetBkColor(void);
     void parse_SetBkMode(void);
     void parse_SetMapMode(void);
     void parse_SetTextColor(void);
     void parse_SetWindowExt(void);
     void parse_SetWindowOrg(void);
     void parse_TextOut(VectorList &VectList);
     void StretchDIBits(void);
     };


/* Register WMF translators here. */
TconvertedPass1 *Factory_WMF(void) {return new TconvertedPass1_WMF;}
FFormatTranslator FormatWMFWrapper("WMF",Factory_WMF);

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;


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
}


/** Load header for one WMF record. */
bool LoadWmfRecord(FILE *f, _StandardMetaRecord &WmfRec)
{
  Rd_dword(f,&WmfRec.Size);
  if(feof(f) || WmfRec.Size<3) return false;
  Rd_word(f,&WmfRec.Function);
  WmfRec.ParamFilePos = ftell(f);
  return true;  
}


void TconvertedPass1_WMF::ReportCorruptedObj(const char *ObjName)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::ReportCorruptedObj() ");fflush(log);
#endif
  if(err==NULL) return;
  perc.Hide();
  fprintf(err,_("\nError: corrupted wmf object: \"%s\"."), ObjName);
}


void TconvertedPass1_WMF::wmf_ESCAPE(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::wmf_ESCAPE() ");fflush(log);
#endif
static WORD MathType[] = {15,12,'M'+256*'a','t'+256*'h','T'+256*'y','p'+256*'e',0};
int Size;
WORD w;

  if(WmfRec.Size-3<sizeof(MathType)/sizeof(WORD)) goto NoMTEF;

  fseek(wpd,WmfRec.ParamFilePos,SEEK_SET);
  for(Size=0; Size<sizeof(MathType)/sizeof(WORD); Size++)
      {
      Rd_word(wpd,&w);
      if(w!=MathType[Size]) goto NoMTEF;
      }

  strcpy(ObjType+6," MTEF");
  if(err != NULL)
    {
    perc.Hide();
    fprintf(err, _("\nNote: MTEF formulas inside WMF are not converted yet."));
    }

  strcpy(ObjType,"!Escape - MTEF");
  return;


NoMTEF:
  strcpy(ObjType,"!Escape");
}


/** This callback from parent allows to provide some generic functionality. */
int TconvertedPass1_WMF::Dispatch(int FuncNo, const void *arg)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::Dispatch(%d) ",FuncNo);fflush(log);
#endif

 switch(FuncNo)
   {
   case DISP_EXTRACTIMAGE:
         {
	 Image **FillME = (Image**)arg;
         if(FillME) *FillME = new Image(Img);
	 return 0;
	 }
   case DISP_NOCONVERTIMAGE:
         if(arg!=NULL)
         {
	   NoConvertImage = *(int*)arg;         
           return 0;
         }
         break;
   }

return(-1);
}


/** Check whether WMF record has sufficient capacity.
 * @param[in]	WSizeRequest	Capacity of data payload in WORDs, without header record. */
bool TconvertedPass1_WMF::CheckWmfRecSz(WORD WSizeRequest)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::CheckWmfRecSz() ");fflush(log);
#endif
  if(WSizeRequest > WmfRec.Size-3)	// {RecordSize}[RecordFunction]
  {
    if(err != NULL)
        fprintf(err,_("\nError: WMF record %X size %d is too small, expected %u!"), 
                WmfRec.ParamFilePos ,WmfRec.Size ,WSizeRequest+2);
    return false;
  }
  return true;
}


void TconvertedPass1_WMF::parse_Arc(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_Arc() ");fflush(log);
#endif
static const char ObjName[] = "!Arc";
SWORD BottomRect, TopRect, RightRect, LeftRect;
SWORD XRadial1, XRadial2, YRadial1, YRadial2;

  if(!CheckWmfRecSz(8))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, (WORD*)&YRadial2);
  Rd_word(wpd, (WORD*)&XRadial2);
  Rd_word(wpd, (WORD*)&YRadial1);
  Rd_word(wpd, (WORD*)&XRadial1);

  Rd_word(wpd, (WORD*)&BottomRect);
  Rd_word(wpd, (WORD*)&RightRect);
  Rd_word(wpd, (WORD*)&TopRect);
  Rd_word(wpd, (WORD*)&LeftRect);

  UpdateBBox(bbx, 0, LeftRect, BottomRect, RightRect-LeftRect, TopRect-BottomRect);

  float Scale = GetScale2PSU((TMapMode)MapMode);
  VectorEllipse *pVecEllipse = new VectorEllipse(Scale*BottomRect, Scale*TopRect, Scale*RightRect, Scale*LeftRect);
  pVecEllipse->AttribFromPSS(PSS);
  pVecEllipse->BrushStyle = FILL_NONE;

  if(TopRect != BottomRect)
  {
    float xs = (LeftRect + RightRect) / 2;
    float ys = (BottomRect + TopRect) / 2;
    Scale = fabs((RightRect-LeftRect) / (float)(TopRect-BottomRect));

    pVecEllipse->bAngle = (180/M_PI) * atan2(Scale*(ys-YRadial1), XRadial1-xs);
    pVecEllipse->eAngle = (180/M_PI) * atan2(Scale*(ys-YRadial2), XRadial2-xs);
  }
  
  VectList.AddObject(pVecEllipse);

strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_WMF::parse_Ellipse(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_Ellipse() ");fflush(log);
#endif
static const char ObjName[] = "!Ellipse";
SWORD BottomRect, TopRect, RightRect, LeftRect;

  if(!CheckWmfRecSz(4))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, (WORD*)&BottomRect);
  Rd_word(wpd, (WORD*)&RightRect);
  Rd_word(wpd, (WORD*)&TopRect);
  Rd_word(wpd, (WORD*)&LeftRect);

  UpdateBBox(bbx, 0, LeftRect, BottomRect, RightRect-LeftRect, TopRect-BottomRect);

  const float Scale = GetScale2PSU((TMapMode)MapMode);

  VectorEllipse *pVecEllipse = new VectorEllipse(Scale*BottomRect, Scale*TopRect, Scale*RightRect, Scale*LeftRect);
  pVecEllipse->AttribFromPSS(PSS);
  
  VectList.AddObject(pVecEllipse);

strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_WMF::parse_Chord(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_Chord() ");fflush(log);
#endif
static const char ObjName[] = "!Chord";
SWORD	XRadial1, YRadial1, XRadial2, YRadial2;
SWORD	BottomRect, RightRect, TopRect, LeftRect;

  if(!CheckWmfRecSz(8))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, (WORD*)&XRadial2);
  Rd_word(wpd, (WORD*)&YRadial2);
  Rd_word(wpd, (WORD*)&XRadial1);
  Rd_word(wpd, (WORD*)&YRadial1);
  Rd_word(wpd, (WORD*)&BottomRect);
  Rd_word(wpd, (WORD*)&RightRect);
  Rd_word(wpd, (WORD*)&TopRect);
  Rd_word(wpd, (WORD*)&LeftRect);

strcpy(ObjType,ObjName+1);    // @TODO: dopsat!
}


void TconvertedPass1_WMF::parse_DibStretchBlt(void)
{
static const char ObjName[] = "!DibStretchBlt";
  //PleaseReport(ObjName+1);

  if(!CheckWmfRecSz(10))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }  

  Image *pImg = &Img;
	// Rewind to the last frame.
  while(pImg->Next!=NULL)
    pImg = pImg->Next;

  if(pImg->Raster==NULL || pImg->Raster->Data2D==NULL)
  {
    WMF_DIBSTRETCHBLT(*pImg, wpd, WmfRec.ParamFilePos);    
    if(pImg->Raster!=NULL && pImg->Palette==NULL) pImg->AttachPalette(PSS.pPalette);
  }
  else
  {
    Image Img2;
    WMF_DIBSTRETCHBLT(Img2, wpd, WmfRec.ParamFilePos);
    if(Img2.Raster!=NULL && Img2.Palette==NULL) Img2.AttachPalette(PSS.pPalette);
    //SavePictureEPS("R:\\4\\debug.eps",Img2);

    if(Img2.Raster!=NULL && Img2.Raster->Size1D>0)
    {
      if(Img2.x == pImg->x && Img2.dx == pImg->dx &&		// The x size must match
         Img2.Raster->Size1D==pImg->Raster->Size1D && Img2.Raster->Size2D==1 && 
         Img2.Raster->GetPlanes()==pImg->Raster->GetPlanes())
      {
        void **NewBlock = (void**)realloc(pImg->Raster->Data2D, (pImg->Raster->Size2D+1)*sizeof(void**));
        if(NewBlock!=NULL)
        {
          NewBlock[pImg->Raster->Size2D] = Img2.Raster->Data2D[0];
          Img2.Raster->Data2D[0] = NULL;
	  // Img2.Raster->Size2D must not be schrinked here, schrink will cause leak. Dtor will free empty ptr.
          pImg->Raster->Data2D = NewBlock;
          pImg->Raster->Size2D++;
          pImg->dy = Img2.y - pImg->y + Img2.dy;
        }
      }
      else
      {
        pImg->Next = new Image;
        pImg = pImg->Next;
        pImg->AttachPalette(Img2.Palette);
        pImg->AttachRaster(Img2.Raster);
        pImg->x = Img2.x;        pImg->y = Img2.y;
        pImg->dx = Img2.dx;      pImg->dy = Img2.dy;
        pImg->RotAngle = Img2.RotAngle;
      }
    }
  }

strcpy(ObjType,ObjName); 
}


void TconvertedPass1_WMF::parse_FontIndirect(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_FontIndirect() ");fflush(log);
#endif
static const char ObjName[] = "!CreateFontIndirect";
SWORD Width, Height, Escapement;
BYTE Underline, Strikeout, Charset, OutPrecision, ClipPrecision, Quality, PitchAndFamily;

  if(!CheckWmfRecSz(9))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, (WORD*)&Height);
  Rd_word(wpd, (WORD*)&Width);

  Rd_word(wpd, (WORD*)&Escapement);		// Defines the angle, in tenths of degrees, between the escapement vector and the x-axis
						// of the device. The escapement vector is parallel to the base line of a row of text.
  Rd_word(wpd, (WORD*)&PSS.FontOrientation10);	// Defines the angle, in tenths of degrees, between each character's base line and the x-axis of the device.
  if(PSS.FontOrientation10==0 && Escapement!=0)
  {						// I do not understand too much how 'Escapement' differs from 'Orientation'.
    PSS.FontOrientation10 = Escapement;		// May be that 'Escapement' is signifficant when whole WMF block gets rotated.
  }

  Rd_word(wpd, &PSS.FontWeight);
  PSS.FontItallic = fgetc(wpd);
  Underline = fgetc(wpd);
  Strikeout = fgetc(wpd);

  Charset = fgetc(wpd);
  switch(Charset)
  {
    case OEM_CHARSET:
    case DEFAULT_CHARSET:	ConvertCpg = NULL;
				break;
    case ANSI_CHARSET:		ConvertCpg = GetTranslator("cp1252TOinternal");	break;
    case SYMBOL_CHARSET:        ConvertCpg = GetTranslator("symbolTOinternal");	break;
    case EASTEUROPE_CHARSET:    ConvertCpg = GetTranslator("cp1250TOinternal"); // see https://stackoverflow.com/questions/22911186/windows-encoding-clarification
				break;
    case RUSSIAN_CHARSET:	ConvertCpg = GetTranslator("cp1251TOinternal"); break;
    case MAC_CHARSET:		ConvertCpg = GetTranslator("MacRomanTOinternal"); break;
    case GREEK_CHARSET:		ConvertCpg = GetTranslator("cp1253TOinternal");	break;
    case HEBREW_CHARSET:	ConvertCpg = GetTranslator("cp1255TOinternal"); break;
    case TURKISH_CHARSET:	ConvertCpg = GetTranslator("cp1254TOinternal"); break;
    case SHIFTJIS_CHARSET:
    case HANGUL_CHARSET:
    case JOHAB_CHARSET:
    case GB2312_CHARSET:
    case CHINESEBIG5_CHARSET:        
    case VIETNAMESE_CHARSET:    
    case ARABIC_CHARSET:
    case BALTIC_CHARSET:    
    case THAI_CHARSET:

    default:			ConvertCpg = NULL; break;
  }
  
  if(ConvertCpg == NULL)
     {
     perc.Hide();
     fprintf(err, _("\nUnsupported charset: %Xh."), (unsigned)Charset);
     }

  PSS.ConvertCpg = ConvertCpg;

  OutPrecision = fgetc(wpd);
  ClipPrecision = fgetc(wpd);
  Quality = fgetc(wpd);
  PitchAndFamily = fgetc(wpd);

  sprintf(ObjType,"%s(H=%d,set=%u,rot=%d)", ObjName+1, (int)Height, (unsigned)Charset, PSS.FontOrientation10/10);

  if(YExtent<0) PSS.FontOrientation10 = -PSS.FontOrientation10;
  if(Height!=0)
  {
    if(Height>0)		// The font height is normally negative.
	PSS.FontOrientation10 = -PSS.FontOrientation10;
    PSS.FontSize = labs(Height)/2.66;
  }
  if(Width!=0) 
    PSS.FontSizeW = Width/2.66;		// [pt] --> [mm]
  else
    PSS.FontSizeW = PSS.FontSize;

  ObjTab.AddObject(new vecFont(PSS));
}


void TconvertedPass1_WMF::parse_MoveTo(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_MoveTo() ");fflush(log);
#endif
static const char ObjName[] = "!MoveTo";

  if(CheckWmfRecSz(2))
    {
    Rd_word(wpd, (WORD*)&PositionY);
    Rd_word(wpd, (WORD*)&PositionX);
    sprintf(ObjType,"%s(%d;%d)", ObjName+1, PositionX, PositionY);
    }
  else
    strcpy(ObjType,ObjName);  
}


void TconvertedPass1_WMF::parse_CreateBrushIndirect(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_CreateBrushIndirect() ");fflush(log);
#endif
static const char ObjName[] = "!CreateBrushIndirect";
WORD BrushStyle, HatchStyle;
  if(!CheckWmfRecSz(3))
    {
      ReportCorruptedObj(ObjName+1);
      strcpy(ObjType, ObjName);
      return;
    }
   
  Rd_word(wpd, &BrushStyle);
  PSS.FillColor.Red   = fgetc(wpd);
  PSS.FillColor.Green = fgetc(wpd);
  PSS.FillColor.Blue  = fgetc(wpd);  
  fseek(wpd,1,SEEK_CUR);
  Rd_word(wpd, &HatchStyle);

  switch(BrushStyle)
  {    
    case BS_SOLID:    PSS.FillPattern=FILL_SOLID; break;
    case BS_HATCHED:  {		      
		      if(labs(YExtent)>5000 || labs(XExtent)>5000)
		      {
		        if(GetScale2PSU((TMapMode)MapMode) == 1)
			{
			  PSS.HatchDistance = MAX(labs(YExtent),labs(XExtent)) / 500.0f;		          
			}
		      }
		      switch(HatchStyle)
		      {
		        case HS_HORIZONTAL:	PSS.FillPattern=(PSS.HatchDistance==1) ? FILL_HORIZONTAL2 : FILL_HORIZONTALx; break;
		        case HS_VERTICAL:	PSS.FillPattern=(PSS.HatchDistance==1) ? FILL_VERTICAL4 : FILL_VERTICALx; break;
                        case HS_FDIAGONAL:	PSS.FillPattern=(PSS.HatchDistance==1) ? FILL_DIAG_DOWN2 : FILL_DIAG_DOWNx; break;
                        case HS_BDIAGONAL:	PSS.FillPattern=(PSS.HatchDistance==1)? FILL_DIAG_UP4 : FILL_DIAG_UPx; break;
                        case HS_CROSS:		PSS.FillPattern=(PSS.HatchDistance==1) ? FILL_CROSS_HATCH2: FILL_CROSS_HATCHx; break;
                        case HS_DIAGCROSS:	PSS.FillPattern=(PSS.HatchDistance==1) ? FILL_DIAG_CROSSHATCH4 : FILL_DIAG_CROSSHATCHx; break;
			default: PSS.FillPattern=FILL_DIAG_UP; break;
		      }
		      if(MixMode==2 && PSS.FillPattern>FILL_SOLID)
			PSS.FillPattern|=0x80;
		      }
		      break;
    case BS_NULL:
    default:	      PSS.FillPattern=FILL_NONE; break;
  }

  ObjTab.AddObject(new vecBrush(PSS));
  sprintf(ObjType, "%s(sty=%u)", ObjName+1, BrushStyle);
}


void TconvertedPass1_WMF::parse_CreatePalette(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_CreatePalette() ");fflush(log);
#endif
static const char ObjName[] = "!CreatePalette";

  if(!CheckWmfRecSz(2))
    {
RecordCorrupted:
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType, ObjName);
    return;
    }

  WORD NumberOfEntries;
  Rd_word(wpd, &NumberOfEntries);	// Start MUST be 0x0300.
  if(NumberOfEntries!=0x300) goto RecordCorrupted;
  Rd_word(wpd, &NumberOfEntries);

  PSS.AttachPalette(NULL);

  if(!CheckWmfRecSz(2+2*NumberOfEntries)) goto RecordCorrupted;

  PSS.pPalette = BuildPalette(NumberOfEntries,8);
  if(PSS.pPalette==NULL) goto RecordCorrupted;
  PSS.pPalette->UsageCount = 1;

  for(unsigned i=0; i<NumberOfEntries; i++)
  {
    DWORD d;
    RGBQuad RGB;

    Rd_dword(wpd, &d);
    RGB.R = d & 0xFF;
    RGB.G = (d >> 8) & 0xFF;
    RGB.B = (d >> 8) & 0xFF;
    PSS.pPalette->Set(i,&RGB);
  }

  ObjTab.AddObject(new attrPalette(PSS.pPalette));
  sprintf(ObjType, "%s(n=%u)", ObjName+1, NumberOfEntries);
}


void TconvertedPass1_WMF::parse_DibCreatePatternBrush(void)
{
static const char ObjName[] = "!DibCreatePatternBrush";

  ObjTab.AddObject(new FakeAttr());
  strcpy(ObjType, ObjName);
}


void TconvertedPass1_WMF::parse_CreatePenIndirect(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_CreatePenIndirect() ");fflush(log);
#endif
static const char ObjName[] = "!CreatePenIndirect";
WORD PenStyle, PenWidthX, PenWidthY;
  if(!CheckWmfRecSz(5))
    {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType, ObjName);
    return;
    }

  Rd_word(wpd, &PenStyle);
  switch(PenStyle & 0xFF)
  {    
    case PS_DASH:	PSS.LineStyle=7; break;// 0x0001, 
    case PS_DOT:	PSS.LineStyle=10; break;// 0x0002,
    case PS_DASHDOT:	PSS.LineStyle=15; break;// 0x0003,
    case PS_DASHDOTDOT: PSS.LineStyle=19; break;// 0x0004, 
    case PS_NULL:	PSS.LineStyle=0; break;	// 0x0005, 
    //case PS_INSIDEFRAME = 0x0006, 
    //case PS_USERSTYLE = 0x0007, 
    //case PS_ALTERNATE = 0x0008,
    case PS_SOLID:	
    default:
			PSS.LineStyle=1; break;	// 0x0000, 
  }
  PenWidthX = PenStyle & 0x0F00;
  switch(PenWidthX)
  {
    case PS_ENDCAP_ROUND:	PSS.LineCap=1; break;	// 0x0000
    case PS_ENDCAP_SQUARE:	PSS.LineCap=2; break;	// 0x0100
    case PS_ENDCAP_FLAT:	PSS.LineCap=0; break;	// 0x0200
  }
  PenWidthX = PenStyle & 0xF000;
  switch(PenWidthX)
  {
    case PS_JOIN_ROUND:		PSS.LineJoin=1; break;	// 0x0000 1 (round join)
    case PS_JOIN_BEVEL:		PSS.LineJoin=2; break;	// 0x1000 2 (bevel join)
    case PS_JOIN_MITER:		PSS.LineJoin=0; break;	// 0x2000 0 (miter join)
  }

  Rd_word(wpd, &PenWidthX);
  Rd_word(wpd, &PenWidthY);
  PSS.LineWidth = GetScale2PSU((TMapMode)MapMode) * ((PenWidthX>PenWidthY) ? PenWidthX : PenWidthY);

  PSS.LineColor.Red   = fgetc(wpd);
  PSS.LineColor.Green = fgetc(wpd);
  PSS.LineColor.Blue  = fgetc(wpd);
  
  ObjTab.AddObject(new vecPen(PSS));
  sprintf(ObjType, "%s(sty=%d,W=%u)", ObjName+1, PenStyle, PenWidthX);
}


void TconvertedPass1_WMF::parse_Rectangle(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_Rectangle() ");fflush(log);
#endif
static const char ObjName[] = "!Rectangle";
SWORD	BottomRect, TopRect, RightRect, LeftRect;

  if(!CheckWmfRecSz(4))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, (WORD*)&BottomRect);
  Rd_word(wpd, (WORD*)&RightRect);
  Rd_word(wpd, (WORD*)&TopRect);
  Rd_word(wpd, (WORD*)&LeftRect);

  UpdateBBox(bbx, 0, LeftRect, BottomRect, RightRect-LeftRect, TopRect-BottomRect);

  const float Scale = GetScale2PSU((TMapMode)MapMode);

  VectorRectangle *pVectRec = new VectorRectangle(Scale*BottomRect, Scale*TopRect, Scale*LeftRect, Scale*RightRect);
  pVectRec->AttribFromPSS(PSS);    
  VectList.AddObject(pVectRec);  

  strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_WMF::parse_SetPixel(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SetPixel() ");fflush(log);
#endif
static const char ObjName[] = "!SetPixel";
SWORD x,y;
RGB_Record PixColor;

  if(!CheckWmfRecSz(4))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }
	
  PixColor.Red = fgetc(wpd);
  PixColor.Green = fgetc(wpd);
  PixColor.Blue = fgetc(wpd);
  fseek(wpd, 1, SEEK_CUR);
  Rd_word(wpd, (WORD*)&x);
  Rd_word(wpd, (WORD*)&y);

  UpdateBBox(bbx, 0, x-0.5, y-0.5, 1, 1);

  const float Scale = GetScale2PSU((TMapMode)MapMode);

  VectorRectangle *pVectRec = new VectorRectangle(Scale*(y-0.5f), Scale*(y+0.5f), Scale*(x-0.5f), Scale*(x+0.5f));
  pVectRec->AttribFromPSS(PSS);
  pVectRec->FillColor = PixColor;
  pVectRec->BrushStyle = FILL_SOLID;
  pVectRec->LineStyle = 0;
  VectList.AddObject(pVectRec);  

  strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_WMF::parse_RoundRect(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_RoundRect() ");fflush(log);
#endif
static const char ObjName[] = "!RoundRect";
SWORD BottomRect, TopRect, RightRect, LeftRect;
SWORD Height, Width;

  if(!CheckWmfRecSz(6))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, (WORD*)&Height);
  Rd_word(wpd, (WORD*)&Width);
  Rd_word(wpd, (WORD*)&BottomRect);
  Rd_word(wpd, (WORD*)&RightRect);
  Rd_word(wpd, (WORD*)&TopRect);
  Rd_word(wpd, (WORD*)&LeftRect);

  UpdateBBox(bbx, 0, LeftRect, BottomRect, RightRect-LeftRect, TopRect-BottomRect);

  const float Scale = GetScale2PSU((TMapMode)MapMode);

  VectorRectangle *pVectRec = new VectorRectangleArc(Scale*BottomRect, Scale*TopRect, Scale*LeftRect, Scale*RightRect, 
						     Scale*Width/2.0f, Scale*Height/2.0f);
  pVectRec->AttribFromPSS(PSS);
  VectList.AddObject(pVectRec);  

  strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_WMF::parse_DeleteObject(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_DeleteObject() ");fflush(log);
#endif
WORD ObjectIndex;
static const char ObjName[] = "!DeleteObject";

  if(!CheckWmfRecSz(1))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }
  
  Rd_word(wpd, (WORD*)&ObjectIndex);
  ObjTab.DeleteObject(ObjectIndex);
  sprintf(ObjType,"%s(%u)", ObjName+1, ObjectIndex);  
}


void TconvertedPass1_WMF::parse_SelectObject(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SelectObject() ");fflush(log);
#endif
WORD ObjectIndex;
static const char ObjName[] = "!SelectObject";

  if(!CheckWmfRecSz(1))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }
  
  Rd_word(wpd, &ObjectIndex);

  const VectorAttribute *vecAttr = ObjTab.GetObjectAt(ObjectIndex);
  if(vecAttr==NULL)
  {
    strcpy(ObjType,ObjName);
    if(err!=NULL)
    {
      perc.Hide();
      fprintf(err,_("\nError: cannot select WMF object on position %d."), ObjectIndex);
    }
    return;
  }

  vecAttr->prepExport(&PSS);
  ConvertCpg = PSS.ConvertCpg;
  sprintf(ObjType,"%s(%u)", ObjName+1, ObjectIndex);  
}


void TconvertedPass1_WMF::parse_SelectPalette(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SelectPalette() ");fflush(log);
#endif
WORD ObjectIndex;
static const char ObjName[] = "!SelectPalette";

  if(!CheckWmfRecSz(1))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }
  
  Rd_word(wpd, &ObjectIndex);

  const VectorAttribute *vecAttr = ObjTab.GetObjectAt(ObjectIndex);
  if(vecAttr==NULL)
  {
OBJECT_DEFFECT:
    sprintf(ObjType,"%s(%u)",ObjName,ObjectIndex);
    if(err!=NULL)
    {
      perc.Hide();
      fprintf(err,_("\nError: cannot select WMF object on position %d."), ObjectIndex);
    }
    return;
  }
  if(vecAttr->getAttribType()!=ATTR_PALETTE) goto OBJECT_DEFFECT;

  vecAttr->prepExport(&PSS);
  ConvertCpg = PSS.ConvertCpg;
  sprintf(ObjType,"%s(%u)", ObjName+1, ObjectIndex);  
}


void TconvertedPass1_WMF::parse_SetBkColor(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SetBkColor() ");fflush(log);
#endif
  if(CheckWmfRecSz(2))
    {
    PSS.FillBackground.Red   = fgetc(wpd);
    PSS.FillBackground.Green = fgetc(wpd);
    PSS.FillBackground.Blue  = fgetc(wpd);
    }

  sprintf(ObjType,"SetBkColor(%2.2X,%2.2X,%2.2X)",PSS.FillBackground.Red,PSS.FillBackground.Green,PSS.FillBackground.Blue);
}


void TconvertedPass1_WMF::parse_Pie(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_Pie() ");fflush(log);
#endif
static const char ObjName[] = "!Pie";
SWORD BottomRect, TopRect, RightRect, LeftRect;
SWORD XRadial1, XRadial2, YRadial1, YRadial2;

  if(!CheckWmfRecSz(8))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, (WORD*)&YRadial2);
  Rd_word(wpd, (WORD*)&XRadial2);
  Rd_word(wpd, (WORD*)&YRadial1);
  Rd_word(wpd, (WORD*)&XRadial1);

  Rd_word(wpd, (WORD*)&BottomRect);
  Rd_word(wpd, (WORD*)&RightRect);
  Rd_word(wpd, (WORD*)&TopRect);
  Rd_word(wpd, (WORD*)&LeftRect);

  UpdateBBox(bbx, 0, LeftRect, BottomRect, RightRect-LeftRect, TopRect-BottomRect);

  float Scale = GetScale2PSU((TMapMode)MapMode);
  VectorEllipse *pVecEllipse = new VectorPie(Scale*BottomRect, Scale*TopRect, Scale*RightRect, Scale*LeftRect);
  pVecEllipse->AttribFromPSS(PSS);

  if(TopRect != BottomRect)
  {
    float xs = (LeftRect + RightRect) / 2;
    float ys = (BottomRect + TopRect) / 2;
    Scale = fabs((RightRect-LeftRect) / (float)(TopRect-BottomRect));

    pVecEllipse->bAngle = (180/M_PI) * atan2(Scale*(ys-YRadial1), XRadial1-xs);
    pVecEllipse->eAngle = (180/M_PI) * atan2(Scale*(ys-YRadial2), XRadial2-xs);
  }
  
  VectList.AddObject(pVecEllipse);

strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_WMF::parse_SetTextColor(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SetTextColor() ");fflush(log);
#endif
  if(CheckWmfRecSz(2))
    {
    PSS.TextColor.Red   = fgetc(wpd);
    PSS.TextColor.Green = fgetc(wpd);
    PSS.TextColor.Blue  = fgetc(wpd);
    }

  strcpy(ObjType,"SetTextColor");
}


void TconvertedPass1_WMF::parse_SetWindowExt(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SetWindowExt() ");fflush(log);
#endif
  Rd_word(wpd, (WORD*)&YExtent);
  Rd_word(wpd, (WORD*)&XExtent);
  sprintf(ObjType,"SetWindowExt(%d,%d)", (int)XExtent, (int)YExtent);
}


void TconvertedPass1_WMF::parse_SetWindowOrg(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SetWindowOrg() ");fflush(log);
#endif
  Rd_word(wpd, (WORD*)&YOffset);
  Rd_word(wpd, (WORD*)&XOffset);
  sprintf(ObjType,"SetWindowOrg(%d,%d)", (int)XOffset, (int)YOffset);
}


void TconvertedPass1_WMF::parse_LineTo(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_LineTo() ");fflush(log);
#endif
static const char ObjName[] = "!LineTo";

  if(CheckWmfRecSz(2))
  {
    SWORD LineX, LineY;

    Rd_word(wpd, (WORD*)&LineY);
    Rd_word(wpd, (WORD*)&LineX);

    UpdateBBox(bbx, 0, PositionX, PositionY, LineX-PositionX, LineY-PositionY);

    float *Points = (float*)malloc(4*sizeof(float));
    if(Points!=NULL)
    {
      const float Scale = GetScale2PSU((TMapMode)MapMode);

      Points[0] = PositionX * Scale;
      Points[1] = PositionY * Scale;
      Points[2] = LineX * Scale;
      Points[3] = LineY * Scale;
      VectorLine *pVecLine = new VectorLine(Points, 2);      

      memcpy(&pVecLine->LineColor, &PSS.LineColor, sizeof(PSS.LineColor));  
      pVecLine->LineStyle = PSS.LineStyle;
      pVecLine->LineCap = PSS.LineCap;
      pVecLine->PenWidth = PSS.LineWidth;
      pVecLine->Close = false;
      VectList.AddObject(pVecLine); pVecLine=NULL;

      sprintf(ObjType,"%s(%d;%d)", ObjName+1, LineX, LineY);      
      return;
    }
  }

  strcpy(ObjType,ObjName);
}


void TconvertedPass1_WMF::parse_Polygon(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_Polygon() ");fflush(log);
#endif
static const char ObjName[] = "!Polygon";
  WORD PolySize;  

  if(!CheckWmfRecSz(1))
  {
POLY_FAIL:
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, &PolySize);
  if(PolySize > (WmfRec.Size - 3 - 1)/2)
    PolySize = (WmfRec.Size - 3 - 1)/2;
  float *Points = LoadPoints(this, PolySize, bbx, NULL);
  if(Points==NULL)  goto POLY_FAIL;  

  const float Scale = GetScale2PSU((TMapMode)MapMode);
  for(int i=0; i<2*PolySize; i++)
  {
    Points[i] *= Scale;		// scale both x & y
  }

  VectorPolygon *pVecPoly = new VectorPolygon(Points, PolySize);
  Points = NULL;
  pVecPoly->AttribFromPSS(PSS);  
  pVecPoly->Close = true;
  VectList.AddObject(pVecPoly); pVecPoly=NULL;

  strcpy(ObjType,ObjName+1);
  return;
}


void TconvertedPass1_WMF::parse_PolyPolygon(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_PolyPolygon() ");fflush(log);
#endif
static const char ObjName[] = "!PolyPolygon";
WORD PolyCount;
WORD *PolySizes;
WORD i;

  if(!CheckWmfRecSz(1+1))
  {
POLY_FAIL:
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, &PolyCount);
  if(PolyCount<=0) goto POLY_FAIL;

  PolySizes = (WORD*)malloc(PolyCount*sizeof(WORD));
  if(PolySizes==NULL) goto POLY_FAIL;
  for(i=0; i<PolyCount;i++)
  {
    Rd_word(wpd, &PolySizes[i]);
  }

  const float Scale = GetScale2PSU((TMapMode)MapMode);
  for(i=0; i<PolyCount; i++)
  {
    if(PolySizes[i]<=0) continue;
    //if(PolySize > (WmfRec.Size - 3 - 1)/2)
    //  PolySize = (WmfRec.Size - 3 - 1)/2;
    float *Points = LoadPoints(this, PolySizes[i], bbx, NULL);
    if(Points==NULL)
        {free(PolySizes);goto POLY_FAIL;}
  
    for(int j=0; j<2*PolySizes[i]; j++)
    {
      Points[j] *= Scale;		// scale both x & y
    }
    VectorPolygon *pVecPoly = new VectorPolygon(Points, PolySizes[i]);
    Points = NULL;
    pVecPoly->AttribFromPSS(PSS);    
    //memcpy(&pVecPoly->FillColor, &PSS.FillColor, sizeof(PSS.FillColor));
    //pVecPoly->BrushStyle = PSS.FillPattern;  
    /*if(i==0)		// debugging only!
      {
      pVecPoly->BrushStyle = 0; //PSS.FillPattern;  
      pVecPoly->LineStyle = 1;
      memset(&pVecPoly->LineColor, 0, sizeof(pVecPoly->LineColor));
      pVecPoly->PenWidth = 10*GetScale2PSU((TMapMode)MapMode);
      } */

    pVecPoly->Close = true;
    VectList.AddObject(pVecPoly); pVecPoly=NULL;
  }
  free(PolySizes);
  strcpy(ObjType,ObjName+1);  
  return;
}


void TconvertedPass1_WMF::parse_PolyLine(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_PolyLine() ");fflush(log);
#endif
static const char ObjName[] = "!Polyline";
  WORD PolySize;  

  if(!CheckWmfRecSz(1))
  {
POLY_FAIL:
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, &PolySize);
  if(PolySize > (WmfRec.Size - 3 - 1)/2)
    PolySize = (WmfRec.Size - 3 - 1)/2;  
  float *Points = LoadPoints(this, PolySize, bbx, NULL);
  if(Points==NULL)  goto POLY_FAIL;

  const float Scale = GetScale2PSU((TMapMode)MapMode);
  for(int i=0; i<2*PolySize; i++)
  {
    Points[i] *= Scale;		// scale both x & y
  }

  VectorLine *pVecLine = new VectorLine(Points, PolySize);
  Points = NULL;
  pVecLine->AttribFromPSS(PSS);  
  pVecLine->Close = false;
  VectList.AddObject(pVecLine); pVecLine=NULL;

  strcpy(ObjType,ObjName+1);  
}


void TconvertedPass1_WMF::parse_SetBkMode(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SetBkMode() ");fflush(log);
#endif
static const char ObjName[] = "!SetBkMode(%u)";
  if(!CheckWmfRecSz(1))
  {
    ReportCorruptedObj(ObjName+1);
    strncpy(ObjType,ObjName,9);
    return;
  }
  WORD BkMode;
  Rd_word(wpd, &BkMode);

  if(BkMode==2)		// Opaque
  {
    MixMode = 2;
    if(PSS.FillPattern>FILL_SOLID) PSS.FillPattern |= 0x80;    
  }
  else			// Transparent
  {
    MixMode = 1;
    PSS.FillPattern&=~0x80;
  }
  sprintf(ObjType,ObjName+1,(unsigned)BkMode);
}


void TconvertedPass1_WMF::parse_SetMapMode(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SetMapMode() ");fflush(log);
#endif
static const char ObjName[] = "!SetMapMode(%u)";
  if(!CheckWmfRecSz(1))
  {
    ReportCorruptedObj(ObjName+1);
    strncpy(ObjType,ObjName,11);
    return;
  }
  Rd_word(wpd, &MapMode);
  sprintf(ObjType,ObjName+1,(unsigned)MapMode);
}


void TconvertedPass1_WMF::parse_SetPolyFillMode(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SetPolyFillMode() ");fflush(log);
#endif
static const char ObjName[] = "!SetPolyFillMode";
WORD PolyFillMode;
  if(!CheckWmfRecSz(1))
  {
    ReportCorruptedObj(ObjName+1);
    strncpy(ObjType,ObjName,16);
    return;
  }  
  Rd_word(wpd, &PolyFillMode);
  PSS.PolyFillMode = (PolyFillMode==1) ? 1 : 0;
  sprintf(ObjType, "%s(%u)", ObjName+1, (unsigned)PolyFillMode);
}


void TconvertedPass1_WMF::parse_SetTextAlign(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_SetTextAlign() ");fflush(log);
#endif
WORD TextAlignmentMode;
static const char ObjName[] = "!SetTextAlign";

  if(!CheckWmfRecSz(1))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }
  
  Rd_word(wpd, &TextAlignmentMode);

  PSS.TextAllign = TextAlignmentMode & 0xFF;
 
  sprintf(ObjType,"%s(%Xh)", ObjName+1, TextAlignmentMode);
}


void TconvertedPass1_WMF::parse_TextOut(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_TextOut() ");fflush(log);
#endif
static const char ObjName[] = "!TextOut";
WORD StringLen;
short int LineLen, CurLineLen;
SWORD XStart;

  if(!CheckWmfRecSz(3))
  {
TEXT_OUT_FAIL:
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_word(wpd, &StringLen);
  if(!CheckWmfRecSz((StringLen+1)/2)) goto TEXT_OUT_FAIL;
  
  const float Scale = GetScale2PSU((TMapMode)MapMode);  
  TextContainer *pTextCont = new TextContainer;  
  pTextCont->PosX = 0;
  pTextCont->PosY = 0;
  pTextCont->TextAllign = PSS.TextAllign;
  pTextCont->FontOrientation = PSS.FontOrientation10 / 10.0f;
  pTextCont->MixMode = MixMode;
  LineLen = CurLineLen = 0;
  XStart = StringLen & 1;
  while(StringLen-->0)
  {
    char ch = fgetc(wpd);
    if(ch==0)
    {
      fseek(wpd,StringLen,SEEK_CUR);
      break;
    }

    if(ch=='\n')
    {
      if(CurLineLen>LineLen) LineLen=CurLineLen;
      if(!pTextCont->isEmpty())
      {
        const float CurPosY = pTextCont->PosY + mm2PSu(PSS.FontSize);
        VectList.AddObject(pTextCont);
        pTextCont = new TextContainer;
        pTextCont->PosX = 0;
        pTextCont->PosY = CurPosY;
        pTextCont->TextAllign = PSS.TextAllign;
        pTextCont->FontOrientation = PSS.FontOrientation10 / 10.0f;
        pTextCont->MixMode = MixMode;
      }
    }
    else CurLineLen++;

    if(ConvertCpg != NULL)
    {
      if(!strcmp(ConvertCpg->Name,"symbolTOinternal"))      
      {
        pTextCont->AddText(ch, "Symbol", PSS);		// Pass symbols directly.
      }
      else
      {        
        AddCharacterToContainer(pTextCont, (*ConvertCpg)[ch], PsNativeCP, PsNativeSym, this, PSS);
      }
    }
    else
    {      
      pTextCont->AddText(ch,PSS);
    }
  }
  if(CurLineLen>LineLen) LineLen=CurLineLen;
  if(XStart>0)			// Word alignment.
    fseek(wpd,1,SEEK_CUR);

  SWORD YStart;
  Rd_word(wpd, (WORD*)&YStart);
  Rd_word(wpd, (WORD*)&XStart);

  pTextCont->PosX = XStart*Scale;
  pTextCont->PosY += YStart*Scale;

  if(pTextCont->isEmpty())    
    delete pTextCont;    
  else    
    VectList.AddObject(pTextCont);    
  pTextCont=NULL;  

  UpdateBBox(bbx, 0, XStart, YStart + 0.1*mm2PSu(PSS.FontSize), 
             LineLen*mm2PSu(PSS.FontSizeW), -1.1*mm2PSu(PSS.FontSize));

  strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_WMF::parse_ExtTextOut(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_ExtTextOut() ");fflush(log);
#endif
static const char ObjName[] = "!ExtTextOut";
SWORD x_pos, y_pos;
WORD fuOptions, TextLen;
short int LineLen, CurLineLen;
unsigned char c;

  if(!CheckWmfRecSz(4))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }
  
  Rd_word(wpd, (WORD*)&y_pos);
  Rd_word(wpd, (WORD*)&x_pos);
  Rd_word(wpd, &TextLen);  
  Rd_word(wpd, &fuOptions);

  const float Scale = GetScale2PSU((TMapMode)MapMode);
  int MaxTextLen = 2*(WmfRec.Size - 4);
  if(fuOptions & 0x0004)		// ETO_CLIPPED Rectangle provided
  {        
    fseek(wpd,8,SEEK_CUR);
    MaxTextLen -= 8;
  }
#ifdef _DEBUG
/*  else
  {
    const float sz = mm2PSu(PSS.FontSize)/2;
    VectorRectangle *pVectRec = new VectorRectangle(Scale*y_pos-sz, Scale*y_pos+sz, Scale*x_pos-sz, Scale*x_pos+sz);
    pVectRec->AttribFromPSS(PSS);    
    VectList.AddObject(pVectRec);
  } */
#endif

  if(MaxTextLen < TextLen)
  {
    if(err!=NULL)
    {
      perc.Hide();
      fprintf(err, _("\nError: text with size %d cannot fit into object, cut to %u."), MaxTextLen, TextLen);
    }
    TextLen = MaxTextLen;
  }

  TextContainer *pTextCont = new TextContainer;  
  pTextCont->PosX = Scale*x_pos;
  pTextCont->PosY = Scale*y_pos;
  pTextCont->TextAllign = PSS.TextAllign;
  pTextCont->FontOrientation = PSS.FontOrientation10 / 10.0f;
  pTextCont->MixMode = MixMode;

  LineLen = CurLineLen = 0;
  if(log!=NULL) fputc(' ',log);
  while(!feof(wpd))
    {
    if(TextLen-- <= 0) break;
    c = fgetc(wpd);
    if(c==0) break;

    if(log!=NULL) fputc(c,log);
    if(c=='\n')
    {
      if(CurLineLen>LineLen) LineLen=CurLineLen;
      if(!pTextCont->isEmpty())
      {
        const float CurPosY = pTextCont->PosY + mm2PSu(PSS.FontSize);
        VectList.AddObject(pTextCont);
        pTextCont = new TextContainer;        
        pTextCont->PosX = Scale*x_pos;        
        pTextCont->PosY = CurPosY;
	pTextCont->TextAllign = PSS.TextAllign;
        pTextCont->FontOrientation = PSS.FontOrientation10 / 10.0f;
        pTextCont->MixMode = MixMode;
      }
    }
    else CurLineLen++;

    if(ConvertCpg != NULL)
      {
      if(!strcmp(ConvertCpg->Name,"symbolTOinternal"))
        pTextCont->AddText((char)c, "Symbol", PSS);	// Push Symbol code page without any change.
      else
        {
        AddCharacterToContainer(pTextCont, (*ConvertCpg)[c], PsNativeCP, PsNativeSym, this, PSS);
        }
      }
    else
      {
      pTextCont->AddText((char)c,PSS);
      }
    }

  if(CurLineLen>LineLen) LineLen=CurLineLen;

  if(pTextCont->isEmpty())    
    delete pTextCont;    
  else
    {
    if((PSS.TextAllign & 6) == 6)	// TA_CENTER
      {      
      x_pos -= LineLen*mm2PSu(PSS.FontSize) / 4;
      }
    VectList.AddObject(pTextCont);    
    }
  pTextCont=NULL;

  //if(VectList.isEmpty()) goto TEXT_OUT_FAIL;  

  UpdateBBox(bbx, 0, x_pos, y_pos+0.1*mm2PSu(PSS.FontSize),		// Extend down reserved space for character.
             LineLen*mm2PSu(PSS.FontSizeW)/2.0, -1.1*mm2PSu(PSS.FontSize));

  strcpy(ObjType,ObjName+1);  
}


void TconvertedPass1_WMF::StretchDIBits(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::StretchDIBits() ");fflush(log);
#endif
Image *pImg = &Img;

	// Rewind to the last frame.
  while(pImg->Next!=NULL)
    pImg = pImg->Next;

  if(pImg->Raster==NULL || pImg->Raster->Data2D==NULL)
  {
    WMF_STRETCHDIB(*pImg, wpd, WmfRec.ParamFilePos);
    if(pImg->Raster!=NULL && pImg->Palette==NULL) pImg->AttachPalette(PSS.pPalette);
  }
  else
  {
    Image Img2;
    WMF_STRETCHDIB(Img2, wpd, WmfRec.ParamFilePos);
    if(Img2.Raster!=NULL && Img2.Palette==NULL) Img2.AttachPalette(PSS.pPalette);
    //SavePictureEPS("R:\\4\\debug.eps",Img2);

    if(Img2.Raster!=NULL && Img2.Raster->Size1D>0)
    {
      if(Img2.x == pImg->x && Img2.dx == pImg->dx &&		// The x size must match
         Img2.Raster->Size1D==pImg->Raster->Size1D && Img2.Raster->Size2D==1 && 
         Img2.Raster->GetPlanes()==pImg->Raster->GetPlanes())
      {
        void **NewBlock = (void**)realloc(pImg->Raster->Data2D, (pImg->Raster->Size2D+1)*sizeof(void**));
        if(NewBlock!=NULL)
        {
          NewBlock[pImg->Raster->Size2D] = Img2.Raster->Data2D[0];
          Img2.Raster->Data2D[0] = NULL;
	  // Img2.Raster->Size2D must not be schrinked here, schrink will cause leak. Dtor will free empty ptr.
          pImg->Raster->Data2D = NewBlock;
          pImg->Raster->Size2D++;
          pImg->dy = Img2.y - pImg->y + Img2.dy;
        }
      }
      else
      {
        pImg->Next = new Image;
        pImg = pImg->Next;
        pImg->AttachPalette(Img2.Palette);
        pImg->AttachRaster(Img2.Raster);
        pImg->x = Img2.x;        pImg->y = Img2.y;
        pImg->dx = Img2.dx;      pImg->dy = Img2.dy;
        pImg->RotAngle = Img2.RotAngle;
      }
    }
  }
  strcpy(ObjType,"StretchDIBits");
}


/*******************************************************************/
/* This procedure provides all needed processing for the first pass*/
int TconvertedPass1_WMF::Convert_first_pass(void)
{
#ifdef DEBUG
  fprintf(log,"\n#Convert_pass1_WMF() ");fflush(log);
#endif
_WindowsMetaHeader WmfHead;
int RetVal = 0;
DWORD NewPos;
const unsigned short CodePageBk = OutCodePage;

  if(Verbosing >= 1) printf(_("Opening Windows MetaFile:"));

  if(LoadWMFHeader(wpd,WmfHead)!=18) return(-1);
  
  if(WmfHead.HeaderSize!=9)
    {
    if(err != NULL)
        fprintf(err, _("\nError: Invalid WMF header size %u, expected size=9!"), WmfHead.HeaderSize);
    return(-1);
    }

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

  ActualPos = ftell(wpd);
  VectorList VectList;
  OutCodePage = 0;
  while(!feof(wpd))
    {    
    if(LoadWmfRecord(wpd,WmfRec))
      {
      *ObjType = 0;
      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: parse_CreatePalette(); break;
	case 0x00F8: strcpy(ObjType,"!CreateBrush"); break;	//?

	case 0x0102: parse_SetBkMode(); break;
	case 0x0103: parse_SetMapMode(); break;
	case 0x0104: strcpy(ObjType,"!SetROP2"); break;
	case 0x0105: strcpy(ObjType,"!SetRelabs"); break;
	case 0x0106: parse_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: parse_SelectObject(); break;
	case 0x012E: parse_SetTextAlign(); break;

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

	case 0x0142: parse_DibCreatePatternBrush(); break;

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

	case 0x01F0: parse_DeleteObject(); break;

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

	case 0x0201: parse_SetBkColor(); break;

	case 0x0209: parse_SetTextColor(); break;
	case 0x020A: strcpy(ObjType,"!SetTextJustification"); break;//?
	case 0x020B: parse_SetWindowOrg(); break;	//?
	case 0x020C: parse_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: parse_LineTo(VectList); break;
	case 0x0214: parse_MoveTo(); break;

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

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

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

	case 0x0234: parse_SelectPalette(); break;

	case 0x02FA: parse_CreatePenIndirect(); break;
	case 0x02FB: parse_FontIndirect(); break;
	case 0x02FC: parse_CreateBrushIndirect(); break;
	case 0x02FD: strcpy(ObjType,"!CreateBitmapIndirect"); break;

	case 0x0324: parse_Polygon(VectList); break;
	case 0x0325: parse_PolyLine(VectList); 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: parse_Ellipse(VectList); break;
	case 0x0419: strcpy(ObjType,"!FloodFill"); break;

	case 0x041B: parse_Rectangle(VectList); break;

	case 0x041F: parse_SetPixel(VectList); break;

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

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

	case 0x0521: parse_TextOut(VectList); break;
	case 0x0538: parse_PolyPolygon(VectList); break;

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

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

	case 0x626: wmf_ESCAPE(); break;

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

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

        case 0x0817: parse_Arc(VectList); break;

	case 0x081A: parse_Pie(VectList); break;

 	case 0x0830: parse_Chord(); break;

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

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

	case 0x0A32: parse_ExtTextOut(VectList); break;

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

	case 0x0B41: parse_DibStretchBlt(); break;

	case 0x0d33: strcpy(ObjType,"!SetDibToDev"); PleaseReport("SetDibToDev"); break;

	case 0x0F43: StretchDIBits(); break;

        default: sprintf(ObjType,"!Unknown#%X", WmfRec.Function);
	}

      if(ObjType[0]=='!') UnknownObjects++;

      if(log!=NULL)
	{
	fprintf(log,_("\n%*s{WMF function:%3Xh; size:%4lu; pos:%lXh}"),
		  recursion*2,"",WmfRec.Function, (long)2*WmfRec.Size, (long)ActualPos);
	if(*ObjType!=0) fprintf(log," %s",ObjType);

        if(ObjType[0] == '!')
          {
	  fprintf(log,"{");
	  fseek(wpd,WmfRec.ParamFilePos,SEEK_SET);
	  for(int i=0; i<WmfRec.Size-3; i++)
	    //fprintf(log,"%X ",WmfRec->Parameters[i]);
	    {
	    WORD w;
            Rd_word(wpd,&w);
	    if(feof(wpd)) break;
	    int j = w % 256;
	    fprintf(log, (i==0)?"%X":",%X", j);
	    if(j>=' ') fprintf(log,"(%c)",j);
	    j = w / 256;
	    fprintf(log,",%X",j);
	    if(j>=' ') fprintf(log,"(%c)",j);

	    if(i>100) {fprintf(log," ... ");break;}
	    }
	  fprintf(log,"}");
          }
	}

      if(*ObjType==0) UnknownObjects++;

      if(NewPos!=0) ActualPos = NewPos;
	       else ActualPos+= 2*WmfRec.Size;      

      fseek(wpd,ActualPos,SEEK_SET);
      if(WmfRec.Function==0)
          break;		// Break loop on WMF End
      }
    else
      ActualPos = ftell(wpd);
    }

    const float Scale = GetScale2PSU((TMapMode)MapMode) * 25.4f / 71.0f;	// convert PSu to WPGu (quite bad).    
    vFlip flipTrx(bbx.MinY, bbx.MaxY);

    Image *Img2 = &Img;
    while(Img2!=NULL)
    {      
      if(Img2->Raster!=NULL)
      {        
        if(Img2->dy<0)
        {
          Img2->dy = -Img2->dy;
          //Img2->y += Img2->dy;                    
        }
        Flip2D(Img2->Raster);
        if(Img2->dx<0)
        {        
         Img2->x += Img2->dx;
         Img2->dx = -Img2->dx;
         Flip1D(Img2->Raster);
        }

        if(YExtent>=0)
            flipTrx.ApplyTransform(Img2->x, Img2->y);
      }
      //if(Img2->Vector)
      //   Img2->Vector.Transform(flipTx);
      Img2->x *= Scale;
      Img2->y *= Scale;
      Img2->dx *= Scale;
      Img2->dy *= -Scale;      
      Img2 = Img2->Next;       
    }

  if(YExtent>=0)
      VectList.Transform(flipTrx);

  if(PSData.length() > 0)
      VectList.AddObject(new PsBlob(PSData.ExtractString()));  

  if(VectList.VectorObjects>0 && Img.VecImage==NULL)
  {    
    Img.AttachVecImg(new VectorImage(VectList,PSS));

    if(Img.dx!=0 && Img.dy!=0 && Img.Raster!=NULL)
    {
      if(Img.VecImage!=NULL)	// Move raster data to different image frame.
      {
        Img2 = &Img;
        while(Img2->Next!=NULL)
          Img2 = Img2->Next;
        Img2->Next = new Image();
        Img2 = Img2->Next;

        Img2->x =  bbx.MinX * Scale;
        Img2->y =  bbx.MinY * Scale;
        Img2->dx = (bbx.MaxX - bbx.MinX) * Scale;
        Img2->dy = (bbx.MaxY - bbx.MinY) * Scale;
        Img2->VecImage = Img.VecImage; Img.VecImage=NULL;
      }
    }
    else	// Use whole frame as bounding box.
    {      
      Img.x =  bbx.MinX * Scale;
      Img.y =  bbx.MinY * Scale;
      Img.dx = (bbx.MaxX - bbx.MinX) * Scale;
      Img.dy = (bbx.MaxY - bbx.MinY) * Scale;  
    }        
  }

  if(!NoConvertImage && (Img.Raster!=NULL || Img.VecImage!=NULL))
    {
    for(Image *pImg=&Img; pImg!=NULL; pImg=pImg->Next)
      if(pImg->Raster!=NULL)
        ReducePalette(pImg,256);

    string NewFilename = MergePaths(OutputDir,RelativeFigDir);
    string wpd_cut = CutFileName(wpd_filename);
    if(recursion==0 && length(wpd_cut)>0)
      NewFilename += wpd_cut + ".eps";
    else
      NewFilename += GetFullFileName(GetSomeImgName(".eps"));

    if(SavePictureEPS(NewFilename(),Img)<0)
	{
        if(err != NULL)
	  {
	  perc.Hide();
	  fprintf(err, _("\nError: Cannot save file: \"%s\"!"), NewFilename());
	  }
	return 0;
        }

    NewFilename = CutFileName(NewFilename); 	//New Filename only

    PutImageIncluder(NewFilename());

    InputPS |= 1;		//mark style as used
    Finalise_Conversion(this);
    RetVal++;
    }

  OutCodePage = CodePageBk;
  return(RetVal);
}


/* WMF files usually have special header before data. */

typedef struct _WmfSpecialHeader
{
  DWORD Key;           /* Magic number (always 9AC6CDD7h) */
  WORD  Handle;        /* Metafile HANDLE number (always 0) */
  SWORD Left;          /* Left coordinate in metafile units */
  SWORD Top;           /* Top coordinate in metafile units */
  SWORD Right;         /* Right coordinate in metafile units */
  SWORD Bottom;        /* Bottom coordinate in metafile units */
  WORD  Inch;          /* Number of metafile units per inch */
  DWORD Reserved;      /* Reserved (always 0) */
  WORD  Checksum;      /* Checksum value for previous 10 WORDs */
} WMFSPECIAL;


static inline long LoadWMFSpecial(FILE *f, _WmfSpecialHeader & WSH)
{
#if defined(__PackedStructures__)
return(fread(&WSH,1,sizeof(_WmfSpecialHeader),f));
#else
return(loadstruct(f,"dwwwwwwdw",
      &WSH.Key, &WSH.Handle,
      &WSH.Left, &WSH.Top, &WSH.Right, &WSH.Bottom,
      &WSH.Inch, &WSH.Reserved, &WSH.Checksum));
#endif
}


class TconvertedPass1_WMFspec: public TconvertedPass1_WMF
     {
public:
     virtual int Convert_first_pass(void);
     };


int TconvertedPass1_WMFspec::Convert_first_pass(void)
{
#ifdef DEBUG
  fprintf(log,"\n#Convert_pass1_WMF() ");fflush(log);
#endif

  {
  WMFSPECIAL hdr;
  if(LoadWMFSpecial(wpd,hdr)!=22) return -1;
  if(hdr.Key!=0x9AC6CDD7) return -2;

  DWORD Checksum = hdr.Key;
  Checksum ^= hdr.Handle;
  Checksum ^= (WORD)hdr.Left;	// Convert to unsigned to prevent sign expansion.
  Checksum ^= (WORD)hdr.Top;
  Checksum ^= (WORD)hdr.Right;
  Checksum ^= (WORD)hdr.Bottom;
  Checksum ^= hdr.Inch;
  Checksum ^= hdr.Reserved;

  Checksum = (Checksum & 0x0000FFFFUL) ^ ((Checksum & 0xFFFF0000UL) >> 16);
  if(Checksum != hdr.Checksum)
    {
    if(err != NULL)
      {      
      fprintf(err, _("\nWarning: Invalid WMF CRC %X, expected %X."),hdr.Checksum,Checksum);
      }
    }
  }  // scope discards hdr

 return TconvertedPass1_WMF::Convert_first_pass();
}

/* Register translator for WMF with special header here. */
TconvertedPass1 *Factory_WMFspec(void) {return new TconvertedPass1_WMFspec;}
FFormatTranslator FormatWMFWrapperSpecial("WMFspecial",Factory_WMFspec);


//////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// EMF //////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////

typedef struct _EnhancedMetaRecord
{
  DWORD Type;		///< An unsigned integer that identifies this record type.
  DWORD Size;		///< An unsigned integer that specifies the size of this record in bytes.
  DWORD ParamFilePos;	///< Index to the file, not contained in data.    
} EMFRECORD;


/** Functor class for EMF world transform. */
class TransformEMF: public AbstractTransformXY
{
public:
  float M11, M12, M21, M22;
  float Dx, Dy;
  
  TransformEMF(void) {M11=M22=1; M21=M12=Dx=Dy=0;}

  virtual void ApplyTransform(float &x, float &y) const;

  float TopPBottom;
};


void TransformEMF::ApplyTransform(float &x, float &y) const
{
  const float xNew = M11*x + M21*y + Dx;
  y = M12*x + M22*y + Dy;
  x = xNew;
}


class TconvertedPass1_EMF: public TconvertedPass1_xMF
{
public:
    SDWORD PositionX, PositionY;
    CpTranslator *ConvertUnicode;
    TransformEMF WorldTx;

    TconvertedPass1_EMF(void) {PositionX = PositionY = 0;}

    virtual int Convert_first_pass(void);

    void parse_CreateBrushIndirect(void);
    void parse_CreatePalette(void);
    void parse_CreatePen(void);
    void parse_DeleteObject(void);
    void parse_Ellipse(VectorList &VectList);
    void parse_ExtCreateFontIndirectW(void);
    void parse_ExtCreatePen(void);
    void parse_ExtTextOutW(VectorList &VectList);
    void parse_LineTo(VectorList &VectList);
    void parse_ModifyWorldTransform(void);
    void parse_SetWorldTransform(void);
    void parse_MoveToEX(void);
    void parse_PolyBezier16(VectorList &VectList);
    void parse_Polygon16(VectorList &VectList);    
    void parse_PolyLine16(VectorList &VectList);
    void parse_PolyPolygon16(VectorList &VectList);
    void parse_PolyPolyLine16(VectorList &VectList);
    void parse_Rectangle(VectorList &VectList);
    void parse_SelectObject(void);
    void parse_SelectPalette(void);
    void parse_SetBkColor(void);
    void parse_SetBkMode(void);
    void parse_SetPixel(VectorList &VectList);
    void parse_SetPolyFillMode(void);
    void parse_SetTextAlign(void);
    void parse_SetTextColor(void);
    void parse_StretchDIBits(VectorList &VectList);

    _EnhancedMetaRecord EmfRec;
};

TconvertedPass1 *Factory_EMF(void) {return new TconvertedPass1_EMF;}
FFormatTranslator FormatEMFWrapper("EMF",Factory_EMF);



typedef struct
{
  DWORD Bounds[4];	///< Rectangular inclusive-inclusive bounds in logical units of the smallest rectangle
  DWORD Frame[4];	///< Rectangular inclusive-inclusive dimensions, in .01 millimeter units, of a rectangle that surrounds the image stored in the metafile.
  DWORD Signature;
  DWORD Version;
  DWORD Bytes;
  DWORD Records;
  WORD  Handles;	///< number of graphics objects that are used during the processing of the metafile.
  WORD  Reserved;	///< An unsigned integer that MUST be 0x0000 and MUST be ignored.
  DWORD nDescription;	///< Number of characters in the array that contains the description of the metafile's contents.
  DWORD offDescription;	///< offset from the beginning of this record to the array that contains the description of the metafile's contents.
  DWORD nPalEntries;	///< Number of entries in the metafile palette.
  DWORD Device[2];	///< A SizeL object ([MS-WMF] section 2.2.2.22) that specifies the size of the reference device, in pixels. 
  DWORD Millimeters[2];	///< A SizeL object that specifies the size of the reference device, in millimeters.
} EMFHEAD;


typedef  enum  
 { 
   EMR_HEADER = 0x00000001, 
   EMR_POLYBEZIER = 0x00000002, 
   EMR_POLYGON = 0x00000003, 
   EMR_POLYLINE = 0x00000004, 
   EMR_POLYBEZIERTO = 0x00000005, 
   EMR_POLYLINETO = 0x00000006, 
   EMR_POLYPOLYLINE = 0x00000007, 
   EMR_POLYPOLYGON = 0x00000008, 
   EMR_SETWINDOWEXTEX = 0x00000009, 
   EMR_SETWINDOWORGEX = 0x0000000A, 
   EMR_SETVIEWPORTEXTEX = 0x0000000B, 
   EMR_SETVIEWPORTORGEX = 0x0000000C, 
   EMR_SETBRUSHORGEX = 0x0000000D, 
   EMR_EOF = 0x0000000E, 
   EMR_SETPIXELV = 0x0000000F, 
   EMR_SETMAPPERFLAGS = 0x00000010, 
   EMR_SETMAPMODE = 0x00000011, 
   EMR_SETBKMODE = 0x00000012, 
   EMR_SETPOLYFILLMODE = 0x00000013, 
   EMR_SETROP2 = 0x00000014, 
   EMR_SETSTRETCHBLTMODE = 0x00000015, 
   EMR_SETTEXTALIGN = 0x00000016, 
   EMR_SETCOLORADJUSTMENT = 0x00000017, 
   EMR_SETTEXTCOLOR = 0x00000018, 
   EMR_SETBKCOLOR = 0x00000019, 
   EMR_OFFSETCLIPRGN = 0x0000001A, 
   EMR_MOVETOEX = 0x0000001B, 
   EMR_SETMETARGN = 0x0000001C, 
   EMR_EXCLUDECLIPRECT = 0x0000001D, 
   EMR_INTERSECTCLIPRECT = 0x0000001E, 
   EMR_SCALEVIEWPORTEXTEX = 0x0000001F, 
   EMR_SCALEWINDOWEXTEX = 0x00000020, 
   EMR_SAVEDC = 0x00000021, 
   EMR_RESTOREDC = 0x00000022, 
   EMR_SETWORLDTRANSFORM = 0x00000023, 
   EMR_MODIFYWORLDTRANSFORM = 0x00000024, 
   EMR_SELECTOBJECT = 0x00000025, 
   EMR_CREATEPEN = 0x00000026, 
   EMR_CREATEBRUSHINDIRECT = 0x00000027, 
   EMR_DELETEOBJECT = 0x00000028, 
   EMR_ANGLEARC = 0x00000029, 
   EMR_ELLIPSE = 0x0000002A, 
   EMR_RECTANGLE = 0x0000002B, 
   EMR_ROUNDRECT = 0x0000002C, 
   EMR_ARC = 0x0000002D, 
   EMR_CHORD = 0x0000002E,
   EMR_PIE = 0x0000002F, 
   EMR_SELECTPALETTE = 0x00000030, 
   EMR_CREATEPALETTE = 0x00000031, 
   EMR_SETPALETTEENTRIES = 0x00000032, 
   EMR_RESIZEPALETTE = 0x00000033, 
   EMR_REALIZEPALETTE = 0x00000034, 
   EMR_EXTFLOODFILL = 0x00000035, 
   EMR_LINETO = 0x00000036, 
   EMR_ARCTO = 0x00000037, 
   EMR_POLYDRAW = 0x00000038, 
   EMR_SETARCDIRECTION = 0x00000039, 
   EMR_SETMITERLIMIT = 0x0000003A, 
   EMR_BEGINPATH = 0x0000003B, 
   EMR_ENDPATH = 0x0000003C, 
   EMR_CLOSEFIGURE = 0x0000003D, 
   EMR_FILLPATH = 0x0000003E, 
   EMR_STROKEANDFILLPATH = 0x0000003F, 
   EMR_STROKEPATH = 0x00000040, 
   EMR_FLATTENPATH = 0x00000041, 
   EMR_WIDENPATH = 0x00000042, 
   EMR_SELECTCLIPPATH = 0x00000043, 
   EMR_ABORTPATH = 0x00000044, 
   EMR_COMMENT = 0x00000046, 
   EMR_FILLRGN = 0x00000047, 
   EMR_FRAMERGN = 0x00000048, 
   EMR_INVERTRGN = 0x00000049, 
   EMR_PAINTRGN = 0x0000004A, 
   EMR_EXTSELECTCLIPRGN = 0x0000004B, 
   EMR_BITBLT = 0x0000004C, 
   EMR_STRETCHBLT = 0x0000004D, 
   EMR_MASKBLT = 0x0000004E, 
   EMR_PLGBLT = 0x0000004F, 
   EMR_SETDIBITSTODEVICE = 0x00000050, 
   EMR_STRETCHDIBITS = 0x00000051, 
   EMR_EXTCREATEFONTINDIRECTW = 0x00000052, 
   EMR_EXTTEXTOUTA = 0x00000053, 
   EMR_EXTTEXTOUTW = 0x00000054, 
   EMR_POLYBEZIER16 = 0x00000055, 
   EMR_POLYGON16 = 0x00000056, 
   EMR_POLYLINE16 = 0x00000057, 
   EMR_POLYBEZIERTO16 = 0x00000058, 
   EMR_POLYLINETO16 = 0x00000059, 
   EMR_POLYPOLYLINE16 = 0x0000005A, 
   EMR_POLYPOLYGON16 = 0x0000005B, 
   EMR_POLYDRAW16 = 0x0000005C, 
   EMR_CREATEMONOBRUSH = 0x0000005D, 
   EMR_CREATEDIBPATTERNBRUSHPT = 0x0000005E, 
   EMR_EXTCREATEPEN = 0x0000005F, 
   EMR_POLYTEXTOUTA = 0x00000060, 
   EMR_POLYTEXTOUTW = 0x00000061, 
   EMR_SETICMMODE = 0x00000062, 
   EMR_CREATECOLORSPACE = 0x00000063, 
   EMR_SETCOLORSPACE = 0x00000064, 
   EMR_DELETECOLORSPACE = 0x00000065, 
   EMR_GLSRECORD = 0x00000066, 
   EMR_GLSBOUNDEDRECORD = 0x00000067, 
   EMR_PIXELFORMAT = 0x00000068, 
   EMR_DRAWESCAPE = 0x00000069, 
   EMR_EXTESCAPE = 0x0000006A, 
   EMR_SMALLTEXTOUT = 0x0000006C, 
   EMR_FORCEUFIMAPPING = 0x0000006D, 
   EMR_NAMEDESCAPE = 0x0000006E, 
   EMR_COLORCORRECTPALETTE = 0x0000006F, 
   EMR_SETICMPROFILEA = 0x00000070, 
   EMR_SETICMPROFILEW = 0x00000071, 
   EMR_ALPHABLEND = 0x00000072, 
   EMR_SETLAYOUT = 0x00000073, 
   EMR_TRANSPARENTBLT = 0x00000074, 
   EMR_GRADIENTFILL = 0x00000076,
   EMR_SETLINKEDUFIS = 0x00000077, 
   EMR_SETTEXTJUSTIFICATION = 0x00000078, 
   EMR_COLORMATCHTOTARGETW = 0x00000079, 
   EMR_CREATECOLORSPACEW = 0x0000007A 
 } EmfRecordType;



inline long LoadEMFHeader(FILE *f, EMFHEAD & SU)
{
#if defined(__PackedStructures__)
return(fread(&SU,1,sizeof(EMFHEAD),f));
#else
return(loadstruct(f,"ddddddddddddwwddddddd",
	&SU.Bounds[0], &SU.Bounds[1], &SU.Bounds[2], &SU.Bounds[3],
        &SU.Frame[0], &SU.Frame[1], &SU.Frame[2], &SU.Frame[3],
	&SU.Signature, &SU.Version, &SU.Bytes, &SU.Records, &SU.Handles, &SU.Reserved,
        &SU.nDescription, &SU.offDescription, &SU.nPalEntries, 
        &SU.Device[0], &SU.Device[1], &SU.Millimeters[0], &SU.Millimeters[1]));
#endif
}


/** Load header for one EMF record. */
bool LoadEmfRecord(FILE *f, _EnhancedMetaRecord &EmfRec)
{
  EmfRec.ParamFilePos = ftell(f);
  Rd_dword(f,&EmfRec.Type);
  Rd_dword(f,&EmfRec.Size);
  if(feof(f) || EmfRec.Size<3) return false;    
  return true;  
}


void TconvertedPass1_EMF::parse_CreateBrushIndirect(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_CreateBrushIndirect ");fflush(log);
#endif
static const char ObjName[] = "!CREATEBRUSHINDIRECT";

  if(EmfRec.Size >= 8+4+12)
    {
    DWORD ihBrush;
    DWORD BrushStyle, BrushColor, BrushHatch;

    Rd_dword(wpd, &ihBrush);

    Rd_dword(wpd, &BrushStyle);
    switch(BrushStyle)
    {    
      case BS_SOLID:	PSS.FillPattern=FILL_SOLID; break;
      case BS_HATCHED:	PSS.FillPattern=FILL_DIAG_UP; break;
      case BS_NULL:
      default:		PSS.FillPattern=FILL_NONE; break;
    }

    Rd_dword(wpd, &BrushColor);
    PSS.FillColor.Red   = BrushColor & 0xFF;
    PSS.FillColor.Green = (BrushColor>>8) & 0xFF;
    PSS.FillColor.Blue  = (BrushColor>>16) & 0xFF;    

    Rd_dword(wpd, &BrushHatch);

    ObjTab.AddObject(new vecBrush(PSS));
    strcpy(ObjType,ObjName+1);
    return;
    }

  strcpy(ObjType,ObjName);
}


void TconvertedPass1_EMF::parse_ExtCreateFontIndirectW(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_ExtCreateFontIndirectW() ");fflush(log);
#endif
static const char ObjName[] = "!EXTCREATEFONTINDIRECTW";
DWORD ihFonts;
SDWORD Height, Width;
DWORD Escapement;	//, Orientation;
DWORD D;
BYTE Underline, Strikeout, Charset, OutPrecision, ClipPrecision, Quality, PitchAndFamily;

  /*if(!CheckWmfRecSz(9))
  {
    ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }*/

  Rd_dword(wpd, &ihFonts);
  Rd_dword(wpd, (DWORD*)&Height);
  Rd_dword(wpd, (DWORD*)&Width);
  Rd_dword(wpd, &Escapement);
  Rd_dword(wpd,&D); PSS.FontOrientation10 = D;
  Rd_dword(wpd,&D); PSS.FontWeight = D;

  PSS.FontItallic = fgetc(wpd);
  Underline = fgetc(wpd);
  Strikeout = fgetc(wpd);
  Charset = fgetc(wpd);

  switch(Charset)
  {
    case OEM_CHARSET:
    case DEFAULT_CHARSET:	ConvertCpg = NULL;
				break;
    case ANSI_CHARSET:		ConvertCpg = GetTranslator("cp1252TOinternal");	break;
    case SYMBOL_CHARSET:        ConvertCpg = GetTranslator("symbolTOinternal");	break;
    case EASTEUROPE_CHARSET:    ConvertCpg = GetTranslator("cp1250TOinternal"); // see https://stackoverflow.com/questions/22911186/windows-encoding-clarification
				break;
    case RUSSIAN_CHARSET:	ConvertCpg = GetTranslator("cp1251TOinternal");	break;
    case MAC_CHARSET:		ConvertCpg = GetTranslator("MacRomanTOinternal"); break;
    case GREEK_CHARSET:		ConvertCpg = GetTranslator("cp1253TOinternal"); // see https://www.compart.com/en/unicode/charsets/windows-1253
				break;
    case HEBREW_CHARSET:	ConvertCpg = GetTranslator("cp1255TOinternal"); // see https://www.compart.com/en/unicode/charsets/windows-1255
				break;
    case TURKISH_CHARSET:	ConvertCpg = GetTranslator("cp1254TOinternal"); break;
    case SHIFTJIS_CHARSET:
    case HANGUL_CHARSET:
    case JOHAB_CHARSET:
    case GB2312_CHARSET:
    case CHINESEBIG5_CHARSET:    
    case VIETNAMESE_CHARSET:    
    case ARABIC_CHARSET:
    case BALTIC_CHARSET:    
    case THAI_CHARSET:

    default:			ConvertCpg = NULL; break;
  }
  
  if(ConvertCpg == NULL)
     {
     perc.Hide();
     fprintf(err, _("\nUnsupported charset: %X."), (unsigned)Charset);
     }

  PSS.ConvertCpg = ConvertCpg;

  OutPrecision = fgetc(wpd);
  ClipPrecision = fgetc(wpd);
  Quality = fgetc(wpd);
  PitchAndFamily = fgetc(wpd);

/* 
  char *FaceName;
  FaceName = (char*)malloc(64);
  if(FaceName != NULL)
  {    
    fread(FaceName,64,1,wpd);
    for(int i=0; i<32; i++)
    {
      WORD wch = *(WORD*)(FaceName+2*i);
      FaceName[i] = (wch>=255) ? 255 : wch;
    }
    FaceName[32] = 0;

    if(!strcmp(FaceName,"Symbol"))
    {
    }

    free(FaceName);
    FaceName = NULL;
  }
*/

  sprintf(ObjType,"%s(H=%d,set=%u,rot=%d)", ObjName+1, (int)Height, (unsigned)Charset, PSS.FontOrientation10/10);

  if(YExtent<0) PSS.FontOrientation10 = -PSS.FontOrientation10;
  if(Height!=0)
  {
    if(Height>0)		// The font height is normally negative.
	PSS.FontOrientation10 = -PSS.FontOrientation10;
    PSS.FontSize = labs(Height)/2.66;
  }
  if(Width!=0) 
    PSS.FontSizeW = Width/2.66;
  else
    PSS.FontSizeW = PSS.FontSize;

  ObjTab.AddObject(new vecFont(PSS));
}


void TconvertedPass1_EMF::parse_CreatePen(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_CreatePen ");fflush(log);
#endif
static const char ObjName[] = "!CREATEPEN";

  if(EmfRec.Size >= 8+4+16)
    {
    DWORD ihPen;
    DWORD PenStyle, PenWidthX, PenWidthY, ColorRef;

    Rd_dword(wpd, &ihPen);

    Rd_dword(wpd, &PenStyle);

    switch(PenStyle & 0xFF)
      {    
      case PS_DASH:	PSS.LineStyle=7; break;// 0x0001, 
      case PS_DOT:	PSS.LineStyle=10; break;// 0x0002,
      case PS_DASHDOT:	PSS.LineStyle=15; break;// 0x0003,
      case PS_DASHDOTDOT: PSS.LineStyle=19; break;// 0x0004, 
      case PS_NULL:	PSS.LineStyle=0; break;	// 0x0005, 
      //case PS_INSIDEFRAME = 0x0006, 
      //case PS_USERSTYLE = 0x0007, 
      //case PS_ALTERNATE = 0x0008,
      case PS_SOLID:	
      default:
			PSS.LineStyle=1; break;	// 0x0000, 
      }
    PenWidthX = PenStyle & 0x0F00;
    switch(PenWidthX)
    {
      case PS_ENDCAP_ROUND:	PSS.LineCap=1; break;	// 0x0000 1 (round caps)
      case PS_ENDCAP_SQUARE:	PSS.LineCap=2; break;	// 0x0100 2 (extended butt caps). 
      case PS_ENDCAP_FLAT:	PSS.LineCap=0; break;	// 0x0200 0 (butt caps)
    }
    PenWidthX = PenStyle & 0xF000;
    switch(PenWidthX)
    {
      case PS_JOIN_ROUND:	PSS.LineJoin=1; break;	// 0x0000 1 (round join)
      case PS_JOIN_BEVEL:	PSS.LineJoin=2; break;	// 0x1000 2 (bevel join)
      case PS_JOIN_MITER:	PSS.LineJoin=0; break;	// 0x2000 0 (miter join)
    }

    Rd_dword(wpd, &PenWidthX);
    Rd_dword(wpd, &PenWidthY);		// The value of its y field MUST be ignored.
    PSS.LineWidth = GetScale2PSU((TMapMode)MapMode) * PenWidthX;

    Rd_dword(wpd, &ColorRef);
    PSS.LineColor.Red   = ColorRef & 0xFF;
    PSS.LineColor.Green = (ColorRef>>8) & 0xFF;
    PSS.LineColor.Blue  = (ColorRef>>16) & 0xFF;

    ObjTab.AddObject(new vecPen(PSS));

    strcpy(ObjType,ObjName+1);
    return;
    }

  strcpy(ObjType,ObjName);
}


void TconvertedPass1_EMF::parse_ExtCreatePen(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_ExtCreatePen ");fflush(log);
#endif
static const char ObjName[] = "!EXTCREATEPEN";

  if(EmfRec.Size >= 8+4+16+20)
    {
    DWORD ihPen;
    DWORD offBmi, cbBmi, offBits, cbBits;

    Rd_dword(wpd, &ihPen);
    Rd_dword(wpd, &offBmi);
    Rd_dword(wpd, &cbBmi);
    Rd_dword(wpd, &offBits);
    Rd_dword(wpd, &cbBits);

    DWORD PenStyle, PenWidth, BrushStyle, ColorRef, BrushHatch;

    Rd_dword(wpd, &PenStyle);
    switch(PenStyle & 0xFF)
      {    
      case PS_DASH:	PSS.LineStyle=7; break;// 0x0001, 
      case PS_DOT:	PSS.LineStyle=10; break;// 0x0002,
      case PS_DASHDOT:	PSS.LineStyle=15; break;// 0x0003,
      case PS_DASHDOTDOT: PSS.LineStyle=19; break;// 0x0004, 
      case PS_NULL:	PSS.LineStyle=0; break;	// 0x0005, 
      //case PS_INSIDEFRAME = 0x0006, 
      //case PS_USERSTYLE = 0x0007, 
      //case PS_ALTERNATE = 0x0008,
      case PS_SOLID:	
      default:
			PSS.LineStyle=1; break;	// 0x0000, 
      }
    PenWidth = PenStyle & 0x0F00;
    switch(PenWidth)
    {
      case PS_ENDCAP_ROUND:	PSS.LineCap=1; break;	// 0x0000
      case PS_ENDCAP_SQUARE:	PSS.LineCap=2; break;	// 0x0100
      case PS_ENDCAP_FLAT:	PSS.LineCap=0; break;	// 0x0200
    }
    PenWidth = PenStyle & 0xF000;
    switch(PenWidth)
    {
      case PS_JOIN_ROUND:	PSS.LineJoin=1; break;	// 0x0000 1 (round join)
      case PS_JOIN_BEVEL:	PSS.LineJoin=2; break;	// 0x1000 2 (bevel join)
      case PS_JOIN_MITER:	PSS.LineJoin=0; break;	// 0x2000 0 (miter join)
    }

    Rd_dword(wpd, &BrushStyle);
    Rd_dword(wpd, &PenWidth);
    PSS.LineWidth = GetScale2PSU((TMapMode)MapMode) * PenWidth;

    Rd_dword(wpd, &ColorRef);
    PSS.LineColor.Red   = ColorRef & 0xFF;
    PSS.LineColor.Green = (ColorRef>>8) & 0xFF;
    PSS.LineColor.Blue  = (ColorRef>>16) & 0xFF;

    Rd_dword(wpd, &BrushHatch);

    ObjTab.AddObject(new vecPen(PSS));

    sprintf(ObjType,"%s(W=%u)", ObjName+1, PenWidth);
    return;
    }

  strcpy(ObjType,ObjName);
}


void TconvertedPass1_EMF::parse_CreatePalette(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_CreatePalette() ");fflush(log);
#endif
static const char ObjName[] = "!CREATEPALETTE";

  if(EmfRec.Size < 8+8)
    {
RecordCorrupted:
    //ReportCorruptedObj(ObjName+1);
    strcpy(ObjType, ObjName);
    return;
    }

  DWORD ihPal;
  Rd_dword(wpd, &ihPal);

  WORD NumberOfEntries;
  Rd_word(wpd, &NumberOfEntries);	// Version MUST be 0x0300.
  if(NumberOfEntries!=0x300) goto RecordCorrupted;
  Rd_word(wpd, &NumberOfEntries);

  PSS.AttachPalette(NULL);

  PSS.pPalette = BuildPalette(NumberOfEntries,8);
  if(PSS.pPalette==NULL) goto RecordCorrupted;
  PSS.pPalette->UsageCount = 1;

  for(unsigned i=0; i<NumberOfEntries; i++)
  {
    DWORD d;
    RGBQuad RGB;

    Rd_dword(wpd, &d);
    RGB.R = d & 0xFF;
    RGB.G = (d >> 8) & 0xFF;
    RGB.B = (d >> 8) & 0xFF;
    PSS.pPalette->Set(i,&RGB);
  }

  ObjTab.AddObject(new attrPalette(PSS.pPalette));
  sprintf(ObjType, "%s(%u)", ObjName+1, NumberOfEntries);
}


void TconvertedPass1_EMF::parse_DeleteObject(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_DeleteObject() ");fflush(log);
#endif
DWORD ObjectIndex;
static const char ObjName[] = "!DELETEOBJECT";

  if(EmfRec.Size >= 8+4)
  { 
  Rd_dword(wpd, &ObjectIndex);
  if(ObjectIndex!=0)
    {
    ObjTab.DeleteObject(ObjectIndex-1);
    sprintf(ObjType,"%s(%u)", ObjName+1, ObjectIndex);  
    return;
    }
  }

  strcpy(ObjType,ObjName);
}


void TconvertedPass1_EMF::parse_Ellipse(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_Ellipse() ");fflush(log);
#endif
static const char ObjName[] = "!ELLIPSE";

  if(EmfRec.Size >= 8+16)
    {
    SDWORD BottomRect, TopRect, RightRect, LeftRect;

    Rd_dword(wpd, (DWORD*)&LeftRect);
    Rd_dword(wpd, (DWORD*)&TopRect);
    Rd_dword(wpd, (DWORD*)&RightRect);
    Rd_dword(wpd, (DWORD*)&BottomRect);

	// TODO: Bounding box musí být upraven podle WorldTx.    
    UpdateBBox(bbx, 0, LeftRect, BottomRect, RightRect-LeftRect, TopRect-BottomRect);

    const float Scale = GetScale2PSU((TMapMode)MapMode);

    VectorEllipse *pVecEllipse = new VectorEllipse(Scale*BottomRect, Scale*TopRect, Scale*RightRect, Scale*LeftRect);
    pVecEllipse->AttribFromPSS(PSS);
  
    pVecEllipse->Transform(WorldTx);
    VectList.AddObject(pVecEllipse);

    strcpy(ObjType,ObjName+1);
    return;
    }

strcpy(ObjType,ObjName);
}


void TconvertedPass1_EMF::parse_ExtTextOutW(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_WMF::parse_ExtTextOutW() ");fflush(log);
#endif
static const char ObjName[] = "!EXTTEXTOUTW";
//short int LineLen, CurLineLen;

  SDWORD Bound1, Bound2, Bound3, Bound4;
  DWORD iGraphicsMode;

  //CrackObject(this, ActualPos+EmfRec.Size);

  Rd_dword(wpd,(DWORD*)&Bound1); Rd_dword(wpd,(DWORD*)&Bound2); Rd_dword(wpd,(DWORD*)&Bound3); Rd_dword(wpd,(DWORD*)&Bound4);
  Rd_dword(wpd,&iGraphicsMode);

  float exScale, eyScale;
  Rd_dword(wpd,(DWORD*)&exScale); Rd_dword(wpd,(DWORD*)&eyScale);

	// EMR text object follows

  SDWORD y_pos, x_pos;
  Rd_dword(wpd, (DWORD*)&x_pos);
  Rd_dword(wpd, (DWORD*)&y_pos);  

  DWORD CharCount;
  Rd_dword(wpd, &CharCount);
  if(CharCount==0) goto ExitErr;
  if(ConvertUnicode==NULL)		// Bail out when Unicode support is not compilled :(.
  {
ExitErr:
    strcpy(ObjType,ObjName);
    return;
  }

  DWORD OffString;	// An unsigned integer that specifies the offset to the output string in bytes, from the start of the record in which this object is contained. 
  Rd_dword(wpd, &OffString);

  fseek(wpd, OffString+ActualPos, SEEK_SET);

  const float Scale = GetScale2PSU((TMapMode)MapMode);
  TextContainer *pTextCont = new TextContainer;  
  pTextCont->PosX = Scale*x_pos;
  pTextCont->PosY = Scale*y_pos + mm2PSu(PSS.FontSize);	// Fix text position.
  pTextCont->TextAllign = PSS.TextAllign;
  pTextCont->FontOrientation = PSS.FontOrientation10 / 10.0f;
  pTextCont->MixMode = MixMode;

  if(log!=NULL && CharCount>0) fputc('\n',log);
  while(CharCount-->0 && !feof(wpd))
  {
    WORD W;
    Rd_word(wpd, &W);
    if(log!=NULL)
    {
      if(W>0xFF)
        fprintf(log, "(%4.4X)", W);
      else
        fputc(W,log);
    }
    if((W&0xF000) == 0xF000)
    {
      if(ConvertCpg != NULL)
          AddCharacterToContainer(pTextCont, (*ConvertCpg)[W&0xFF], PsNativeCP, PsNativeSym, this, PSS);
    }
    else
      AddCharacterToContainer(pTextCont, (*ConvertUnicode)[W], PsNativeCP, PsNativeSym, this, PSS);
  }

  if(pTextCont->isEmpty())    
    delete pTextCont;    
  else
  {    
    pTextCont->Transform(WorldTx);
    VectList.AddObject(pTextCont);
#ifdef _DEBUG
/*
    const float sz = mm2PSu(PSS.FontSize)/2;
    VectorRectangle *pVectRec = new VectorRectangle(Scale*y_pos, Scale*y_pos+sz, pTextCont->PosX, pTextCont->PosX+sz);
    pVectRec->AttribFromPSS(PSS);    
    VectList.AddObject(pVectRec);
*/
#endif
  }
  pTextCont = NULL;  

/*
  int MaxTextLen = 2*(WmfRec.Size - 4);
  if(fuOptions & 0x0004)		// ETO_CLIPPED Rectangle provided
  {
    fseek(wpd, 8, SEEK_CUR);	//TODO: dopsat!
    MaxTextLen -= 8;
  }

  if(MaxTextLen < TextLen)
  {
    if(err!=NULL)
    {
      perc.Hide();
      fprintf(err, _("\nError: text with size %d cannot fit into object, cut to %u."), MaxTextLen, TextLen);
    }
    TextLen = MaxTextLen;
  }

  const float Scale = GetScale2PSU((TMapMode)MapMode);
  TextContainer *pTextCont = new TextContainer;  
  pTextCont->PosX = Scale*x_pos;
  pTextCont->PosY = Scale*y_pos;
  pTextCont->TextAllign = PSS.TextAllign;
  pTextCont->FontOrientation = PSS.FontOrientation10 / 10.0f;
  pTextCont->FillPattern = PSS.FillPattern;

  LineLen = CurLineLen = 0;
  if(log!=NULL) fputc(' ',log);
  while(!feof(wpd))
    {
    if(TextLen-- <= 0) break;
    c = fgetc(wpd);
    if(c==0) break;

    if(log!=NULL) fputc(c,log);
    if(c=='\n')
    {
      if(CurLineLen>LineLen) LineLen=CurLineLen;
      if(!pTextCont->isEmpty())
      {
        const float CurPosY = pTextCont->PosY + mm2PSu(PSS.FontSize);
        VectList.AddObject(pTextCont);
        pTextCont = new TextContainer;        
        pTextCont->PosX = Scale*x_pos;        
        pTextCont->PosY = CurPosY;
        pTextCont->TextAllign = PSS.TextAllign;
        pTextCont->FontOrientation = PSS.FontOrientation10 / 10.0f;
        pTextCont->FillPattern = PSS.FillPattern;
      }
    }
    else CurLineLen++;

    if(ConvertCpg != NULL)
      {
      if(!strcmp(ConvertCpg->Name,"symbolTOinternal"))
        pTextCont->AddText((char)c, "Symbol", PSS);	// Push Symbol code page without any change.
      else
        {
        AddCharacterToContainer(pTextCont, (*ConvertCpg)[c], PsNativeCP, PsNativeSym, this, PSS);
        }
      }
    else
      {
      pTextCont->AddText((char)c,PSS);
      }
    }
  if(pTextCont->isEmpty())    
    delete pTextCont;    
  else    
    VectList.AddObject(pTextCont);    
  pTextCont=NULL;

  //if(VectList.isEmpty()) goto TEXT_OUT_FAIL;
  if(CurLineLen>LineLen) LineLen=CurLineLen;

  UpdateBBox(bbx, 0, x_pos, y_pos+0.1*mm2PSu(PSS.FontSize),		// Extend down reserved space for character.
             LineLen*mm2PSu(PSS.FontSizeW), -1.1*mm2PSu(PSS.FontSize));
*/
  
  strcpy(ObjType,ObjName+1);
  return;
}


void TconvertedPass1_EMF::parse_ModifyWorldTransform(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_ModifyWorldTransform() ");fflush(log);
#endif
static const char ObjName[] = "!MODIFYWORLDTRANSFORM";
float M11b, M12b, M21b, M22b;
float Dxb, Dyb;


  if(EmfRec.Size < 8+6*4)
    {
    strcpy(ObjType,ObjName);
    return;
    }

  RdFLOAT_LoEnd(&M11b,wpd);
  RdFLOAT_LoEnd(&M12b,wpd);
  RdFLOAT_LoEnd(&M21b,wpd);
  RdFLOAT_LoEnd(&M22b,wpd);
  RdFLOAT_LoEnd(&Dxb,wpd);
  RdFLOAT_LoEnd(&Dyb,wpd);

  const float NewM11 = M11b*WorldTx.M11 + M21b*WorldTx.M12;
  const float NewM21 = M11b*WorldTx.M21 + M21b*WorldTx.M22;
  const float NewDx  = M11b*WorldTx.Dx + M21b*WorldTx.Dy + Dxb;

  const float NewM12 = M12b*WorldTx.M11 + M22b*WorldTx.M12;
  const float NewM22 = M12b*WorldTx.M21 + M22b*WorldTx.M22;
  const float NewDy  = M12b*WorldTx.Dx + M22b*WorldTx.Dy + Dyb;

  WorldTx.M11 = NewM11;
  WorldTx.M21 = NewM21;
  WorldTx.M12 = NewM12;
  WorldTx.M22 = NewM22;
  WorldTx.Dx = NewDx;
  WorldTx.Dy = NewDy;

  strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_EMF::parse_SetWorldTransform(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_SetWorldTransform() ");fflush(log);
#endif
static const char ObjName[] = "!SETWORLDTRANSFORM";

  if(EmfRec.Size < 8+6*4)
    {
    strcpy(ObjType,ObjName);
    return;
    }

  RdFLOAT_LoEnd(&WorldTx.M11,wpd);
  RdFLOAT_LoEnd(&WorldTx.M12,wpd);
  RdFLOAT_LoEnd(&WorldTx.M21,wpd);
  RdFLOAT_LoEnd(&WorldTx.M22,wpd);
  RdFLOAT_LoEnd(&WorldTx.Dx,wpd);
  RdFLOAT_LoEnd(&WorldTx.Dy,wpd);

  strcpy(ObjType,ObjName+1);
}


void TconvertedPass1_EMF::parse_MoveToEX(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_MoveToEx() ");fflush(log);
#endif
static const char ObjName[] = "!MOVETOEX";

  if(EmfRec.Size >= 8+8)
    {    
    Rd_dword(wpd, (DWORD*)&PositionX);		// @TODO: extend PositionX,Y to 32 bits.    
    Rd_dword(wpd, (DWORD*)&PositionY);
    sprintf(ObjType,"%s(%d;%d)", ObjName+1, PositionX, PositionY);
    }
  else
    strcpy(ObjType,ObjName);  
}


void TconvertedPass1_EMF::parse_LineTo(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_LineTo() ");fflush(log);
#endif
static const char ObjName[] = "!LINETO";

  if(EmfRec.Size >= 8+8)
  {
    SDWORD LineX, LineY;

    Rd_dword(wpd, (DWORD*)&LineX);
    Rd_dword(wpd, (DWORD*)&LineY);    

    float *Points = (float*)malloc(4*sizeof(float));
    if(Points!=NULL)
    {
      const float Scale = GetScale2PSU((TMapMode)MapMode);

      Points[0] = PositionX;
      Points[1] = PositionY;
      Points[2] = LineX;
      Points[3] = LineY;
      VectorLine *pVecLine = new VectorLine(Points, 2);      
      pVecLine->Transform(WorldTx);
      UpdateBBox(bbx, 0, Points[0], Points[1], Points[3]-Points[0], Points[2]-Points[1]); // Update BBox after world transform.
      for(int i=0; i<4; i++) Points[i]*=Scale;

      memcpy(&pVecLine->LineColor, &PSS.LineColor, sizeof(PSS.LineColor));  
      pVecLine->Close = false;      
      VectList.AddObject(pVecLine); pVecLine=NULL;

      sprintf(ObjType,"%s(%d;%d)", ObjName+1, LineX, LineY);
      return;
    }
  }

  strcpy(ObjType,ObjName);
}


void TconvertedPass1_EMF::parse_Polygon16(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_Polygon16() ");fflush(log);
#endif
static const char ObjName[] = "!POLYGON16";
  SDWORD Bounds[4];
  DWORD Count;  

  if(EmfRec.Size < 20+8)
  {
POLY_FAIL:
    //ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_dword(wpd, (DWORD*)&Bounds[0]);	//LeftRect
  Rd_dword(wpd, (DWORD*)&Bounds[1]);	//TopRect
  Rd_dword(wpd, (DWORD*)&Bounds[2]);	//RightRect
  Rd_dword(wpd, (DWORD*)&Bounds[3]);	//BottomRect

  Rd_dword(wpd, &Count);
  if(Count > (EmfRec.Size - 28)/4)
    Count = (EmfRec.Size - 28)/4;
  float *Points = LoadPoints(this, Count, bbx, &WorldTx);
  if(Points==NULL)  goto POLY_FAIL;  

  const float Scale = GetScale2PSU((TMapMode)MapMode);
  for(int i=0; i<2*Count; i++)
  {
    Points[i] *= Scale;		// scale both x & y
  }

  VectorPolygon *pVecPoly = new VectorPolygon(Points, Count);
  Points = NULL;
  pVecPoly->AttribFromPSS(PSS);  
  pVecPoly->Close = true;  
  VectList.AddObject(pVecPoly); pVecPoly=NULL;

  strcpy(ObjType,ObjName+1);
  return;
}


void TconvertedPass1_EMF::parse_PolyLine16(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_PolyLine16() ");fflush(log);
#endif
static const char ObjName[] = "!POLYLINE16";

  if(EmfRec.Size >= 8+20)
  {
    SDWORD Bound1, Bound2, Bound3, Bound4;
    DWORD Count;

    Rd_dword(wpd,(DWORD*)&Bound1); Rd_dword(wpd,(DWORD*)&Bound2); Rd_dword(wpd,(DWORD*)&Bound3); Rd_dword(wpd,(DWORD*)&Bound4);
    Rd_dword(wpd, &Count);
    if(Count > (EmfRec.Size-28) /4)
      Count = (EmfRec.Size-28) / 4;
    if(Count>0)
    {
      float *Points = LoadPoints(this, Count, bbx, &WorldTx);
      if(Points!=NULL)
      {
        const float Scale = GetScale2PSU((TMapMode)MapMode);
        for(int i=0; i<2*Count; i++)
        {
          Points[i] *= Scale;		// scale both x & y
        }

        VectorPolygon *pVecPoly = new VectorPolygon(Points,Count);
        Points = NULL;      

        pVecPoly->AttribFromPSS(PSS);  
        pVecPoly->Close = false;
        //pVecPoly->Transform(WorldTx);
        VectList.AddObject(pVecPoly); pVecPoly=NULL;

        strcpy(ObjType,ObjName+1);
        return;
      }
    }
  }

  strcpy(ObjType,ObjName);
}


void TconvertedPass1_EMF::parse_PolyBezier16(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_PolyBezier16() ");fflush(log);
#endif
static const char ObjName[] = "!POLYBEZIER16";

  if(EmfRec.Size >= 8+20)
  {
    SDWORD Bound1, Bound2, Bound3, Bound4;
    DWORD Count;

    Rd_dword(wpd,(DWORD*)&Bound1); Rd_dword(wpd,(DWORD*)&Bound2); Rd_dword(wpd,(DWORD*)&Bound3); Rd_dword(wpd,(DWORD*)&Bound4);
    Rd_dword(wpd, &Count);
    if(Count > (EmfRec.Size-28) /4)
      Count = (EmfRec.Size-28) / 4;
    if(Count>0)
    {
      float *Points = LoadPoints(this, Count, bbx, &WorldTx);
      if(Points!=NULL)
      {
        const float Scale = GetScale2PSU((TMapMode)MapMode);
        for(int i=0; i<2*Count; i++)
        {
          Points[i] *= Scale;		// scale both x & y
        }

        VectorCurve *pVecCurve = new VectorCurve(Points,Count);      
        Points = NULL;      

        pVecCurve->AttribFromPSS(PSS);  
        pVecCurve->Close = false;
        //pVecCurve->Transform(WorldTx);
        VectList.AddObject(pVecCurve); pVecCurve=NULL;

        strcpy(ObjType,ObjName+1);
        return;
      }
    }
  }

  strcpy(ObjType,ObjName);
}


void TconvertedPass1_EMF::parse_PolyPolygon16(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_PolyPolygon16() ");fflush(log);
#endif
static const char ObjName[] = "!POLYPOLYGON16";
  SDWORD Bounds[4];
  DWORD NumberOfPolygons;
  DWORD TotalPolygonCount;
  int i;

  if(EmfRec.Size < 20+8)
  {
POLY_FAIL:
    //ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_dword(wpd, (DWORD*)&Bounds[0]);	//LeftRect
  Rd_dword(wpd, (DWORD*)&Bounds[1]);	//TopRect
  Rd_dword(wpd, (DWORD*)&Bounds[2]);	//RightRect
  Rd_dword(wpd, (DWORD*)&Bounds[3]);	//BottomRect

  Rd_dword(wpd, &NumberOfPolygons);
  Rd_dword(wpd, &TotalPolygonCount);

  DWORD *PolypolygonPointCount = (DWORD*)malloc(sizeof(DWORD)*NumberOfPolygons);
  if(PolypolygonPointCount==NULL) goto POLY_FAIL;

  for(i=0; i<NumberOfPolygons; i++)
      Rd_dword(wpd, &PolypolygonPointCount[i]);

  const float Scale = GetScale2PSU((TMapMode)MapMode);
  for(i=0; i<NumberOfPolygons; i++)
    if(PolypolygonPointCount[i]>0)
      {
        float *Points = LoadPoints(this, PolypolygonPointCount[i], bbx, &WorldTx);
        if(Points==NULL) break;
        
        for(int j=0; j<2*PolypolygonPointCount[i]; j++)
        {
          Points[j] *= Scale;		// scale both x & y
        }

        VectorPolygon *pVecPoly = new VectorPolygon(Points, PolypolygonPointCount[i]);
        Points = NULL;
        pVecPoly->AttribFromPSS(PSS);  
        pVecPoly->Close = true;
        //pVecPoly->Transform(WorldTx);
        VectList.AddObject(pVecPoly); pVecPoly=NULL;
      }

  strcpy(ObjType,ObjName+1);
  return;
}


void TconvertedPass1_EMF::parse_PolyPolyLine16(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_PolyPolyLine16() ");fflush(log);
#endif
static const char ObjName[] = "!POLYPOLYLINE16";
int i;

  if(EmfRec.Size >= 8+24)
  {
    SDWORD Bound1, Bound2, Bound3, Bound4;
    DWORD NumberOfPolylines;
    DWORD TotalPointCount;
    
    Rd_dword(wpd,(DWORD*)&Bound1); Rd_dword(wpd,(DWORD*)&Bound2); Rd_dword(wpd,(DWORD*)&Bound3); Rd_dword(wpd,(DWORD*)&Bound4);
    Rd_dword(wpd, &NumberOfPolylines);
    Rd_dword(wpd, &TotalPointCount);

    DWORD *PolylinePointCount = (DWORD*)malloc(sizeof(DWORD)*NumberOfPolylines);
    if(PolylinePointCount==NULL) goto POLY_FAIL;

    for(i=0; i<NumberOfPolylines; i++)
        Rd_dword(wpd, &PolylinePointCount[i]);

    const float Scale = GetScale2PSU((TMapMode)MapMode);
    for(i=0; i<NumberOfPolylines; i++)
      if(PolylinePointCount[i]>0)
      {
        float *Points = LoadPoints(this, PolylinePointCount[i], bbx, &WorldTx);
        if(Points==NULL) break;		// PolylinePointCount must be deallocated
        
        for(int j=0; j<2*PolylinePointCount[i]; j++)
        {
          Points[j] *= Scale;		// scale both x & y
        }

        VectorPolygon *pVecPoly = new VectorPolygon(Points,PolylinePointCount[i]);
        Points = NULL;      

        pVecPoly->AttribFromPSS(PSS);  
        pVecPoly->Close = false;
        //pVecPoly->Transform(WorldTx);
        VectList.AddObject(pVecPoly); pVecPoly=NULL;

        strcpy(ObjType,ObjName+1);
      }

    free(PolylinePointCount);
    return;    
  }

POLY_FAIL:
  strcpy(ObjType,ObjName);
}


void TconvertedPass1_EMF::parse_Rectangle(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_Rectangle() ");fflush(log);
#endif
static const char ObjName[] = "!RECTANGLE";

  if(EmfRec.Size >= 8+16)
  {
    SDWORD	BottomRect, TopRect, RightRect, LeftRect;

    Rd_dword(wpd, (DWORD*)&LeftRect);
    Rd_dword(wpd, (DWORD*)&TopRect);
    Rd_dword(wpd, (DWORD*)&RightRect);
    Rd_dword(wpd, (DWORD*)&BottomRect);

    UpdateBBox(bbx, 0, LeftRect, BottomRect, RightRect-LeftRect, TopRect-BottomRect);

    const float Scale = GetScale2PSU((TMapMode)MapMode);

    VectorRectangle *pVectRec = new VectorRectangle(Scale*BottomRect, Scale*TopRect, Scale*LeftRect, Scale*RightRect);
    pVectRec->AttribFromPSS(PSS);
    pVectRec->Transform(WorldTx);
    VectList.AddObject(pVectRec);

    strcpy(ObjType,ObjName+1);
    return;
  }

  strcpy(ObjType,ObjName);
}

 typedef  enum  
 { 
   WHITE_BRUSH = 0x0000000,
   LTGRAY_BRUSH = 0x0000001, 
   GRAY_BRUSH = 0x0000002, 
   DKGRAY_BRUSH = 0x0000003, 
   BLACK_BRUSH = 0x0000004, 
   NULL_BRUSH = 0x0000005, 
   WHITE_PEN = 0x0000006, 
   BLACK_PEN = 0x0000007, 
   NULL_PEN = 0x0000008, 
   OEM_FIXED_FONT = 0x000000A, 
   ANSI_FIXED_FONT = 0x000000B, 
   ANSI_VAR_FONT = 0x000000C, 
   SYSTEM_FONT = 0x000000D, 
   DEVICE_DEFAULT_FONT = 0x000000E, 
   DEFAULT_PALETTE = 0x000000F, 
   SYSTEM_FIXED_FONT = 0x0000010, 
   DEFAULT_GUI_FONT = 0x0000011, 
   DC_BRUSH = 0x0000012, 
   DC_PEN = 0x0000013 
 } EMF_StockObject;


void TconvertedPass1_EMF::parse_SelectObject(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_SelectObject() ");fflush(log);
#endif
DWORD ObjectIndex;
static const char ObjName[] = "!SELECTOBJECT";

  if(EmfRec.Size < 8+4)
  {
    //ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }
  
  Rd_dword(wpd, &ObjectIndex);

  if(ObjectIndex >= 0x80000000)		// stock objects.
  {
    switch(ObjectIndex & 0x7FFFFFFF)
    {
      case WHITE_BRUSH:
            PSS.FillColor.Red = PSS.FillColor.Green = PSS.FillColor.Blue  = 255;
	    PSS.FillPattern = FILL_SOLID;
	    break;
      case LTGRAY_BRUSH:
	    PSS.FillColor.Red = PSS.FillColor.Green = PSS.FillColor.Blue  = 191;
	    PSS.FillPattern = FILL_SOLID;
	    break;
      case GRAY_BRUSH:
            PSS.FillColor.Red = PSS.FillColor.Green = PSS.FillColor.Blue  = 127;
	    PSS.FillPattern = FILL_SOLID;
	    break;
      case DKGRAY_BRUSH:
            PSS.FillColor.Red = PSS.FillColor.Green = PSS.FillColor.Blue  = 63;
	    PSS.FillPattern = FILL_SOLID;
	    break;
      case BLACK_BRUSH:
            PSS.FillColor.Red = PSS.FillColor.Green = PSS.FillColor.Blue  = 0;
	    PSS.FillPattern = FILL_SOLID;
	    break;
      case NULL_BRUSH:
	    PSS.FillPattern = FILL_NONE;
	    break; 
      case WHITE_PEN:
            PSS.LineColor.Red = PSS.LineColor.Green = PSS.LineColor.Blue  = 255;
	    PSS.LineStyle = 1;
	    break;
      case BLACK_PEN:
	    PSS.LineColor.Red = PSS.LineColor.Green = PSS.LineColor.Blue  = 0;
	    PSS.LineStyle = 1;
	    break;
      case NULL_PEN:
	    PSS.LineStyle = 0;
	    break;
      default:
	    sprintf(ObjType,"%s(%Xh)", ObjName, ObjectIndex);
	    return;
    }
    sprintf(ObjType,"%s(%Xh)", ObjName+1, ObjectIndex);    
  }
  else
  {
    if(ObjectIndex == 0) goto OBJECT_DEFFECT;
    const VectorAttribute *vecAttr = ObjTab.GetObjectAt(ObjectIndex-1);
    if(vecAttr==NULL) goto OBJECT_DEFFECT;
    
    vecAttr->prepExport(&PSS);
    ConvertCpg = PSS.ConvertCpg;

    sprintf(ObjType,"%s(%u)", ObjName+1, ObjectIndex);
  }
  return;

OBJECT_DEFFECT:
  sprintf(ObjType,"%s(%u)",ObjName,ObjectIndex);
  return;
}


void TconvertedPass1_EMF::parse_SelectPalette(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_SelectPalette() ");fflush(log);
#endif
DWORD ObjectIndex;
static const char ObjName[] = "!SELECTPALETTE";

  if(EmfRec.Size < 8+4)
  {
    //ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }
  
  Rd_dword(wpd, &ObjectIndex);

  if(ObjectIndex >= 0x80000000)		// stock objects.
  {
    switch(ObjectIndex & 0x7FFFFFFF)
    {
      case DEFAULT_PALETTE:
	      PSS.AttachPalette(NULL);	/// Deallocate a current palette. Default palette is system dependent huh!
	      break;
      default:
	      sprintf(ObjType,"%s(%Xh)", ObjName, ObjectIndex);
	      return;
    }
    sprintf(ObjType,"%s(%Xh)", ObjName+1, ObjectIndex);    
  }
  else
  {
    if(ObjectIndex == 0) goto OBJECT_DEFFECT;
    const VectorAttribute *vecAttr = ObjTab.GetObjectAt(ObjectIndex-1);
    if(vecAttr==NULL) goto OBJECT_DEFFECT;
    if(vecAttr->getAttribType()!=ATTR_PALETTE) goto OBJECT_DEFFECT;

    vecAttr->prepExport(&PSS);
    ConvertCpg = PSS.ConvertCpg;

    sprintf(ObjType,"%s(%u)", ObjName+1, ObjectIndex);
  }
  return;

OBJECT_DEFFECT:
  sprintf(ObjType,"%s(%u)",ObjName,ObjectIndex);
  return;
}


void TconvertedPass1_EMF::parse_SetBkColor(void)
{
static const char ObjName[] = "!SETBKCOLOR";
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_SetBkColor() ");fflush(log);
#endif

  if(EmfRec.Size < 8+4)
  {
    strcpy(ObjType,ObjName);
    return;
  }

  DWORD D;
  Rd_dword(wpd, &D);
  PSS.FillBackground.Red   = D & 0xFF;
  PSS.FillBackground.Green = (D>>8) & 0xFF;
  PSS.FillBackground.Blue  = (D>>16) & 0xFF;

  sprintf(ObjType,"%s(%6.6Xh)", ObjName+1, D);
}


void TconvertedPass1_EMF::parse_SetBkMode(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_SetBkMode() ");fflush(log);
#endif
static const char ObjName[] = "!SETBKMODE";
DWORD BkMode;
  if(EmfRec.Size < 8+4)
  {
    //ReportCorruptedObj(ObjName+1);
    strncpy(ObjType,ObjName,16);
    return;
  }  
  Rd_dword(wpd, &BkMode);
  if(BkMode==2)		// Opaque
  {
    MixMode = 2;
    if(PSS.FillPattern>FILL_SOLID) PSS.FillPattern|=0x80;    
  }
  else			// Transparent
  {
    MixMode = 1;
    PSS.FillPattern&=~0x80;
  }
  sprintf(ObjType, "%s(%u)", ObjName+1, (unsigned)BkMode);
}


void TconvertedPass1_EMF::parse_SetPixel(VectorList &VectList)
{
static const char ObjName[] = "!SETPIXELV";
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_SetPixel() ");fflush(log);
#endif
SDWORD x,y;
RGB_Record PixColor;

  if(EmfRec.Size < 8+8+4)
  {
    strcpy(ObjType,ObjName);
    return;
  }
  
  Rd_dword(wpd, (DWORD*)&x);
  Rd_dword(wpd, (DWORD*)&y);
  PixColor.Red = fgetc(wpd);
  PixColor.Green = fgetc(wpd);
  PixColor.Blue = fgetc(wpd);
  fseek(wpd, 1, SEEK_CUR);

  UpdateBBox(bbx, 0, x-0.5f, y-0.5f, 1, 1);

  const float Scale = GetScale2PSU((TMapMode)MapMode);

  VectorRectangle *pVectRec = new VectorRectangle(Scale*(y-0.5f), Scale*(y+0.5f), Scale*(x-0.5f), Scale*(x+0.5f));
  pVectRec->AttribFromPSS(PSS);
  pVectRec->FillColor = PixColor;
  pVectRec->BrushStyle = FILL_SOLID;
  pVectRec->LineStyle = 0;
  pVectRec->Transform(WorldTx);
  VectList.AddObject(pVectRec);  

  strcpy(ObjType,ObjName+1);

  DWORD D;
  Rd_dword(wpd, &D);
  PSS.FillBackground.Red   = D & 0xFF;
  PSS.FillBackground.Green = (D>>8) & 0xFF;
  PSS.FillBackground.Blue  = (D>>16) & 0xFF;

  sprintf(ObjType,"%s(%6.6Xh)", ObjName+1, D);
}


void TconvertedPass1_EMF::parse_SetPolyFillMode(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_SetPolyFillMode() ");fflush(log);
#endif
static const char ObjName[] = "!SETPOLYFILLMODE";
DWORD PolygonFillMode;
  if(EmfRec.Size < 8+4)
  {
    //ReportCorruptedObj(ObjName+1);
    strncpy(ObjType,ObjName,16);
    return;
  }  
  Rd_dword(wpd, &PolygonFillMode);
  PSS.PolyFillMode = (PolygonFillMode==1) ? 1 : 0;
  sprintf(ObjType, "%s(%u)", ObjName+1, (unsigned)PolygonFillMode);
}


void TconvertedPass1_EMF::parse_SetTextAlign(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_SetTextAlign() ");fflush(log);
#endif
DWORD TextAlignmentMode;
static const char ObjName[] = "!SetTextAlign";

  if(EmfRec.Size < 8+4)
  {
    //ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }
  
  Rd_dword(wpd, &TextAlignmentMode);

  PSS.TextAllign = TextAlignmentMode & 0xFF;
 
  sprintf(ObjType,"%s(%Xh)", ObjName+1, TextAlignmentMode);
}


void TconvertedPass1_EMF::parse_SetTextColor(void)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_SetTextColor() ");fflush(log);
#endif
static const char ObjName[] = "!SETTEXTCOLOR";

  if(EmfRec.Size >= 8+4)
  {
    DWORD D;
    Rd_dword(wpd, &D);
    PSS.TextColor.Red   = D & 0xFF;
    PSS.TextColor.Green = (D>>8) & 0xFF;
    PSS.TextColor.Blue  = (D>>16) & 0xFF;
    sprintf(ObjType,"%s(%6.6Xh)", ObjName+1, D);    
    return;
  }

  strcpy(ObjType,ObjName);
}


/** This function extracts bitmap from a EMF stream. */
void EMF_STRETCHDIB(Image &Img, FILE *f, DWORD ParamFilePos)
{
DWORD BIH_biSize;

  fseek(f,ParamFilePos,SEEK_SET);
  if(RdDWORD_LoEnd(&BIH_biSize,f)!=4)
  {	// @TODO: Possible PNG or JPG contents.
    return;
  }

  if(BIH_biSize!=40) return;

  fseek(f,ParamFilePos,SEEK_SET);  
  LoadBmpStream(Img,f,0);
}


void TconvertedPass1_EMF::parse_StretchDIBits(VectorList &VectList)
{
#ifdef DEBUG
  fprintf(log,"\n#TconvertedPass1_EMF::parse_StretchDIBits() ");fflush(log);
#endif
static const char ObjName[] = "!STRETCHDIBITS";
SDWORD Bounds[4];
SDWORD xDest, yDest, xSrc, ySrc, cxSrc, cySrc;
DWORD offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc;
DWORD UsageSrc, BitBltRasterOperation;
SDWORD cxDest, cyDest;
Image *pImg = &Img;

  //CrackObject(this, ActualPos+EmfRec.Size);

  if(EmfRec.Size < 8+18*4)
  {
ObjectCorrupted:
    //ReportCorruptedObj(ObjName+1);
    strcpy(ObjType,ObjName);
    return;
  }

  Rd_dword(wpd, (DWORD*)&Bounds[0]);	//LeftRect
  Rd_dword(wpd, (DWORD*)&Bounds[1]);	//TopRect
  Rd_dword(wpd, (DWORD*)&Bounds[2]);	//RightRect
  Rd_dword(wpd, (DWORD*)&Bounds[3]);	//BottomRect

  Rd_dword(wpd, (DWORD*)&xDest);
  Rd_dword(wpd, (DWORD*)&yDest);
  Rd_dword(wpd, (DWORD*)&xSrc);
  Rd_dword(wpd, (DWORD*)&ySrc);
  Rd_dword(wpd, (DWORD*)&cxSrc);
  Rd_dword(wpd, (DWORD*)&cySrc);

  Rd_dword(wpd, &offBmiSrc);
  Rd_dword(wpd, &cbBmiSrc);
  Rd_dword(wpd, &offBitsSrc);
  Rd_dword(wpd, &cbBitsSrc);
  Rd_dword(wpd, &UsageSrc);
  Rd_dword(wpd, &BitBltRasterOperation);

  Rd_dword(wpd, (DWORD*)&cxDest);
  Rd_dword(wpd, (DWORD*)&cyDest);  

  if(EmfRec.Size < offBmiSrc) goto ObjectCorrupted;
  offBmiSrc = ftell(wpd) + offBmiSrc - (8+18*4);

	// Rewind to the last frame.
  while(pImg->Next!=NULL)
        pImg = pImg->Next;

  if(pImg->Raster==NULL || pImg->Raster->Data2D==NULL)
  {
    Image Img2;
    EMF_STRETCHDIB(Img2, wpd, offBmiSrc);
    if(Img2.Raster != NULL)
    {
      VectorRaster *vr;
      if(fabs(Img2.RotAngle) > 1e-5)
        vr = new VectorRaster(xDest+cxDest/2, yDest+cyDest/2, cxDest, cyDest, Img2.RotAngle);
      else
        vr = new VectorRaster(yDest, yDest+cyDest, xDest+cxDest, xDest);
      vr->AttachRaster(Img2.Raster);
      if(Img2.Palette != NULL)
          vr->AttachPalette(Img2.Palette);
      else
      {
	if(pImg->Palette==NULL)
	    vr->AttachPalette(PSS.pPalette);
	else
	    vr->AttachPalette(Img2.Palette);
      }
      vr->Transform(WorldTx);

      float dx = vr->RightCenterX - vr->CenterX;
      float dy = vr->RightCenterY - vr->CenterY;
      UpdateBBox(bbx, 0, vr->CenterX-dx, vr->CenterY-dy, 2*dx, 2*dy);
      dx = vr->TopCenterX - vr->CenterX;
      dy = vr->TopCenterY - vr->CenterY;
      UpdateBBox(bbx, 0, vr->CenterX-dx, vr->CenterY-dy, 2*dx, 2*dy);

      VectList.AddObject(vr);
    }
  }
  else
  {
    Image Img2;

    EMF_STRETCHDIB(Img2, wpd, offBmiSrc);
    Img2.x = xDest;
    Img2.y = yDest;
    Img2.dx = cxDest;
    Img2.dy = cyDest;
    if(Img2.Raster!=NULL && Img2.Palette==NULL) Img2.AttachPalette(PSS.pPalette);
    //SavePictureEPS("R:\\4\\debug.eps",Img2);

    if(Img2.Raster!=NULL && Img2.Raster->Size1D>0)
    {
      if(Img2.x == pImg->x && Img2.dx == pImg->dx &&		// The x size must match
         Img2.Raster->Size1D==pImg->Raster->Size1D && Img2.Raster->Size2D==1 && 
         Img2.Raster->GetPlanes()==pImg->Raster->GetPlanes())
      {
        void **NewBlock = (void**)realloc(pImg->Raster->Data2D, (pImg->Raster->Size2D+1)*sizeof(void**));
        if(NewBlock!=NULL)
        {
          NewBlock[pImg->Raster->Size2D] = Img2.Raster->Data2D[0];
          Img2.Raster->Data2D[0] = NULL;
	  // Img2.Raster->Size2D must not be schrinked here, schrink will cause leak. Dtor will free empty ptr.
          pImg->Raster->Data2D = NewBlock;
          pImg->Raster->Size2D++;
          pImg->dy = Img2.y - pImg->y + Img2.dy;
        }
      }
      else
      {
        pImg->Next = new Image;
        pImg = pImg->Next;
        pImg->AttachPalette(Img2.Palette);
        pImg->AttachRaster(Img2.Raster);
        pImg->x = Img2.x;        pImg->y = Img2.y;
        pImg->dx = Img2.dx;      pImg->dy = Img2.dy;
        pImg->RotAngle = Img2.RotAngle;
      }
    }
  }
  strcpy(ObjType, ObjName+1);
}


int TconvertedPass1_EMF::Convert_first_pass(void)
{
#ifdef DEBUG
  fprintf(log,"\n#Convert_pass1_EMF() ");fflush(log);
#endif
EMFHEAD EmfHead;
int RetVal = 0;
const unsigned short CodePageBk = OutCodePage;

  if(Verbosing >= 1) printf(_("Opening Windows Enhanced MetaFile:"));

  if(!LoadEmfRecord(wpd, EmfRec)) return -1;
  ActualPos = EmfRec.ParamFilePos;  
  if(EmfRec.Type!=1 || EmfRec.Size<80) return -2;

  if(LoadEMFHeader(wpd,EmfHead)!=80) return -3;
  if(EmfHead.Signature!=0x464D4520) return -4;

  ConvertUnicode = GetTranslator("unicodeTOinternal");
  fseek(wpd, EmfRec.ParamFilePos+EmfRec.Size, SEEK_SET);

  VectorList VectList;
  while(!feof(wpd) && LoadEmfRecord(wpd,EmfRec))
  {
    switch(EmfRec.Type)
    {
      case EMR_HEADER:		strcpy(ObjType,"!HEADER"); break;	// 0x00000001
      case EMR_POLYBEZIER:	strcpy(ObjType,"!POLYBEZIER"); PleaseReport("POLYBEZIER"); break;	// 0x00000002
      case EMR_POLYGON:		strcpy(ObjType,"!POLYGON"); PleaseReport("POLYGON"); break;	// 0x00000003
      case EMR_POLYLINE:	strcpy(ObjType,"!POLYLINE"); PleaseReport("POLYLINE"); break;	// 0x00000004
      case EMR_POLYBEZIERTO:	strcpy(ObjType,"!POLYBEZIERTO"); PleaseReport("POLYBEZIERTO"); break;	// 0x00000005
      case EMR_POLYLINETO:	strcpy(ObjType,"!POLYLINETO"); PleaseReport("POLYLINETO"); break;	// 0x00000006
      case EMR_POLYPOLYLINE:	strcpy(ObjType,"!POLYPOLYLINE"); PleaseReport("POLYPOLYLINE"); break;	// 0x00000007
      case EMR_POLYPOLYGON:	strcpy(ObjType,"!POLYPOLYGON"); PleaseReport("POLYPOLYGON"); break;	// 0x00000008
      case EMR_SETWINDOWEXTEX:	strcpy(ObjType,"!SETWINDOWEXTEX"); break;	// 0x00000009
      case EMR_SETWINDOWORGEX:	strcpy(ObjType,"!SETWINDOWORGEX"); break;	// 0x0000000A
      case EMR_SETVIEWPORTEXTEX:strcpy(ObjType,"!SETVIEWPORTEXTEX"); break;	// 0x0000000B
      case EMR_SETVIEWPORTORGEX:strcpy(ObjType,"!SETVIEWPORTORGEX"); break;	// 0x0000000C
      case EMR_SETBRUSHORGEX:	strcpy(ObjType,"!SETBRUSHORGEX"); break;	// 0x0000000D
      case EMR_EOF: strcpy(ObjType,"!EOF"); break;	// 0x0000000E
      case EMR_SETPIXELV:	parse_SetPixel(VectList); break;	// 0x0000000F 
      case EMR_SETMAPPERFLAGS:	strcpy(ObjType,"!SETMAPPERFLAGS"); break;	// 0x00000010
      case EMR_SETMAPMODE:	strcpy(ObjType,"!SETMAPMODE"); break;	// 0x00000011
      case EMR_SETBKMODE:	parse_SetBkMode(); break;	// 0x00000012
      case EMR_SETPOLYFILLMODE:	parse_SetPolyFillMode(); break;	// 0x00000013
      case EMR_SETROP2: strcpy(ObjType,"!SETROP2"); break;	// 0x00000014
      case EMR_SETSTRETCHBLTMODE: strcpy(ObjType,"!SETSTRETCHBLTMODE"); break;	// 0x00000015
      case EMR_SETTEXTALIGN:	parse_SetTextAlign(); break;	// 0x00000016
      case EMR_SETCOLORADJUSTMENT: strcpy(ObjType,"!SETCOLORADJUSTMENT"); break;	// 0x00000017
      case EMR_SETTEXTCOLOR:	parse_SetTextColor(); break;	// 0x00000018
      case EMR_SETBKCOLOR:	parse_SetBkColor(); break;	// 0x00000019
      case EMR_OFFSETCLIPRGN:	strcpy(ObjType,"!OFFSETCLIPRGN"); break;	// 0x0000001A
      case EMR_MOVETOEX:	parse_MoveToEX(); break;	// 0x0000001B
      case EMR_SETMETARGN: strcpy(ObjType,"!SETMETARGN"); break;	// 0x0000001C
      case EMR_EXCLUDECLIPRECT: strcpy(ObjType,"!EXCLUDECLIPRECT"); break;	// 0x0000001D
      case EMR_INTERSECTCLIPRECT: strcpy(ObjType,"!INTERSECTCLIPRECT"); break;	// 0x0000001E
      case EMR_SCALEVIEWPORTEXTEX: strcpy(ObjType,"!SCALEVIEWPORTEXTEX"); break;	// 0x0000001F
      case EMR_SCALEWINDOWEXTEX: strcpy(ObjType,"!SCALEWINDOWEXTEX"); break;	// 0x00000020
      case EMR_SAVEDC:		strcpy(ObjType,"!SAVEDC"); break;	// 0x00000021
      case EMR_RESTOREDC:	strcpy(ObjType,"!RESTOREDC"); break;	// 0x00000022
      case EMR_SETWORLDTRANSFORM:	parse_SetWorldTransform(); break;	// 0x00000023
      case EMR_MODIFYWORLDTRANSFORM:	parse_ModifyWorldTransform(); break;	// 0x00000024
      case EMR_SELECTOBJECT:	parse_SelectObject(); break;		// 0x00000025
      case EMR_CREATEPEN:	parse_CreatePen(); break;		// 0x00000026
      case EMR_CREATEBRUSHINDIRECT: parse_CreateBrushIndirect(); break;	// 0x00000027
      case EMR_DELETEOBJECT:	parse_DeleteObject(); break;		// 0x00000028
      case EMR_ANGLEARC:	strcpy(ObjType,"!ANGLEARC"); PleaseReport("ANGLEARC"); break;	// 0x00000029
      case EMR_ELLIPSE:		parse_Ellipse(VectList); break;		// 0x0000002A
      case EMR_RECTANGLE:	parse_Rectangle(VectList); break;	// 0x0000002B
      case EMR_ROUNDRECT:	strcpy(ObjType,"!ROUNDRECT"); PleaseReport("ROUNDRECT"); break;	// 0x0000002C
      case EMR_ARC:		strcpy(ObjType,"!ARC"); PleaseReport("ARC"); break;	// 0x0000002D
      case EMR_CHORD:		strcpy(ObjType,"!CHORD"); PleaseReport("CHORD"); break;	// 0x0000002E
      case EMR_PIE:		strcpy(ObjType,"!PIE"); PleaseReport("PIE"); break;	// 0x0000002F
      case EMR_SELECTPALETTE:   parse_SelectPalette(); break;		// 0x00000030
      case EMR_CREATEPALETTE:	parse_CreatePalette(); break;		// 0x00000031
      case EMR_SETPALETTEENTRIES: strcpy(ObjType,"!SETPALETTEENTRIES"); break;	// 0x00000032
      case EMR_RESIZEPALETTE:	strcpy(ObjType,"!RESIZEPALETTE"); break;	// 0x00000033
      case EMR_REALIZEPALETTE:	strcpy(ObjType,"!REALIZEPALETTE"); break;	// 0x00000034
      case EMR_EXTFLOODFILL:	strcpy(ObjType,"!EXTFLOODFILL"); break;	// 0x00000035
      case EMR_LINETO:		parse_LineTo(VectList); break;	// 0x00000036
      case EMR_ARCTO:		strcpy(ObjType,"!ARCTO"); PleaseReport("ARCTO"); break;	// 0x00000037
      case EMR_POLYDRAW:	strcpy(ObjType,"!POLYDRAW"); PleaseReport("POLYDRAW");  break;	// 0x00000038
      case EMR_SETARCDIRECTION: strcpy(ObjType,"!SETARCDIRECTION"); break;	// 0x00000039
      case EMR_SETMITERLIMIT:	strcpy(ObjType,"!SETMITERLIMIT"); break;	// 0x0000003A
      case EMR_BEGINPATH:	strcpy(ObjType,"!BEGINPATH"); break;	// 0x0000003B
      case EMR_ENDPATH:		strcpy(ObjType,"!ENDPATH"); break;	// 0x0000003C
      case EMR_CLOSEFIGURE:	strcpy(ObjType,"!CLOSEFIGURE"); break;	// 0x0000003D
      case EMR_FILLPATH:	strcpy(ObjType,"!FILLPATH"); break;	// 0x0000003E
      case EMR_STROKEANDFILLPATH:strcpy(ObjType,"!STROKEANDFILLPATH"); break;	// 0x0000003F
      case EMR_STROKEPATH:	strcpy(ObjType,"!STROKEPATH"); break;	// 0x00000040
      case EMR_FLATTENPATH:	strcpy(ObjType,"!FLATTENPATH"); break;	// 0x00000041
      case EMR_WIDENPATH:	strcpy(ObjType,"!WIDENPATH"); break;	// 0x00000042
      case EMR_SELECTCLIPPATH:	strcpy(ObjType,"!SELECTCLIPPATH"); break;	// 0x00000043
      case EMR_ABORTPATH:	strcpy(ObjType,"!ABORTPATH"); break;	// 0x00000044
      case EMR_COMMENT:		strcpy(ObjType,"!COMMENT"); break;	// 0x00000046
      case EMR_FILLRGN:		strcpy(ObjType,"!FILLRGN"); break;	// 0x00000047
      case EMR_FRAMERGN:	strcpy(ObjType,"!FRAMERGN"); break;	// 0x00000048
      case EMR_INVERTRGN:	strcpy(ObjType,"!INVERTRGN"); break;	// 0x00000049
      case EMR_PAINTRGN:	strcpy(ObjType,"!PAINTRGN"); break;	// 0x0000004A
      case EMR_EXTSELECTCLIPRGN:strcpy(ObjType,"!EXTSELECTCLIPRGN"); break;	// 0x0000004B
      case EMR_BITBLT:		strcpy(ObjType,"!BITBLT"); break;	// 0x0000004C
      case EMR_STRETCHBLT:	strcpy(ObjType,"!STRETCHBLT"); break;	// 0x0000004D
      case EMR_MASKBLT:		strcpy(ObjType,"!MASKBLT"); break;	// 0x0000004E
      case EMR_PLGBLT:		strcpy(ObjType,"!PLGBLT"); break;	// 0x0000004F
      case EMR_SETDIBITSTODEVICE:strcpy(ObjType,"!SETDIBITSTODEVICE"); break;	// 0x00000050
      case EMR_STRETCHDIBITS:	parse_StretchDIBits(VectList); break;	// 0x00000051
      case EMR_EXTCREATEFONTINDIRECTW: parse_ExtCreateFontIndirectW(); break;	// 0x00000052
      case EMR_EXTTEXTOUTA:	strcpy(ObjType,"!EXTTEXTOUTA"); PleaseReport("EXTTEXTOUTA"); break;	// 0x00000053
      case EMR_EXTTEXTOUTW:	parse_ExtTextOutW(VectList); break;	// 0x00000054
      case EMR_POLYBEZIER16:    parse_PolyBezier16(VectList); break;	// 0x00000055
      case EMR_POLYGON16:	parse_Polygon16(VectList); break;	// 0x00000056
      case EMR_POLYLINE16:	parse_PolyLine16(VectList); break;	// 0x00000057
      case EMR_POLYBEZIERTO16: strcpy(ObjType,"!POLYBEZIERTO16"); PleaseReport("POLYBEZIERTO16"); break;	// 0x00000058
      case EMR_POLYLINETO16: strcpy(ObjType,"!POLYLINETO16"); PleaseReport("POLYLINETO16"); break;	// 0x00000059
      case EMR_POLYPOLYLINE16:	parse_PolyPolyLine16(VectList); break;	// 0x0000005A
      case EMR_POLYPOLYGON16:	parse_PolyPolygon16(VectList); break;	// 0x0000005B
      case EMR_POLYDRAW16: strcpy(ObjType,"!POLYDRAW16"); break;	// 0x0000005C
      case EMR_CREATEMONOBRUSH: strcpy(ObjType,"!CREATEMONOBRUSH"); break;	// 0x0000005D
      case EMR_CREATEDIBPATTERNBRUSHPT: strcpy(ObjType,"!CREATEDIBPATTERNBRUSHPT"); break;	// 0x0000005E
      case EMR_EXTCREATEPEN:	parse_ExtCreatePen(); break;	// 0x0000005F
      case EMR_POLYTEXTOUTA:	strcpy(ObjType,"!POLYTEXTOUTA"); PleaseReport("POLYTEXTOUTA"); break;	// 0x00000060
      case EMR_POLYTEXTOUTW:	strcpy(ObjType,"!POLYTEXTOUTW"); PleaseReport("POLYTEXTOUTW"); break;	// 0x00000061
      case EMR_SETICMMODE:	strcpy(ObjType,"!SETICMMODE"); break;	// 0x00000062
      case EMR_CREATECOLORSPACE: strcpy(ObjType,"!CREATECOLORSPACE"); break;	// 0x00000063
      case EMR_SETCOLORSPACE:	strcpy(ObjType,"!SETCOLORSPACE"); break;	// 0x00000064
      case EMR_DELETECOLORSPACE: strcpy(ObjType,"!DELETECOLORSPACE"); break;	// 0x00000065
      case EMR_GLSRECORD: strcpy(ObjType,"!GLSRECORD"); break;	// 0x00000066
      case EMR_GLSBOUNDEDRECORD: strcpy(ObjType,"!GLSBOUNDEDRECORD"); break;	// 0x00000067
      case EMR_PIXELFORMAT:	strcpy(ObjType,"!PIXELFORMAT"); break;	// 0x00000068
      case EMR_DRAWESCAPE:	strcpy(ObjType,"!DRAWESCAPE"); break;	// 0x00000069
      case EMR_EXTESCAPE:	strcpy(ObjType,"!EXTESCAPE"); break;	// 0x0000006A
      case EMR_SMALLTEXTOUT:	strcpy(ObjType,"!SMALLTEXTOUT"); break;	// 0x0000006C
      case EMR_FORCEUFIMAPPING: strcpy(ObjType,"!FORCEUFIMAPPING"); break;	// 0x0000006D
      case EMR_NAMEDESCAPE:	strcpy(ObjType,"!NAMEDESCAPE"); break;	// 0x0000006E
      case EMR_COLORCORRECTPALETTE: strcpy(ObjType,"!COLORCORRECTPALETTE"); break;	// 0x0000006F
      case EMR_SETICMPROFILEA:	strcpy(ObjType,"!SETICMPROFILEA"); break;	// 0x00000070
      case EMR_SETICMPROFILEW:	strcpy(ObjType,"!SETICMPROFILEW"); break;	// 0x00000071
      case EMR_ALPHABLEND:	strcpy(ObjType,"!ALPHABLEND"); break;	// 0x00000072
      case EMR_SETLAYOUT:	strcpy(ObjType,"!SETLAYOUT"); break;	// 0x00000073
      case EMR_TRANSPARENTBLT:	strcpy(ObjType,"!TRANSPARENTBLT"); break;	// 0x00000074
      case EMR_GRADIENTFILL:	strcpy(ObjType,"!GRADIENTFILL"); break;	// 0x00000076
      case EMR_SETLINKEDUFIS:	strcpy(ObjType,"!SETLINKEDUFIS"); break;	// 0x00000077
      case EMR_SETTEXTJUSTIFICATION: strcpy(ObjType,"!SETTEXTJUSTIFICATION"); break;	// 0x00000078
      case EMR_COLORMATCHTOTARGETW: strcpy(ObjType,"!COLORMATCHTOTARGETW"); break;	// 0x00000079
      case EMR_CREATECOLORSPACEW: strcpy(ObjType,"!CREATECOLORSPACEW"); break;	// 0x0000007A
      default: sprintf(ObjType,"!Unknown#%Xh", (unsigned)EmfRec.Type);
    }
    if(ObjType[0]=='!') UnknownObjects++;
    
    if(log!=NULL)
    {   /**/
      fprintf(log, _("\n%*s{EMF func:%3Xh; size:%4lu; pos:%lXh}"),
		recursion*2,"",EmfRec.Type, (long)EmfRec.Size, (long)EmfRec.ParamFilePos);
      if(*ObjType!=0) fprintf(log," %s",ObjType);
    }

    ActualPos = EmfRec.ParamFilePos + EmfRec.Size;
    fseek(wpd, ActualPos, SEEK_SET);    
  }

  const float Scale = GetScale2PSU((TMapMode)MapMode) * 25.4f / 71.0f;	// convert PSu to WPGu (quite bad).
  vFlip flipTrx(bbx.MinY, bbx.MaxY);

  Image *Img2 = &Img;
    while(Img2!=NULL)
    {      
      if(Img2->Raster!=NULL)
      {        
        if(Img2->dy < 0)
        {
          Img2->dy = -Img2->dy;
          //Img2->y += Img2->dy;                    
        }
        Flip2D(Img2->Raster);
        if(Img2->dx<0)
        {        
         Img2->x += Img2->dx;
         Img2->dx = -Img2->dx;
         Flip1D(Img2->Raster);
        }

        if(YExtent>=0)
            flipTrx.ApplyTransform(Img2->x, Img2->y);
      }
      //if(Img2->Vector)
      //   Img2->Vector.Transform(flipTx);
      Img2->x *= Scale;
      Img2->y *= Scale;
      Img2->dx *= Scale;
      Img2->dy *= -Scale;      
      Img2 = Img2->Next;       
    }

  if(YExtent>=0)
      VectList.Transform(flipTrx);

  if(PSData.length() > 0)
      VectList.AddObject(new PsBlob(PSData.ExtractString()));  

  if(VectList.VectorObjects>0 && Img.VecImage==NULL)
  {    
    Img.AttachVecImg(new VectorImage(VectList,PSS));

    if(Img.dx!=0 && Img.dy!=0 && Img.Raster!=NULL)
      {
      if(Img.VecImage!=NULL)	// Move raster data to different image frame.
        {
        Img2 = &Img;
        while(Img2->Next!=NULL)
          Img2 = Img2->Next;
        Img2->Next = new Image();
        Img2 = Img2->Next;

        Img2->x =  bbx.MinX * Scale;
        Img2->y =  bbx.MinY * Scale;
        Img2->dx = (bbx.MaxX - bbx.MinX) * Scale;
        Img2->dy = (bbx.MaxY - bbx.MinY) * Scale;
        Img2->VecImage = Img.VecImage; Img.VecImage=NULL;
        }
      }
    else	// Use whole frame as bounding box.
      {      
      Img.x =  bbx.MinX * Scale;
      Img.y =  bbx.MinY * Scale;
      Img.dx = (bbx.MaxX - bbx.MinX) * Scale;
      Img.dy = (bbx.MaxY - bbx.MinY) * Scale;  
      }        
  }

  if(!NoConvertImage && (Img.Raster!=NULL || Img.VecImage!=NULL))
    {
    for(Image *pImg=&Img; pImg!=NULL; pImg=pImg->Next)
      if(pImg->Raster!=NULL)
        ReducePalette(pImg,256);

    string NewFilename = MergePaths(OutputDir,RelativeFigDir);
    string wpd_cut = CutFileName(wpd_filename);
    if(recursion==0 && length(wpd_cut)>0)
      NewFilename += wpd_cut + ".eps";
    else
      NewFilename += GetFullFileName(GetSomeImgName(".eps"));
    if(SavePictureEPS(NewFilename(),Img)<0)
	{
        if(err != NULL)
	  {
	  perc.Hide();
	  fprintf(err, _("\nError: Cannot save file: \"%s\"!"), NewFilename());
	  }
	return 0;
        }

    NewFilename = CutFileName(NewFilename); 	//New Filename only

    PutImageIncluder(NewFilename());

    InputPS |= 1;		//mark style as used
    Finalise_Conversion(this);
    RetVal++;
    }

  OutCodePage = CodePageBk;
  return(RetVal);
}



/*--------------------End of PASS1_WMF--------------------*/
