[Mono-list] PDF creation library for Mono?

Willem J.W. Semmelink willems@digicore.co.za
Tue, 5 Oct 2004 09:12:18 +0200


> -----Original Message-----
> From: Marek Habersack [mailto:grendel@caudium.net]=3D20
> Sent: Tuesday, 5 October 2004 10:31 AM
> To: mono-list@lists.ximian.com
> Subject: [Mono-list] PDF creation library for Mono?
>=3D20
> Hello,
>=3D20
>   I was wondering whether anyone knows about a free, managed=3D20
> PDF creation library that works with Mono? I've googled for=3D20


Hi Marek
I attach a class below that I am currently working on. I give it away as =
GPL.=20
I have no project registered for it (yet), but feel free to send me bug =
reports and suggestions via email.


This is how you use the class:

PDFExport expt =3D new PDFExport();
String filename =3D "Test.pdf";
//Assign Info and other properties before beginning the export
expt.Information.Title =3D "Document Title";
expt.Information.Subject=3D"Document Subject";
expt.Information.AuthorName =3D "Willem";
expt.Information.Keywords =3D "Test Export";
expt.Information.Creator =3D "My Test Program";
expt.PageSize =3D SBReport.Export.PageSizes.pgA4;
if (Strm=3D=3Dnull)
	expt.BeginExport(filename); //Illustrate export to file
else {
	expt.BeginExport(Strm);	//Illustrate export to stream (2nd HTML =
example)
}=20
	expt.NewPage();		=09
expt.WriteText("Toets A",20,10,"Arial",10);
expt.WriteText("Toets B",40,20,"Times New Roman",10);
expt.WriteText("Toets C",60,40,"Courier New",10);
expt.WriteText("Willem Semmelink",120,80,"Script",20);
expt.DrawVLine(150,150,200);
SBReport.RptColour clr =3D new SBReport.RptColour(250,0,0);
System.Drawing.Color fillclr =3D System.Drawing.Color.Aquamarine;
expt.DrawHLine(155,150,200,LineStyles.Dash,2,clr);
expt.DrawRectangle(200,200,300,120,LineStyles.Solid,2,clr,fillclr,FillPat=
terns.DiagCrossLines);
expt.NewPage();
fillclr =3D System.Drawing.Color.DarkOrchid;
expt.WriteText("Sonya Semmelink",120,80,"Arial",20);
expt.DrawHLine(50,150,200);
expt.DrawVLine(50,150,200,LineStyles.Dots,1,clr);
expt.DrawRectangle(200,200,300,120,LineStyles.Solid,2,clr,fillclr,FillPat=
terns.HorizLines);
expt.EndExport();
System.Console.WriteLine(filename + " was created");

Regards
Willem Semmelink


//Below follows the PDF class:
using System;
//using System.FileStream;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
namespace SBReport.Export
{
	/// <summary>
	/// Summary description for Class.
	/// </summary>
	public class PDFExport : IExportInterface
	{
		public PDFExport()
		{
		}
	=09
		#region Properties=20
			=09
		#endregion

		#region Public methods
	=09
		//Code common to both public BeginExport methods
		protected override void OnStartDoc()
		{
			//Initialize all data
			xrefTable =3D new ArrayList();			// Table containing object offsets			=
		=09
			//PDFWriter =3D new =
System.IO.StreamWriter(PDFOutStream,System.Text.Encoding.ASCII);
			m_PageObjRefs=3D"";							// Clear the page references				=09
			m_StartXOffs=3D0;								// Reset startxref value
			m_LastObjId=3D-1;								// Reset object count
			m_PagesCount=3D0;								// Reset number of pages in doc
			m_PageContents=3D"";							// Clean curent page contents
			m_Offset =3D 10;								// PDF header contains 0...9 bytes, incl CRLF
														// so the first object will write at position 10
			m_PageProcSetPatterns=3D"";					// Clear patterns for current page
			m_IsFirstPage=3Dtrue;							// Is the first page of the document
			m_Patterns =3D new ArrayList();				// Table containing pattern IDs
			foreach(int i in Enum.GetValues(typeof(FillPatterns)))		=09
			{ //Create an empty array item (i.e. value of 0) for each enumerated =
pattern
				m_Patterns.Add(0);						=20
			}				=09
			m_Fonts=3Dnew Hashtable();					//Start with no fonts in document
			m_PageFonts=3D"";								//No fonts on current page
		=09
			//Start writing to the stream				//PDF Spec Paragraph 5.13	=09
			StreamWrite("%PDF-1.3" + CRLF);				// Write the PDF header
			xrefTable.Add(GetNewObjID());				// First Object has offset of 0				=09
	=09
			//Get Object reference for Pages object [it is written at end of doc]
			m_PagesObjId =3D GetNewObjID();
		}
		//No XML comment - defined in parent
		protected override void OnEndDoc()
		{
			int rootObjectId,outlineObjectId;			=09

			//Finish the curent page____________________________
			FlushCurrentPage();

			//Write Pages Object________________________ Adobe Spec 6.3
			string text =3D "/Type /Pages" + CRLF +		//Write object type
				"/Count " + m_PagesCount.ToString();	//Number of pages in document
			text +=3D CRLF + "/Kids [" + m_PageObjRefs + "]";	//Add references to =
all pages
					=09
			PDFWriteObj(m_PagesObjId,true,				//This object ID; dictionary<<, >>  =

				text);									//Contents of the pages object			=09

			//Write Outline Object_____________________  Adobe Spec 6.7
			outlineObjectId =3D GetNewObjID();			//Save obj ID of Outline object=20
			PDFWriteObj(								//Write Outlines Object
				outlineObjectId,true,					//This object number; dictionary<<, >>=20
				"/Type /Outlines" + CRLF +				//Write object type
				"/Count 0");							//Empty object for now			=09

			//Write the root object_____________________ Adobe Spec 6.2
			rootObjectId =3D GetNewObjID();				//Save obj ID of catalog object as =
root		=09
			PDFWriteObj(								//Write Catalog Object
				rootObjectId,true,						//This object number; dictionary<<, >>=20
				"/Type /Catalog" + CRLF +				//Write object type
				"/Pages " + PDFObjRef(m_PagesObjId) + CRLF+	//Pages reference =3D 3		=
	=09
				"/Outlines " +PDFObjRef(outlineObjectId)+CRLF+ //Outlines reference =
=3D 2
				"/Pagemode /UseOutlines");				//Start Acrobat Reader to view =
Outlines

			// Write final stuff to end the file properly
			int infoObjectID=3DWriteDocumentInfo();		//Write the document info =
object=09
			WriteCrossRef();							//Write the Cross Reference Table		=09
			WriteTrailer(rootObjectId,infoObjectID);	//Write the Trailer

			//Clean up memory that was used
			xrefTable.Clear();
		}

