Click here to Skip to main content
15,887,596 members
Articles / Programming Languages / C#
Article

Gios PDF .NET library

Rate me:
Please Sign up or sign in to vote.
4.89/5 (157 votes)
18 Apr 2005LGPL32 min read 2.2M   13.1K   558   358
A .NET library for generating impressive PDF reports.

Image 1

Introduction

This article describes how to use the Gios Pdf.NET open source library, a complete object-oriented .NET library for generating impressive reports with few lines of code.

Background

I started writing this library because I really couldn’t find a good C# library for exporting my reports. When you open a PDF document with Notepad to find out if it’s possible to edit it… well… you change your mind!

...But if you download the PDF format specifications from Adobe’s official site… you can demystify everything!

In this article, it’s not my intention to teach “how to write a clone of my library” but “how to use it” … By the way, if you want to try to write your own library… try it: it’s not impossible and it's a good (and difficult!) exercise!

Using the code

Start instantiating the document with a new PdfDocument object. Remember to set the document format. In this case we specify width and height in centimeters. Document format is provided by the PdfDocumentFormat class:

C#
PdfDocument myPdfDocument = 
  new PdfDocument(PdfDocumentFormat.InCentimeters(21,29.7));

Now we create a table of 100 lines, 6 columns and 4 points of padding:

C#
PdfTable myPdfTable = 
  myPdfDocument.NewTable(new Font("Verdana",12),200,6,4);

Importing data from the datatables... (also column names for the headers!):

C#
myPdfTable.ImportDataTable(Table);

Set the format for correct date-time representation:

C#
myPdfTable.Columns[2].SetContentFormat("{0:dd/MM/yyyy}");

Now we set our Graphic Design: Colors and Borders...

C#
myPdfTable.HeadersRow.SetColors(Color.White,Color.Navy);
myPdfTable.SetColors(Color.Black,Color.White,Color.Gainsboro);
myPdfTable.SetBorders(Color.Black,1,BorderType.CompleteGrid);

With just one method, we can set the proportional width of the columns. It's a "percentage like" assignment, but the sum can be different from 100.

C#
myPdfTable.SetColumnsWidth(new int[]{5,25,16,20,20,15});

You can also set colors for a range of cells, in this case, a row:

C#
myPdfTable.Rows[7].SetColors(Color.Black,Color.LightGreen);

Now we set some alignment... for the whole table and then, for a column:

C#
myPdfTable.SetContentAlignment(ContentAlignment.MiddleCenter);                      
myPdfTable.Columns[1].SetContentAlignment(ContentAlignment.MiddleLeft);

This is the most important feature of the library: each page generated by the table can be managed in all the details:

C#
while (!myPdfTable.AllTablePagesCreated)
{
    // we create a new page to put the generation of the new TablePage:

    PdfPage newPdfPage=myPdfDocument.NewPage();
    PdfTablePage newPdfTablePage = 
      myPdfTable.CreateTablePage(new PdfArea(myPdfDocument,48,120,500,670));

    // we also put a Label 
 
    PdfTextArea pta=new PdfTextArea(new Font("Verdana",26, FontStyle.Bold), 
      Color.Red, new PdfArea(myPdfDocument,0,20,595,120), 
      ContentAlignment.MiddleCenter,"Contact List");

    // nice thing: we can put all the objects
    // in the following lines, so we can have
    // a great control of layer sequence... 

    newPdfPage.Add(newPdfTablePage);
    newPdfPage.Add(pta);

    // Now we create a loop for serching for people born in 1968. If we find
    // one, we will draw a circle over
    // the birthday cell. This is possible using the
    // the CellArea, that is the Area occupied by a rasterized Cell.
 
    for (int index=newPdfTablePage.FirstRow;index<=newPdfTablePage.LastRow;index++)
       if (((DateTime)myPdfTable.Rows[index][2].Content).Year==1968)
       {
          PdfCircle pc=newPdfTablePage.CellArea(index,2).InnerCircle(Color.Blue,2);
          pc.StrokeWidth=3.5;
          newPdfPage.Add(pc);
       }

    // we save each generated page before start rendering the next.
    newPdfPage.SaveToDocument();

}

At last... remember to save the document!

C#
myPdfDocument.SaveToFile("Example1.pdf");

And this is the result:

Image 2

Remember, you can also output the PDF to a generic Stream. These are the lines for a Web Response:

