using FastReport.Utils;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows.Forms;
namespace FastReport.Export.Odf
{
///
/// Base class for any ODF exports.
///
public partial class ODFExport : ExportBase
{
#region Constants
private const float odfDivider = 37.82f;
private const float odfMargDiv = 10f;
private const float odfPageDiv = 10f;
#endregion Constants
///
/// Enum of OpenOffice formats.
///
public enum OpenOfficeFormat
{
///
/// OpenOffice Spreadsheet format.
///
Spreadsheet,
///
/// OpenOffice Writer format.
///
Writer
}
///
/// Standard of ODF format.
///
public enum OdfStandard
{
///
/// ODF 1.0/1.1
///
None = 0,
///
/// ODF 1.2
///
Odf1_2 = 1,
///
/// XODF 1.0/1.1
///
Xodf1_1 = 2,
///
/// XODF 1.2
///
Xodf1_2 = 3
}
#region Private fields
private string creator;
private OpenOfficeFormat exportType;
private bool firstPage;
private ExportMatrix matrix;
private float pageBottom;
private bool pageBreaks;
private float pageHeight;
private bool pageLandscape;
private float pageLeft;
private float pageRight;
private float pageTop;
private float pageWidth;
private bool wysiwyg;
private OdfStandard odfCompliance = OdfStandard.None;
private bool isXODT = false;
private bool useTagText = false;
private bool writeVersion = false;
private bool extendedStyles = false;
private bool writeRdf = false;
private CultureInfo localization;
private bool exportLocale;
#endregion Private fields
#region Properties
///
/// Creator of the document
///
public string Creator
{
get { return creator; }
set { creator = value; }
}
///
/// Is XODT format
///
public bool IsXOTD
{
get { return isXODT; }
set { isXODT = value; }
}
///
/// Switch of page breaks
///
public bool PageBreaks
{
get { return pageBreaks; }
set { pageBreaks = value; }
}
///
/// Wysiwyg mode, set for better results
///
public bool Wysiwyg
{
get { return wysiwyg; }
set { wysiwyg = value; }
}
///
/// Gets or sets locale for all document.
///
public CultureInfo Locale
{
get { return localization; }
set { localization = value; }
}
///
/// Gets or sets a value indicating that locale export are enabled.
///
public bool ExportLocale
{
get { return exportLocale; }
set { exportLocale = value; }
}
internal OpenOfficeFormat ExportType
{
get { return exportType; }
set { exportType = value; }
}
///
/// Gets or sets ODF Compliance standard.
///
public OdfStandard OdfCompliance
{
get
{
return odfCompliance;
}
set
{
odfCompliance = value;
switch (odfCompliance)
{
case OdfStandard.Xodf1_1:
useTagText = true;
isXODT = true;
writeVersion = false;
extendedStyles = false;
writeRdf = false;
break;
case OdfStandard.None:
writeVersion = false;
extendedStyles = false;
writeRdf = false;
break;
case OdfStandard.Xodf1_2:
useTagText = true;
isXODT = true;
writeVersion = true;
extendedStyles = true;
writeRdf = true;
break;
case OdfStandard.Odf1_2:
writeVersion = true;
extendedStyles = true;
writeRdf = true;
break;
}
}
}
#endregion Properties
#region Private Methods
private string GetOdfVersion()
{
switch (OdfCompliance)
{
case OdfStandard.Xodf1_2:
case OdfStandard.Odf1_2:
return "1.2";
case OdfStandard.Xodf1_1:
case OdfStandard.None:
default:
return "1.0";
}
}
private int ExportCell(Stream file, ZipArchive zip, ExportIEMObject obj, int dx, int dy, ref int picCount)
{
Write(file, String.Format(" 1 || dy > 1)
{
Write(file, String.Format("table:number-columns-spanned=\"{0}\" ", dx.ToString()));
Write(file, String.Format("table:number-rows-spanned=\"{0}\" ", dy.ToString()));
}
WriteLine(file, ">");
if (obj.IsText)
{
// text
ExportText(file, obj);
}
else if (obj.Width > 0)
{
// picture
ExportPicture(file, zip, obj, ++picCount);
}
WriteLine(file, "");
return picCount;
}
private void ExportODF(Stream stream)
{
ZipArchive zip = new ZipArchive();
string ExportMime = exportType == OpenOfficeFormat.Spreadsheet ? "spreadsheet" : "text";
OdfCreateMime(zip, "mimetype", ExportMime);
OdfMakeDocStyles(zip, "styles.xml");
#region Content.xml
MemoryStream file = new MemoryStream();
WriteLine(file, "");
Write(file, "");
WriteLine(file, "");
OdfFontFaceDecals(file);
OdfAutomaticStyles(file);
// body
WriteLine(file, "");
if (!useTagText)
WriteLine(file, "");
else
WriteLine(file, "");
TableBegin(file, 1);
// rows
int picCount = OdfRows(file, zip);
TableEnd(file);
if (!useTagText)
WriteLine(file, "");
else
WriteLine(file, "");
WriteLine(file, "");
WriteLine(file, "");
zip.AddStream("content.xml", file);
#endregion Content.xml
OdfCreateManifest(zip, "META-INF/manifest.xml", picCount, ExportMime);
OdfCreateMeta(zip, "meta.xml", Creator);
if (writeRdf) OdfCreateRDF(zip, "manifest.rdf");
zip.SaveToStream(Stream);
zip.Clear();
}
private void ExportPicture(Stream file, ZipArchive zip, ExportIEMObject obj, int picCount)
{
string picName = picCount.ToString() + ".png";
zip.AddStream("Pictures/Pic" + picName, obj.PictureStream);
if (exportType == OpenOfficeFormat.Writer)
Write(file, "");
Write(file,
String.Format("",
(picCount - 1).ToString(),
picCount.ToString(),
GetStringValue(obj.Width),
GetStringValue(obj.Height)
));
Write(file,
String.Format("",
picName
));
Write(file, "");
if (exportType == OpenOfficeFormat.Writer)
WriteLine(file, "");
}
private void ExportText(Stream file, ExportIEMObject obj)
{
Write(file, "");
WriteLine(file,
String.Format("{0}",
ExportUtils.OdtString(obj.Text, obj.TextRenderType)));
}
private string GetBorderLineStyle(BorderLine line, string name)
{
return String.Format("fo:border-{0}=\"{1}cm {2} {3}\" ",
name,
GetStringValue(line.Width),
OdfGetFrameName(line.Style),
ExportUtils.HTMLColorCode(line.Color));
}
private string GetStringValue(float value)
{
return ExportUtils.FloatToString(value / odfDivider);
}
private void HorizAlignStyle(Stream file, HorzAlign hAlign)
{
if (hAlign == HorzAlign.Left)
Write(file, "fo:text-align=\"start\" ");
else if (hAlign == HorzAlign.Center)
Write(file, "fo:text-align=\"center\" ");
else if (hAlign == HorzAlign.Right)
Write(file, "fo:text-align=\"end\" ");
else if (hAlign == HorzAlign.Justify)
Write(file, "fo:text-align=\"justify\" ");
}
private void MarginStyle(Stream file, Padding padding)
{
if (padding.Left > 0)
Write(file,
String.Format("fo:margin-left=\"{0}cm\" ",
GetStringValue(padding.Left)));
if (padding.Right > 0)
Write(file,
String.Format("fo:margin-right=\"{0}cm\" ",
GetStringValue(padding.Right)));
if (padding.Top > 0)
Write(file,
String.Format("fo:margin-top=\"{0}cm\" ",
GetStringValue(padding.Top)));
if (padding.Bottom > 0)
Write(file,
String.Format("fo:margin-bottom=\"{0}cm\" ",
GetStringValue(padding.Bottom)));
}
private void OdfAutomaticStyles(Stream file)
{
WriteLine(file, "");
OdfColumnStyles(file);
OdfRowStyles(file);
OdfStyles(file);
if (exportType == OpenOfficeFormat.Writer)
{
WriterStyles(file);
}
WriteLine(file, "");
Write(file, "");
WriteLine(file, "");
WriteLine(file, "");
}
private void OdfColumns(Stream file)
{
for (int x = 1; x < matrix.Width; x++)
WriteLine(file,
String.Format("",
GetStringValue((matrix.XPosById(x) - matrix.XPosById(x - 1)))
));
}
private void OdfColumnStyles(Stream file)
{
List fList = new List();
for (int i = 1; i < matrix.Width; i++)
{
string s = GetStringValue((matrix.XPosById(i) - matrix.XPosById(i - 1)));
if (fList.IndexOf(s) == -1)
fList.Add(s);
}
fList.Sort();
for (int i = 0; i < fList.Count; i++)
{
WriteLine(file,
String.Format(
"",
fList[i]
));
WriteLine(file,
String.Format(
"",
fList[i]));
}
}
private void OdfCreateManifest(ZipArchive zip, string fileName, int PicCount, string MValue)
{
MemoryStream file = new MemoryStream();
WriteLine(file, "");
Write(file, "");
WriteLine(file, String.Format(" ", MValue));
WriteLine(file, " ");
WriteLine(file, " ");
if (writeRdf) WriteLine(file, " ");
WriteLine(file, " ");
for (int i = 1; i <= PicCount; i++)
WriteLine(file, String.Format(" ", i.ToString()));
WriteLine(file, "");
zip.AddStream(fileName, file);
}
private void OdfCreateMeta(ZipArchive zip, string fileName, string Creator)
{
StringBuilder sb = new StringBuilder(570);
sb.AppendLine("");
sb.Append("");
sb.AppendLine(" ");
sb.Append(" fast-report.com/Fast Report.NET/build:").Append(Config.Version).AppendLine("");
sb.Append(" ").Append(ExportUtils.XmlString(Creator, TextRenderType.Default)).AppendLine("");
sb.Append(" ").Append(SystemFake.DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss")).AppendLine("");
sb.AppendLine(" ");
sb.AppendLine("");
MemoryStream file = new MemoryStream();
Write(file, sb.ToString());
zip.AddStream(fileName, file);
}
private void OdfCreateRDF(ZipArchive zip, string fileName)
{
MemoryStream file = new MemoryStream();
WriteLine(file, "");
WriteLine(file, "");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, " ");
WriteLine(file, "");
zip.AddStream(fileName, file);
}
private void OdfCreateMime(ZipArchive zip, string fileName, string MValue)
{
MemoryStream file = new MemoryStream();
Write(file, String.Concat("application/vnd.oasis.opendocument.", MValue));
zip.AddStream(fileName, file);
}
private void OdfFontFaceDecals(Stream file)
{
List fList = new List();
for (int i = 0; i < matrix.StylesCount; i++)
{
ExportIEMStyle style = matrix.StyleById(i);
if ((style.Font != null) && (fList.IndexOf(style.Font.Name) == -1))
fList.Add(style.Font.Name);
}
WriteLine(file, "");
fList.Sort();
for (int i = 0; i < fList.Count; i++)
{
WriteLine(file,
String.Format(
"",
fList[i]
));
}
WriteLine(file, "");
}
private string OdfGetFrameName(LineStyle style)
{
switch (style)
{
case LineStyle.Dash:
case LineStyle.DashDot:
case LineStyle.DashDotDot:
case LineStyle.Dot:
return "solid";
case LineStyle.Double:
return "double";
default:
return "solid";
}
}
private void OdfMakeDocStyles(ZipArchive zip, string fileName)
{
MemoryStream file = new MemoryStream();
WriteLine(file, "");
Write(file, "");
WriteLine(file, "");
WriteLine(file, "");
WriteLine(file,
String.Format("",
ExportUtils.FloatToString(pageWidth / odfPageDiv),
ExportUtils.FloatToString(pageHeight / odfPageDiv),
ExportUtils.FloatToString(pageTop / odfMargDiv),
ExportUtils.FloatToString(pageBottom / odfMargDiv),
ExportUtils.FloatToString(pageLeft / odfMargDiv),
ExportUtils.FloatToString(pageRight / odfMargDiv)
));
WriteLine(file, "");
WriteLine(file, "");
WriteLine(file, "");
WriteLine(file, "");
WriteLine(file, "");
WriteLine(file, "");
WriteLine(file, "");
zip.AddStream(fileName, file);
}
private string OdfMakeXmlHeader()
{
return " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\"" +
" xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\"" +
" xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\"" +
" xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\"" +
" xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\"" +
" xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\"" +
" xmlns:xlink=\"http://www.w3.org/1999/xlink\"" +
" xmlns:dc=\"http://purl.org/dc/elements/1.1/\"" +
" xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\"" +
" xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\"" +
" xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\"" +
" xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\"" +
" xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\"" +
" xmlns:math=\"http://www.w3.org/1998/Math/MathML\"" +
" xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\"" +
" xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\"" +
" xmlns:dom=\"http://www.w3.org/2001/xml-events\"" +
" xmlns:xforms=\"http://www.w3.org/2002/xforms\"" +
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"";
}
private int OdfRows(Stream file, ZipArchive zip)
{
int picCount = 0;
int page = 0;
for (int y = 0; y < matrix.Height - 1; y++)
{
string pageB = String.Empty;
if ((pageBreaks) && (matrix.YPosById(y) >= matrix.PageBreak(page)))
{
page++;
pageB = "pb";
TableEnd(file);
TableBegin(file, page + 1);
}
WriteLine(file,
String.Format("",
GetStringValue((matrix.YPosById(y + 1) - matrix.YPosById(y))),
pageB));
for (int x = 0; x < matrix.Width - 1; x++)
{
int i = matrix.Cell(x, y);
if (i != -1)
{
ExportIEMObject obj = matrix.ObjectById(i);
if (obj.Counter == 0)
{
obj.Counter = 1;
int fx, fy, dx, dy;
matrix.ObjectPos(i, out fx, out fy, out dx, out dy);
ExportCell(file, zip, obj, dx, dy, ref picCount);
}
else
{
Write(file, "");
}
}
else
{
Write(file, "");
else
WriteLine(file, "/>");
}
}
WriteLine(file, "");
}
return picCount;
}
private void OdfRowStyles(Stream file)
{
List> positions = new List>();
int page = 0;
for (int i = 0; i < matrix.Height - 1; i++)
{
bool breakValue = false;
if ((pageBreaks) && (matrix.YPosById(i) >= matrix.PageBreak(page)))
{
page++;
breakValue = true;
}
KeyValuePair value =
new KeyValuePair(matrix.YPosById(i + 1) - matrix.YPosById(i), breakValue);
if (positions.IndexOf(value) == -1)
{
positions.Add(value);
}
}
for (int i = 0; i < positions.Count; i++)
{
string rowPos = GetStringValue(positions[i].Key);
string pageB = positions[i].Value ? "pb" : String.Empty;
WriteLine(file,
String.Format(
"",
rowPos,
pageB));
string pageAuto = positions[i].Value ? "page" : "auto";
WriteLine(file,
String.Format(
"",
pageAuto,
rowPos));
WriteLine(file, "");
}
WriteLine(file, "");
WriteLine(file, "");
WriteLine(file, "");
WriteLine(file, "");
}
private void OdfStyles(Stream file)
{
for (int i = 0; i < matrix.StylesCount; i++)
{
ExportIEMStyle style = matrix.StyleById(i);
WriteLine(file,
String.Format("",
i.ToString()));
OdfTableCellStyles(file, style);
if (exportType == OpenOfficeFormat.Spreadsheet)
{
ParagraphStyle(file, style);
TextPropertiesStyle(file, style);
}
WriteLine(file, "");
}
}
private void OdfTableCellStyles(Stream file, ExportIEMStyle style)
{
Write(file,
String.Format(" 0)
{
Write(file,
String.Format("style:rotation-angle=\"{0}\" style:rotation-align=\"none\" ",
(360 - style.Angle).ToString()));
}
if (style.VAlign == VertAlign.Center)
Write(file, "style:vertical-align=\"middle\" ");
if (style.VAlign == VertAlign.Top)
Write(file, "style:vertical-align=\"top\" ");
if (style.VAlign == VertAlign.Bottom)
Write(file, "style:vertical-align=\"bottom\" ");
if ((style.Border.Lines & BorderLines.Left) > 0)
Write(file, GetBorderLineStyle(style.Border.LeftLine, "left"));
if ((style.Border.Lines & BorderLines.Right) > 0)
Write(file, GetBorderLineStyle(style.Border.RightLine, "right"));
if ((style.Border.Lines & BorderLines.Top) > 0)
Write(file, GetBorderLineStyle(style.Border.TopLine, "top"));
if ((style.Border.Lines & BorderLines.Bottom) > 0)
Write(file, GetBorderLineStyle(style.Border.BottomLine, "bottom"));
Write(file, "/>");
}
private void ParagraphStyle(Stream file, ExportIEMStyle style)
{
Write(file, "");
}
private void TableBegin(Stream file, int tableNumber)
{
// table
WriteLine(file,
String.Format("", tableNumber));
// columns
OdfColumns(file);
}
private void TableEnd(Stream file)
{
WriteLine(file, "");
}
private void TextPropertiesStyle(Stream file, ExportIEMStyle style)
{
Write(file,
String.Format(" 0)
Write(file, " style:text-underline-style=\"solid\" " +
"style:text-underline-width=\"auto\" " +
"style:text-underline-color=\"font-color\" ");
if ((style.Font.Style & FontStyle.Italic) > 0)
Write(file, " style:font-style=\"italic\" ");
if ((style.Font.Style & FontStyle.Bold) > 0)
Write(file,
" fo:font-weight=\"bold\" style:font-weight-asian=\"bold\" style:font-weight-complex=\"bold\"");
WriteLine(file, String.Format(" fo:color=\"{0}\"/>",
ExportUtils.HTMLColorCode(style.TextColor)));
}
private void Write(Stream stream, string value)
{
byte[] buf = Encoding.UTF8.GetBytes(value);
stream.Write(buf, 0, buf.Length);
}
private void WriteLine(Stream stream, string value)
{
byte[] buf = Encoding.UTF8.GetBytes(value);
stream.Write(buf, 0, buf.Length);
stream.WriteByte(13);
stream.WriteByte(10);
}
private void WriterStyles(Stream file)
{
for (int i = 0; i < matrix.StylesCount; i++)
{
ExportIEMStyle style = matrix.StyleById(i);
WriteLine(file,
String.Format("",
i.ToString()));
ParagraphStyle(file, style);
TextPropertiesStyle(file, style);
WriteLine(file, "");
}
}
#endregion Private Methods
#region Protected Methods
///
protected override void ExportBand(BandBase band)
{
base.ExportBand(band);
matrix.AddBand(band, this);
}
///
protected override void ExportPageBegin(ReportPage page)
{
base.ExportPageBegin(page);
matrix.AddPageBegin(page);
}
///
protected override void ExportPageEnd(ReportPage page)
{
matrix.AddPageEnd(page);
if (firstPage)
{
pageBottom = page.BottomMargin;
pageLeft = page.LeftMargin;
pageRight = page.RightMargin;
pageTop = page.TopMargin;
pageWidth = ExportUtils.GetPageWidth(page);
pageHeight = ExportUtils.GetPageHeight(page);
pageLandscape = page.Landscape;
firstPage = false;
}
}
///
protected override void Finish()
{
matrix.Prepare();
ExportODF(Stream);
}
///
protected override void Start()
{
base.Start();
matrix = new ExportMatrix();
if (wysiwyg)
matrix.Inaccuracy = 0.5f;
else
matrix.Inaccuracy = 10;
matrix.RotatedAsImage = true;
matrix.PlainRich = true;
matrix.AreaFill = true;
matrix.Report = Report;
matrix.MaxCellHeight = 400;
matrix.Images = true;
matrix.ImageFormat = ImageFormat.Png;
matrix.ShowProgress = ShowProgress;
firstPage = true;
}
#endregion Protected Methods
#region Public Constructors
///
/// Initializes a new instance of the class.
///
public ODFExport()
{
exportType = OpenOfficeFormat.Spreadsheet;
ExportLocale = false;
pageBreaks = true;
wysiwyg = true;
creator = "FastReport .NET";
}
#endregion Public Constructors
#region Public Methods
///
public override void Serialize(FRWriter writer)
{
base.Serialize(writer);
writer.WriteBool("Wysiwyg", Wysiwyg);
writer.WriteBool("PageBreaks", PageBreaks);
writer.WriteBool("ExportLocale", ExportLocale);
writer.WriteValue("Locale", Locale);
}
#endregion Public Methods
}
///
/// Open Document Spreadsheet export (Open Office Calc).
///
public class ODSExport : ODFExport
{
#region Public Constructors
///
/// Initializes a new instance of the class.
///
public ODSExport()
{
ExportType = OpenOfficeFormat.Spreadsheet;
}
#endregion Public Constructors
#region Protected Methods
///
protected override string GetFileFilter()
{
if (IsXOTD)
return new MyRes("FileFilters").Get("XodsFile");
return new MyRes("FileFilters").Get("OdsFile");
}
#endregion Protected Methods
}
///
/// Open Document Text export (Open Office Writer).
///
public class ODTExport : ODFExport
{
#region Public Constructors
///
/// Initializes a new instance of the class.
///
public ODTExport()
{
ExportType = OpenOfficeFormat.Writer;
}
#endregion Public Constructors
#region Protected Methods
///
protected override string GetFileFilter()
{
if (IsXOTD)
return new MyRes("FileFilters").Get("XodtFile");
return new MyRes("FileFilters").Get("OdtFile");
}
#endregion Protected Methods
}
}