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;