Make a Word document containing pictures in C#


[pictures]

Occasionally you may want to combine selected pictures to make a Word document. This example shows one way you can search for files matching a pattern and then add them to a new Word document.

This is a fairly long example, so I’ve divided it into sections.

How To Use It

Enter a directory name in the upper TextBox. Alternatively click the ellipsis button on the right to select a directory.

Select or enter a file matching pattern and check the Include Subdirectories box if desired. Then click ListFiles. The program searches the directory (and optionally its subdirectories) for files matching the pattern and lists them in the CheckedListBox.

Initially all of the files are checked. You can individually check and uncheck files, or use the CheckBox above the ListBox to select or deselect all of the files at the same time.

Enter the name of the output file and click Create Document to make the Word document.

Assemblies

Before you can get the example to work, you need to add a reference to the Word interop library. Ideally you could add a reference to the .NET interop assembly in the Add Reference dialog’s .NET tab. Unfortunately that assembly uses a few things that are in another assembly, and that assembly seems to be present only in COM version. It’s particularly annoying in this example because the only things missing from the .NET assembly are two enumerations. They’re basically just integers, but the Visual Studio doesn’t know how to convert them into the proper data types.

You could add the .NET reference and the COM reference, but they contain some duplication, so Visual Studio would get confused about which version of various methods you wanted to use. You can overcome that problem, but why bother? As long as you need to include the COM assembly anyway, you can just do that and not worry about the .NET version.

To add the necessary reference, open the Project menu and select Add Reference. Select the COM tab and add a reference to “Microsoft Word 14.0 Object Library,” or whatever version you have installed on your system.

(If you figure out how to make the program work using only .NET assemblies, please post a comment below.)

Finding Files

The two most interesting pieces of the program are those that list files matching the pattern you enter and that create the Word document. The following code lists the files.

