こんにちは
今回、DLLを動的にロードするプラグイン式のアプリを
作っています。
DLLから画像を単に返してもらったり、
本体側で読み込み済みの画像(JPEGやPNGなど形式不特定)データを
DLL側に投げ、DLL側でなんやら処理された画像データを返してもらう…
といった、ペイントソフトのプラグイン機能のようなものを実現しようとしています。
パラメータとしてTBitmapが使えないのは明白なのですが、
調べてみるとそれっぽいのがいろいろあって迷っています
HDC
HBitmap
tagBitmap
THandle
Pointer(PByte?PInteger?)
本体側はDelphi XEで作るため、内部的にTBitmapをメインに使うので
DLLから来たデータをTBitmapに入れ込めるような設計にしたいと考えています。
DLL側はネイティブなDLLを作れる言語なら不特定としています。
PNGかJPEGか、といった情報は渡さないのですが
色深度(16bit、24bitなど)や画像サイズは渡したいと考えています。
(最悪は別パラメータでやろうと思っていますが…)
どの型をパラメータとして使えば一番楽なのか、
またできればその型での使用例のようなものの
アドバイスをいただけるとありがたいです。
以上よろしくお願いします
ぺんたごんさん こんにちは
一般的かどうかは別として、メモリー上にBitmap形式で保存したものを
もとにやりとりをすれば、やりやすいのでは? と思います。
例えば、こんな感じ
//************* 呼び出し元 *****************
procedure TForm1.Button1Click(Sender: TObject);
var Mem : TMemoryStream;
hMem : THandle;
WHND : THandle;
DllName : String;
p : Pointer;
SaveJpeg : procedure(FName : PChar; hImage,iSize : Cardinal); stdcall;
begin
if OpenDialog1.Execute then begin
Mem := TMemoryStream.Create;
try
DllName := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
DllName := DllName + 'JpegSaveDll.Dll';
Mem.Clear;
Image1.Picture.LoadFromFile(OpenDialog1.FileName);
Image1.Picture.Bitmap.SaveToStream(Mem);
Mem.Position := 0;
hMem := GlobalAlloc(GHND,Mem.Size);
p := GlobalLock(hMem);
Mem.Read(p^,Mem.Size);
if hMem <> 0 then begin
WHND := LoadLibrary(PChar(DllName + #0));
if WHND >= HINSTANCE_ERROR then begin
p := GetProcAddress(WHND, 'SaveJpeg');
if p <> nil then begin
@SaveJpeg := p;
SaveJpeg('E:\test.jpg',hMem);
end;
end;
end;
finally
Mem.Free;
GlobalUnLock(hMem);
GlobalFree(hMem);
end;
end;
end;
//****************** DLL *****************
type
_TStream = class(TCustomMemoryStream);
procedure SaveJpeg(FName : PChar; hImage : Cardinal); stdcall;
var Jpg : TJpegImage;
Bmp : TBitmap;
ptr : Pointer;
Mem : TMemoryStream;
begin
jpg := TJpegImage.Create;
Bmp := TBitmap.Create;
Mem := TMemoryStream.Create;
ptr := GlobalLock(hImage);
try
_TStream(Mem).SetPointer(ptr,GlobalSize(hImage));
Mem.Position := 0;
Bmp.LoadFromStream(Mem);
Jpg.Assign(Bmp);
Jpg.SaveToFile(FName);
finally
GlobalUnLock(hImage);
Jpg.Free;
Bmp.Free;
Mem.Free;
end;
end;
exports
SaveJpeg;
//******************* ここまで ******************
上記の例は、単純にTImageにBitmapを読み込んでメモリーに保存
その後、DLL側でJpegに保存しているだけですが、画像をDLLで編集して
戻したいのであれば、DLL側をfunctionで定義して戻り値をメモリーハンドル
にすれば、OKかと。
ただ、Bitmapでやりとりすると、無駄にメモリーを食いますが・・・
Susieなんかだと、BitmapBitsとBitmapInfoのやりとりだったような・・・
うろ覚え・・・
(上記例は、あくまでも手抜きサンプルです。(^^; )
あら、間違ってますね・・・
procedure TForm1.Button1Click(Sender: TObject);
var Mem : TMemoryStream;
hMem : THandle;
WHND : THandle;
DllName : String;
p : Pointer;
//** SaveJpeg : procedure(FName : PChar; hImage,iSize : Cardinal); stdcall;
SaveJpeg : procedure(FName : PChar; hImage : Cardinal); stdcall;
これで・・・
EXE側
XXX(Bitmap.Canvas.Handle)
DLL側
prcoedure XXX(AHandle: HDC);
begin
Bitmap := TBitmap.Create;
Bitmap.Handle := AHandle;
Bitmap.Handle := 0;
Bitmap.Handle.Free;
end;
KHE00221さん こんにちは。
HDCですか・・・ なるほどです。
ちょっとやってみました。
元のCanvasのサイズに変更がなければ、これで十分かな・・・
拡大縮小や回転等が必要な場合は、もう少し捻らないと・・・
まぁサンプルなので・・・
メイン側
procedure TForm1.Button3Click(Sender: TObject);
var DllName : String;
p : Pointer;
WHND : THandle;
SaveJpgCanvas : procedure(FName : PChar; ACanvas : HDC; w,h : Integer); stdcall;
begin
if OpenDialog1.Execute then begin
DllName := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
DllName := DllName + 'JpegSaveDll.Dll';
Image1.Picture.LoadFromFile(OpenDialog1.FileName);
WHND := LoadLibrary(PChar(DllName + #0));
if WHND >= HINSTANCE_ERROR then begin
p := GetProcAddress(WHND, 'SaveJpgCanvas');
if p <> nil then begin
@SaveJpgCanvas := p;
SaveJpgCanvas('E:\test2.jpg',Image1.Picture.Bitmap.Canvas.Handle , Image1.Picture.BITMAP.Width, Image1.Picture.Bitmap.Height);
end;
end;
end;
end;
DLL側
procedure SaveJpgCanvas(FName : PChar; ACanvas : HDC; W,h : Integer); stdcall;
var Bmp : TBitmap;
Jpg : TJpegImage;
begin
Bmp := TBitmap.Create;
Jpg := TJpegImage.Create;
try
Bmp.width := w;
Bmp.Height := h;
Bmp.PixelFormat := pf24Bit;
BitBlt(Bmp.Canvas.Handle,0,0,w,h,ACanvas,0,0,SRCCOPY);
//メイン側で変更確認するための描画
Bmp.Canvas.Font.Size := 24;
Bmp.Canvas.TextOut(100,100,'test test test');
Bitblt(ACanvas,0,0,w,h,Bmp.Canvas.Handle,0,0,SRCCOPY);
Jpg.Assign(Bmp);
Jpg.SaveToFile(FName);
finally
Bmp.Free;
Jpg.Free;
end;
end;
遅くなりました、XE2セットアップ完了しました^^
サイズ変更はプラグイン式なのであり得ます、というか考慮するつもりです。
HDCだと受け渡しは楽そうですがサイズ変更が面倒なのですか…
頂いた案でいろいろ試行錯誤してみます
ありがとうございました!
チェック忘れ…
ツイート | ![]() |