using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Windows.Forms; using System.Xml; namespace Pur.PublicTools { class publicRTF { //class RtfToHtmlConverter //{ // private const string FlowDocumentFormat = "{0}"; // public static string ConvertRtfToHtml(string rtfText) // { // var xamlText = string.Format(FlowDocumentFormat, ConvertRtfToXaml(rtfText)); // return HtmlFromXamlConverter.ConvertXamlToHtml(xamlText, false); // } // private static string ConvertRtfToXaml(string rtfText) // { // RichTextBox richTextBox = new RichTextBox(); // if (string.IsNullOrEmpty(rtfText)) return ""; // var textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd); // //Create a MemoryStream of the Rtf content // using (var rtfMemoryStream = new MemoryStream()) // { // using (var rtfStreamWriter = new StreamWriter(rtfMemoryStream)) // { // rtfStreamWriter.Write(rtfText); // rtfStreamWriter.Flush(); // rtfMemoryStream.Seek(0, SeekOrigin.Begin); // //Load the MemoryStream into TextRange ranging from start to end of RichTextBox. // textRange.Load(rtfMemoryStream, DataFormats.Rtf); // } // } // using (var rtfMemoryStream = new MemoryStream()) // { // textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd); // textRange.Save(rtfMemoryStream, DataFormats.Xaml); // rtfMemoryStream.Seek(0, SeekOrigin.Begin); // using (var rtfStreamReader = new StreamReader(rtfMemoryStream)) // { // return rtfStreamReader.ReadToEnd(); // } // } // } //} //public static class HtmlFromXamlConverter //{ // // --------------------------------------------------------------------- // // // // Internal Methods // // // // --------------------------------------------------------------------- // #region Internal Methods // /// // /// Main entry point for Xaml-to-Html converter. // /// Converts a xaml string into html string. // /// // /// // /// Xaml strinng to convert. // /// // /// // /// Html string produced from a source xaml. // /// // public static string ConvertXamlToHtml(string xamlString, bool asFullDocument) // { // XmlTextReader xamlReader; // StringBuilder htmlStringBuilder; // XmlTextWriter htmlWriter; // xamlReader = new XmlTextReader(new StringReader(xamlString)); // htmlStringBuilder = new StringBuilder(100); // htmlWriter = new XmlTextWriter(new StringWriter(htmlStringBuilder)); // if (!WriteFlowDocument(xamlReader, htmlWriter, asFullDocument)) // { // return ""; // } // string htmlString = htmlStringBuilder.ToString(); // return htmlString; // } // #endregion Internal Methods // // --------------------------------------------------------------------- // // // // Private Methods // // // // --------------------------------------------------------------------- // #region Private Methods // /// // /// Processes a root level element of XAML (normally it's FlowDocument element). // /// // /// // /// XmlTextReader for a source xaml. // /// // /// // /// XmlTextWriter producing resulting html // /// // private static bool WriteFlowDocument(XmlTextReader xamlReader, XmlTextWriter htmlWriter, bool asFullDocument) // { // if (!ReadNextToken(xamlReader)) // { // // Xaml content is empty - nothing to convert // return false; // } // if (xamlReader.NodeType != XmlNodeType.Element || xamlReader.Name != "FlowDocument") // { // // Root FlowDocument elemet is missing // return false; // } // // Create a buffer StringBuilder for collecting css properties for inline STYLE attributes // // on every element level (it will be re-initialized on every level). // StringBuilder inlineStyle = new StringBuilder(); // if (asFullDocument) // { // htmlWriter.WriteStartElement("HTML"); // htmlWriter.WriteStartElement("BODY"); // } // WriteFormattingProperties(xamlReader, htmlWriter, inlineStyle); // WriteElementContent(xamlReader, htmlWriter, inlineStyle); // if (asFullDocument) // { // htmlWriter.WriteEndElement(); // htmlWriter.WriteEndElement(); // } // return true; // } // /// // /// Reads attributes of the current xaml element and converts // /// them into appropriate html attributes or css styles. // /// // /// // /// XmlTextReader which is expected to be at XmlNodeType.Element // /// (opening element tag) position. // /// The reader will remain at the same level after function complete. // /// // /// // /// XmlTextWriter for output html, which is expected to be in // /// after WriteStartElement state. // /// // /// // /// String builder for collecting css properties for inline STYLE attribute. // /// // private static void WriteFormattingProperties(XmlTextReader xamlReader, XmlTextWriter htmlWriter, StringBuilder inlineStyle) // { // Debug.Assert(xamlReader.NodeType == XmlNodeType.Element); // // Clear string builder for the inline style // inlineStyle.Remove(0, inlineStyle.Length); // if (!xamlReader.HasAttributes) // { // return; // } // bool borderSet = false; // while (xamlReader.MoveToNextAttribute()) // { // string css = null; // switch (xamlReader.Name) // { // // Character fomatting properties // // ------------------------------ // case "Background": // css = "background-color:" + ParseXamlColor(xamlReader.Value) + ";"; // break; // case "FontFamily": // css = "font-family:" + xamlReader.Value + ";"; // break; // case "FontStyle": // css = "font-style:" + xamlReader.Value.ToLower() + ";"; // break; // case "FontWeight": // css = "font-weight:" + xamlReader.Value.ToLower() + ";"; // break; // case "FontStretch": // break; // case "FontSize": // css = "font-size:" + xamlReader.Value + ";"; // break; // case "Foreground": // css = "color:" + ParseXamlColor(xamlReader.Value) + ";"; // break; // case "TextDecorations": // if (xamlReader.Value.ToLower() == "strikethrough") // css = "text-decoration:line-through;"; // else // css = "text-decoration:underline;"; // break; // case "TextEffects": // break; // case "Emphasis": // break; // case "StandardLigatures": // break; // case "Variants": // break; // case "Capitals": // break; // case "Fraction": // break; // // Paragraph formatting properties // // ------------------------------- // case "Padding": // css = "padding:" + ParseXamlThickness(xamlReader.Value) + ";"; // break; // case "Margin": // css = "margin:" + ParseXamlThickness(xamlReader.Value) + ";"; // break; // case "BorderThickness": // css = "border-width:" + ParseXamlThickness(xamlReader.Value) + ";"; // borderSet = true; // break; // case "BorderBrush": // css = "border-color:" + ParseXamlColor(xamlReader.Value) + ";"; // borderSet = true; // break; // case "LineHeight": // break; // case "TextIndent": // css = "text-indent:" + xamlReader.Value + ";"; // break; // case "TextAlignment": // css = "text-align:" + xamlReader.Value + ";"; // break; // case "IsKeptTogether": // break; // case "IsKeptWithNext": // break; // case "ColumnBreakBefore": // break; // case "PageBreakBefore": // break; // case "FlowDirection": // break; // // Table attributes // // ---------------- // case "Width": // css = "width:" + xamlReader.Value + ";"; // break; // case "ColumnSpan": // htmlWriter.WriteAttributeString("COLSPAN", xamlReader.Value); // break; // case "RowSpan": // htmlWriter.WriteAttributeString("ROWSPAN", xamlReader.Value); // break; // // Hyperlink Attributes // case "NavigateUri": // htmlWriter.WriteAttributeString("HREF", xamlReader.Value); // break; // case "TargetName": // htmlWriter.WriteAttributeString("TARGET", xamlReader.Value); // break; // } // if (css != null) // { // inlineStyle.Append(css); // } // } // if (borderSet) // { // inlineStyle.Append("border-style:solid;mso-element:para-border-div;"); // } // // Return the xamlReader back to element level // xamlReader.MoveToElement(); // Debug.Assert(xamlReader.NodeType == XmlNodeType.Element); // } // private static string ParseXamlColor(string color) // { // if (color.StartsWith("#")) // { // // Remove transparancy value // color = "#" + color.Substring(3); // } // return color; // } // private static string ParseXamlThickness(string thickness) // { // string[] values = thickness.Split(','); // for (int i = 0; i < values.Length; i++) // { // double value; // if (double.TryParse(values[i], out value)) // { // values[i] = Math.Ceiling(value).ToString(); // } // else // { // values[i] = "1"; // } // } // string cssThickness; // switch (values.Length) // { // case 1: // cssThickness = thickness; // break; // case 2: // cssThickness = values[1] + " " + values[0]; // break; // case 4: // cssThickness = values[1] + " " + values[2] + " " + values[3] + " " + values[0]; // break; // default: // cssThickness = values[0]; // break; // } // return cssThickness; // } // /// // /// Reads a content of current xaml element, converts it // /// // /// // /// XmlTextReader which is expected to be at XmlNodeType.Element // /// (opening element tag) position. // /// // /// // /// May be null, in which case we are skipping the xaml element; // /// witout producing any output to html. // /// // /// // /// StringBuilder used for collecting css properties for inline STYLE attribute. // /// // private static void WriteElementContent(XmlTextReader xamlReader, XmlTextWriter htmlWriter, StringBuilder inlineStyle) // { // Debug.Assert(xamlReader.NodeType == XmlNodeType.Element); // bool elementContentStarted = false; // if (xamlReader.IsEmptyElement) // { // if (htmlWriter != null && !elementContentStarted && inlineStyle.Length > 0) // { // // Output STYLE attribute and clear inlineStyle buffer. // htmlWriter.WriteAttributeString("STYLE", inlineStyle.ToString()); // inlineStyle.Remove(0, inlineStyle.Length); // } // elementContentStarted = true; // } // else // { // while (ReadNextToken(xamlReader) && xamlReader.NodeType != XmlNodeType.EndElement) // { // switch (xamlReader.NodeType) // { // case XmlNodeType.Element: // if (xamlReader.Name.Contains(".")) // { // AddComplexProperty(xamlReader, inlineStyle); // } // else // { // if (htmlWriter != null && !elementContentStarted && inlineStyle.Length > 0) // { // // Output STYLE attribute and clear inlineStyle buffer. // htmlWriter.WriteAttributeString("STYLE", inlineStyle.ToString()); // inlineStyle.Remove(0, inlineStyle.Length); // } // elementContentStarted = true; // WriteElement(xamlReader, htmlWriter, inlineStyle); // } // Debug.Assert(xamlReader.NodeType == XmlNodeType.EndElement || xamlReader.NodeType == XmlNodeType.Element && xamlReader.IsEmptyElement); // break; // case XmlNodeType.Comment: // if (htmlWriter != null) // { // if (!elementContentStarted && inlineStyle.Length > 0) // { // htmlWriter.WriteAttributeString("STYLE", inlineStyle.ToString()); // } // htmlWriter.WriteComment(xamlReader.Value); // } // elementContentStarted = true; // break; // case XmlNodeType.CDATA: // case XmlNodeType.Text: // case XmlNodeType.SignificantWhitespace: // if (htmlWriter != null) // { // if (!elementContentStarted && inlineStyle.Length > 0) // { // htmlWriter.WriteAttributeString("STYLE", inlineStyle.ToString()); // } // htmlWriter.WriteString(xamlReader.Value); // } // elementContentStarted = true; // break; // } // } // Debug.Assert(xamlReader.NodeType == XmlNodeType.EndElement); // } // } // /// // /// Conberts an element notation of complex property into // /// // /// // /// On entry this XmlTextReader must be on Element start tag; // /// on exit - on EndElement tag. // /// // /// // /// StringBuilder containing a value for STYLE attribute. // /// // private static void AddComplexProperty(XmlTextReader xamlReader, StringBuilder inlineStyle) // { // Debug.Assert(xamlReader.NodeType == XmlNodeType.Element); // if (inlineStyle != null && xamlReader.Name.EndsWith(".TextDecorations")) // { // inlineStyle.Append("text-decoration:underline;"); // } // // Skip the element representing the complex property // WriteElementContent(xamlReader, /*htmlWriter:*/null, /*inlineStyle:*/null); // } // /// // /// Converts a xaml element into an appropriate html element. // /// // /// // /// On entry this XmlTextReader must be on Element start tag; // /// on exit - on EndElement tag. // /// // /// // /// May be null, in which case we are skipping xaml content // /// without producing any html output // /// // /// // /// StringBuilder used for collecting css properties for inline STYLE attributes on every level. // /// // private static void WriteElement(XmlTextReader xamlReader, XmlTextWriter htmlWriter, StringBuilder inlineStyle) // { // Debug.Assert(xamlReader.NodeType == XmlNodeType.Element); // if (htmlWriter == null) // { // // Skipping mode; recurse into the xaml element without any output // WriteElementContent(xamlReader, /*htmlWriter:*/null, null); // } // else // { // string htmlElementName = null; // switch (xamlReader.Name) // { // case "Run": // case "Span": // htmlElementName = "SPAN"; // break; // case "InlineUIContainer": // htmlElementName = "SPAN"; // break; // case "Bold": // htmlElementName = "B"; // break; // case "Italic": // htmlElementName = "I"; // break; // case "Paragraph": // htmlElementName = "P"; // break; // case "BlockUIContainer": // htmlElementName = "DIV"; // break; // case "Section": // htmlElementName = "DIV"; // break; // case "Table": // htmlElementName = "TABLE"; // break; // case "TableColumn": // htmlElementName = "COL"; // break; // case "TableRowGroup": // htmlElementName = "TBODY"; // break; // case "TableRow": // htmlElementName = "TR"; // break; // case "TableCell": // htmlElementName = "TD"; // break; // case "List": // string marker = xamlReader.GetAttribute("MarkerStyle"); // if (marker == null || marker == "None" || marker == "Disc" || marker == "Circle" || marker == "Square" || marker == "Box") // { // htmlElementName = "UL"; // } // else // { // htmlElementName = "OL"; // } // break; // case "ListItem": // htmlElementName = "LI"; // break; // case "Hyperlink": // htmlElementName = "A"; // break; // default: // htmlElementName = null; // Ignore the element // break; // } // if (htmlWriter != null && htmlElementName != null) // { // htmlWriter.WriteStartElement(htmlElementName); // WriteFormattingProperties(xamlReader, htmlWriter, inlineStyle); // WriteElementContent(xamlReader, htmlWriter, inlineStyle); // htmlWriter.WriteEndElement(); // } // else // { // // Skip this unrecognized xaml element // WriteElementContent(xamlReader, /*htmlWriter:*/null, null); // } // } // } // // Reader advance helpers // // ---------------------- // /// // /// Reads several items from xamlReader skipping all non-significant stuff. // /// // /// // /// XmlTextReader from tokens are being read. // /// // /// // /// True if new token is available; false if end of stream reached. // /// // private static bool ReadNextToken(XmlReader xamlReader) // { // while (xamlReader.Read()) // { // Debug.Assert(xamlReader.ReadState == ReadState.Interactive, "Reader is expected to be in Interactive state (" + xamlReader.ReadState + ")"); // switch (xamlReader.NodeType) // { // case XmlNodeType.Element: // case XmlNodeType.EndElement: // case XmlNodeType.None: // case XmlNodeType.CDATA: // case XmlNodeType.Text: // case XmlNodeType.SignificantWhitespace: // return true; // case XmlNodeType.Whitespace: // if (xamlReader.XmlSpace == XmlSpace.Preserve) // { // return true; // } // // ignore insignificant whitespace // break; // case XmlNodeType.EndEntity: // case XmlNodeType.EntityReference: // // Implement entity reading // //xamlReader.ResolveEntity(); // //xamlReader.Read(); // //ReadChildNodes( parent, parentBaseUri, xamlReader, positionInfo); // break; // for now we ignore entities as insignificant stuff // case XmlNodeType.Comment: // return true; // case XmlNodeType.ProcessingInstruction: // case XmlNodeType.DocumentType: // case XmlNodeType.XmlDeclaration: // default: // // Ignorable stuff // break; // } // } // return false; // } // #endregion Private Methods // // --------------------------------------------------------------------- // // // // Private Fields // // // // --------------------------------------------------------------------- // #region Private Fields // #endregion Private Fields //} } }