1. Cesar Lopez-Nataren
  2. rewrite-tool

Source

rewrite-tool / GatherImageMapping / Program.cs

//
// (C) MindTouch Inc, 2012
//

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Text;
using MindTouch.Deki.Util.Csv;
using MindTouch.Dream;
using MindTouch.Xml;

namespace GatherImageMapping {
    internal class Program {

        //--- Privata types ---
        private class Mapping {
            public string Index;
            public string FrameMakerFullFilename;
            public string FrameMakerFilename;
            public string Mif2GoFullFilename;
            public string Mif2GoFilename;
        }

        //--- Private fields
        private static readonly IList<RectangleF> _imagesToSkip = new List<RectangleF>(); 

        //--- Methods ---
        private static void Main(string[] args) {
            try {
                
                // Image bounds to ignore
                var imagesToSkip = new CsvTable(args[2], new UTF8Encoding(), "INDEX");
                foreach(var imageToSkip in imagesToSkip) {
                    _imagesToSkip.Add(new RectangleF(Int32.Parse(imageToSkip["X"]), Int32.Parse(imageToSkip["Y"]), Int32.Parse(imageToSkip["WIDTH"]), Int32.Parse(imageToSkip["HEIGHT"])));
                }

                // Filenames for the HTML files to map
                var frameMakerFilename = args[0];
                var mif2GoFilename = args[1];

                // Build the XML documents
                var frameMakerDoc = XDocFactory.LoadFrom(frameMakerFilename, MimeType.HTML);
                var mif2GoDoc = XDocFactory.LoadFrom(mif2GoFilename, MimeType.HTML);

                // Base paths
                var mif2GoBasePath = Path.GetDirectoryName(mif2GoFilename);
                var frameMakerBasePath = Path.GetDirectoryName(frameMakerFilename);

                // Display initial information
                var executingAssembly = Assembly.GetExecutingAssembly();
                Console.WriteLine("Executing '{0}', at '{1}'", executingAssembly.FullName, executingAssembly.Location);
                Console.WriteLine("Will parse '{0}' and '{1}'", frameMakerFilename, mif2GoFilename);
                Console.WriteLine("The base paths are '{0}' and '{1}'", frameMakerBasePath, mif2GoBasePath);

                // Mappings: index, page path, frameMaker filename, mif2go filename
                var i = 0;

                // Gather the framemaker images
                var mappings = new List<Mapping>();

                // Fix lists to include their items within the <li> elements
                FixList(frameMakerDoc);

                // Remove the rulers
                var fmImageList = frameMakerDoc["//img"].ToList();
                for(int x = 0; x < fmImageList.Count; x++) {
                    var img = fmImageList[x];
                    var imageName = img["@src"].AsText;

                    // Skip the rulers
                    var graphicUnits = GraphicsUnit.Pixel;
                    var image = File.Open(Path.Combine(frameMakerBasePath, imageName), FileMode.Open);
                    var bitmap = new Bitmap(image);
                    var currentRectBounds = bitmap.GetBounds(ref graphicUnits);
                    var isRuler = false;
                    foreach(var imageToSkip in _imagesToSkip) {
                        isRuler = currentRectBounds == imageToSkip;
                        if(!isRuler) {
                            continue;
                        }
                        image.Close();
                        bitmap.Dispose();
                        break;
                    }
                    image.Close();
                    bitmap.Dispose();
                    if(isRuler) {
                        img.Remove();
                    }
                }
                
                foreach(var img in frameMakerDoc["//img"]) {
                    var imageName = img["@src"].AsText;

                    // Skip the rulers
                    var graphicUnits = GraphicsUnit.Pixel;
                    var image = File.Open(Path.Combine(frameMakerBasePath, imageName), FileMode.Open);
                    var bitmap = new Bitmap(image);
                    var currentRectBounds = bitmap.GetBounds(ref graphicUnits);
                    var isRuler = false;
                    foreach(var imageToSkip in _imagesToSkip) {
                        isRuler = currentRectBounds == imageToSkip;
                        if(!isRuler) {
                            continue;
                        }
                        image.Close();
                        bitmap.Dispose();
                        break;
                    }
                    image.Close();
                    bitmap.Dispose();
                    if(isRuler) {
                        img.Remove();
                        continue;
                    }

                    Console.WriteLine("Encountered '{0}' on the FrameMaker file", imageName);
                    mappings.Add(new Mapping {
                                                 Index = i++.ToString(),
                                                 FrameMakerFilename = imageName,
                                                 FrameMakerFullFilename = Path.Combine(frameMakerBasePath, imageName)
                                             });
                    image.Close();
                }

                // Reset the index
                i = 0;
                var fmImageToMif2Go = new Dictionary<string, Mapping>();
                // Gather the mif2go images
                foreach (var img in mif2GoDoc["//img"]) {
                    try {
                        var mapping = mappings[i++];
                        var imageName = img["@src"].AsText;
                        mapping.Mif2GoFullFilename = Path.Combine(mif2GoBasePath, imageName);
                        mapping.Mif2GoFilename = imageName;
                        Console.WriteLine("Encountered '{0}' on the Mif2Go file", imageName);
                        fmImageToMif2Go[mapping.FrameMakerFilename] = mapping;
                    } catch(Exception exc) {
                        Console.WriteLine(img);
                        Console.WriteLine(exc);
                    }
                }

                // Save it as a csv file
                var file = File.Open(Path.Combine(frameMakerBasePath, Path.GetFileNameWithoutExtension(frameMakerFilename) + "-mappings.csv"), FileMode.Create);
                var results = new StreamWriter(file);
                results.WriteLine("index, framemaker filename, mif2go filename");
                foreach(var mapping in mappings) {
                    results.WriteLine(string.Format(@"{0}, {1}, {2}", mapping.Index, mapping.FrameMakerFullFilename, mapping.Mif2GoFullFilename));
                }
                results.Close();

                // Rewrite the uri's
                foreach (var img in frameMakerDoc["//img"]) {
                    Console.WriteLine("Will be rewriting '{0}'", img);
                    Mapping mappedTo;
                    var currentImgSrc = img["@src"];
                    if(!fmImageToMif2Go.TryGetValue(currentImgSrc.AsText, out mappedTo)) {
                        continue;
                    }
                    var mappedFilename = GetRelativePath(mappedTo);
                    Console.WriteLine("Rewriting to '{0}'", mappedFilename);
                    currentImgSrc.ReplaceValue(mappedFilename);
                    Console.WriteLine("Rewrote to '{0}'", img);

                    // Resize the images
                    if(!img.HasAttr("height") && !img.HasAttr("width")) {

                        // let css scale images to within content area
                        img.Attr("style", "max-width: 100%; max-height: 100%");
                    }
                }

                // Save the mapped file
                var extension = Path.GetExtension(frameMakerFilename);
                var writtenResult = Path.Combine(frameMakerBasePath, Path.GetFileNameWithoutExtension(frameMakerFilename) + "-mapped" + extension);
                Console.WriteLine("Will write the mapped file to '{0}'", writtenResult);
                frameMakerDoc.Save(writtenResult);
            } catch(Exception e) {
                Console.WriteLine(e.Message);
                Console.WriteLine(e.StackTrace);
            }
            Console.WriteLine("Press enter to finish");
            Console.ReadLine();
        }