		//No XML comment - defined in parent
		public override void NewPage()
		{ =20
			if (! m_IsFirstPage) { //If this is not the first page, write =
previous page to stream
				FlushCurrentPage();
			}
			m_PageContents=3D"";				//Start with a clean page contents object =
array
			m_PageProcSetPatterns=3D"";		//Start with no patterns in ProcSet
			m_IsFirstPage=3Dfalse;			//Next time we call this function, we will =
flush crrent page
			m_PagesCount++;					//Increment pages counter
			m_PageFonts=3D"";					//Start page with no fonts in resource list
		}
	=09
		//No XML comment - defined in parent
		public override void WriteText(string text,int left, int =
top,SBReport.Font font)
		{ //Adobe Specification Chapter 11
			string fontRef =3D PDFAddFont(font);  //Returns something like "/F1"
			int objId=3DGetNewObjID();
			int pgHeight =3D PAGE_DIMENSIONS[(int)m_PageSize,1];		=09
			PDFWriteStreamObj(objId,"",
				            "BT" + CRLF +
							fontRef+" " + font.Size.ToString() + " Tf" + CRLF +=20
							"-0.1940 Tc" + CRLF + //Character spacing
							left.ToString() + " " +
							(pgHeight - top).ToString() + " " + //PDF measures from bottom of =
pg
							"Td ("+text+") Tj" + CRLF +
							"ET" + CRLF				          =20
					);//PDFWriteObj
			if (m_PageContents.Length > 0) {
					m_PageContents +=3D " ";
			}
			m_PageContents +=3D PDFObjRef(objId);
		}	=09
	=09

		public override void DrawHLine(int fromX, int fromY,int length,
			LineStyles style,int thickness,	RptColour clr )
		{
			DrawPDFLine(fromX,fromY,fromX+length,fromY,style,thickness,clr);
		}

		public override void DrawVLine(int fromX, int fromY,int length,
			LineStyles style,int thickness,
			RptColour clr
			)
		{
			DrawPDFLine(fromX,fromY,fromX,fromY+length,style,thickness,clr);
		}	=09
		=09
		//No XML comment - defined in parent
		public override void DrawRectangle(int left, int top,int width, int =
height,
				LineStyles style,int thickness, RptColour lineClr, RptColour =
fillClr,
				FillPatterns pattern)
		{ //Adobe specification Paragraph 7.1, Chapter 12
			int objId=3DGetNewObjID();
			int pgHeight =3D PAGE_DIMENSIONS[(int)m_PageSize,1];
			string widthstr =3D "";
			string colorstr=3D  PDFColour(lineClr,true);
			string fillClrStr=3D"";
			if (fillClr !=3Dnull) fillClrStr=3DPDFColour(fillClr,false);
			if (thickness > 1) {widthstr =3D thickness.ToString() + " w" + CRLF;}
			string stylestr=3DPDFLineStyle(style);
			string patternStr =3D "";
			string fillStr  =3D ((fillClr=3D=3Dnull)? "S":"B") + CRLF;
			if (pattern !=3D FillPatterns.Solid)=20
			{
				fillStr =3D "S" + CRLF;
				PDFFillPattern(pattern);					//Create a pattern object if it does =
not exist
				patternStr =3D //"/Pattern cs /P" +
						   "/CS1 cs" + CRLF +
						   String.Format("{0,4} {1,4} {2,4}",				=09
								((double)fillClr.Red/255),	//We do not use the PDFColour =
function
								((double)fillClr.Green/255),  //because we do not want the "rg" =
at the end
								((double)fillClr.Blue/255)) +
						   " /P" +=09
						  ((int) pattern).ToString() +
						  " scn" + CRLF +						=09
						  left.ToString() + " " +
						  (pgHeight-top).ToString() + " " +
						  width.ToString() + " " +
						  ( - height).ToString() + " re" + CRLF +
						  "f" + CRLF;						 =20
			}
			PDFWriteStreamObj(objId,"",		=09
						patternStr +
						colorstr +=20
						fillClrStr+
						widthstr + stylestr +    =20
						left.ToString() + " " +
						(pgHeight-top).ToString() + " " +
						width.ToString() + " " +
						( - height).ToString() + " re" + CRLF +
						fillStr=09
				);//PDFWriteObj
			if (m_PageContents.Length > 0)=20
			{
				m_PageContents +=3D " ";
			}
			m_PageContents +=3D PDFObjRef(objId);			=09
		}
=09
		#endregion Public Methods
		//---------------------------------------------------
		#region Private Functions/Methods

		/// <summary>
		/// Write an object to the PDF file and add it's offset to the
		/// xref table.
		/// </summary>
		/// <param name=3D"objno">Object number</param>
		/// <param name=3D"dictionary">Write <c><<</c> at start and <c>>></c> =
at end</param>
		/// <param name=3D"dictionaryText">Object contents - printed in =
dictionary</param>
		private void PDFWriteObj(int objno,bool dictionary,string =
dictionaryText)
		{
			string txt =3D objno.ToString() + " 0 obj" + CRLF;
			if (dictionary) {=20
				txt +=3D "<<" + CRLF;=20
			}
			txt +=3D dictionaryText + CRLF;
			if (dictionary) {
				txt +=3D ">>" + CRLF;=09
			}
			//if (writeEndObj)=20
			//{
				txt +=3D "endobj"+ CRLF+CRLF;=20
			//}						=09
			xrefTable[objno] =3Dm_Offset;				//Insert offset at object index
			m_Offset +=3D txt.Length;					//Calculate offset for next object		=09
			StreamWrite(txt);
		}


		/// <summary>
		/// Write an object with an embedded stream
		/// </summary>
		/// <param name=3D"objno">Object ID</param>
		/// <param name=3D"dictionaryText">Object text - printed in =
dictionary</param>
		/// <param name=3D"streamText">Stream contents</param>
		private void PDFWriteStreamObj(int objno, string dictionaryText, =
string streamText)
		{ //Adobe Specification Paragraph 4.8
			int streamLen =3D streamText.Length;
			string fullText =3D "<< " +=20
				(dictionaryText =3D=3D ""? "":(CRLF+dictionaryText + CRLF)) +=20
				"/Length " + streamLen.ToString() +=20
				(dictionaryText =3D=3D ""? " >>":CRLF+">>")+
				CRLF +
				"stream" + CRLF +
				streamText +=20
				"endstream";		=09
			PDFWriteObj(objno,false,fullText);
		}
	=09

