Delphi Programming / Object Pascal
サイトのトップページへ リンクのページへ ロゴマーク
[掲載 2009年05月12日] [更新 2013年11月28日] ワード操作フォームEx
ワード操作フォームEx   参考コード類
ワードの画像・図形を保存
動作確認等 Windows 7 U64(SP1) + Delphi XE(UP1) + Word 2010
複数の画像・図形を個別に保存するサンプルは Delphi XE2(UP5)







選択中の図形類を保存  -  クリップボード使用


通常ワードの図形だけ保存することはできません.次のコードは,クリップボードを利用して図形を保存します.選択中の図形をメタファイル,ビットマップ,JPEG画像で保存します.
複数の画像あるいは図形が選択されている場合,それらを結合した画像,図形となります.もし個別に保存するのであれば,選択中の Shape オブジェクトを順番に取得して操作することになります.


リスト1 
//=============================================================================
//  選択中の図形類を保存
//
//  選択中のものを
//  1. メタファイル
//  2. ビットマップ
//  3. JPEGファイル
//  の3つの形式で保存する
//  usesにJpeg,Clipbrdが必要
//=============================================================================
procedure TplWordFormEx2.Button1Click(Sender: TObject);
var
  FilePath1 : String;
  FilePath2 : String;
  FilePath3 : String;
  AMeta     : TMetaFile;
  ABmp      : TBitmap;
  AJpeg     : TJpegImage;
begin
  try
    //選択したオブジェクトをクリップボードにコピー
    wdfWordApp.Selection.Copy;

    //各画像のオブジェクトを生成
    AMeta := TMetaFile.Create;
    ABmp  := TBitmap.Create;
    AJpeg := TJpegImage.Create;

    try
      //保存先フォルダ
      SavePictureDialog1.InitialDir := ExtractFilePath(Application.ExeName);
      SavePictureDialog1.Filter     := 'ImageFiles|*.emf;*.bmp;*.jpg';

      if SavePictureDialog1.Execute then begin
        Update;

        //各々の画像の保存名(フルパス)
        FilePath1 := ChangeFileExt(SavePictureDialog1.FileName, '') + '.emf';
        FilePath2 := ChangeFileExt(SavePictureDialog1.FileName, '') + '.bmp';
        FilePath3 := ChangeFileExt(SavePictureDialog1.FileName, '') + '.jpg';

        //メタファイルを保存
        AMeta.Assign(Clipboard);
        AMeta.SaveToFile(FilePath1);

        //メタファイルをビットマップに変換して保存
        ABmp.Width  := AMeta.Width;
        ABmp.Height := AMeta.Height;
        ABmp.Canvas.Draw(0, 0, AMeta);
        ABmp.SaveToFile(FilePath2);

        //ビットマップをJPEGに変換して保存
        AJpeg.Assign(ABmp);
        AJpeg.SaveToFile(FilePath3);
      end;
    finally
      FreeAndNil(AMeta);
      FreeAndNil(ABmp);
      FreeAndNil(AJpeg);
    end;
  except
  end;
end;




図形の名前または番号を指定して保存  -  クリップボード使用


同じくクリップボードを利用して図形を保存します.図形を名前または番号で指定する場合です.


リスト2 
//=============================================================================
//  図形の名前または番号を指定して保存
//
//  指定した図形を
//  1. メタファイル
//  2. ビットマップ
//  3. JPEGファイル
//  の3つの形式で保存する
//  usesにJpeg,Clipbrdが必要
//=============================================================================
procedure TplWordFormEx2.Button2Click(Sender: TObject);
var
  ItemStr   : OleVariant;
  FilePath1 : String;
  FilePath2 : String;
  FilePath3 : String;
  AMeta     : TMetaFile;
  ABmp      : TBitmap;
  AJpeg     : TJpegImage;
begin
  try
    //図形を指定してクリップボードに
    ItemStr := 'Picture 2';
    wdfWordDoc.Shapes.Item(ItemStr).Select(EmptyParam);
    //クリップボードに送る
    wdfWordApp.Selection.Copy;
    //選択解除
    wdfWordApp.Selection.Collapse(EmptyParam);

    //各画像のオブジェクトを生成
    AMeta := TMetaFile.Create;
    ABmp  := TBitmap.Create;
    AJpeg := TJpegImage.Create;

    try
      //保存先フォルダ
      SavePictureDialog1.InitialDir := ExtractFilePath(Application.ExeName);
      SavePictureDialog1.Filter     := 'ImageFiles|*.emf;*.bmp;*.jpg';

      if SavePictureDialog1.Execute then begin
        Update;

        //各々の画像の保存名(フルパス)
        FilePath1 := ChangeFileExt(SavePictureDialog1.FileName, '') + '.emf';
        FilePath2 := ChangeFileExt(SavePictureDialog1.FileName, '') + '.bmp';
        FilePath3 := ChangeFileExt(SavePictureDialog1.FileName, '') + '.jpg';

        //メタファイルを保存
        AMeta.Assign(Clipboard);
        AMeta.SaveToFile(FilePath1);

        //メタファイルをビットマップに変換して保存
        ABmp.Width  := AMeta.Width;
        ABmp.Height := AMeta.Height;
        ABmp.Canvas.Draw(0, 0, AMeta);
        ABmp.SaveToFile(FilePath2);
        //ビットマップをJPEGに変換して保存
        AJpeg.Assign(ABmp);
        AJpeg.SaveToFile(FilePath3);
      end;
    finally
      FreeAndNil(AMeta);
      FreeAndNil(ABmp);
      FreeAndNil(AJpeg);
    end;
  except
    //図形の選択に失敗した場合
  end;
