using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Text.RegularExpressions; using System.Drawing; using System.Xml; namespace fmtxml { public partial class RtfToSvg { public RtfToSvg(string rtfFileName) { RtfFileName = rtfFileName; _FormatFolder = RtfFile.Directory; } private static DirectoryInfo _FormatFolder; public RtfToSvg(FileInfo rtfFile) { RtfFile = rtfFile; _FormatFolder = RtfFile.Directory; } private bool? _IsGenMac; public bool IsGenMac { get { if (_IsGenMac == null) Convert(); return (bool)_IsGenMac; } set { _IsGenMac = value; } } private string _RtfFileName; public string RtfFileName { get { return _RtfFileName; } set { _RtfFileName = value; _RtfFile = new FileInfo(_RtfFileName); } } private FileInfo _RtfFile; public FileInfo RtfFile { get { return _RtfFile; } set { _RtfFile = value; _RtfFileName = _RtfFile.FullName; } } private string _Svg; public string Svg { get { if (_Svg == null) Convert(); return _Svg; } } private string Convert() { string buff = LoadFile(RtfFile);// Load Text _Svg = CreateSvg(RtfFile, buff);// Convert to SVG return _Svg; } /// /// Load the file into a string by bytes /// /// /// private static string LoadFile(FileInfo file) { byte[] bytes = new byte[file.Length]; using (FileStream fs = file.OpenRead()) { fs.Read(bytes, 0, (int)file.Length); fs.Close(); } StringBuilder sb = new StringBuilder(); foreach (byte byt in bytes) sb.Append((char)byt); return sb.ToString(); } private const string _TripleBang = "\xAD\xAD\xAD\xA8\xA8"; Regex regLines = new Regex(@"([^\r\n]*)?\r?\n", RegexOptions.Singleline); // If processing any of the RGE (except RGEDEV) C0 macros, adjust the x location of the ellipse, so that // 32bit printing matches 16bit. This flag shows that we're in a format that needs this adjustment. private static bool _InRge = false; private static bool _DoingRgeC0 = false; private string CreateSvg(FileInfo file, string buff) { IsGenMac = (buff.Substring(0, 5) == _TripleBang); if(!IsGenMac) return null; _InRge = (file.Name.ToUpper().Contains("RGE") && !file.Name.ToUpper().Contains("RGEDEV")); StringBuilder sb = new StringBuilder(); MatchCollection lines = regLines.Matches(buff); bool svg = false; bool group = false; bool hasC0 = false; foreach (Match line in lines) { string text = line.Groups[1].Value; if (text == _TripleBang) if (!svg) svg = AddSvgPrefix(file, sb, svg); else AddSvgSuffix(sb, hasC0); else if (text.StartsWith("\xAD\xAD")) { hasC0 |= AddGroupStart(sb, ref group, text).ToLower() == "c0"; _DoingRgeC0 = (hasC0 && _InRge); } else if (text == "END") { group = AddGroupEnd(sb, group); _DoingRgeC0 = false; } else if (text != "") ProcessCommand(sb, text, file); } return sb.ToString(); } private static void AddSvgSuffix(StringBuilder sb, bool hasC0) { if (!hasC0) { AddC0(sb); } sb.Append(string.Format("\r\n")); } private static bool AddGroupEnd(StringBuilder sb, bool group) { if (group) sb.Append(" \r\n"); group = false; _Xoff = 0; _Yoff = 0; return group; } private static string AddGroupStart(StringBuilder sb, ref bool group, string text) { AddGroupEnd(sb, group); group = true; string grpID = text.Substring(2).ToUpper(); sb.Append(string.Format(" \r\n", grpID)); return grpID; } private static void AddC0(StringBuilder sb) { // note that cx = 1 has been tested with NSP. sb.Append(" \r\n"); sb.Append(" \r\n"); sb.Append(" \r\n"); } private static bool AddSvgPrefix(FileInfo file, StringBuilder sb, bool svg) { sb.Append("\r\n"); sb.Append("\r\n"); sb.Append("\r\n"); sb.Append(string.Format(" {0}\r\n", file.Name.ToLower().Replace(".rtf", ""))); svg = true; return svg; } private static Regex regCommand = new Regex(@"^[A-Z][^ \r\n]*", RegexOptions.Multiline); private static void ProcessCommand(StringBuilder sb, string text, FileInfo file) { Match commandMatch = regCommand.Match(text); ECommand command = (ECommand)Enum.Parse(typeof(ECommand), commandMatch.Value); Converters[(int)command](sb, text); } private enum ECommand : int { LINE, BOX, ELLIPSE, TEXT, BITMAP, GDIADJ, RTFADJ, ABSOLUTE } private delegate void Converter(StringBuilder sb, string text); private static Converter[] _Converters; private static Converter[] Converters { get { if (_Converters == null) SetupConverters(); return RtfToSvg._Converters; } set { _Converters = value; } } private static void SetupConverters() { Converters = new Converter[Enum.GetNames(typeof(ECommand)).Length]; Converters[(int)ECommand.LINE] = new Converter(AddLine); Converters[(int)ECommand.BOX] = new Converter(AddRect); Converters[(int)ECommand.ELLIPSE] = new Converter(AddEllipse); Converters[(int)ECommand.TEXT] = new Converter(AddText); Converters[(int)ECommand.BITMAP] = new Converter(AddImage); Converters[(int)ECommand.GDIADJ] = new Converter(AddGdiAdj); Converters[(int)ECommand.RTFADJ] = new Converter(AddRtfAdj); Converters[(int)ECommand.ABSOLUTE] = new Converter(AddAbsolute); } private static Regex regGdiAdj = new Regex(@"GDIADJ ([-0-9]*) ([-0-9]*)$", RegexOptions.Multiline); private static void AddGdiAdj(StringBuilder sb, string text) { Match gdiadjMatch = regGdiAdj.Match(text); _Xoff = int.Parse(gdiadjMatch.Groups[1].Value); _Yoff = int.Parse(gdiadjMatch.Groups[2].Value); } private static void AddAbsolute(StringBuilder sb, string text) { sb.Append(" ABSOLUTE"); } private static void AddRtfAdj(StringBuilder sb, string text) { // Not needed } private static Regex regBitmap = new Regex(@"BITMAP ([-0-9]*) ([-0-9]*) (.*)$", RegexOptions.Multiline); private static void AddImage(StringBuilder sb, string text) { Match bitmapMatch = regBitmap.Match(text); //string bmFileName = FixXmlText(bitmapMatch.Groups[3].Value); string bmFileName = FixFileName(bitmapMatch.Groups[3].Value); Bitmap bmp = new Bitmap(bmFileName); string bmWidth = bmp.Width.ToString() + "px"; string bmHeight = bmp.Height.ToString() + "px"; //Console.WriteLine("'{0}'", bmFileName); sb.Append(string.Format(" \r\n", TwipsToPointsX(bitmapMatch.Groups[1].Value), TwipsToPointsY(bitmapMatch.Groups[2].Value), bmWidth, bmHeight, bmFileName)); } private static Regex regText = new Regex(@"TEXT ([-0-9]*) ([-0-9]*) ([-0-9]*) ([-0-9]*) ([-0-9]*) ""([^""]*)""", RegexOptions.Multiline); private static void AddText(StringBuilder sb, string text) { Match textMatch = regText.Match(text); sb.Append(string.Format(" {5}\r\n", TwipsToPointsX(textMatch.Groups[1].Value), TwipsToPointsY(textMatch.Groups[2].Value), FontSizeToPoints(textMatch.Groups[3].Value), FontToFamily(textMatch.Groups[4].Value), FontStyle(textMatch.Groups[5].Value), FixXmlText(textMatch.Groups[6].Value))); } private static Regex regEllipse = new Regex(@"ELLIPSE ([-0-9]*) ([-0-9]*) ([-0-9]*) ([-0-9]*) ([-0-9]*)", RegexOptions.Multiline); private static void AddEllipse(StringBuilder sb, string text) { Match ellipseMatch = regEllipse.Match(text); // code in the new veproms that draws the ellipse must use the 'y' location differently. So // add in the radius to the 'y' to get the correct value. float yadj = TwipsToPointsEllipse(ellipseMatch.Groups[4].Value); sb.Append(string.Format(" \r\n", _DoingRgeC0?6.5:TwipsToPointsX(ellipseMatch.Groups[1].Value), yadj + TwipsToPointsY(ellipseMatch.Groups[2].Value), TwipsToPointsEllipse(ellipseMatch.Groups[3].Value), TwipsToPointsEllipse(ellipseMatch.Groups[4].Value), TwipsToPoints(ellipseMatch.Groups[5].Value))); } private static Regex regBox = new Regex(@"BOX ([-0-9]*) ([-0-9]*) ([-0-9]*) ([-0-9]*) ([-0-9]*)", RegexOptions.Multiline); private static void AddRect(StringBuilder sb, string text) { Match boxMatch = regBox.Match(text); sb.Append(string.Format(" \r\n", TwipsToPointsX(boxMatch.Groups[1].Value), TwipsToPointsY(boxMatch.Groups[2].Value), TwipsToPoints(boxMatch.Groups[3].Value), TwipsToPoints(boxMatch.Groups[4].Value), TwipsToPoints(boxMatch.Groups[5].Value))); } private static int _Xoff = 0; private static int _Yoff = 0; private static Regex regLine = new Regex(@"LINE ([-0-9]*) ([-0-9]*) ([-0-9]*) ([-0-9]*) ([-0-9]*)", RegexOptions.Multiline); private static void AddLine(StringBuilder sb, string text) { Match lineMatch = regLine.Match(text); sb.Append(string.Format(" \r\n", TwipsToPointsX(lineMatch.Groups[1].Value), TwipsToPointsY(lineMatch.Groups[2].Value), TwipsToPoints(lineMatch.Groups[3].Value) + TwipsToPointsX(lineMatch.Groups[1].Value), TwipsToPoints(lineMatch.Groups[4].Value) + TwipsToPointsY(lineMatch.Groups[2].Value), TwipsToPoints(lineMatch.Groups[5].Value))); } private static string FontStyle(string style) { StringBuilder sb = new StringBuilder(); int iStyle = int.Parse(style); if ((iStyle & 1) == 1) sb.Append("font-weight=\"bold\" "); if ((iStyle & 2) == 2) sb.Append("text-decoration=\"underline\" "); if ((iStyle & 4) == 4) sb.Append("font-style=\"italic\" "); return sb.ToString(); } private static string FixFileName(string fileName) { return Regex.Replace(fileName, @"^.*FORMAT\\", _FormatFolder.FullName + @"\"); } private static string FixXmlText(string str) { str = str.Replace("&", "&"); str = str.Replace("'", "'"); str = str.Replace("\"", """); str = str.Replace("<", "<"); str = str.Replace(">", ">"); str = str.Replace("\x0B", " "); str = str.Replace(" ", "{sp}"); str = str.Replace("\xAE",@"\u8594?"); // Turkey Point uses a Right Arrow from VESYMB return str; } private static string[] FontChoice = { "Times New Roman", "VESymb XXXXXX", "VolianDraw XXXXXX", "Prestige Elite Tall", "Courier New", "Arial", "Letter Gothic", "Times New Roman", "Letter Gothic Tall", "Letter Gothic Tall", "Gothic Ultra", "VolianScript" }; private static float TwipsToPoints(string twips) { return float.Parse(twips) / 20; } private static float TwipsToPointsEllipse(string twips) { // divide the ellipse by 40. This is the 20 to convert from twips to points // and an addition divide by 2 since the definition in 16bit is diameter & // in 32 is radius. return float.Parse(twips) / 40; } private static float TwipsToPointsX(string twips) { return (_Xoff + float.Parse(twips)) / 20; } private static float TwipsToPointsY(string twips) { return (_Yoff + float.Parse(twips)) / 20; } private static float FontSizeToPoints(string fontSize) { return float.Parse(fontSize) / 2; } private static string FontToFamily(string fontID) { if (int.Parse(fontID) >= FontChoice.Length) return "Font-" + fontID; return FontChoice[int.Parse(fontID)]; } public void Save(string svgFileName) { FileInfo outFile = new FileInfo(svgFileName); if (outFile.Exists) outFile.Delete(); XmlDocument xDoc = new XmlDocument(); try { //if (svgFileName.Contains("nsppe")) // Console.WriteLine("stop"); xDoc.LoadXml(Svg); AppendPlantSpecific(svgFileName, xDoc); xDoc.Save(outFile.FullName); } catch (Exception ex) { Console.WriteLine("Error generating {0}", svgFileName); Console.WriteLine("ex = {0}", ex); } } } }