		//returns something like /F1 - reference to font by internal name
		private string PDFAddFont(SBReport.Font font)
		{
			/*const string widths =3D 		=09
				"[278 278 355 556 556 889 667 190 333 333 389 "+
				"584 278 333 278 278 556 556 556 556 556 556 556 "+
				"556 556 556 278 278 584 584 584 556 1015 667 667 "+
				"722 722 667 610 778 722 278 500 667 556 832 722 "+
				"778 667 778 722 667 610 722 667 944 667 667 610 "+
				"278 278 278 469 556 333 556 556 500 556 556 278 "+
				"556 556 222 222 500 222 832 556 556 556 556 333 "+
				"500 278 556 500 722 500 500 500 334 260 334 584 "+
				"750 556 750 222 556 333 1000 556 556 333 1000 667 "+
				"333 1000 750 610 750 750 222 222 333 333 350 556 "+
				"1000 333 1000 500 333 944 750 500 667 278 333 556 "+
				"556 556 556 260 556 333 736 370 556 584 333 736 552 "+
				"400 549 333 333 333 576 537 278 333 333 365 556 834 "+
				"834 834 610 667 667 667 667 667 667 1000 722 667 667 "+
				"667 667 278 278 278 278 722 722 778 778 778 778 778 "+
				"584 778 722 722 722 722 667 667 610 556 556 556 556 "+
				"556 556 889 500 556 556 556 556 278 278 278 278 556 "+
				"556 556 556 556 556 556 549 610 556 556 556 556 500 556 500]";
			*/
			string fontReference;
			int fontObjectId;
			if(m_Fonts.ContainsKey(font.Name))
			{	//Font has been used before - return it's object ID
				string s =3D (string)m_Fonts[font.Name];
				fontReference=3Ds.Substring(0,s.IndexOf(","));
				fontObjectId=3Dint.Parse(s.Substring(s.IndexOf(",")+1));
			}=20
			else
			{	//Font not yet used, stream out its details=20
				fontObjectId=3DGetNewObjID();
				fontReference =3D "/F" + (m_Fonts.Count+1).ToString();			=09
				m_Fonts.Add(font.Name,fontReference+","+fontObjectId.ToString());	=
//Remember which fonts we streamed out

				SBReport.FontMetrics fontMetrics =3D font.CalcFontMetrics();
				int FontFlags =3D 0 +
					(fontMetrics.IsFixedWidth? 1:0) +
					(fontMetrics.IsSerif?		2:0) +
					(fontMetrics.IsSymbol?		4:0) +
					(fontMetrics.IsScript?		8:0) +
					(fontMetrics.IsSymbol?		0:32)+ //32 is on right: not symblic
					(font.Italic?				64:0);

				string widths =3D "";
				for(int i =3D 32; i <=3D 255; i++)
				{ //get the width of each character in the font
					widths +=3D fontMetrics.CharWidths[i].ToString() + " ";
				}

				//Adobe Spec 7.7
				int widthsObjID=3DGetNewObjID();
				int fontdescrID=3DGetNewObjID();
				PDFWriteObj(fontObjectId,true,			//font object id; dictionary:<<, >> =
=09
					/*	_________ Type 1 Font Descriptor  __________			=09
					 * "/Type /Font" + CRLF +				//Object type
					 * "/Subtype /Type1" + CRLF +				=09
					 *((font.Name=3D=3D"Arial")? "/BaseFont /Helvetica" : "/BaseFont =
/Times-Roman")
					 * */
				=09
					/*  _________ TrueType Font Descriptor _________*/
					"/Type /Font" + CRLF +				//Object type
					"/Subtype /TrueType" + CRLF +
					"/Name " + fontReference + CRLF +
					"/BaseFont /" + PDFFontName(font.Name) +  =20
						((font.Bold=3D=3Dtrue || font.Italic=3D=3Dtrue)?=20
						//true:	add font styles after font name
						"," +=20
						(font.Bold=3D=3Dtrue? "":"Bold") +=20
						(font.Italic=3D=3Dtrue? "":"Italic")											=09
						//false: no font style added
						:"")
						+ CRLF  +
					"/Encoding /WinAnsiEncoding" + CRLF +=20
						/* "WinAnsiEncoding", "MacRomanEncoding", "MacExpertEncoding",
						 *  "StandardEncoding", "PDFDocEncoding"
						 * */
					"/FirstChar 32" + CRLF +		//Replace with variable
					"/LastChar  255" + CRLF + 	//Replace with variable			=09
					//"/Widths " + PDFObjRef(widthsObjID) + CRLF+
					"/Widths [" + widths + "]"+ CRLF+
					"/FontDescriptor " + PDFObjRef(fontdescrID)
					); 							=09

				//PDFWriteObj(widthsObjID,true,widths);
				PDFWriteObj(fontdescrID,true,
					"/Type /FontDescriptor" + CRLF +				=09
					"/FontName /" + PDFFontName(font.Name) + CRLF + =20
					"/Flags " + FontFlags.ToString() + CRLF +
					"/FontBBox ["  +
							fontMetrics.FontBox.left + " " +
							fontMetrics.FontBox.top  + " " +
							fontMetrics.FontBox.right+ " " +
							fontMetrics.FontBox.bottom+ "]" + CRLF+
							//[-250 -144 2664 864]" +CRLF+
					"/Ascent "+ fontMetrics.Ascent + CRLF +		//"/Ascent 864" + CRLF +
					"/CapHeight "+ fontMetrics.Ascent + CRLF +	//"/CapHeight 864" + =
CRLF +
					"/Descent "+fontMetrics.Descent + CRLF +	//"/Descent -144" + CRLF +	=
			=09
					"/AvgWidth "+fontMetrics.AvgWidth + CRLF +	//"/AvgWidth 432" + CRLF =
+
					"/MaxWidth "+fontMetrics.MaxWidth + CRLF +	//"/MaxWidth 2664" + =
CRLF +
					"/StemV 0" + CRLF +
					"/ItalicAngle 0"=09
					);
			}//if ContainsKey
		=09
			//Only add to page resources if it is not yet there
			if (m_PageFonts.IndexOf(fontReference) < 0)	{=20
				m_PageFonts +=3D fontReference + " " + PDFObjRef(fontObjectId) + " =
";
			}
			return fontReference;
		}

		//PDF does not like spaces in names like "Times New Roman". Remove =
spaces
		private string PDFFontName(string oldName)
		{
			return oldName.Replace(" ","");
		}

		private void FlushCurrentPage()
		{ //Write the last (current) page to the stream,=20
			=20
			//ProcSet______________________________________ Adobe Spec 7.6
			int procset=3DGetNewObjID();
			string ProcSetText =3D"/Font << " + m_PageFonts + " >> " + CRLF+
								"/ProcSet [/PDF /Text /ImageC]";					=09
					=09
			if (m_PageProcSetPatterns.Length >0)			//Adobe Spec Example 7.32
			{
				ProcSetText +=3D CRLF + "/Pattern << " + m_PageProcSetPatterns + " =
>>" + CRLF +
					"/ColorSpace << /CS1 [/Pattern /DeviceRGB] >>";
			}		=09
			PDFWriteObj(procset,true,ProcSetText);=20
						=09
			//Page Object
			double pgWidth =3D PAGE_DIMENSIONS[(int)m_PageSize,0];
			double pgHeight =3D PAGE_DIMENSIONS[(int)m_PageSize,1];
			string text =3D "/Type /Page" + CRLF +	//Define object type
				"/Parent " + PDFObjRef(m_PagesObjId) + CRLF +=20
				"/MediaBox [0 0 " +=20
					pgWidth.ToString() + " " + 	//Define page size
					pgHeight.ToString() + "]" +	CRLF +
				"/Resources " + PDFObjRef(procset) + CRLF +=20
				//"/Resources << " +
				//"/Font << /" + fName + " " + PDFObjRef(fontid) + " >> " +
				//"/ProcSet " + PDFObjRef(procset) +	">>" + CRLF +
				"/Contents " +
				(  m_PageContents.Length <=3D 5? m_PageContents : "[" + =
m_PageContents + "]")			=09
				;
			int newObjID =3D GetNewObjID();
			PDFWriteObj(newObjID,true,					//This object number
				text);=09
			if (m_PageObjRefs.Length > 0){
				m_PageObjRefs +=3D " ";
			}
			m_PageObjRefs +=3D PDFObjRef(newObjID);
		}

