目標是寫一個工具程式,將Word中的第一個內嵌圖檔另存成JPG。

以下的程式範例有幾個重點可以參考:

  1. 利用C#操作Word物件
  2. Path.GetFullPath可以將相對路徑轉成絕對路徑,跟ASP.NET的Server.MapPath有異曲同工作之妙
  3. 內嵌圖檔以InlineShape方式存在,網路上有很多範例是將它Copy到Clipboard(剪貼簿)再當作圖檔取出,但我測試不成功,C#看不到Word貼上的東西。最後利用InlineShape轉成Metafile後達到另存圖檔的目標。
  4. Image.GetThumbnailImage可以直接產生縮圖,可惜它不會自動保持寬高比例,要自己計算。
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Imaging;
//記得要Reference Microsoft Word 1*.0 Object Library
using Microsoft.Office.Interop.Word;
 
namespace WordPicExtract
{
    class Program
    {
        static void Main(string[] args)
        {
            ApplicationClass wordApp = new ApplicationClass();
            object missing = System.Reflection.Missing.Value;
 
            try
            {
                object fileName = args[0];
                int w = int.Parse(args[1]);
                int h = int.Parse(args[2]);
                if (!File.Exists(fileName.ToString())) {
                    Console.WriteLine("Can't find file[" + fileName + "]");
                    return;
                }
                //Convert to full path, or Word can't find it
                //Path.GetFullPath可以將相對路徑轉成絕對路徑
                fileName = Path.GetFullPath(fileName.ToString());
                object readOnly = true;
                object isVisible = true;
                Console.WriteLine("File [" + fileName + "] opening...");
                //用C#操作Word DOM的小缺點,沒用到的參數要傳入ref missing
                Document doc = wordApp.Documents.Open(
                    ref fileName, ref missing, ref readOnly, ref missing,
                    ref missing, ref missing, ref missing, ref missing,
                    ref missing, ref missing, ref missing, ref isVisible,
                    ref missing, ref missing, ref missing, ref missing);
                if (doc.InlineShapes.Count > 0)
                {
                    //由Word裡的陣列是從1開始的
                    InlineShape shp = doc.InlineShapes[1];
                    //Google上很多文章都用Clipboard把InlineShape轉成Image
                    //但我在x64上C#抓不到Word裡複製的內容
                    //所以改用Metafile類別
                    MemoryStream ms = new MemoryStream(
                        (byte[])shp.Range.EnhMetaFileBits);
                    Metafile mf = new Metafile(ms);
                    //用縮圖尺寸限制算出寬、高縮放比例
                    double ratioW = Convert.ToDouble(mf.Width) / w;
                    double ratioH = Convert.ToDouble(mf.Height) / h;
                    //需要縮小
                    if (ratioW > 1 || ratioH > 1)
                    {
                        //保持寬/高比例
                        if (ratioW < ratioH)
                            w = Convert.ToInt32(
                                h * (Convert.ToDouble(mf.Width) / mf.Height));
                        else
                            h = Convert.ToInt32(
                                w * (Convert.ToDouble(mf.Height) / mf.Width));
                    }
                    else
                    {
                        //不需縮小,維持原尺寸
                        w = mf.Width; h = mf.Height;
                    }
                    //用Word檔案Rename成.jpg
                    string imgFileName = 
                        Path.ChangeExtension(fileName.ToString(), "jpg");
                    //利用Image.GetThumbnailImage產生縮圖
                    Image thumbnail = mf.GetThumbnailImage(w, h, 
                        new Image.GetThumbnailImageAbort(ThumbnailCallback), 
                        IntPtr.Zero);
                    thumbnail.Save(imgFileName);
                    Console.WriteLine("Image [" + imgFileName + "] saved!");
                }
                doc.Close(ref missing, ref missing, ref missing);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error:" + ex.Message);
            }
            finally
            {
                wordApp.Quit(ref missing, ref missing, ref missing);
            }
        }
 
        public static bool ThumbnailCallback()
        {
            return false;
        }
 
    }
}

注意: 記得要參考Word的COM+ Library物件,版本依你所裝的Word版本而定。Word 12.0是Word 2007,Word 2003則是Word 11.0。


Comments

# by 殞落天使

請問一下,如果在要散布的程式碼上,不確定客戶端所安裝的 Office 是 2003 或是 2007 的話,有什麼方法可以動態的按照系統環境做參考呢?

# by Jeffrey

to 殞落天使, 似乎得靠System.Reflection動態載入,或是動態產生Code即時編譯。MSDN Forum有類似的討論: http://tinyurl.com/cdu4zf

# by 殞落天使

你好: 這是我用你給的關毽字查到的資訊 謝謝你 http://huan-lin.blogspot.com/2009/02/dynamically-loaded-dll-with-cshar-4.html

# by yhjhl520

好样的!终于找出一个不同于剪切板里不同的代码.

Post a comment