none
Word文書のプレビュー画像を取得する方法 RRS feed

  • 質問

  • 以下の環境で開発しております。
      Windows XP SP3
      VS2003 Ver 7.1.6030
      Office2003 (11.8307.8221) SP3

    WORDのプレビュー画像を取得する方法を模索しています。

    以下のコードですと文書のプレビュー表示はできます。

      object  fileName   = @"C:\sample.doc";
      object  isReadOnly = true;
      object  missing    = System.Reflection.Missing.Value;

      Word._Application    word = new Word.Application();
      word.Visible = true;

      // ドキュメント読み込み
      Word._Document  document = word.Documents.Open(ref fileName,
        ref missing, ref isReadOnly, 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);

      // プレビュー表示する
      word.PrintPreview = true;

    この後にプレビュー画像をBITMAPとして取得したいのです。
    何か良い方法はないでしょうか。

    よろしくお願い致します。

    2009年7月22日 1:26

回答

  • Word のクラスから直接取得する方法は見つかりませんでした。
    プレビュー表示はできるとのことなので
    条件つきではありますが以下の手段はいかがでしょうか。

    ・プレビューの枠が画像に含まれてもよければ、全画面コピーを取得する。
    ・プレビューの大きさが常に同じなら、座標指定して部分画面コピーを取得する。

    • 回答としてマーク kumatta 2009年8月14日 1:09
    2009年8月4日 1:07