		///<summary>PDF object reference</summary>
		private string PDFObjRef(int o)
		{ //Adobe Specification Paragraph 4.11
			return  o.ToString() + " 0 R";
		}


		/// <summary>Write the PDF cross-reference table</summary>
		private void WriteCrossRef()
		{ //Adobe speification Paragraph 5.15
			m_StartXOffs =3D m_Offset;			//Save offset of xref=20
			StreamWrite("xref" + CRLF);		//Intro to the xref table

			//First number indicates we start at object 0 [first entry in this =
subsection]
			//Second number is the number of cross reference entries
			StreamWrite("0 " + xrefTable.Count.ToString() + CRLF);=20
			int i =3D 0;
			foreach (int offset in xrefTable)
			{ //Each entry must be exactly 20 bytes, including end-of-line marker
				//offset =3D number of bytes from the begining of the file to the=20
				//beginning of the object: must be 10 bytes long, padded with =
leading zeroes
				if (i=3D=3D0) StreamWrite("0000000000 65535 f"+CRLF);
				else=20
				{
					StreamWrite(String.Format("{0:D10} 00000 n{1}",offset, CRLF));
				}
				++i;
			}
		}


		/// <summary>Write the last part of the PDF file</summary>
		private void WriteTrailer(int root,int info)
		{	//Adobe Specificaton Paragraph 5.16
			StreamWrite("trailer" + CRLF + "<<" + CRLF);
			StreamWrite("/Size "  + xrefTable.Count.ToString() + CRLF);
			StreamWrite("/Root "  + PDFObjRef(root) + CRLF);=09
			if (info > 0)
			{
				StreamWrite("/Info "  + PDFObjRef(info) + CRLF);=09
			}
			StreamWrite(">>"+CRLF+"startxref"+CRLF+m_StartXOffs+CRLF);	//Save =
position of xref table
		=09
			//Specification says nothing about newline after %%EOF. Acrobat =
reader works without it
			//Ghostview owever complains - since gv is used a lot on linux I =
added CRLF.
			StreamWrite("%%EOF"+CRLF); 				//End-of-file marker
		}


		/// <summary>Write a Document Info object</summary>
		/// <returns>Object ID of the object</returns>
		private int WriteDocumentInfo() //returns Object ID of the info object
		{ // Adobe Specification Paragraph 6.10
			string text =3D "";
		=09
			//Title________________________________________________
			if(Information.Title.Length > 0)
			{
				text +=3D "/Title (" + ConvertStrToPDF(Information.Title) + ")" + =
CRLF;
			}
			//Subject______________________________________________
			if(Information.Subject.Length > 0)
			{
				text +=3D "/Subject (" +ConvertStrToPDF(Information.Subject) + ")" + =
CRLF;
			}
			//Author_______________________________________________
			if (Information.AuthorName.Length > 0)
			{			=09
				text +=3D "/Author (" + ConvertStrToPDF(Information.AuthorName) + =
")" + CRLF;
			}
			//Creationdate_________________________________________
			DateTime now =3D DateTime.Now;
			TimeZone z =3D TimeZone.CurrentTimeZone;
			TimeSpan t =3D z.GetUtcOffset(now);
			text +=3D "/CreationDate (D:" +=20
					now.ToString("yyyyMMddHHmmss") +
					"+" + t.Hours.ToString("D2") + "'"+t.Minutes +"')" + CRLF;
		=09
			//Document Keywords____________________________________
			if (Information.Keywords.Length > 0)
			{		=09
				text +=3D "/Keywords (" + ConvertStrToPDF(Information.Keywords) + =
")" + CRLF;
			}

			//Program that created the PDF document
			if (Information.Creator.Length > 0)
			{
				text +=3D "/Creator (" + ConvertStrToPDF(Information.Creator) + ")" =
+ CRLF;
			}

			//Producer of the PDF document
			text +=3D "/Producer (" + ConvertStrToPDF(ProductVersion) + ")";

			//Write the info object________________________________
			int newObjID =3D GetNewObjID();
			PDFWriteObj(newObjID,true,				//This object number; dictionary:<<, >> =

				text);								//document info
			return newObjID;
		}


		/// <summary>Increment Object ID and return it</summary>
		/// <returns>New Object ID number</returns>
		private int GetNewObjID()	=09
		{
			xrefTable.Add(0);	  //Increase xross reference table size [Insert ID =
in table when writing obj]
			return ++m_LastObjId; //Return a new number to keep Object IDs unique
		}


//		/// <summary>Output the data to the file or stream</summary>
//		/// <param name=3D"s">String of data to write</param>
//		private void StreamWrite(string s)
//		{ //If we write a string, the length is first written - we DONT want =
that: make charArray
//			PDFWriter.Write(s.ToCharArray());
//		}


		/// <summary>Normalize string so that special characters are handled =
