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 オブジェクトを順番に取得して操作することになります.
copy code
// =============================================================================
// 選択中の図形類を保存
//
// 選択中のものを
// 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 ;
図形の名前または番号を指定して保存 - クリップボード使用
同じくクリップボードを利用して図形を保存します.図形を名前または番号で指定する場合です.
copy code
// =============================================================================
// 図形の名前または番号を指定して保存
//
// 指定した図形を
// 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 以降で使用可能)
copy code
// =============================================================================
// 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 ;