// List files that match the pattern.
private void btnListFiles_Click(object sender, EventArgs e)
{
    // Get the directory.
    string path = txtDirectory.Text.Trim();
    if (path.Length == 0)
    {
        MessageBox.Show("Please enter a directory name");
        return;
    }

    // Get the file pattern text without parentheses.
    string pattern_text = cboPattern.Text;
    if (pattern_text.Contains("("))
    {
        int pos1 = pattern_text.IndexOf("(");
        int pos2 = pattern_text.IndexOf(")");
        pattern_text =
            pattern_text.Substring(pos1 + 1, pos2 - pos1 - 1);
    }

    // Get individual file matching patterns.
    List<string> patterns = new List<string>();
    foreach (string pattern in pattern_text.Split(
        new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
    {
        patterns.Add(pattern.Trim());
    }

    // Get the files.
    SearchOption search_option = SearchOption.TopDirectoryOnly;
    if (chkIncludeSubdirectories.Checked)
        search_option = SearchOption.AllDirectories;
    clbFiles.Items.Clear();
    chkAll.Checked = false;
    foreach (string pattern in patterns)
    {
        // Get files matching this pattern.
        foreach (string filename in
            Directory.GetFiles(path, pattern, search_option))
        {
            // See if we not yet listed this file.
            if (!clbFiles.Items.Contains(filename))
            {
                // Add the filename to the list.
                clbFiles.Items.Add(filename);
            }
        }
    }

    // Initially select all files.
    chkAll.Checked = true;
}

This code starts by getting the directory name. It then gets the file patterns from the text you entered and splits them apart. For example, one of the pre-defined patterns is “Picture Files (*.png; *.jpg; *.gif; *.bmp).” If you select this pattern, the program extracts the patterns inside the parentheses and then splits them apart into the patterns *.png, *.jpg, *.gif, and *.bmp.

Next, the code loops through the patterns. For each pattern, it uses the Directory.GetFiles method to get the files matching the pattern. If the clbFiles CheckedListBox doesn’t already contain a particular file, the code adds it. (The code doesn’t add a file if it is already in the list in case a file matches more than one pattern.)

Building the Word Document

I’ve posted other examples that show how to create Word documents from a C# program but here’s a quick review. After you add the object library reference, you can make the library easier to use if you add the following using directive to your code.

using Word = Microsoft.Office.Interop.Word;

The following code shows how the program creates the Word document.

// Create the Word document.
private void btnCreateFile_Click(object sender, EventArgs e)
{
    // Get the file name.
    string filename = txtFilename.Text.Trim();
    if (filename.Length == 0)
    {
        MessageBox.Show("Please enter a document name");
        return;
    }

    // Get the Word application object.
    Word._Application word_app = new Word.ApplicationClass();

    // Make Word visible (optional).
    word_app.Visible = true;

    // Create the Word document.
    object missing = Type.Missing;
    Word._Document word_doc = word_app.Documents.Add(
        ref missing, ref missing, ref missing, ref missing);

    // Add the image files.
    Word.Paragraph para;
    foreach (string picture_file in clbFiles.CheckedItems)
    {
        // Make a paragraph.
        para = word_doc.Paragraphs.Add(ref missing);

        // Add the picture to the paragraph.
        Word.InlineShape inline_shape =
            para.Range.InlineShapes.AddPicture(
                picture_file, ref missing, ref missing,
                ref missing);

        // Format the picture.
        Word.Shape shape = inline_shape.ConvertToShape();

        // Scale uniformly by 50%.
        shape.LockAspectRatio =
            Microsoft.Office.Core.MsoTriState.msoTrue;
        shape.ScaleHeight(0.5f,
            Microsoft.Office.Core.MsoTriState.msoTrue,
            Microsoft.Office.Core.MsoScaleFrom.msoScaleFromTopLeft);
        shape.WrapFormat.Type = Word.WdWrapType.wdWrapInline;
        
        // Add the file's name.
        para.Range.InsertParagraphAfter();
        para.Range.InsertAfter(picture_file);
    }

    // Save the document.
    object filename_obj = filename;
    word_doc.SaveAs(ref filename_obj, ref missing, ref missing,
        ref missing, ref missing, ref missing, ref missing,
        ref missing, ref missing, ref missing, ref missing,
        ref missing, ref missing, ref missing, ref missing,
        ref missing);

    // Close.
    object save_changes = false;
    word_doc.Close(ref save_changes, ref missing, ref missing);
    word_app.Quit(ref save_changes, ref missing, ref missing);

    MessageBox.Show("Done");
}

This event handler first gets the name of the file that you want to create. It then creates a Word application server object. This object provides all of the Word functionality that the program will use.

This example makes the Word application visible while it works. If you don’t want to see the file as it is created, set the server’s Visible property to false.

Calls to the Word server’s methods are a bit unusual. You must provide all of the arguments expected by a method and you cannot simply pass null in for any argument that you don’t want to use. Instead you must pass the special value Type.Missing and you must pass it by reference.

To make using Type.Missing a tiny bit easier and more concise, the program creates an object variable named missing and sets it equal to Type.Missing.

Next the program calls the Word server’s Documents.Add method to create a new file. It passes the value missing for the method’s arguments. (Those arguments would specify the template to use and whether the document should be visible.)

The code then loops over the file names that you selected in the CheckedListBox. For each file name, the program calls the Word document object’s Paragraphs.Add method to make a new paragraph. It uses the paragraph’s Range property (many operations in Word rely on Range objects). It calls the Range object’s InlineShapes collection’s AddPicture method to create a picture in the paragraph. It passes the AddPicture method the file’s name.

Next, the program needs to manipulate the picture a little, so it converts it into an InlineShape object. It scales the object by 50% vertically and horizontally and sets the picture’s wrapping mode to place the image inline within the text.

The code then adds a paragraph at the end of the current paragraph and inserts the file’s name there.

After it has finished loading all of the pictures, the program saves the Word document and closes the Word application server.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in files, graphics, interoperability, Office, Word and tagged , , , , , , , , , , , , , , . Bookmark the permalink.

3 Responses to Make a Word document containing pictures in C#

  1. Tanato says:

    After C#4.0 you can use named parameter instead of have to use a bunch of “ref Type.Missing”. Much more elegant solution.

  2. Rod Stephens says:

    I totally agree! Much easier to read.

    In fact, even if you are using a lot of the arguments, you can name them to make it easier to understand what each of the values you pass in represents.

  3. Pingback: Use Word to make a PDF containing pictures in C# - C# HelperC# Helper

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.