appropriately</summary>
		/// <param name=3D"s">String to normalize</param>
		/// <returns>Strin after normalisation</returns>
		private string ConvertStrToPDF(string s)
		{	//convert  "\", "(", and  ")" to "\x".
			string tmp=3Ds;
			tmp.Replace(@"\", @"\\");
			tmp.Replace(@"(", @"\(");
			tmp.Replace(@")", @"\)");
			tmp.Replace("\r", @"\r");
			tmp.Replace("\n", @"\n");
			return tmp;
		}
	=09
	=09
		/// <summary>Create colour</summary>
		/// <param name=3D"c">colour to use</param>
		/// <param name=3D"f">g or rg if false (fill); G or RG if true =
(stroke)</param>
		/// <returns>PDF string representation</returns>
		private string PDFColour(RptColour c,bool f)
		{ //Adobe specification, Paragraph 8.5, 12.1
			string colorstr;
			if ((c.Red+c.Green+c.Blue)=3D=3D0)=20
			{
				if (m_IsBlack) {
					colorstr =3D ""; //Conserve file size: need not repeat last color
				} else {
					m_IsBlack=3Dtrue;
					colorstr =3D ((f)? "0 G":"0 g") + CRLF;
				}
			}
			else=20
			{
				m_IsBlack=3Dfalse;
				colorstr =3D String.Format("{0,4} {1,4} {2,4} {3}",				=09
						((double)c.Red/255),
						((double)c.Green/255),
						((double)c.Blue/255),
						((f)? "RG":"rg") + CRLF
					);
			}
			return (colorstr);
		}

		private void DrawPDFLine(int fromX, int fromY,int toX, int toY,
			LineStyles style,int thickness,
			RptColour clr
			)
		{ // Adobe Specification Paragrap 12.1
			int objId=3DGetNewObjID();
			int pgHeight =3D PAGE_DIMENSIONS[(int)m_PageSize,1];
			string widthstr =3D "";
			string colorstr=3D PDFColour(clr,true);		=09
			if (thickness > 1) {widthstr =3D thickness.ToString() + " w" + CRLF;}
			string stylestr=3DPDFLineStyle(style);		=09
			PDFWriteStreamObj(objId,"",
				colorstr+
				widthstr + stylestr +    =20
				fromX.ToString() + " " +
				(pgHeight-fromY).ToString() +" m" + CRLF +
				toX.ToString() + " " +
				(pgHeight-toY).ToString() + " l" + CRLF +
				"s" + CRLF				          =20
				);//PDFWriteObj
			if (m_PageContents.Length > 0)=20
			{
				m_PageContents +=3D " ";
			}
			m_PageContents +=3D PDFObjRef(objId);				                             =
=20
		}

		/// <summary>Sets line style</summary>	=09
		/// <returns>String to be written in PDF file</returns>
		private string PDFLineStyle(LineStyles style)
		{ //Adobe Specification, Paragraph 8.3
			string stylestr=3D"";
			switch(style)
			{
				case LineStyles.Dots:
					m_IsSolid=3Dfalse;
					stylestr=3D"[1 2] 0 d" + CRLF; //1 on 2 off=20
					break;
				case LineStyles.Dash:
					m_IsSolid=3Dfalse;
					//Adobe's spec has example of [3 3] as 3 on, 3 off, but that =
displays=20
					//almost solid - had to make [3 5] or [3 6] to get decent spaces =
in-between.
					stylestr=3D"[3 5] 0 d" + CRLF;
					break;
				//Adobe spec seems not to allow for dash-dot, etc
				default:
					if (m_IsSolid) {
						stylestr=3D"";	//save file size: need not repeat for each line
					} else {
						m_IsSolid=3Dtrue;
						stylestr=3D"[4 0] 0 d" + CRLF;
					}
					break;
			}
			return stylestr;
		}


		/// <summary>Create a fill pattern object.</summary>
		/// <param name=3D"pattern">Pattern to create. An Error is thrown if =
the Solid pattern is passed.</param>
		/// <returns>Object ID of the pattern</returns>
		private int PDFFillPattern(FillPatterns pattern)
		{ //Adobe Specification Paragraph 7.17 - see example of star pattern =
(Example 7.33)
			int objId =3D (int) m_Patterns[(int) pattern];
			if (objId > 0) // If the pattern has been defined, we simply return =
it's Object ID
			{
				AddPatternToProcSet(objId,(int)pattern); //Ensure it is in current =
page's resources
				return objId; //Re-use same pattern object
			}=20
			else  //Add the pattern object to the file
			{
				objId=3DGetNewObjID();
				//int procSetId =3D GetNewObjID();=09
				//PDFWriteObj(procSetId,true,"/ProcSet [/PDF] "); //Create a ProcSet =
for the pattern

				string ObjectText =3D=20
					"/Type /Pattern" + CRLF + 				=09
					"/PatternType 1" + CRLF +	//Tiling pattern (smoothing not yet =
implemented)
					"/Resources << >>" + CRLF + //+ PDFObjRef(procSetId) + CRLF +
					"/PaintType 2"   + CRLF +	//Use external colour, i.e. colour not =
defined in pattern
					"/TilingType 1"  + CRLF ;	//Pattern cells are spaced consistently
					//Matrix not defined, accept default of identity matrix
								=09
				//Now we define the pattern in the stream part of the object
				string PatternStr=3D"";
				switch (pattern)
				{
					case FillPatterns.VertLines:
						ObjectText +=3D=20
							"/BBox [0 0 7 8]" + CRLF +  //Pattern bounding box Spec Example =
7.33				=09
							"/XStep 8"		  + CRLF +	//Note This is differrent between Example=20
							"/YStep 7";					//7.33 and 7.32 [Bitmap vs vector-drawn]

						 PatternStr =3D "0 0 m"	+ CRLF +  "0 8 l"	+ CRLF +  "s" + CRLF +
									  "2 0 m"	+ CRLF +  "2 8 l"	+ CRLF +  "s" + CRLF +
									  "4 0 m"	+ CRLF +  "4 8 l"	+ CRLF +  "s"       + CRLF +
									  "6 0 m"	+ CRLF +  "6 8 l"	+ CRLF +  "s";
						 break;
					case FillPatterns.HorizLines:
						ObjectText +=3D=20
							"/BBox [0 0 8 7]" + CRLF +  //Pattern bounding box Spec Example =
7.33				=09
							"/XStep 7"		  + CRLF +	//Note This is differrent between Example=20
							"/YStep 8";					//7.33 and 7.32 [Bitmap vs vector-drawn]

						PatternStr=3D "0 0 m"	+ CRLF +  "8 0 l"	+ CRLF +  "s" + CRLF +
									"0 2 m"	+ CRLF +  "8 2 l"	+ CRLF +  "s" + CRLF +
									"0 4 m"	+ CRLF +  "8 4 l"	+ CRLF +  "s" + CRLF +
									"0 6 m"	+ CRLF +  "8 6 l"	+ CRLF +  "s";								=09
						 break;
					case FillPatterns.CrossLines:
						ObjectText +=3D=20
							"/BBox [0 0 8 8]" + CRLF +  //Pattern bounding box Spec Example =
7.33				=09
							"/XStep 6"		  + CRLF +	//Note This is differrent between Example=20
							"/YStep 6";					//7.33 and 7.32 [Bitmap vs vector-drawn]

						PatternStr=3D "0 0 m"	+ CRLF +  "8 0 l"	+ CRLF + "s" + CRLF +
									"0 2 m"	+ CRLF +  "8 2 l"	+ CRLF + "s" + CRLF +
									"0 4 m"	+ CRLF +  "8 4 l"	+ CRLF + "s" + CRLF +
									"0 6 m"	+ CRLF +  "8 6 l"	+ CRLF + "s" + CRLF +
								//Vert
									"0 0 m"	+ CRLF +  "0 8 l"	+ CRLF + "s" + CRLF +
									"2 0 m"	+ CRLF +  "2 8 l"	+ CRLF + "s" + CRLF +
									"4 0 m"	+ CRLF +  "4 8 l"	+ CRLF + "s" + CRLF +
									"6 0 m"	+ CRLF +  "6 8 l"	+ CRLF + "s";
						break;=09
					case FillPatterns.DiagFwLines:
						ObjectText +=3D=20
							"/BBox [0 0 5 5]" + CRLF +  //Pattern bounding box Spec Example =
7.33				=09
							"/XStep 5"		  + CRLF +	//Note This is differrent between Example=20
							"/YStep 5";					//7.33 and 7.32 [Bitmap vs vector-drawn]
					=09
						PatternStr=3D "0 0 m"	+ CRLF +  "5 5 l"	+ CRLF + "s" + CRLF +
									"-3 3 m"	+ CRLF +  "3 -3 l"	+ CRLF + "s";
						break;=09
					case FillPatterns.DiagBwLines:
						ObjectText +=3D=20
							"/BBox [0 0 5 5]" + CRLF +  //Pattern bounding box Spec Example =
7.33				=09
							"/XStep 5"		  + CRLF +	//Note This is differrent between Example=20
							"/YStep 5";					//7.33 and 7.32 [Bitmap vs vector-drawn]
					=09
						PatternStr=3D "0 5 m"	+ CRLF +  "5 0 l"	+ CRLF + "s" + CRLF +
									"3 -3 m"	+ CRLF +  "-3 3 l"	+ CRLF + "s";
						break;=09
					case FillPatterns.DiagCrossLines:
						ObjectText +=3D=20
							"/BBox [0 0 5 5]" + CRLF +  //Pattern bounding box Spec Example =
7.33				=09
							"/XStep 5"		  + CRLF +	//Note This is differrent between Example=20
							"/YStep 5";					//7.33 and 7.32 [Bitmap vs vector-drawn]
					=09
						PatternStr=3D=20
							"0 0 m"	+ CRLF +  "5 5 l"	+ CRLF + "s" + CRLF +
							"-3 3 m"	+ CRLF +  "3 -3 l"	+ CRLF + "s"+CRLF+
							"0 5 m"	+ CRLF +  "5 0 l"	+ CRLF + "s" + CRLF +
							"3 -3 m"	+ CRLF +  "-3 3 l"	+ CRLF + "s";
						break;	=09
					case FillPatterns.Solid:
						 throw new ArgumentOutOfRangeException("pattern");
				}
				string StreamText =3D PatternStr + CRLF;							=09

				PDFWriteStreamObj(objId,ObjectText,StreamText);=09
				m_Patterns[(int) pattern] =3D objId;
				AddPatternToProcSet(objId,(int)pattern); //Ensure it is in current =
page's resources
				return objId;
			}
		}


		private void AddPatternToProcSet(int objId,int pattern)
		{		=09
			string patternName =3D "/P" + pattern.ToString();
			if (m_PageProcSetPatterns.IndexOf(patternName) < 0)
			{
				if (m_PageProcSetPatterns.Length > 0)
				{
					m_PageProcSetPatterns +=3D " ";
				}
				m_PageProcSetPatterns +=3D patternName + " " + PDFObjRef(objId);
			}
		}

		#endregion Private functions/Methods

		#region Private data members	=09
		private System.IO.Stream PDFOutStream;	// Stream in which the PDF =
