Exporting Documents from Teamroom/NSF files using C#

I just want to say, before I get into this in any depth, that IBM sucks when it comes to documentation. I use to think that Microsoft was bad, but IBM is now the king of sucky documentation (or tutorials, or anything else). If it wasn't for Gupta's article here, I'd still be ripping my hair out. Anyway, at work we have a product called Teamroom. It's basically a Lotus/IBM equivalent to SharePoint... Sort of anyway... That being said, I had the honor of being tasked with taking the information from there and exporting it out so that we could do a migration to a different system.

Now if IBM had built the system using databases or really anything that made sense, we'd be fine. Instead they use huffman encoding on all documents (well almost all anyway from what we can tell) without sharing the algorithm (no idea if there is a header or not) and they use NSF files. For those that don't know, NSF files are basically Lotus Notes files (I'm not talking about the NES sound format files). The way you get into them is by using the API that IBM provides. However, without the Interop.Domino.dll file (which you can get from the article I link to above), you wont be able to use it in C#... So first, go to the link above and download his example. It contains the DLL that you need. Once you have that, add the reference, etc. and then finally the code below should work:

        public static void GetDocuments(string StartDirectory,string OutputDirecotry)
        {
            List<System.IO.FileInfo> Files=Utilities.FileManager.FileList(StartDirectory);
            List<System.IO.DirectoryInfo> Directories = Utilities.FileManager.DirectoryList(StartDirectory);
            foreach (System.IO.FileInfo File in Files)
            {
                if (File.Extension.Equals(".nsf", StringComparison.CurrentCultureIgnoreCase))
                {
                    XmlDocument TempDoc = GetFromNSFdb(File.FullName);
                    string DocumentName = "";
                    List<Values> Docs = ParseKeys(TempDoc, File.FullName, out DocumentName);
                    if (File.Name.Equals("Main.nsf"))
                    {
                        GetDocuments(Docs, OutputDirecotry, File.FullName);
                    }
                    else
                    {
                        if (Docs.Count > 0)
                        {
                            Utilities.FileManager.CreateDirectory(OutputDirecotry + "/" + DocumentName);
                            GetDocuments(Docs, OutputDirecotry + "/" + DocumentName, File.FullName);
                        }
                    }
                }
            }
            foreach (System.IO.DirectoryInfo Directory in Directories)
            {
                if (!Directory.Name.Equals("Search.ft", StringComparison.CurrentCultureIgnoreCase))
                {
                    Utilities.FileManager.CreateDirectory(OutputDirecotry + "/" + Directory.Name);
                    GetDocuments(Directory.FullName, OutputDirecotry + "/" + Directory.Name);
                }
            }
        }

        public static XmlDocument GetFromNSFdb(string strNSFdbName)
        {

            try
            {
                Domino.ISession session = new NotesSessionClass();
                session.Initialize(YOURPASSWORD);
                Domino.NotesDatabase database = session.GetDatabase("", strNSFdbName, false);
                Domino.NotesNoteCollection noteCollecton = database.CreateNoteCollection(true);
                noteCollecton.SelectAllAdminNotes(true);
                noteCollecton.SelectAllCodeElements(true);
                noteCollecton.SelectAllDataNotes(true);
                noteCollecton.SelectAllDesignElements(true);
                noteCollecton.SelectAllFormatElements(true);
                noteCollecton.SelectAllIndexElements(true);
                noteCollecton.SelectForms = true;
                noteCollecton.BuildCollection();
                Domino.NotesDXLExporter exporter = (Domino.NotesDXLExporter)session.CreateDXLExporter();
                string strNsfXML = exporter.Export(noteCollecton);
                string strDocrmv = strNsfXML.Replace("<!DOCTYPE database SYSTEM 'xmlschemas/domino_6_5_3.dtd'>", "").Replace("xmlns='http://www.lotus.com/dxl'", ""); XmlDocument xDocLoad = new XmlDocument();
                xDocLoad.LoadXml(strDocrmv);
                return xDocLoad;
            }
            catch { return null; }
        }

        public static List<Values> ParseKeys(XmlDocument TempDoc,string strNSFdbName,out string DocumentName)
        {
            XmlNode TempNode = TempDoc["database"];
            DocumentName = TempNode.Attributes["title"].Value;
            List<Values> TempDic = new List<Values>();
            string CurrentKey = "";
            string FileName = "";
            foreach (XmlNode Child in TempNode.ChildNodes)
            {
                if (Child.HasChildNodes)
                {
                    foreach (XmlNode Child2 in Child.ChildNodes)
                    {
                        if (Child2.Name.Equals("noteinfo", StringComparison.CurrentCultureIgnoreCase)
                            && Child2.Attributes["noteid"]!=null)
                        {
                            CurrentKey = Child2.Attributes["noteid"].Value;
                            break;
                        }
                    }
                    foreach (XmlNode Child2 in Child.ChildNodes)
                    {
                        if (Child2.HasChildNodes)
                        {
                            if (Child2.Name.Equals("item", StringComparison.CurrentCultureIgnoreCase)
                                && Child2.Attributes["name"]!=null
                                && Child2.Attributes["name"].Value.Equals("$FILE", StringComparison.CurrentCultureIgnoreCase))
                            {
                                foreach (XmlNode Child3 in Child2.ChildNodes)
                                {
                                    if (Child3.Name.Equals("object", StringComparison.CurrentCultureIgnoreCase))
                                    {
                                        foreach (XmlNode Child4 in Child3.ChildNodes)
                                        {
                                            if (Child4.Name.Equals("file", StringComparison.CurrentCultureIgnoreCase))
                                            {
                                                    FileName = Child4.Attributes["name"].Value;
                                                    Values TempValue = new Values();
                                                    TempValue.Key = FileName;
                                                    TempValue.Value = CurrentKey;
                                                    TempDic.Add(TempValue);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return TempDic;
        }

        public static void GetDocuments(List<Values> Docs, string OutputDirectory, string strNSFdbName)
        {
            Domino.ISession session = new NotesSessionClass();
            session.Initialize(YOURPASSWORD);
            Domino.NotesDatabase database = session.GetDatabase("", strNSFdbName, false);
            foreach (Values Key in Docs)
            {
                Domino.NotesDocumentClass TempDoc = (Domino.NotesDocumentClass)database.GetDocumentByID(Key.Value);
                Domino.NotesEmbeddedObjectClass Object = (Domino.NotesEmbeddedObjectClass)TempDoc.GetAttachment(Key.Key);
                Object.ExtractFile(OutputDirectory + "/" + Key.Key);
            }
        }

    public class Values
    {
        public string Key;
        public string Value;
    }

In the code above, the function you want to call is GetDocuments(string StartDirectory, string OutputDirectory). That function searches the input directory for nsf files, loads each one, finds the documents, and exports them to the output directory using the same directory structure (although sub rooms/pages are going to be in their own directory based off of the title of the sub room/page so you can tell what they are). The class above is simply used as a holder for information between the functions. Also note that this uses my utility library a bit and on top of this, you're going to have to have Lotus Domino/Notes installed on the computer and set the lines that say session.Initialize(YOURPASSWORD) to actually use your password (or potentially a blank string, "", depending on how you have Lotus set up). However, all of that taken into consideration, it does indeed work. The code is different from the version we're using at work but the functions have been tested. Anyway, I hope this helps someone out there so that they aren't ripping their hair out... So try it out (or heavily modify it for your own uses), leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 1/29/2009 at 2:38 PM
Tags: , , ,
Categories: C#
Post Information: Permalink | Comments (4) | Post RSSRSS comment feed

Sepia Tone in C#

Sepia Tone is the coloring of a black and white photo to simulate early photos (the sort of faded/brownish ones you see from time to time). There aren't that many practical reasons to want to use it but it does give the image an "old time" look. That from a stylistic stand point can be rather cool. And lucky for us, it's extremely easy to implement in C#:

        public static Bitmap ConvertSepiaTone(Bitmap Image)
        {
            System.Drawing.Bitmap TempBitmap = Image;

            System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap.Width, TempBitmap.Height);
            System.Drawing.Graphics NewGraphics = System.Drawing.Graphics.FromImage(NewBitmap);
            float[][] FloatColorMatrix ={
                    new float[] {.393f, .349f, .272f, 0, 0},
                    new float[] {.769f, .686f, .534f, 0, 0},
                    new float[] {.189f, .168f, .131f, 0, 0},
                    new float[] {0, 0, 0, 1, 0},
                    new float[] {0, 0, 0, 0, 1}
                };

            System.Drawing.Imaging.ColorMatrix NewColorMatrix = new System.Drawing.Imaging.ColorMatrix(FloatColorMatrix);
            System.Drawing.Imaging.ImageAttributes Attributes = new System.Drawing.Imaging.ImageAttributes();
            Attributes.SetColorMatrix(NewColorMatrix);
            NewGraphics.DrawImage(TempBitmap, new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), 0, 0, TempBitmap.Width, TempBitmap.Height, System.Drawing.GraphicsUnit.Pixel, Attributes);
            NewGraphics.Dispose();
            return NewBitmap;
        }

The code above is similar to my code for converting an image to black and white. However you'll notice that the matrix is slightly different (not to mention this takes in a Bitmap object and returns a Bitmap object...).  The matrix in this case takes more of the values for red and green while downplaying the blue a bit which in turn gives us the brownish color. That's our only difference really, and since I talked about the color matrix a bit more in the black and white posting I'm going to simply shut up and leave it at that. Anyway, hopefully this helps you out in some way. So try it out, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 1/26/2009 at 1:22 PM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Image Dilation in C#

This is probably not the most useful image manipulation function that you will ever see but it's fun (well if you're a programmer that enjoys screwing with people, it can be fun anyway). Anyway, image dilation is simply the taking of high intensity pixels (usually foreground pixels but not always) and grow the size of their boundaries. In other words we bleed out wards, causing bright colors to blur. It can be used for a number of effects, filling in of small spots in images, etc. For example, whenever you see a white screen (as though you're looking into direct bright light) and suddenly you see a dark blurry figure that slowly comes into focus, they're using this effect (in conjunction with a couple others).

The way this filter works is it takes a pixel (p0) and looks at a number of pixels around it (the shape of this can be anything but is usually a box around the center pixel). It then finds the pixel within that group with the highest intensity (in black and white images, the value closest to white and in color images you can break it down by red, green, and blue values) and changes the value of the pixel (p0) to that value. It does this for the entire image, causing the brighter values to bleed out.

Anyway, as always I wrote some code to accomplish this and figured I'd share:

        public static Bitmap Dilate(Bitmap Image, int Size)
        {
            System.Drawing.Bitmap TempBitmap = Image;
            System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap.Width, TempBitmap.Height);
            System.Drawing.Graphics NewGraphics = System.Drawing.Graphics.FromImage(NewBitmap);
            NewGraphics.DrawImage(TempBitmap, new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), System.Drawing.GraphicsUnit.Pixel);
            NewGraphics.Dispose();
            Random TempRandom = new Random();
            int ApetureMin = -(Size / 2);
            int ApetureMax = (Size / 2);
            for (int x = 0; x < NewBitmap.Width; ++x)
            {
                for (int y = 0; y < NewBitmap.Height; ++y)
                {
                    int RValue = 0;
                    int GValue = 0;
                    int BValue = 0;
                    for (int x2 = ApetureMin; x2 < ApetureMax; ++x2)
                    {
                        int TempX = x + x2;
                        if (TempX >= 0 && TempX < NewBitmap.Width)
                        {
                            for (int y2 = ApetureMin; y2 < ApetureMax; ++y2)
                            {
                                int TempY = y + y2;
                                if (TempY >= 0 && TempY < NewBitmap.Height)
                                {
                                    Color TempColor = TempBitmap.GetPixel(TempX, TempY);
                                    if (TempColor.R > RValue)
                                        RValue = TempColor.R;
                                    if (TempColor.G > GValue)
                                        GValue = TempColor.G;
                                    if (TempColor.B > BValue)
                                        BValue = TempColor.B;
                                }
                            }
                        }
                    }
                    Color TempPixel = Color.FromArgb(RValue, GValue, BValue);
                    NewBitmap.SetPixel(x, y, TempPixel);
                }
            }
            return NewBitmap;
        }

The code above takes in an image and the size of the box (I haven't written code to take in a defined box structure but it can be changed to do so). It then returns a new Bitmap object with the dilation completed.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 1/23/2009 at 11:24 AM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed