DLLと画像データをやり取りする型は?

解決


ぺんたごん  2011-08-19 00:51:55  No: 40846

こんにちは

今回、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など)や画像サイズは渡したいと考えています。
(最悪は別パラメータでやろうと思っていますが…)

どの型をパラメータとして使えば一番楽なのか、
またできればその型での使用例のようなものの
アドバイスをいただけるとありがたいです。

以上よろしくお願いします


Sara  2011-08-29 22:40:11  No: 40847

ぺんたごんさん  こんにちは

一般的かどうかは別として、メモリー上に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のやりとりだったような・・・
うろ覚え・・・

(上記例は、あくまでも手抜きサンプルです。(^^;  )


Sara  2011-08-29 22:43:03  No: 40848

あら、間違ってますね・・・

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;

これで・・・


KHE00221  2011-09-01 03:31:49  No: 40849

EXE側

XXX(Bitmap.Canvas.Handle)

DLL側

prcoedure XXX(AHandle: HDC);
begin
  Bitmap := TBitmap.Create;
  Bitmap.Handle := AHandle;

  Bitmap.Handle := 0;
  Bitmap.Handle.Free;
end;


Sara  2011-09-01 19:56:12  No: 40850

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;


ぺんたごん  2011-09-03 20:36:40  No: 40851

遅くなりました、XE2セットアップ完了しました^^

サイズ変更はプラグイン式なのであり得ます、というか考慮するつもりです。
HDCだと受け渡しは楽そうですがサイズ変更が面倒なのですか…

頂いた案でいろいろ試行錯誤してみます
ありがとうございました!


ぺんたごん  2011-09-03 20:37:47  No: 40852

チェック忘れ…


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加