C#
Response.ClearHeaders();
Response.AppendHeader("Content-disposition", 
   string.Format("attachment;filename={0}","Report.pdf"));
Response.ContentType="application/pdf"; 
myPdfDocument.SaveToStream(Response.OutputStream);
Response.End();

History

  • April 18, 2005 - Initial release.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Web Developer
Italy Italy
Freelance software ASPNET / C# Software Developer

I live in Torino, Italy

my homepage is: http://www.paologios.com

Comments and Discussions

 
AnswerRe: visual studio version? Pin
Paolo Gios25-May-05 1:29
Paolo Gios25-May-05 1:29 
AnswerRe: visual studio version? Pin
Tim McFadden25-May-05 5:12
Tim McFadden25-May-05 5:12 
GeneralTable Headers Pin
sporting25-May-05 0:06
sporting25-May-05 0:06 
GeneralRe: Table Headers Pin
Paolo Gios25-May-05 5:47
Paolo Gios25-May-05 5:47 
Generalwmf Pin
killminusnine24-May-05 0:46
killminusnine24-May-05 0:46 
GeneralRe: wmf Pin
infal10-Jun-05 3:21
infal10-Jun-05 3:21 
GeneralRe: wmf Pin
killminusnine12-Jun-05 22:33
killminusnine12-Jun-05 22:33 
GeneralRe: wmf Pin
infal14-Jun-05 1:53
infal14-Jun-05 1:53 
First of all you can get "Window Metafile (wmf) Reference" from
http://www.skynet.ie/~caolan/publink/libwmf/libwmf/doc/support.html[^]

The enumeration procedure in C++ follows:

BOOL WINAPI UserEnumMetaFile16( HDC hdc, HMETAFILE& hmf,<br />
			      MFENUMPROC lpEnumFunc, LPARAM lpData )<br />
{<br />
    UINT mfLength=0;<br />
    METAHEADER *mh = UserGetMetaHeader16(hmf, mfLength);<br />
    METARECORD *mr;<br />
    HANDLETABLE *ht;<br />
    HGLOBAL hHT;<br />
    unsigned int offset = 0;<br />
    BOOL result = true;<br />
    // BOOL loaded = false;<br />
<br />
    if(!mh) return false;<br />
    if(mh->mtType == METAFILE_DISK) <br />
    { <br />
        UserReleaseMetaHeader16(hmf);<br />
        /* Create a memory-based copy */<br />
        // if not created<br />
        return FALSE;<br />
        // else loaded = true<br />
    }<br />
<br />
    /*<br />
    // save the current pen, brush and font (i.e. if you wish to play metarecords with WINAPI)<br />
    HPEN hPen = GetCurrentObject(hdc, OBJ_PEN);<br />
    HBRUSH hBrush = GetCurrentObject(hdc, OBJ_BRUSH);<br />
    HFONT hFont = GetCurrentObject(hdc, OBJ_FONT);<br />
    */<br />
<br />
    /*<br />
    // create the handle table if enumeration procedure plays metarecords with WINAPI <br />
<br />
    hHT = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,<br />
		     sizeof(HANDLETABLE) * mh->mtNoObjects);<br />
    ht = (HANDLETABLE*)GlobalLock(hHT);<br />
    */<br />
<br />
    offset = mh->mtHeaderSize * 2;<br />
<br />
    // loop through metafile records <br />
    while (offset < (mh->mtSize * 2))<br />
    {<br />
      DWORD ret;<br />
      mr = (METARECORD *)((char *)mh + offset);<br />
      ret = lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData );<br />
      if (!(ret))<br />
	    {<br />
	    result = FALSE;<br />
	    break;<br />
	}<br />
<br />
    <br />
	offset += (mr->rdSize * 2);<br />
    }<br />
<br />
    /*<br />
    // restore GDI-Objects if you need<br />
    SelectObject(hdc, hBrush);<br />
    SelectObject(hdc, hPen);<br />
    SelectObject(hdc, hFont);<br />
    */<br />
<br />
    /*<br />
    // free objects in handle table if enumeration procedure plays metarecords with WINAPI <br />
    for(i = 0; i < mh->mtNoObjects; i++)<br />
      if(*(ht->objectHandle + i) != 0)<br />
        DeleteObject( (HGDIOBJ)(ULONG_PTR)(*(ht->objectHandle + i) ));<br />
    */<br />
<br />
    // free handle table (if it was locked, it will be unlocked by this function too)<br />
    GlobalFree(hHT);<br />
    /*<br />
    if(loaded) free memory based copy        <br />
    */<br />
