Search code examples
c#type-conversionopenxmlnovacode-docx

c# Novacode.Picture to System.Drawing.Image


I'm reading in a .docx file using the Novacode API, and am unable to create or display any images within the file to a WinForm app due to not being able to convert from a Novacode Picture (pic) or Image to a system image. I've noticed that there's very little info inside the pic itself, with no way to get any pixel data that I can see. So I have been unable to utilize any of the usual conversion ideas.

I've also looked up how Word saves images inside the files as well as Novacode source for any hints and I've come up with nothing.

My question then is is there a way to convert a Novacode Picture to a system one, or should I use something different to gather the image data like OpenXML? If so, would Novacode and OpenXML conflict in any way?

There's also this answer that might be another place to start.

Any help is much appreciated.


Solution

  • Okay. This is what I ended up doing. Thanks to gattsbr for the advice. This only works if you can grab all the images in order, and have descending names for all the images.

    using System.IO.Compression; // Had to add an assembly for this
    using Novacode;
    
    // Have to specify to remove ambiguous error from Novacode
    Dictionary<string, System.Drawing.Image> images = new Dictionary<string, System.Drawing.Image>();
    
    void LoadTree()
    {
        // In case of previous exception
        if(File.Exists("Images.zip")) { File.Delete("Images.zip"); }
    
        // Allow the file to be open while parsing
        using(FileStream stream = File.Open("Images.docx", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        {
            using(DocX doc = DocX.Load(stream))
            {
                // Work rest of document
    
                // Still parse here to get the names of the images
                // Might have to drag and drop images into the file, rather than insert through Word
                foreach(Picture pic in doc.Pictures)
                {
                    string name = pic.Description;
    
                    if(null == name) { continue; }
    
                    name = name.Substring(name.LastIndexOf("\\") + 1);
                    name = name.Substring(0, name.Length - 4);
    
                    images[name] = null;
                }
    
                // Save while still open
                doc.SaveAs("Images.zip");
            }
        }
    
        // Use temp zip directory to extract images
        using(ZipArchive zip = ZipFile.OpenRead("Images.zip"))
        {
            // Gather all image names, in order
            // They're retrieved from the bottom up, so reverse
            string[] keys = images.Keys.OrderByDescending(o => o).Reverse().ToArray();
    
            for(int i = 1; ; i++)
            {
                // Also had to add an assembly for ZipArchiveEntry
                ZipArchiveEntry entry = zip.GetEntry(String.Format("word/media/image{0}.png", i));
    
                if(null == entry) { break; }
    
                Stream stream = entry.Open();
    
                images[keys[i - 1]] = new Bitmap(stream);
            }
        }
    
        // Remove temp directory
        File.Delete("Images.zip");
    }