> -----Original Message-----
> From: Marek Habersack [mailto:[EMAIL PROTECTED]
> Sent: Tuesday, 5 October 2004 10:31 AM
> To: [EMAIL PROTECTED]
> Subject: [Mono-list] PDF creation library for Mono?
>=20
> Hello,
>=20
> I was wondering whether anyone knows about a free, managed=20
> PDF creation library that works with Mono? I've googled for=20
Hi Marek
I attach a class below that I am currently working on. I give it away as GPL.
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 = new PDFExport();
String filename = "Test.pdf";
//Assign Info and other properties before beginning the export
expt.Information.Title = "Document Title";
expt.Information.Subject="Document Subject";
expt.Information.AuthorName = "Willem";
expt.Information.Keywords = "Test Export";
expt.Information.Creator = "My Test Program";
expt.PageSize = SBReport.Export.PageSizes.pgA4;
if (Strm==null)
expt.BeginExport(filename); //Illustrate export to file
else {
expt.BeginExport(Strm); //Illustrate export to stream (2nd HTML example)
}
expt.NewPage();
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 = new SBReport.RptColour(250,0,0);
System.Drawing.Color fillclr = System.Drawing.Color.Aquamarine;
expt.DrawHLine(155,150,200,LineStyles.Dash,2,clr);
expt.DrawRectangle(200,200,300,120,LineStyles.Solid,2,clr,fillclr,FillPatterns.DiagCrossLines);
expt.NewPage();
fillclr = 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,FillPatterns.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()
{
}
#region Properties
#endregion
#region Public methods
//Code common to both public BeginExport methods
protected override void OnStartDoc()
{
//Initialize all data
xrefTable = new ArrayList(); // Table
containing object offsets
//PDFWriter = new
System.IO.StreamWriter(PDFOutStream,System.Text.Encoding.ASCII);
m_PageObjRefs="";
// Clear the page references
m_StartXOffs=0;
// Reset startxref value
m_LastObjId=-1;
// Reset object count
m_PagesCount=0;
// Reset number of pages in doc
m_PageContents="";
// Clean curent page contents
m_Offset = 10;
// PDF header contains 0...9 bytes, incl CRLF
// so the first object will write at position 10
m_PageProcSetPatterns="";
// Clear patterns for current page
m_IsFirstPage=true;
// Is the first page of the document
m_Patterns = new ArrayList(); //
Table containing pattern IDs
foreach(int i in Enum.GetValues(typeof(FillPatterns)))
{ //Create an empty array item (i.e. value of 0) for each
enumerated pattern
m_Patterns.Add(0);
}
m_Fonts=new Hashtable();
//Start with no fonts in document
m_PageFonts="";
//No fonts on current page
//Start writing to the stream //PDF
Spec Paragraph 5.13
StreamWrite("%PDF-1.3" + CRLF); //
Write the PDF header
xrefTable.Add(GetNewObjID()); //
First Object has offset of 0
//Get Object reference for Pages object [it is written at end
of doc]
m_PagesObjId = GetNewObjID();
}
//No XML comment - defined in parent
protected override void OnEndDoc()
{
int rootObjectId,outlineObjectId;
//Finish the curent page____________________________
FlushCurrentPage();
//Write Pages Object________________________ Adobe Spec 6.3
string text = "/Type /Pages" + CRLF + //Write object
type
"/Count " + m_PagesCount.ToString(); //Number of
pages in document
text += CRLF + "/Kids [" + m_PageObjRefs + "]"; //Add
references to all pages
PDFWriteObj(m_PagesObjId,true, //This
object ID; dictionary<<, >>
text);
//Contents of the pages object
//Write Outline Object_____________________ Adobe Spec 6.7
outlineObjectId = GetNewObjID(); //Save
obj ID of Outline object
PDFWriteObj(
//Write Outlines Object
outlineObjectId,true,
//This object number; dictionary<<, >>
"/Type /Outlines" + CRLF +
//Write object type
"/Count 0");
//Empty object for now
//Write the root object_____________________ Adobe Spec 6.2
rootObjectId = GetNewObjID(); //Save
obj ID of catalog object as root
PDFWriteObj(
//Write Catalog Object
rootObjectId,true,
//This object number; dictionary<<, >>
"/Type /Catalog" + CRLF +
//Write object type
"/Pages " + PDFObjRef(m_PagesObjId) + CRLF+
//Pages reference = 3
"/Outlines " +PDFObjRef(outlineObjectId)+CRLF+
//Outlines reference = 2
"/Pagemode /UseOutlines");
//Start Acrobat Reader to view Outlines
// Write final stuff to end the file properly
int infoObjectID=WriteDocumentInfo(); //Write the
document info object
WriteCrossRef();
//Write the Cross Reference Table
WriteTrailer(rootObjectId,infoObjectID); //Write the
Trailer
//Clean up memory that was used
xrefTable.Clear();
}
//No XML comment - defined in parent
public override void NewPage()
{
if (! m_IsFirstPage) { //If this is not the first page, write
previous page to stream
FlushCurrentPage();
}
m_PageContents=""; //Start with a
clean page contents object array
m_PageProcSetPatterns=""; //Start with no
patterns in ProcSet
m_IsFirstPage=false; //Next time we call
this function, we will flush crrent page
m_PagesCount++; //Increment
pages counter
m_PageFonts=""; //Start page
with no fonts in resource list
}
//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 = PDFAddFont(font); //Returns something like
"/F1"
int objId=GetNewObjID();
int pgHeight = PAGE_DIMENSIONS[(int)m_PageSize,1];
PDFWriteStreamObj(objId,"",
"BT" + CRLF +
fontRef+" " +
font.Size.ToString() + " Tf" + CRLF +
"-0.1940 Tc" + CRLF +
//Character spacing
left.ToString() + " " +
(pgHeight - top).ToString() +
" " + //PDF measures from bottom of pg
"Td ("+text+") Tj" + CRLF +
"ET" + CRLF
);//PDFWriteObj
if (m_PageContents.Length > 0) {
m_PageContents += " ";
}
m_PageContents += PDFObjRef(objId);
}
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);
}
//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=GetNewObjID();
int pgHeight = PAGE_DIMENSIONS[(int)m_PageSize,1];
string widthstr = "";
string colorstr= PDFColour(lineClr,true);
string fillClrStr="";
if (fillClr !=null) fillClrStr=PDFColour(fillClr,false);
if (thickness > 1) {widthstr = thickness.ToString() + " w" +
CRLF;}
string stylestr=PDFLineStyle(style);
string patternStr = "";
string fillStr = ((fillClr==null)? "S":"B") + CRLF;
if (pattern != FillPatterns.Solid)
{
fillStr = "S" + CRLF;
PDFFillPattern(pattern);
//Create a pattern object if it does not exist
patternStr = //"/Pattern cs /P" +
"/CS1 cs" + CRLF +
String.Format("{0,4} {1,4} {2,4}",
((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" +
((int) pattern).ToString() +
" scn" + CRLF +
left.ToString() + " " +
(pgHeight-top).ToString() + " " +
width.ToString() + " " +
( - height).ToString() + " re" +
CRLF +
"f" + CRLF;
}
PDFWriteStreamObj(objId,"",
patternStr +
colorstr +
fillClrStr+
widthstr + stylestr +
left.ToString() + " " +
(pgHeight-top).ToString() + " " +
width.ToString() + " " +
( - height).ToString() + " re" + CRLF +
fillStr
);//PDFWriteObj
if (m_PageContents.Length > 0)
{
m_PageContents += " ";
}
m_PageContents += PDFObjRef(objId);
}
#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="objno">Object number</param>
/// <param name="dictionary">Write <c><<</c> at start and <c>>></c> at
end</param>
/// <param name="dictionaryText">Object contents - printed in
dictionary</param>
private void PDFWriteObj(int objno,bool dictionary,string
dictionaryText)
{
string txt = objno.ToString() + " 0 obj" + CRLF;
if (dictionary) {
txt += "<<" + CRLF;
}
txt += dictionaryText + CRLF;
if (dictionary) {
txt += ">>" + CRLF;
}
//if (writeEndObj)
//{
txt += "endobj"+ CRLF+CRLF;
//}
xrefTable[objno] =m_Offset;
//Insert offset at object index
m_Offset += txt.Length;
//Calculate offset for next object
StreamWrite(txt);
}
/// <summary>
/// Write an object with an embedded stream
/// </summary>
/// <param name="objno">Object ID</param>
/// <param name="dictionaryText">Object text - printed in
dictionary</param>
/// <param name="streamText">Stream contents</param>
private void PDFWriteStreamObj(int objno, string dictionaryText,
string streamText)
{ //Adobe Specification Paragraph 4.8
int streamLen = streamText.Length;
string fullText = "<< " +
(dictionaryText == ""? "":(CRLF+dictionaryText +
CRLF)) +
"/Length " + streamLen.ToString() +
(dictionaryText == ""? " >>":CRLF+">>")+
CRLF +
"stream" + CRLF +
streamText +
"endstream";
PDFWriteObj(objno,false,fullText);
}
//returns something like /F1 - reference to font by internal name
private string PDFAddFont(SBReport.Font font)
{
/*const string widths =
"[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 = (string)m_Fonts[font.Name];
fontReference=s.Substring(0,s.IndexOf(","));
fontObjectId=int.Parse(s.Substring(s.IndexOf(",")+1));
}
else
{ //Font not yet used, stream out its details
fontObjectId=GetNewObjID();
fontReference = "/F" + (m_Fonts.Count+1).ToString();
m_Fonts.Add(font.Name,fontReference+","+fontObjectId.ToString()); //Remember
which fonts we streamed out
SBReport.FontMetrics fontMetrics =
font.CalcFontMetrics();
int FontFlags = 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 = "";
for(int i = 32; i <= 255; i++)
{ //get the width of each character in the font
widths += fontMetrics.CharWidths[i].ToString()
+ " ";
}
//Adobe Spec 7.7
int widthsObjID=GetNewObjID();
int fontdescrID=GetNewObjID();
PDFWriteObj(fontObjectId,true, //font
object id; dictionary:<<, >>
/* _________ Type 1 Font Descriptor
__________
* "/Type /Font" + CRLF +
//Object type
* "/Subtype /Type1" + CRLF +
*((font.Name=="Arial")? "/BaseFont
/Helvetica" : "/BaseFont /Times-Roman")
* */
/* _________ TrueType Font Descriptor
_________*/
"/Type /Font" + CRLF +
//Object type
"/Subtype /TrueType" + CRLF +
"/Name " + fontReference + CRLF +
"/BaseFont /" + PDFFontName(font.Name) +
((font.Bold==true ||
font.Italic==true)?
//true: add font styles after font name
"," +
(font.Bold==true? "":"Bold") +
(font.Italic==true? "":"Italic")
//false: no font style added
:"")
+ CRLF +
"/Encoding /WinAnsiEncoding" + CRLF +
/* "WinAnsiEncoding",
"MacRomanEncoding", "MacExpertEncoding",
* "StandardEncoding",
"PDFDocEncoding"
* */
"/FirstChar 32" + CRLF +
//Replace with variable
"/LastChar 255" + CRLF + //Replace with
variable
//"/Widths " + PDFObjRef(widthsObjID) + CRLF+
"/Widths [" + widths + "]"+ CRLF+
"/FontDescriptor " + PDFObjRef(fontdescrID)
);
//PDFWriteObj(widthsObjID,true,widths);
PDFWriteObj(fontdescrID,true,
"/Type /FontDescriptor" + CRLF +
"/FontName /" + PDFFontName(font.Name) + CRLF
+
"/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 +
"/AvgWidth "+fontMetrics.AvgWidth + CRLF +
//"/AvgWidth 432" + CRLF +
"/MaxWidth "+fontMetrics.MaxWidth + CRLF +
//"/MaxWidth 2664" + CRLF +
"/StemV 0" + CRLF +
"/ItalicAngle 0"
);
}//if ContainsKey
//Only add to page resources if it is not yet there
if (m_PageFonts.IndexOf(fontReference) < 0) {
m_PageFonts += 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,
//ProcSet______________________________________ Adobe Spec 7.6
int procset=GetNewObjID();
string ProcSetText ="/Font << " + m_PageFonts + " >> " + CRLF+
"/ProcSet [/PDF /Text
/ImageC]";
if (m_PageProcSetPatterns.Length >0)
//Adobe Spec Example 7.32
{
ProcSetText += CRLF + "/Pattern << " +
m_PageProcSetPatterns + " >>" + CRLF +
"/ColorSpace << /CS1 [/Pattern /DeviceRGB] >>";
}
PDFWriteObj(procset,true,ProcSetText);
//Page Object
double pgWidth = PAGE_DIMENSIONS[(int)m_PageSize,0];
double pgHeight = PAGE_DIMENSIONS[(int)m_PageSize,1];
string text = "/Type /Page" + CRLF + //Define object type
"/Parent " + PDFObjRef(m_PagesObjId) + CRLF +
"/MediaBox [0 0 " +
pgWidth.ToString() + " " + //Define page
size
pgHeight.ToString() + "]" + CRLF +
"/Resources " + PDFObjRef(procset) + CRLF +
//"/Resources << " +
//"/Font << /" + fName + " " + PDFObjRef(fontid) + "
>> " +
//"/ProcSet " + PDFObjRef(procset) + ">>" + CRLF +
"/Contents " +
( m_PageContents.Length <= 5? m_PageContents : "[" +
m_PageContents + "]")
;
int newObjID = GetNewObjID();
PDFWriteObj(newObjID,true,
//This object number
text);
if (m_PageObjRefs.Length > 0){
m_PageObjRefs += " ";
}
m_PageObjRefs += 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 = m_Offset; //Save offset
of xref
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);
int i = 0;
foreach (int offset in xrefTable)
{ //Each entry must be exactly 20 bytes, including end-of-line
marker
//offset = number of bytes from the begining of the
file to the
//beginning of the object: must be 10 bytes long,
padded with leading zeroes
if (i==0) StreamWrite("0000000000 65535 f"+CRLF);
else
{
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);
if (info > 0)
{
StreamWrite("/Info " + PDFObjRef(info) + CRLF);
}
StreamWrite(">>"+CRLF+"startxref"+CRLF+m_StartXOffs+CRLF);
//Save position of xref table
//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 = "";
//Title________________________________________________
if(Information.Title.Length > 0)
{
text += "/Title (" +
ConvertStrToPDF(Information.Title) + ")" + CRLF;
}
//Subject______________________________________________
if(Information.Subject.Length > 0)
{
text += "/Subject ("
+ConvertStrToPDF(Information.Subject) + ")" + CRLF;
}
//Author_______________________________________________
if (Information.AuthorName.Length > 0)
{
text += "/Author (" +
ConvertStrToPDF(Information.AuthorName) + ")" + CRLF;
}
//Creationdate_________________________________________
DateTime now = DateTime.Now;
TimeZone z = TimeZone.CurrentTimeZone;
TimeSpan t = z.GetUtcOffset(now);
text += "/CreationDate (D:" +
now.ToString("yyyyMMddHHmmss") +
"+" + t.Hours.ToString("D2") + "'"+t.Minutes
+"')" + CRLF;
//Document Keywords____________________________________
if (Information.Keywords.Length > 0)
{
text += "/Keywords (" +
ConvertStrToPDF(Information.Keywords) + ")" + CRLF;
}
//Program that created the PDF document
if (Information.Creator.Length > 0)
{
text += "/Creator (" +
ConvertStrToPDF(Information.Creator) + ")" + CRLF;
}
//Producer of the PDF document
text += "/Producer (" + ConvertStrToPDF(ProductVersion) + ")";
//Write the info object________________________________
int newObjID = 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()
{
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="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="s">String to normalize</param>
/// <returns>Strin after normalisation</returns>
private string ConvertStrToPDF(string s)
{ //convert "\", "(", and ")" to "\x".
string tmp=s;
tmp.Replace(@"\", @"\\");
tmp.Replace(@"(", @"\(");
tmp.Replace(@")", @"\)");
tmp.Replace("\r", @"\r");
tmp.Replace("\n", @"\n");
return tmp;
}
/// <summary>Create colour</summary>
/// <param name="c">colour to use</param>
/// <param name="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)==0)
{
if (m_IsBlack) {
colorstr = ""; //Conserve file size: need not
repeat last color
} else {
m_IsBlack=true;
colorstr = ((f)? "0 G":"0 g") + CRLF;
}
}
else
{
m_IsBlack=false;
colorstr = String.Format("{0,4} {1,4} {2,4} {3}",
((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=GetNewObjID();
int pgHeight = PAGE_DIMENSIONS[(int)m_PageSize,1];
string widthstr = "";
string colorstr= PDFColour(clr,true);
if (thickness > 1) {widthstr = thickness.ToString() + " w" +
CRLF;}
string stylestr=PDFLineStyle(style);
PDFWriteStreamObj(objId,"",
colorstr+
widthstr + stylestr +
fromX.ToString() + " " +
(pgHeight-fromY).ToString() +" m" + CRLF +
toX.ToString() + " " +
(pgHeight-toY).ToString() + " l" + CRLF +
"s" + CRLF
);//PDFWriteObj
if (m_PageContents.Length > 0)
{
m_PageContents += " ";
}
m_PageContents += PDFObjRef(objId);
}
/// <summary>Sets line style</summary>
/// <returns>String to be written in PDF file</returns>
private string PDFLineStyle(LineStyles style)
{ //Adobe Specification, Paragraph 8.3
string stylestr="";
switch(style)
{
case LineStyles.Dots:
m_IsSolid=false;
stylestr="[1 2] 0 d" + CRLF; //1 on 2 off
break;
case LineStyles.Dash:
m_IsSolid=false;
//Adobe's spec has example of [3 3] as 3 on, 3
off, but that displays
//almost solid - had to make [3 5] or [3 6] to
get decent spaces in-between.
stylestr="[3 5] 0 d" + CRLF;
break;
//Adobe spec seems not to allow for dash-dot, etc
default:
if (m_IsSolid) {
stylestr=""; //save file size: need
not repeat for each line
} else {
m_IsSolid=true;
stylestr="[4 0] 0 d" + CRLF;
}
break;
}
return stylestr;
}
/// <summary>Create a fill pattern object.</summary>
/// <param name="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 = (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
}
else //Add the pattern object to the file
{
objId=GetNewObjID();
//int procSetId = GetNewObjID();
//PDFWriteObj(procSetId,true,"/ProcSet [/PDF] ");
//Create a ProcSet for the pattern
string ObjectText =
"/Type /Pattern" + CRLF +
"/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
//Now we define the pattern in the stream part of the
object
string PatternStr="";
switch (pattern)
{
case FillPatterns.VertLines:
ObjectText +=
"/BBox [0 0 7 8]" + CRLF +
//Pattern bounding box Spec Example 7.33
"/XStep 8" +
CRLF + //Note This is differrent between Example
"/YStep 7";
//7.33 and 7.32 [Bitmap vs vector-drawn]
PatternStr = "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 +=
"/BBox [0 0 8 7]" + CRLF +
//Pattern bounding box Spec Example 7.33
"/XStep 7" +
CRLF + //Note This is differrent between Example
"/YStep 8";
//7.33 and 7.32 [Bitmap vs vector-drawn]
PatternStr= "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";
break;
case FillPatterns.CrossLines:
ObjectText +=
"/BBox [0 0 8 8]" + CRLF +
//Pattern bounding box Spec Example 7.33
"/XStep 6" +
CRLF + //Note This is differrent between Example
"/YStep 6";
//7.33 and 7.32 [Bitmap vs vector-drawn]
PatternStr= "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;
case FillPatterns.DiagFwLines:
ObjectText +=
"/BBox [0 0 5 5]" + CRLF +
//Pattern bounding box Spec Example 7.33
"/XStep 5" +
CRLF + //Note This is differrent between Example
"/YStep 5";
//7.33 and 7.32 [Bitmap vs vector-drawn]
PatternStr= "0 0 m" + CRLF + "5 5
l" + CRLF + "s" + CRLF +
"-3 3 m"
+ CRLF + "3 -3 l" + CRLF + "s";
break;
case FillPatterns.DiagBwLines:
ObjectText +=
"/BBox [0 0 5 5]" + CRLF +
//Pattern bounding box Spec Example 7.33
"/XStep 5" +
CRLF + //Note This is differrent between Example
"/YStep 5";
//7.33 and 7.32 [Bitmap vs vector-drawn]
PatternStr= "0 5 m" + CRLF + "5 0
l" + CRLF + "s" + CRLF +
"3 -3 m"
+ CRLF + "-3 3 l" + CRLF + "s";
break;
case FillPatterns.DiagCrossLines:
ObjectText +=
"/BBox [0 0 5 5]" + CRLF +
//Pattern bounding box Spec Example 7.33
"/XStep 5" +
CRLF + //Note This is differrent between Example
"/YStep 5";
//7.33 and 7.32 [Bitmap vs vector-drawn]
PatternStr=
"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;
case FillPatterns.Solid:
throw new
ArgumentOutOfRangeException("pattern");
}
string StreamText = PatternStr + CRLF;
PDFWriteStreamObj(objId,ObjectText,StreamText);
m_Patterns[(int) pattern] = objId;
AddPatternToProcSet(objId,(int)pattern); //Ensure it
is in current page's resources
return objId;
}
}
private void AddPatternToProcSet(int objId,int pattern)
{
string patternName = "/P" + pattern.ToString();
if (m_PageProcSetPatterns.IndexOf(patternName) < 0)
{
if (m_PageProcSetPatterns.Length > 0)
{
m_PageProcSetPatterns += " ";
}
m_PageProcSetPatterns += patternName + " " +
PDFObjRef(objId);
}
}
#endregion Private functions/Methods
#region Private data members
private System.IO.Stream PDFOutStream; // Stream in which the PDF
output is sent
private System.IO.StreamWriter PDFWriter;
private ArrayList xrefTable;
private string m_PageObjRefs="";
private int m_StartXOffs = 0;
private int m_LastObjId =0;
private int m_PagesObjId=0;
private int m_Offset;
private bool m_IsBlack=true; //True if we do not
need to repeat black colour
private bool m_IsSolid=true; //True if Solid line -
need not repeat for each line
private ArrayList m_Patterns; //List of ObjetID's,
Array index = FillPatterns enum
private Hashtable m_Fonts=null; //List of all
fonts used in the document
//Create a separate Page class for te following?
private string m_PageContents="";
private string m_PageProcSetPatterns="";
private bool m_IsFirstPage=true;
private int m_PagesCount=0; //Number of pages in
document
private string m_PageFonts=""; //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
{
/// <summary>
/// Title of the document. PDF files have an info object where the
/// document's title can be saved.
/// </summary>
public string Title
{
get {return m_Title; }
set {m_Title = value; }
}
private string m_Title;
/// <summary>
/// Subject of the document. PDF files have an info object where the
/// document's subject can be saved.
/// </summary>
public string Subject
{
get {return m_Subject; }
set {m_Subject = value; }
}
private string m_Subject;
/// <summary>
/// Name of document author. PDF files have an info object where the
/// name of the document's author can be saved.
/// </summary>
public string AuthorName
{
get {return m_AuthorName; }
set {m_AuthorName = value; }
}
private string m_AuthorName;
/// <summary>
/// Keywords for the document. PDF files have an info object where the
/// keywords can be saved.
/// </summary>
public string Keywords
{
get {return m_Keywords; }
set {m_Keywords = value; }
}
private string m_Keywords;
/// <summary>
/// Creator of the document. PDF files have an info object where the
/// program name that created the document can be saved.
/// </summary>
public string Creator
{
get {return m_Creator; }
set {m_Creator = value; }
}
private string m_Creator;
}
/// <summary>
/// Interface to export the report
/// </summary>
public abstract class IExportInterface
{
#region properties
public DocInfo Information;
///<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
/// changing this property will be in the new size,
/// 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 = value;}
}
protected PageSizes m_PageSize=PageSizes.pgA4;
/// <summary>
/// File name to use when saving the document to a file
/// </summary>
public string FileName
{
get{return m_FileName; }
set{m_FileName=value;}
}
protected string m_FileName="";
#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
/// 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="filename">File to which we must export</param>
public void BeginExport(string filename)
{
m_FileName = filename;
System.IO.FileInfo fi = new FileInfo(filename);
m_fileFull=fi.FullName.Substring(0,fi.FullName.LastIndexOf('.'));
m_fileBase=fi.Name.Substring(0,fi.Name.LastIndexOf('.'));
m_fileExt =fi.Extension; //extension part of file name
CreateFileStream(filename);
OnStartDoc();
}
/// <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
/// also creates a stream for file output.
/// This function can be implemented to create a
System.IO.BinaryWriter
/// 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 = new FileInfo(filename);
/// if (fi.Exists) {fi.Delete();}
/// MyStream = new System.IO.FileStream(filename,FileMode.CreateNew);
/// BeginExport();
/// }
/// public override void BeginExport(System.IO.Stream stream)
/// {
/// MyStream = stream;
/// BeginExport();
/// }
/// private void BeginExport()
/// {
/// MyWriter = new System.IO.BinaryWriter(MyStream);
/// MyWriter.Write("Hello World".ToCharArray());
/// } //The EndExport function will close both the writer and the
stream.
/// </code>
/// <param name="stream">Stream to which we must export</param>
public void BeginExport(System.IO.Stream stream)
{
m_fileFull=""; //name of path+file but no extension
m_fileBase=""; //name of file with no extension
m_fileExt =""; //extension part of file name
DocOutStream = stream;
DocWriter = new
System.IO.StreamWriter(DocOutStream,System.Text.Encoding.ASCII);
OnStartDoc();
}
/// <summary>
/// Create a new Page in the export.
/// </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
/// after changing PageSize will be in the new size,
/// 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();
}
#region WriteText
///<summary>Write text on the current page. Font style is
regular.</summary>
/// <param name="text">text to be written</param>
/// <param name="left">Position in pixels from left edge of
page</param>
/// <param name="top">Position in pixels from top edge of page</param>
/// <param name="fontName">Name of font to use</param>
/// <param name="fontsize">Font Size of text</param>
public void WriteText(string text,int left, int top,string
fontName,int fontsize)
{
SBReport.Font font = new SBReport.Font(fontName,fontsize);
WriteText(text,left,top,font);
}
///<summary>Write text on the current page. Font style is
regular.</summary>
/// <param name="text">text to be written</param>
/// <param name="left">Position in pixels from left edge of
page</param>
/// <param name="top">Position in pixels from top edge of page</param>
/// <param name="font">Defines the font to be used</param>
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="fromX">Start position in pixels from left edge of
page</param>
/// <param name="fromY">Start position in pixels from top edge of
page</param>
/// <param name="length">Width of the line measured in pixels
(difference between line left and right)</param>
public void DrawHLine(int fromX, int fromY,int length)
{
LineStyles style = SBReport.Export.LineStyles.Solid;
SBReport.RptColour clr = 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="fromX">Start position in pixels from left edge of
page</param>
/// <param name="fromY">Start position in pixels from top edge of
page</param>
/// <param name="length">Width of the line measured in pixels
(difference between line left and right)</param>
/// <param name="style">Solid, Dashed, etc</param>
/// <param name="thickness">Line width</param>
public void DrawHLine(int fromX, int fromY,int length,
LineStyles style,int thickness)
{
SBReport.RptColour clr = new RptColour(0,0,0); //Black
DrawHLine(fromX,fromY,length,style,thickness,clr);
}
///<summary>Draw colour line of specified width and style on the
current page.</summary>
/// <param name="fromX">Start position in pixels from left edge of
page</param>
/// <param name="fromY">Start position in pixels from top edge of
page</param>
/// <param name="length">Width of the line measured in pixels
(difference between line left and right)</param>
/// <param name="LineStyles">Solid, Dashed, etc</param>
/// <param name="style">Solid, dotted, etc</param>
/// <param name="thickness">Line width measured in pixels</param>
/// <param name="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="fromX">Start position in pixels from left edge of
page</param>
/// <param name="fromY">Start position in pixels from top edge of
page</param>
/// <param name="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 = SBReport.Export.LineStyles.Solid;
SBReport.RptColour clr = 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="fromX">Start position in pixels from left edge of
page</param>
/// <param name="fromY">Start position in pixels from top edge of
page</param>
/// <param name="length">Height of the line measured in pixels
(difference between line top and bottom)</param>
/// <param name="style">Solid, Dashed, etc</param>
/// <param name="thickness">Line width</param>
public void DrawVLine(int fromX, int fromY,int length,
LineStyles style,int thickness)
{
SBReport.RptColour clr = new RptColour(0,0,0); //Black
DrawVLine(fromX,fromY,length,style,thickness,clr);
}
///<summary>Draw colour line of specified width and style on the
current page.</summary>
/// <param name="fromX">Start position in pixels from left edge of
page</param>
/// <param name="fromY">Start position in pixels from top edge of
page</param>
/// <param name="length">Height of the line measured in pixels
(difference between line top and bottom)</param>
/// <param name="LineStyles">Solid, Dashed, etc</param>
/// <param name="style">Solid, dotted, etc</param>
/// <param name="thickness">Line width measured in pixels</param>
/// <param name="clr">Line colour</param>
abstract public void DrawVLine(int fromX, int fromY,int length,
LineStyles style,int thickness, RptColour clr );
#endregion DrawVLine
#region DrawRectangle
///<summary>Draw solid black rectanle of width 1 on the current page.
//////The rectangle is not filled (transparent).
///</summary>
/// <param name="left">Start position in pixels from left edge of
page</param>
/// <param name="top">Start position in pixels from top edge of
page</param>
/// <param name="width">Distance in pixels from left edge to right
edge of rectangle</param>
/// <param name="height">Distance in pixels from top edge to bottom
edge of rectangle</param>
public void DrawRectangle(int left, int top,int width, int height)
{
RptColour C=new RptColour(); //Black
DrawRectangle(left,top,width,height,LineStyles.Solid,1,C,null,FillPatterns.Solid);
}
///<summary>Draw black rectangle of specified width and style on the
current page.
///The rectangle is not filled (transparent).
///</summary>
/// <param name="left">Start position in pixels from left edge of
page</param>
/// <param name="top">Start position in pixels from top edge of
page</param>
/// <param name="width">Distance in pixels from left edge to right
edge of rectangle</param>
/// <param name="height">Distance in pixels from top edge to bottom
edge of rectangle</param>
/// <param name="style">Solid, Dashed, etc</param>
/// <param name="thickness">Line width</param>
public void DrawRectangle(int left, int top,int width, int height,
LineStyles style,int thickness)
{
RptColour C=new RptColour(); //Black
DrawRectangle(left,top,width,height,style,thickness,C,null,
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
///not null, it is filled with a solid fill type of the specified
colour.
///</summary>
/// <param name="left">Start position in pixels from left edge of
page</param>
/// <param name="top">Start position in pixels from top edge of
page</param>
/// <param name="width">Distance in pixels from left edge to right
edge of rectangle</param>
/// <param name="height">Distance in pixels from top edge to bottom
edge of rectangle</param>
/// <param name="LineStyles">Solid, Dashed, etc</param>
/// <param name="style">Solid, dotted, etc</param>
/// <param name="thickness">Line width measured in pixels</param>
/// <param name="lineClr">Line colour</param>
/// <param name="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
///not null, it is filled with the specified pattern in the specified
colour.
///</summary>
/// <param name="left">Start position in pixels from left edge of
page</param>
/// <param name="top">Start position in pixels from top edge of
page</param>
/// <param name="width">Distance in pixels from left edge to right
edge of rectangle</param>
/// <param name="height">Distance in pixels from top edge to bottom
edge of rectangle</param>
/// <param name="LineStyles">Solid, Dashed, etc</param>
/// <param name="style">Solid, dotted, etc</param>
/// <param name="thickness">Line width measured in pixels</param>
/// <param name="lineClr">Line colour</param>
/// <param name="fillClr">Fill colour. Pass null for no fill.</param>
/// <param name="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();
/// <summary>Output the data to the file or stream</summary>
/// <param name="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="fileName">File name to create</param>
protected void CreateFileStream(string fileName)
{
System.IO.FileInfo fi = new FileInfo(fileName);
if (fi.Exists) {fi.Delete();}
DocOutStream = new
System.IO.FileStream(fileName,System.IO.FileMode.CreateNew);
DocWriter = 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="fileName">File name to create</param>
protected void CloseStream()
{
DocWriter.Close();
DocOutStream.Close();
}
protected const string CRLF = "\r\n";
protected const string ProductVersion = "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={
//PgWidth PgHeight [Pixels]
{612, 792}, //A4
{612, 792} //Letter
};
protected string m_fileFull=""; //name of path+file but no extension
protected string m_fileBase=""; //name of file with no extension
protected string m_fileExt =""; //extension part of file name
#endregion protected properties
}
}
_______________________________________________
Mono-list maillist - [EMAIL PROTECTED]
http://lists.ximian.com/mailman/listinfo/mono-list