<br />
    /*<br />
    // here you can create metafile back from changed records<br />
    hmf = SetMetaFileBitsEx(mfLength, (const BYTE*)mh);<br />
    */<br />
    UserReleaseMetaHeader16(hmf);<br />
    return result;<br />
}


Next procedure returns ptr to METAHEADER associated with HMETAFILE

static METAHEADER *UserGetMetaHeader16( HMETAFILE hmf , UINT& mfl)<br />
{<br />
    unsigned int needs = GetMetaFileBitsEx(hmf ,0, 0);<br />
    HGLOBAL bits = GlobalAlloc(GPTR, needs);<br />
    mfl = GetMetaFileBitsEx(hmf ,needs, bits);<br />
    LPVOID lp = GlobalLock(bits);<br />
    return (METAHEADER*)(lp);<br />
}


And the next one releases memory beginning at METAHEADER associated with HMETAFILE

static BOOL UserReleaseMetaHeader16( HMETAFILE hmf )<br />
{<br />
    return (GlobalFree(hmf) == 0);<br />
}


At least here the unedited code I have used to rotate metafile in place or to
create a new rotated metafile


<br />
#define COPYRECORDS 0<br />
static const double M_PI=3.1415926535897932384626433832795;<br />
int CALLBACK EnumMetafileProc( HDC hDC, HANDLETABLE *lpHTable, METARECORD *lpMFR, int nObj, LPARAM lpData )<br />
{<br />
	HWND	hWndList = ((PWMFENUMUDATA)lpData)->hWnd;<br />
	HDC	    dstDC = ((PWMFENUMUDATA)lpData)->mHdcDest;<br />
	//ENHMETAHEADER* emHDR= ((PWMFENUMUDATA)lpData)->mHdr;<br />
	RECTL* Bounds= ((PWMFENUMUDATA)lpData)->Bounds;<br />
	TCHAR	szBuffer[200];<br />
	// LPTSTR	pString;<br />
	DWORD	i;<br />
	SIZE	size;<br />
	HDC		hTempDC;<br />
	HFONT	hFont, hOldFont;<br />
	TEXTMETRIC	tm;<br />
	int		nOldExtent, nNewExtent;<br />
	DWORD paramSize;<br />
	char paramSizeAsStr[200];<br />
	const char* FuncName;<br />
    <br />
#if !COPYRECORDS<br />
    PMETARECORD MR=lpMFR;<br />
#else<br />
    HANDLE hMem = GlobalAlloc(GHND, lpMFR->rdSize*sizeof(WORD));<br />
    PMETARECORD MR = (PMETARECORD)GlobalLock(hMem);<br />
    memcpy(MR, lpMFR, lpMFR->rdSize*sizeof(WORD));<br />
#endif<br />
<br />
    static bool DefaultTextAlign=true;<br />
<br />
<br />
<br />
	// If it's a known record type, get the string from the global string array<br />
	FuncName=WMFRecordName(MR->rdFunction);<br />
	if( FuncName!=0 )<br />
		// wsprintf( szBuffer, "%010d Words : %s", MR->rdSize, FuncName );<br />
	else<br />
		// wsprintf( szBuffer, "%010d Words : %s", MR->rdSize, "Unknown" );<br />
<br />
	// Allocate a string big enough for the record text and the parameter bytes<br />
	// pString = (LPTSTR)malloc( lstrlen(szBuffer) + (MR->rdSize * 12) +100);<br />
	// Begin with the record string<br />
	// lstrcpy( pString, szBuffer );<br />
	// Calculate the size of params in WORD's<br />
	paramSize=(MR->rdSize)-3;<br />
	// itoa(paramSize,paramSizeAsStr, 10);<br />
	// strcat( pString, " >> Dword Params:" );<br />
	// strcat( pString, paramSizeAsStr );<br />
	// strcat( pString, " >>" );<br />
    bool output=true;<br />
	switch (MR->rdFunction)<br />
	{<br />
        <br />
		case WMF_DIBBITBLT:<br />
		{<br />
            short int SrcY = ((short int*)MR->rdParm)[2];<br />
            short int SrcX = ((short int*)MR->rdParm)[3];<br />
			TransformPoint(Bounds, (short int&)MR->rdParm[3], (short int&)MR->rdParm[2]);<br />
            short int DstHeight = ((short int*)MR->rdParm)[4];<br />
            bool hasDIB=(DstHeight==0);<br />
            int destParams=4;<br />
            if (!hasDIB) DstHeight = ((short int*)MR->rdParm)[5];<br />
            else destParams++;<br />
            short int DstWidth = ((short int*)MR->rdParm)[destParams+1];<br />
            short int DstY = ((short int*)MR->rdParm)[destParams+2];<br />
            short int DstX = ((short int*)MR->rdParm)[destParams+3];<br />
			TransformRectangleParams(Bounds, true, ((short int*)MR->rdParm)[destParams+3], ((short int*)MR->rdParm)[destParams+2], ((short int*)MR->rdParm)[destParams+1], ((short int*)MR->rdParm)[destParams]);<br />
			// wsprintf( szBuffer, " BitBlt (srcY=%hi, srcX=%hi, dstHeight=%hi, dstWidth=%hi, dstY=%hi, dstX=%hi)", SrcY, SrcX, DstHeight, DstWidth, DstY, DstX);<br />
            break;<br />
        }<br />
		case WMF_SCALEVIEWPORTEXT:<br />
		{<br />
            SIZE s;<br />
            GetViewportExtEx(hDC, &s);<br />
            short int yDenom = ((short int*)MR->rdParm)[0];<br />
            short int yNum   = ((short int*)MR->rdParm)[1];<br />
            short int xDenom = ((short int*)MR->rdParm)[2];<br />
            short int xNum   = ((short int*)MR->rdParm)[3];<br />
			// wsprintf( szBuffer, " ScaleViewportExtEx (yDenom=%hi, yNum=%hi, xDenom=%hi, xNum=%hi)", yDenom, yNum, xDenom, xNum);<br />
            break;<br />
        }<br />
		case WMF_SETMAPMODE:<br />
		{<br />
			short int MapMode = ((short int*)MR->rdParm)[0];<br />
			//short int MapMode2 = (short int&)(MR->rdParm[0]);<br />
            switch (MapMode)<br />
            {<br />
            case MM_ANISOTROPIC: <br />
              // wsprintf( szBuffer, " setmapmode MM_ANISOTROPIC" );<br />
              break;<br />
            case MM_ISOTROPIC: <br />
              // wsprintf( szBuffer, " setmapmode MM_ISOTROPIC" );<br />
              break;<br />
            case MM_HIENGLISH: <br />
              // wsprintf( szBuffer, " setmapmode MM_HIENGLISH" );<br />
              break;<br />
            case MM_LOENGLISH: <br />
              // wsprintf( szBuffer, " setmapmode MM_LOENGLISH" );<br />
              break;<br />
            case MM_HIMETRIC: <br />
              // wsprintf( szBuffer, " setmapmode MM_HIMETRIC" );<br />
              break;<br />
            case MM_LOMETRIC: <br />
              // wsprintf( szBuffer, " setmapmode MM_LOMETRIC" );<br />
              break;<br />
            case MM_TEXT: <br />
              // wsprintf( szBuffer, " setmapmode MM_TEXT" );<br />
              break;<br />
            case MM_TWIPS: <br />
              // wsprintf( szBuffer, " setmapmode MM_TWIPS" );<br />
              break;<br />
            }<br />
			((short int*)MR->rdParm)[0]=MM_TEXT;<br />
			break;<br />
		}<br />
		case WMF_MOVETO:<br />
		{<br />
            // output = false;<br />
			TransformPoint(Bounds, (short int&)MR->rdParm[1], (short int&)MR->rdParm[0]);<br />
            short int y = MR->rdParm[0];<br />
            short int x = MR->rdParm[1];<br />
			// wsprintf( szBuffer, " moveto (x=%hi, y=%hi)", x, y );<br />
			break;<br />
		}<br />
		case WMF_LINETO:<br />
		{<br />
            // output = false;<br />
			TransformPoint(Bounds, (short int&)MR->rdParm[1], (short int&)MR->rdParm[0]);<br />
            short int y = MR->rdParm[0];<br />
            short int x = MR->rdParm[1];<br />
			// wsprintf( szBuffer, " lineto (x=%hi, y=%hi)", x, y );<br />
			break;<br />
		}<br />
        case WMF_RECTANGLE:<br />
		{<br />
            // output = false;<br />
			// TransformRectangle(Bounds, true, (short int&)MR->rdParm[3], (short int&)MR->rdParm[2], (short int&)MR->rdParm[1], (short int&)MR->rdParm[0]);<br />
			short int b = MR->rdParm[0];<br />
			short int r = MR->rdParm[1];<br />
			short int t = MR->rdParm[2];<br />
			short int l = MR->rdParm[3];<br />
			TransformRectangle(Bounds, true, ((short int*)MR->rdParm)[3], ((short int*)MR->rdParm)[2], ((short int*)MR->rdParm)[1], ((short int*)MR->rdParm)[0]);<br />
            /*<br />
			TransformPoint(Bounds, (short int&)MR->rdParm[3], (short int&)MR->rdParm[2]);<br />
			TransformPoint(Bounds, (short int&)MR->rdParm[1], (short int&)MR->rdParm[0]);<br />
            */<br />
			/*short int*/ b = MR->rdParm[0];<br />
			/*short int*/ r = MR->rdParm[1];<br />
			/*short int*/ t = MR->rdParm[2];<br />
			/*short int*/ l = MR->rdParm[3];<br />
			/// <br />
			/// TransformPoint(emHDR, (short int&)MR->rdParm[3], (short int&)MR->rdParm[2]);<br />
			/// TransformPoint(emHDR, (short int&)MR->rdParm[1], (short int&)MR->rdParm[0]);<br />
			/// <br />
			// wsprintf( szBuffer, " rectangle (l=%hi, t=%hi, r=%hi, b=%hi)", l, t, r, b );<br />
			break;<br />
<br />
		}<br />
        case WMF_ELLIPSE:<br />
		{<br />
			short int b = MR->rdParm[0];<br />
			short int r = MR->rdParm[1];<br />
			short int t = MR->rdParm[2];<br />
			short int l = MR->rdParm[3];<br />
			TransformRectangle(Bounds, true, ((short int*)MR->rdParm)[3], ((short int*)MR->rdParm)[2], ((short int*)MR->rdParm)[1], ((short int*)MR->rdParm)[0]);<br />
			// wsprintf( szBuffer, " ellipse (l=%hi, t=%hi, r=%hi, b=%hi)", l, t, r, b );<br />
			break;<br />
		}<br />
        case WMF_POLYGON:<br />
        case WMF_POLYLINE:<br />
		{<br />
			short int len = MR->rdParm[0];<br />
            for (int k = 0; k < len; ++k) {<br />
			  TransformPoint(Bounds, ((short int*)MR->rdParm)[k*2+1], ((short int*)MR->rdParm)[k*2+2]);<br />
            };<br />
			// wsprintf( szBuffer, " polygon/polyline");<br />
			break;<br />
		}<br />
        <br />
        case WMF_SETTEXTALIGN:<br />
        {<br />
            DefaultTextAlign = false;<br />
            // The low-order byte contains the horizontal setting<br />
            // The high-order byte contains the vertical setting<br />
            // TA_CENTER ==> weiter nach oben<br />
           // ((short int*)(MR->rdParm))[0]=(TA_BOTTOM | TA_RIGHT);<br />
            short int Align=((short int*)MR->rdParm)[0];<br />
            //<br />
            bool Bottom = ((Align & TA_BOTTOM) == TA_BOTTOM);<br />
            bool Baseline = ((Align & TA_BASELINE) == TA_BASELINE);<br />
            bool Top = !(Bottom || Baseline);<br />
            //<br />
            bool Right = ((Align & TA_RIGHT) == TA_RIGHT);<br />
            bool Center = ((Align & TA_CENTER) == TA_CENTER);<br />
            bool Left = !(Right || Center);<br />
<br />
            bool NoUpdateCP = ((Align & TA_NOUPDATECP) == TA_NOUPDATECP);<br />
            bool UpdateCP = ((Align & TA_UPDATECP) == TA_UPDATECP);<br />
            /*<br />
            ((short int*)(MR->rdParm))[0]=(TA_BOTTOM | TA_RIGHT);<br />
            */<br />
            //((short int*)(MR->rdParm))[0]=(TA_TOP | TA_RIGHT);<br />
            //SetTextAlign<br />
            break;<br />
        }<br />
        <br />
        /*<br />
        case WMF_TEXTOUT:<br />
        {<br />
            short int Align=MR->rdParm[0];<br />
            MR->rdParm[0]=TA_BOTTOM | TA_RIGHT;<br />
            break;<br />
        }<br />
        */<br />
            <br />
        case WMF_EXTTEXTOUT:<br />
        {<br />
            if (DefaultTextAlign)<br />
            {<br />
                // TA_RIGHT "Text goes down"<br />
                // TA_LEFT | TA_TOP "what we need"<br />
                METARECORD TextAlign;<br />
                TextAlign.rdSize=4;<br />
                TextAlign.rdFunction=WMF_SETTEXTALIGN;<br />
                TextAlign.rdParm[0]=TA_LEFT | TA_TOP;<br />
                PlayMetaFileRecord(dstDC, lpHTable, &TextAlign, nObj);<br />
                DefaultTextAlign = false;<br />
            }<br />
            //output=false;<br />
            //break;<br />
            short int flag = ((short int*)(MR->rdParm))[3];<br />
			TransformPoint(Bounds, ((short int*)(MR->rdParm))[1], ((short int*)(MR->rdParm))[0]);<br />
//			TransformPoint(Bounds, ((short int*)(MR->rdParm))[0], ((short int*)(MR->rdParm))[1]);<br />
           // ((short int*)(MR->rdParm))[1]+=140; // + "clips right"<br />
           // ((short int*)(MR->rdParm))[0]+=50; // + "down under"<br />
//			TransformPoint(Bounds, (short int&)MR->rdParm[1], (short int&)MR->rdParm[0]);<br />
            //short int count = MR->rdParm[2];<br />
            //short int flag = MR->rdParm[3];<br />
            short int len = ((short int*)(MR->rdParm))[2];<br />
            int next=4;<br />
            short int left, top, right, bottom;<br />
            if ((flag & (ETO_CLIPPED | ETO_OPAQUE)) != 0) {<br />
                ///<br />
                ///        x1 = meta.readShort();<br />
                ///        y1 = meta.readShort();<br />
                ///        x2 = meta.readShort();<br />
                ///        y2 = meta.readShort();<br />
                ///        <br />
//                        TransformRectangle(Bounds, (short int&)MR->rdParm[4], (short int&)MR->rdParm[5], (short int&)MR->rdParm[6], (short int&)MR->rdParm[7]);<br />
//                        TransformRectangle(Bounds, false, ((short int*)(MR->rdParm))[7], ((short int*)(MR->rdParm))[6], ((short int*)(MR->rdParm))[5], ((short int*)(MR->rdParm))[4]);<br />
                        <br />
                        left= ((short int*)(MR->rdParm))[4];<br />
                        top = ((short int*)(MR->rdParm))[5];<br />
                        right = ((short int*)(MR->rdParm))[6];<br />
                        bottom = ((short int*)(MR->rdParm))[7];<br />
                        TransformRectangle(Bounds, false, ((short int*)(MR->rdParm))[4],<br />
                                                          ((short int*)(MR->rdParm))[5], <br />
                                                          ((short int*)(MR->rdParm))[6], <br />
                                                          ((short int*)(MR->rdParm))[7]);<br />
                        /*<br />
                        left= ((short int*)(MR->rdParm))[4];<br />
                        top = ((short int*)(MR->rdParm))[5],;<br />
                        right = ((short int*)(MR->rdParm))[6];<br />
                        bottom = ((short int*)(MR->rdParm))[7]);<br />
                        */<br />
                        next=8;                                                         <br />
            };<br />
            const char* str=(const char*)&((short int*)(MR->rdParm))[next];<br />
            char* str_copy=new char[len+1];<br />
            strncpy(str_copy, str, len);<br />
            str_copy[len]=0;<br />
			if (next==4)<br />
               // wsprintf( szBuffer, " exttextout (length=%hi, string=\"%s\")", len, str_copy);<br />
            else <br />
                //wsprintf( szBuffer, " exttextout (length=%hi, string=\"%s\", left=%hi, top=%hi, right=%hi, bottom=%hi)", len, str_copy, left, top, right, bottom);<br />
            delete [] str_copy;<br />
            break;<br />
        }<br />
        <br />
        case WMF_CREATEFONTINDIRECT:<br />
        {<br />
                short int height = abs((short int)MR->rdParm[0]);<br />
			    //meta.skip(2);<br />
                /*<br />
			    short int esc = (float)((short int)MR->rdParm[2] / 1800.0 * M_PI);<br />
			    short int orn = (float)((short int)MR->rdParm[3] / 1800.0 * M_PI);<br />
                */<br />
			    short int esc = ((short int*)(MR->rdParm))[2];<br />
			    short int orn = ((short int*)(MR->rdParm))[3];<br />
			    // meta.skip(2);<br />
			    short int bold = ((short int*)(MR->rdParm))[4];// >= BOLDTHRESHOLD ? MARKER_BOLD : 0);<br />
			    short int italic = ((unsigned char*)(MR->rdParm))[10];// != 0 ? MARKER_ITALIC : 0);<br />
			    short int underline = ((unsigned char*)(MR->rdParm)[11] != 0);<br />
			    short int strikeout = ((unsigned char*)(MR->rdParm)[12] != 0);<br />
			    short int charset = ((unsigned char*)(MR->rdParm))[13];<br />
			    // meta.skip(3); ==> goto byte 17<br />
                short int pitchAndFamily = ((unsigned char*)(MR->rdParm))[17];<br />
<br />
			    // wsprintf( szBuffer, " createfontindirect (height=%hi, esc=%hi, bold=%hi, italic=%hi)", height, esc, bold, italic );<br />
			    lstrcat( pString, szBuffer );<br />
<br />
                esc += 900;<br />
			    orn += 900;<br />
                /*<br />
			    ((short int*)(MR->rdParm))[2] = (short int)((float)esc * 1800.0 / M_PI);<br />
			    ((short int*)(MR->rdParm))[3] = (short int)((float)orn * 1800.0 / M_PI);<br />
                */<br />
			    ((short int*)(MR->rdParm))[2] = esc;<br />
			    ((short int*)(MR->rdParm))[3] = orn;<br />
                // output=false;<br />
                break;<br />
        }<br />
		default:<br />
	};<br />
    int r=0;<br />
    {<br />
        if (output)<br />
          r=PlayMetaFileRecord(dstDC, lpHTable, MR, nObj);<br />
    }<br />
	ReleaseDC( NULL, hTempDC );<br />
<br />
#if COPYRECORDS<br />
    // Unlock and free<br />
//    memcpy(lpMFR, MR, lpMFR->rdSize*sizeof(WORD));<br />
    GlobalUnlock(hMem);<br />
    GlobalFree(hMem);<br />
#endif<br />
<br />
	return 1;<br />
}<br />