        private static string GetRelativePath(Mapping mapping) {
            var fmFullnameParts = mapping.FrameMakerFullFilename.Split(new []{ Path.DirectorySeparatorChar });
            var mif2GoFullnameParts = mapping.Mif2GoFullFilename.Split(new[] {Path.DirectorySeparatorChar});
            var relativePathParts = new List<string>();
            for(int i = 0; i < fmFullnameParts.Length; i++) {
                if(fmFullnameParts[i].EqualsInvariantIgnoreCase(mif2GoFullnameParts[i])) {
                    continue;
                }
                for(var j = i; j < fmFullnameParts.Length - 1; j++) {
                    relativePathParts.Add("..");
                }
                relativePathParts.AddRange(mif2GoFullnameParts.SubArray(i));
                break;
            }
            return String.Join("/", relativePathParts.ToArray());
        }

        private static void FixList(XDoc doc) {
            foreach(var ol in doc["//ol"]) {
                var olElements = ol["child::node()"];
                IDictionary<XDoc, IList<XDoc>> xmlElementToChildren = new Dictionary<XDoc, IList<XDoc>>();
                var stack = new Stack<XDoc>();

                // Gather the children
                foreach(var olElement in olElements) {
                    if(olElement.Name.EqualsInvariantIgnoreCase("li")) {
                        IList<XDoc> elementChildren;
                        if(!xmlElementToChildren.TryGetValue(olElement, out elementChildren)) {
                            elementChildren = new List<XDoc>();
                            xmlElementToChildren[olElement] = elementChildren;
                        }
                        stack.Push(olElement);
                    } else {
                        IList<XDoc> elementChildren;
                        if(stack.Count <= 0) {
                            continue;
                        }
                        var currentContext = stack.Peek();
                        if(!xmlElementToChildren.TryGetValue(currentContext, out elementChildren)) {
                            continue;
                        }
                        olElement.Remove();
                        elementChildren.Add(olElement);
                    }
                }

                // Properly nest the children
                foreach(var kvp in xmlElementToChildren) {
                    var element = kvp.Key;
                    var children = kvp.Value;
                    var current = element;
                    foreach(var child in children) {                       
                        if("Note-Indented".EqualsInvariantIgnoreCase(child[".//@class"].AsText)) {
                            var id = Guid.NewGuid();
                            element.Add(child[".//@class"].Parent.Attr("tempid", id.ToString()));
                            current = element[string.Format(".//*[@tempid='{0}']", id)];
                            current[".//@tempid"].Remove();
                        } else {
                            current.Add(child);
                        }
                    }
                }
            }
        }
    }
}