output is sent
		private System.IO.StreamWriter PDFWriter;=20
		private ArrayList xrefTable; 	=09
		private string m_PageObjRefs=3D"";
		private int m_StartXOffs =3D 0;
		private int m_LastObjId =3D0;=09
		private int m_PagesObjId=3D0;
		private int m_Offset;
	=09
		private bool m_IsBlack=3Dtrue;			//True if we do not need to repeat =
black colour
		private bool m_IsSolid=3Dtrue;			//True if Solid line - need not =
repeat for each line
		private ArrayList m_Patterns;			//List of ObjetID's, Array index =3D =
FillPatterns enum
		private Hashtable m_Fonts=3Dnull;				//List of all fonts used in the =
document
	=09
		//Create a separate Page class for te following?
		private string	m_PageContents=3D"";
		private string	m_PageProcSetPatterns=3D"";
		private bool	m_IsFirstPage=3Dtrue;=09
		private int     m_PagesCount=3D0;			//Number of pages in document
		private string  m_PageFonts=3D"";			//List of ObjectID's of fonts used =
on this page
		#endregion
	}
}
//END OF PDF CLASS
using System;
using System.Drawing;
using System.IO;
namespace SBReport.Export
{

	public struct DocInfo
	{	=09
		/// <summary>
		/// Title of the document. PDF files have an info object where the=20
		/// document's title can be saved.=20
		/// </summary>
		public string Title
		{
			get {return m_Title; }
			set {m_Title =3D value; }
		}
		private string m_Title;

		/// <summary>
		/// Subject of the document. PDF files have an info object where the=20
		/// document's subject can be saved.=20
		/// </summary>
		public string Subject
		{
			get {return m_Subject; }
			set {m_Subject =3D value; }
		}
		private string m_Subject;

		/// <summary>
		/// Name of document author. PDF files have an info object where the=20
		/// name of the document's author can be saved.=20
		/// </summary>
		public string AuthorName
		{
			get {return m_AuthorName; }
			set {m_AuthorName =3D value; }
		}
		private string m_AuthorName;

		/// <summary>
		/// Keywords for the document. PDF files have an info object where the =

		/// keywords can be saved.=20
		/// </summary>
		public string Keywords
		{
			get {return m_Keywords; }
			set {m_Keywords =3D value; }
		}
		private string m_Keywords;

		/// <summary>
		/// Creator of the document. PDF files have an info object where the=20
		/// program name that created the document can be saved.=20
		/// </summary>
		public string Creator
		{
			get {return m_Creator; }
			set {m_Creator =3D value; }
		}
		private string m_Creator;
	}
=09

	/// <summary>
	/// Interface to export the report
	/// </summary>
	public abstract class IExportInterface
	{	=09
		#region properties
		public DocInfo Information;
			=09
		///<summary>Determines the size of the page.</summary>
		///<remarks>Changing this property in runtime affects all pages after
		/// changing. The current page, and all new pages created after=20
		/// changing this property will be in the new size,=20
		/// whilst all pages that were created before changing this property, =
will
		/// remain in the old size.</remarks>
		public PageSizes PageSize
		{
			get{return m_PageSize; }
			set{m_PageSize =3D value;}
		}
		protected PageSizes m_PageSize=3DPageSizes.pgA4;
	=09
		/// <summary>
		/// File name to use when saving the document to a file
		/// </summary>
		public string FileName
		{
			get{return m_FileName; }
			set{m_FileName=3Dvalue;}
		}
		protected string m_FileName=3D"";
		#endregion properties