This code gives you also information about font properties not described in above reference.

If some people have really interest to use WMF/EMF with this project, maybe I will found time to do this later in C#.

Alex
GeneralRe: wmf Pin
killminusnine15-Jun-05 4:21
killminusnine15-Jun-05 4:21 
GeneralRe: wmf Pin
infal15-Jun-05 5:32
infal15-Jun-05 5:32 
GeneralCannot Open Pin
kmchong23-May-05 1:00
kmchong23-May-05 1:00 
GeneralRe: Cannot Open Pin
Paolo Gios23-May-05 1:07
Paolo Gios23-May-05 1:07 
GeneralRe: Cannot Open Pin
kmchong23-May-05 17:16
kmchong23-May-05 17:16 
GeneralRe: Cannot Open Pin
Paolo Gios23-May-05 21:53
Paolo Gios23-May-05 21:53 
GeneralGiustify text Pin
pappopappo200018-May-05 5:02
pappopappo200018-May-05 5:02 
GeneralRe: Giustify text Pin
Paolo Gios18-May-05 5:09
Paolo Gios18-May-05 5:09 
GeneralDo GIF images work. Pin
Member 197372318-May-05 4:46
Member 197372318-May-05 4:46 
GeneralRe: Do GIF images work. Pin
Paolo Gios18-May-05 4:53
Paolo Gios18-May-05 4:53 
GeneralRe: GIF &amp; TIF/MTIF Pin
cbruun4-Jun-05 23:26
cbruun4-Jun-05 23:26 
GeneralIt doesn't work in a web project Pin
Diego F.12-May-05 6:54
Diego F.12-May-05 6:54 
GeneralRe: It doesn't work in a web project Pin
Paolo Gios12-May-05 7:58
Paolo Gios12-May-05 7:58 
GeneralRe: It doesn't work in a web project Pin
Diego F.12-May-05 9:58
Diego F.12-May-05 9:58 
GeneralRe: It doesn't work in a web project Pin
Diego F.12-May-05 10:35
Diego F.12-May-05 10:35 
GeneralIt works! Pin
Diego F.12-May-05 21:14
Diego F.12-May-05 21:14 
GeneralRe: It works! Pin
Paolo Gios12-May-05 22:40
Paolo Gios12-May-05 22:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.