end;




選択中の複数の画像・図形を個別に保存  -  クリップボード使用


最初のサンプルは,選択中の画像を名前を付けて保存しましたが,複数の画像が選択されている場合,複数の画像が 1 つの画像として保存されます.
次のサンプルは,複数の画像または図形を個別に保存する例です.ただし,docx 形式文書内の画像または図形であって,Delphi XE2 以上専用です.また図形は,文書内の配置方法によっては保存できません.

クリップボードには 1 つのデータしか格納できません.マイクロソフトの Office アプリケーションは Office クリップボードという独自の実装で,過去のコピー内容を記録しています.複数のオブジェクトをコピーした場合は,それらのオブジェクトを独立して保持しています.
Microsoft Office 関連アプリは,Art::GVML Clipformat という独自形式のクリップボードのフォーマット形式があります.これは,画像そのもの,または図形類を XML 形式で格納するようになっています.以下のコードは,このクリップボードのフォーマット形式の内,画像として格納されているものだけを取得して保存します.

この Art::GVML Clipformat 形式のデータの構造は,zip 形式となっています.そこで,TZipFile クラスを使用して,画像だけを取り出してディスクに保存します.


[備考]
Windows XP に付属していた Clipbrd.exe (クリップボードビューア) は,Windows Vista, 7 には付属していません.Windows XP の System32 フォルダからコピーすれぱ使用することができます.特にシステムフォルダに置く必要はありません.単体で動作します.


リスト3 
Delphi XE2 以降用のコード (TZipFile は Delphi XE2 以降で使用可能) 
//=============================================================================
//  Art::GVML Clipformat形式のクリップボードデータの検出と保存
//  docx形式の文書でないと動作不可
//
//  [挿入][図]はInllineでもInlineでなくとても保存可能
//  [挿入][図形](オートシェイプ)はInllineでは保存不可
//
//  usesにClipbrd, System.Zip, StrUtilsが必要
//=============================================================================
procedure TplWordFormEx2.Button3Click(Sender: TObject);
const
  CustomDataStr: String = 'Art::GVML Clipformat';
var
  zipStream   : TMemoryStream;
  hBuffer     : THandle;
  pBuffer     : Pointer;
  DataFormat  : UINT;
  ZipClass    : TZipFile;
  DestFileDir : String;
  FileListArr : TArray<string>;
  strText     : String;
begin
  //選択したオブジェクトをクリップボードにコピー
  wdfWordApp.Selection.Copy;

  //クリップボードのデータフォーマット形式の値を取得
  DataFormat := RegisterClipboardFormat(PChar(CustomDataStr));

  if Clipboard.HasFormat(DataFormat) then begin
    //その形式だったらクリップボードからZipStreamにデータを取得
    zipStream := TMemoryStream.Create;
    try
      ClipBoard.Open;

      hBuffer := Clipboard.GetAsHandle(DataFormat);
      pBuffer := GlobalLock(hBuffer);

      zipStream.WriteBuffer(pBuffer^, GlobalSize(hBuffer));
      GlobalUnlock(hBuffer);
      Clipboard.Close;

      //データ(図・画像)の保存先のフォルダを作成
      DestFileDir := ExtractFilePath(Application.ExeName) + 'AAA';
      ForceDirectories(DestFileDir);

      //Art::GVML Clipformat形式はZip形式なのでZipからデータを取出して保存
      ZipClass := TZipFile.Create;
      try
        zipStream.Position := 0;
        ZipClass.Open(zipStream, zmRead);
        FileListArr := ZipClass.FileNames;
        for strText in FileListArr do begin
          if ContainsText(StrText, 'clipboard/media/image') then begin
            ZipClass.Extract(strText, DestFileDir, False);
          end;
        end;
      finally
        ZipClass.Close;
        FreeAndNil(ZipClass);
      end;
    finally
      FreeAndNil(zipStream);
    end;
  end;
end;


フォーマットの形式 DataFormat の値は,FmtName : array [0..MAX_PATH-1] of Char; と定義して,次のようにして取得することもできます.


  DataFormat := 0;
  for i := 0 to Clipboard.FormatCount -1 do begin
    DataFormat := ClipBoard.Formats[i];
    GetClipBoardFormatName(DataFormat, FmtName, SizeOf(FmtName));
    strText := FmtName;
    if UpperCase(strText) = UpperCase(CustomDataStr) then begin
      break;
    end;
  end;