		#region public methods
		/// <summary>
		/// Start the export, and write it to disk in the file given by the =
parameter.
		/// If a file already exists with the specifiec name, the file will be =
overwritten
		/// by the new exported file.
		/// </summary>
		/// <remarks>This function will be implemented to create a =
System.IO.FileStream=20
		/// class. The remainder of the execution wil be as if BeginExport was
		/// called with the stream as a parameter - see the stream version of =
this function.</remarks>
		/// <param name=3D"filename">File to which we must export</param>
		public void BeginExport(string filename)
		{
			m_FileName =3D filename;
			System.IO.FileInfo fi =3D new FileInfo(filename);	=09
			m_fileFull=3Dfi.FullName.Substring(0,fi.FullName.LastIndexOf('.'));=20
			m_fileBase=3Dfi.Name.Substring(0,fi.Name.LastIndexOf('.'));=20
			m_fileExt =3Dfi.Extension;	//extension part of file name
		=09
			CreateFileStream(filename);
			OnStartDoc();
		}
	=09
		/// <summary>
		/// Start the export, and write it to a stream as given in the =
parameter.
		/// </summary>
		/// </summary>
		/// <remarks>By exporting all output to a stream, we open up more =
possibilities
		/// for exporting. To ensure compatibility, the file version of this =
function=20
		/// also creates a stream for file output.
		/// This function can be implemented to create a =
System.IO.BinaryWriter=20
		/// with the stream as a parameter to it's constructor. All export is =
then done
		/// via the binary writer to the given stream:
		/// <code>
		/// System.IO.FileStream MyStream;
		/// System.IO.BinaryWriter MyWriter;
		/// public override void BeginExport(string filename)
		/// {
		///   FileInfo fi =3D new FileInfo(filename);
		///	  if (fi.Exists) {fi.Delete();} =20
		///   MyStream =3D new =
System.IO.FileStream(filename,FileMode.CreateNew);
		///   BeginExport();
		/// }
		/// public override void BeginExport(System.IO.Stream stream)
		/// {
		///		MyStream =3D stream;
		///		BeginExport();
		/// }
		/// private void BeginExport()
		/// {
		///		MyWriter =3D new System.IO.BinaryWriter(MyStream);
		///		MyWriter.Write("Hello World".ToCharArray());=20
		/// } //The EndExport function will close both the writer and the =
stream.
		/// </code>
		/// <param name=3D"stream">Stream to which we must export</param>	=09
		public void BeginExport(System.IO.Stream stream)
		{
			m_fileFull=3D""; //name of path+file  but no extension
			m_fileBase=3D""; //name of file with no extension
			m_fileExt =3D""; //extension part of file name
			DocOutStream =3D stream;
			DocWriter =3D new =
System.IO.StreamWriter(DocOutStream,System.Text.Encoding.ASCII);
			OnStartDoc();
		}


		/// <summary>
		/// Create a new Page in the export.=20
		/// </summary>
		/// <remarks>All subsequent drawing will be displayed on the new page. =

		/// The size of the page is set to the current value of the
		/// PageSize property. The current page and all calls to NewPage=20
		/// after changing PageSize will be in the new size,=20
		/// whilst all pages that were created before changing PageSize, will
		/// remain in the old size.
		/// </remarks>
		abstract public void NewPage();

		/// <summary>
		/// End the export by writing the proper document termination =
characters to the stream.
		/// </summary>
		public void EndExport()
		{
			OnEndDoc();

			CloseStream();		=09
		}

		#region WriteText
		///<summary>Write text on the current page. Font style is =
regular.</summary>
		/// <param name=3D"text">text to be written</param>
		/// <param name=3D"left">Position in pixels from left edge of =
page</param>
		/// <param name=3D"top">Position in pixels from top edge of =
page</param>
		/// <param name=3D"fontName">Name of font to use</param>
		/// <param name=3D"fontsize">Font Size of text</param>
		public void WriteText(string text,int left, int top,string =
fontName,int fontsize)
		{
			SBReport.Font font =3D new SBReport.Font(fontName,fontsize);
			WriteText(text,left,top,font);
		}


		///<summary>Write text on the current page. Font style is =
regular.</summary>
		/// <param name=3D"text">text to be written</param>
		/// <param name=3D"left">Position in pixels from left edge of =
page</param>
		/// <param name=3D"top">Position in pixels from top edge of =
page</param>
		/// <param name=3D"font">Defines the font to be used</param>	=09
		abstract public void WriteText(string text,int left, int =
top,SBReport.Font font);
		#endregion WriteText

		#region DrawHLine
		///<summary>Draw solid black line of width 1 on the current =
page.</summary>
		/// <param name=3D"fromX">Start position in pixels from left edge of =
page</param>
		/// <param name=3D"fromY">Start position in pixels from top edge of =
page</param>
		/// <param name=3D"length">Width of the line measured in pixels =
(difference between line left and right)</param>	=09
		public void DrawHLine(int fromX, int fromY,int length)
		{
			LineStyles style =3D SBReport.Export.LineStyles.Solid;
			SBReport.RptColour clr =3D new RptColour(0,0,0); //Black
			DrawHLine(fromX,fromY,length,style,1,clr);
	}
		///<summary>Draw black line of specified width and style on the =
current page.</summary>
		/// <param name=3D"fromX">Start position in pixels from left edge of =
page</param>
		/// <param name=3D"fromY">Start position in pixels from top edge of =
page</param>
		/// <param name=3D"length">Width of the line measured in pixels =
(difference between line left and right)</param>
		/// <param name=3D"style">Solid, Dashed, etc</param>
		/// <param name=3D"thickness">Line width</param>
		public void DrawHLine(int fromX, int fromY,int length,
			LineStyles style,int thickness)
		{
			SBReport.RptColour clr =3D new RptColour(0,0,0); //Black
			DrawHLine(fromX,fromY,length,style,thickness,clr);	=09
		}
		=09
		///<summary>Draw colour line of specified width and style on the =
current page.</summary>
		/// <param name=3D"fromX">Start position in pixels from left edge of =
page</param>
		/// <param name=3D"fromY">Start position in pixels from top edge of =
page</param>
		/// <param name=3D"length">Width of the line measured in pixels =
(difference between line left and right)</param>
		/// <param name=3D"LineStyles">Solid, Dashed, etc</param>
		/// <param name=3D"style">Solid, dotted, etc</param>
		/// <param name=3D"thickness">Line width measured in pixels</param>
		/// <param name=3D"clr">Line colour</param>
		abstract public void DrawHLine(int fromX, int fromY,int length,
			LineStyles style,int thickness, RptColour clr );
		#endregion DrawHLine