すべての返信

  • Word のクラスから直接取得する方法は見つかりませんでした。
    プレビュー表示はできるとのことなので
    条件つきではありますが以下の手段はいかがでしょうか。

    ・プレビューの枠が画像に含まれてもよければ、全画面コピーを取得する。
    ・プレビューの大きさが常に同じなら、座標指定して部分画面コピーを取得する。

    • 回答としてマーク kumatta 2009年8月14日 1:09
    2009年8月4日 1:07
  • ご回答ありがとうございます。

    >Word のクラスから直接取得する方法は見つかりませんでした。
    やはりそうなのですね…。
    欲しいのは高解像度な全体像であり恒久的なロジックなため、印刷バッファを利用するなど別の手法を考えたいと思います。

    2009年8月5日 6:47
  • 追記

    ■ WORDから特定のプリンタ(GenericプリンタのようなWindowsヌルプリンタ)に印刷処理をかけ、そのスプールファイルを取得することでページ単位の画像を取得することができました。ただしこの方法ではEMFOnly形式=GDIレコードでしか取得できないという限定条件があるようです。

    このケースでは用紙サイズが重要です。マージンを含めたくない場合など、独自に用紙を作成しておかなければなりません。
    「コントロールパネル」→「プリンタとFAX」→メインメニューの「ファイル」→「サーバーのプロパティ」→「新しい用紙を作成する」
    という流れで印刷用紙を手動で追加できるのですが、これをプログラムから操作して
    マージンをカットした用紙サイズに変更→そのサイズのtemporaly用紙の作成→印刷(サイズが合っているだけで勝手にtemporaly用紙が選ばれる)→スプルファイル取得→EMFファイルとして保存→temporaly用紙の削除
    というフローで処理します。
    用紙が横向きの場合、widthとheightが逆転する点に注意してください。

    ただ、上記でも「GDIレコードでしか取得できない」と記載している通りこの方法では品質の悪いベクター画像しか取得できません。期待したのはEmfPlusOnly形式もしくはEmfPlusDual形式=GDI+レコードを含んだベクター画像です。これが実現できなければ、品質が悪くて使い物になりませんでした。

    ■ 他のアプローチとしてクリップボードを使用する方法を考えました。ページ単位で範囲選択し、クリップボードに格納してEMF形式で取り出す方法です。ただし.NetFrameworkのMetafileクラスはEMFでのSaveメソッドをまともに実装していないため、独自にEMF保存するロジックが必要です。
    ※ Graphicオブジェクトにメタデータを描画してファイル保存したり、DelphiやVB6.0で作ったプラグインを経由したり・・・

    またこの方法ですとEMFとしてではなくWindows3.1時代の旧WMF形式(WmfPlaceable形式)で取得することも可能でした。この場合、.NetFrameworkを使用しない古い環境(つまりアンマネージなライブラリや開発環境)の使用を強いられます。私はDelphiとVB6.0でやってみましたが、いずれも成功しました。

    ■ WORDはページ単位で「オブジェクト」としてうまく図形化しないと高品質なEMFになりません。ただ漠然と範囲選択してクリップボードに格納するだけではダメなようです。私は独自のロジックで方法を確立しましたが、それはここでは割愛します。

    この記事がいつか誰かの役に立つことを期待します。
    以上です。

    2009年8月14日 1:48
  • アイデアレベルですけど、XPS 形式で出力すれば、それをページ単位で画像化することは、それほど難しくないんじゃないですかね?
    2009年8月14日 2:44
    モデレータ
  • >XPS形式

    開発環境がVS2003とOffice2003のようなのであげてなかったんですが、以下のようなソースでXPSからビットマップが得られます。
    #WPFが要るのでVS2003だけで画像にするのは無理かと

    この方法だとXPSに出力できればEXCELでもWORDでも画像が得られます。
    ただ、そのXPSを出力するのにMicrosoft XPS Document Writerへファイル印刷させる必要があります。
    これはActivePrinterをMicrosoft XPS Document WriterにしてやればXPSファイルが得られます。

    Word97で試しても印刷をファイル出力先を指定できるので割と簡単に実現
    Excel2000以降ではPrintOutにファイル指定できるので簡単です。Excel97ではファイル出力先指定が面倒でした…
    #Word/EXCELの操作は面倒なのでVB.NETを使用

    using System;
    using System.Collections.Generic;
    using System.Windows.Xps.Packaging; //ReachFramework
    using System.Windows.Xps; //ReachFramework
    using System.Windows.Documents; //PresentationCore
    using System.Windows; //WindowBase
    using System.Windows.Media.Imaging;//PresentationCore
    
    namespace XPS
    {
        internal static class XPSTool
        {
            public static SortedList<int, System.Drawing.Bitmap> GetBitmaps(string xpsPath)
            {
                return GetBitmaps(xpsPath, null, false);
            }
            public static SortedList<int, System.Drawing.Bitmap> GetBitmaps(string xpsPath, IEnumerable<int> pages)
            {
                return GetBitmaps(xpsPath, pages, false);
            }
    
            /// <summary>XPSファイルのページを画像にして取得</summary>
            /// <param name="xpsPath">XPSファイルへのパス</param>
            /// <param name="pages">取得したいページのリスト nullで全ページ</param>
            /// <param name="breakPageError">true:変換エラーで打ち切るか false:エラー</param>
            /// <returns></returns>
            public static SortedList<int, System.Drawing.Bitmap> GetBitmaps(string xpsPath, IEnumerable<int> pages, bool breakPageError)
            {
                SortedList<int, System.Drawing.Bitmap> list = new SortedList<int, System.Drawing.Bitmap>();
    
                try
                {
                    using (XpsDocument xpsDoc = new XpsDocument(xpsPath, System.IO.FileAccess.Read))
                    {
                        FixedDocumentSequence docSeq = xpsDoc.GetFixedDocumentSequence();
                        DocumentReferenceCollection drc = docSeq.References;
    
                        foreach (DocumentReference dr in drc)
                        {
                            FixedDocument fixdoc = dr.GetDocument(false);
                            if (pages == null)
                            {
                                int pageCount = docSeq.DocumentPaginator.PageCount;
                                for (int page = 0; page < pageCount; page++)
                                {
                                    FixedPage fixedPage = (FixedPage)docSeq.DocumentPaginator.GetPage(page).Visual;
                                    list.Add(page, TranslateBitmap(fixedPage));
                                }
                            }
                            else
                            {
                                foreach (int page in pages)
                                {
                                    FixedPage fixedPage = (FixedPage)fixdoc.DocumentPaginator.GetPage(page).Visual; ;
                                    list.Add(page, TranslateBitmap(fixedPage));
                                }
                            }
                        }
                    }
                }
                catch
                {
                    if (!breakPageError)
                    {
                        throw;
                    }
                }
                return list;
            }
    
            /// <summary>描画状態が固定されているページをPNGに変換</summary>
            private static System.Drawing.Bitmap TranslateBitmap(FixedPage fixedPage)
            {
                System.Drawing.Bitmap bmp = null;
                double width;
                double height;
                width = fixedPage.Width;
                height = fixedPage.Height;
    
                System.Windows.Size size = new System.Windows.Size(width, height);
                fixedPage.Measure(size);
                fixedPage.Arrange(new System.Windows.Rect(new System.Windows.Point(), size));
                fixedPage.UpdateLayout();
    
                BitmapImage bmpimage = new System.Windows.Media.Imaging.BitmapImage();
    
                //96dpiが基本?
                RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)size.Width, (int)size.Height, 96, 96, System.Windows.Media.PixelFormats.Default);
    
                renderTarget.Render(fixedPage);
    
                BitmapEncoder encoder = new PngBitmapEncoder();
                BitmapFrame frame = BitmapFrame.Create(renderTarget);
                encoder.Frames.Add(frame);
    
                using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                {
                    encoder.Save(ms);
                    ms.Position = 0;
                    bmp = new System.Drawing.Bitmap(ms);
                }
                return bmp;
            }
        }
    }
    
    2009年8月14日 4:53
  • >gekka様
    サンプルコード、ありがとうございます。
    今後の参考にさせて頂きます。

    XPSというフォーマットですが、私は知りませんでした。
    色々やってみたのですが、画像の再現性が非常に高いフォーマットですね。EMFのようにいびつになることがありません。
    圧縮ファイルとして生成されるので転送効率も良さそうです。
    lhazで解凍してみたらデータが階層化されていて、WMF/EMFのような解析の困難さもないようです。
    解読しやすくて効率的で…優れたフォーマットだと思います。画像、フォント、スタイル、色々なことがExploler上の操作で分かってしまいます。

    Windowsの次期標準ベクター画像はSVGかと思っていましたがXPSになっていくんでしょうか。
    WindowsXPでもプリンタドライバを入れるだけでライターとして使えますし、今後のために注視したいと思います。

    ただMSのすることなので不安もあります。
    WMFやEMF、自分たちで実装しておきながらまともなサポートや実装を怠ったり、
    .Net Frameworkという新しいプラットフォームでWMFやEMFを簡単に切り捨てたり。

    2009年8月17日 1:10