		#region DrawVLine
		///<summary>Draw solid black line of width 1 on the current =
page.</summary>
		/// <param name=3D"fromX">Start position in pixels from left edge of =
page</param>
		/// <param name=3D"fromY">Start position in pixels from top edge of =
page</param>
		/// <param name=3D"length">Height of the line measured in pixels =
(difference between line top and bottom)</param>
		public void DrawVLine(int fromX, int fromY,int length)
		{
			LineStyles style =3D SBReport.Export.LineStyles.Solid;
			SBReport.RptColour clr =3D new RptColour(0,0,0); //Black
			DrawVLine(fromX,fromY,length,style,1,clr);
		}
		///<summary>Draw black line of specified width and style on the =
current page.</summary>
		/// <param name=3D"fromX">Start position in pixels from left edge of =
page</param>
		/// <param name=3D"fromY">Start position in pixels from top edge of =
page</param>
		/// <param name=3D"length">Height of the line measured in pixels =
(difference between line top and bottom)</param>
		/// <param name=3D"style">Solid, Dashed, etc</param>
		/// <param name=3D"thickness">Line width</param>
		public void DrawVLine(int fromX, int fromY,int length,
			LineStyles style,int thickness)
		{
			SBReport.RptColour clr =3D new RptColour(0,0,0); //Black
			DrawVLine(fromX,fromY,length,style,thickness,clr);	=09
		}
		=09
		///<summary>Draw colour line of specified width and style on the =
current page.</summary>
		/// <param name=3D"fromX">Start position in pixels from left edge of =
page</param>
		/// <param name=3D"fromY">Start position in pixels from top edge of =
page</param>
		/// <param name=3D"length">Height of the line measured in pixels =
(difference between line top and bottom)</param>
		/// <param name=3D"LineStyles">Solid, Dashed, etc</param>
		/// <param name=3D"style">Solid, dotted, etc</param>
		/// <param name=3D"thickness">Line width measured in pixels</param>
		/// <param name=3D"clr">Line colour</param>
		abstract public void DrawVLine(int fromX, int fromY,int length,
			LineStyles style,int thickness, RptColour clr );
		#endregion DrawVLine
	=09
		#region DrawRectangle
		///<summary>Draw solid black rectanle of width 1 on the current page.
		//////The rectangle is not filled (transparent).
		///</summary>
		/// <param name=3D"left">Start position in pixels from left edge of =
page</param>
		/// <param name=3D"top">Start position in pixels from top edge of =
page</param>
		/// <param name=3D"width">Distance in pixels from left edge to right =
edge of rectangle</param>
		/// <param name=3D"height">Distance in pixels from top edge to bottom =
edge of rectangle</param>	=09
		public void DrawRectangle(int left, int top,int width, int height)
		{
			RptColour C=3Dnew RptColour(); //Black
			=
DrawRectangle(left,top,width,height,LineStyles.Solid,1,C,null,FillPattern=
s.Solid);
		}

		///<summary>Draw black rectangle of specified width and style on the =
current page.
		///The rectangle is not filled (transparent).
		///</summary>
		/// <param name=3D"left">Start position in pixels from left edge of =
page</param>
		/// <param name=3D"top">Start position in pixels from top edge of =
page</param>
		/// <param name=3D"width">Distance in pixels from left edge to right =
edge of rectangle</param>
		/// <param name=3D"height">Distance in pixels from top edge to bottom =
edge of rectangle</param>
		/// <param name=3D"style">Solid, Dashed, etc</param>
		/// <param name=3D"thickness">Line width</param>	=09
		public void DrawRectangle(int left, int top,int width, int height,
			LineStyles style,int thickness)
		{
			RptColour C=3Dnew RptColour(); //Black
			DrawRectangle(left,top,width,height,style,thickness,C,null,
				FillPatterns.Solid );
		}=09

		///<summary>Draw colour rectangle of specified width and style on the =
current page.
		///If the fill colour is null, the rectangle is not filled. If the =
fill colour is=20
		///not null, it is filled with a solid fill type of the specified =
colour.
		///</summary>
		/// <param name=3D"left">Start position in pixels from left edge of =
page</param>
		/// <param name=3D"top">Start position in pixels from top edge of =
page</param>
		/// <param name=3D"width">Distance in pixels from left edge to right =
edge of rectangle</param>
		/// <param name=3D"height">Distance in pixels from top edge to bottom =
edge of rectangle</param>
		/// <param name=3D"LineStyles">Solid, Dashed, etc</param>
		/// <param name=3D"style">Solid, dotted, etc</param>
		/// <param name=3D"thickness">Line width measured in pixels</param>
		/// <param name=3D"lineClr">Line colour</param>
		/// <param name=3D"fillClr">Fill colour. Pass null for no =
fill.</param>
		public void DrawRectangle(int left, int top,int width, int height,
			LineStyles style,int thickness, RptColour lineClr, RptColour fillClr)
		{
			DrawRectangle(left, top,width, height,style,thickness, =
lineClr,fillClr,FillPatterns.Solid);
		}

		///<summary>Draw colour rectangle of specified width and style on the =
current page.
		///If the fill colour is null, the rectangle is not filled. If the =
fill colour is=20
		///not null, it is filled with the specified pattern in the specified =
colour.
		///</summary>
		/// <param name=3D"left">Start position in pixels from left edge of =
page</param>
		/// <param name=3D"top">Start position in pixels from top edge of =
page</param>
		/// <param name=3D"width">Distance in pixels from left edge to right =
edge of rectangle</param>
		/// <param name=3D"height">Distance in pixels from top edge to bottom =
edge of rectangle</param>
		/// <param name=3D"LineStyles">Solid, Dashed, etc</param>
		/// <param name=3D"style">Solid, dotted, etc</param>
		/// <param name=3D"thickness">Line width measured in pixels</param>
		/// <param name=3D"lineClr">Line colour</param>
		/// <param name=3D"fillClr">Fill colour. Pass null for no =
fill.</param>
		/// <param name=3D"pattern">Pattern to fill the box</param>
		abstract public void DrawRectangle(int left, int top,int width, int =
height,
			LineStyles style,int thickness, RptColour lineClr, RptColour fillClr,
			FillPatterns pattern);
		#endregion DrawRectangle
		#endregion Public methods

		#region Protected properties
		/// <summary>
		/// Code common to both public BeginExport methods is placed here
		/// </summary>
		protected abstract void OnStartDoc();
		protected abstract void OnEndDoc();
	=09
		/// <summary>Output the data to the file or stream</summary>
		/// <param name=3D"s">String of data to write</param>
		protected void StreamWrite(string s)
		{ //If we write a string, the length is first written - we DONT want =
that: make charArray
			DocWriter.Write(s.ToCharArray());
		}

		/// <summary>
		/// To be called by child classes when they output to more than one =
file, e.g. HTML class
		/// </summary>
		/// <param name=3D"fileName">File name to create</param>
		protected void CreateFileStream(string fileName)
		{
			System.IO.FileInfo fi =3D new FileInfo(fileName);
			if (fi.Exists) {fi.Delete();}		=09
			DocOutStream =3D new =
System.IO.FileStream(fileName,System.IO.FileMode.CreateNew);
			DocWriter =3D new =
System.IO.StreamWriter(DocOutStream,System.Text.Encoding.ASCII);
		}

		/// <summary>
		/// To be called by child classes when they output to more than one =
file, e.g. HTML class
		/// </summary>
		/// <param name=3D"fileName">File name to create</param>
		protected void CloseStream()
		{	=09
			DocWriter.Close();
			DocOutStream.Close();
		}
	=09
		protected const string CRLF =3D "\r\n";
		protected const string ProductVersion =3D "Seabreeze SBReports (c) =
Willem Semmelink";
		protected System.IO.Stream DocOutStream;		// Stream in which the HTML =
output is sent
		protected System.IO.StreamWriter DocWriter; 	//
		protected static readonly int[,] PAGE_DIMENSIONS=3D{
			 //PgWidth		PgHeight	[Pixels]
			{612, 			792},		//A4
			{612,			792}		//Letter
														 };
		protected string m_fileFull=3D""; //name of path+file but no extension
		protected string m_fileBase=3D""; //name of file with no extension
		protected string m_fileExt =3D""; //extension part of file name
		#endregion protected properties
	}

}