Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Screenshot von DirectX (https://www.delphipraxis.net/142182-screenshot-von-directx.html)

Garfield 23. Okt 2009 10:55


Screenshot von DirectX
 
Mit der folgenden Procedure kann ich das aktuell angezeigte Bild als Bitmap speichern:

Delphi-Quellcode:
procedure TDSPlayer.SetSaveImage(Value: String);
var
  BufferSize : Integer;
  DIBImage  : Array of Byte;
  pDIBImage : Pointer;
  lWidth    : Integer;
  lHeight   : Integer;
  hRes      : HRESULT;
  bmphdr    : BITMAPFILEHEADER;
  bmpinfo   : BITMAPINFOHEADER;
  nWritten  : DWORD;
  fh        : THandle;
begin
  fh := 0;
  pDIBImage := nil;
  {
  *  Wenn ein Videostream vorhanden ist, das Bild holen.
  }
  if isVideo
  then try
    {
    *  HRESULT GetCurrentImage(
    *    [in, out] long *pBufferSize,
    *    [out]    long *pDIBImage
    *  );
    *
    *  Beim ersten Aufruf muss die Buffersize 0 und der Pointer nil sein, dann
    *  erhält man die erforderliche Buffersize.
    }
    pDIBImage := nil;
    BufferSize := 0;
    hRes := FBasicVideo.getCurrentImage(BufferSize, pDIBImage^);
    if (hRes <> S_OK)
    then raise Exception.Create(Format('%s'#10#13'Error Code: %s', [GetErrorString(hRes), IntToHex(hRes, 8)]));
    {
    *  Es wird der Speicher bereitgestellt und der Aufruf erfolgt mit der rich-
    *  tigen Speichergröße sowie dem Zeiger auf den bereitgestellten Speicher.
    }
    setLength(DIBImage, BufferSize);
    pDIBImage := @DIBImage[0];
    FBasicVideo.GetCurrentImage(BufferSize, pDIBImage^);
    {
    *  Bitmapgröße
    }
    FBasicVideo.get_VideoWidth(lWidth);
    FBasicVideo.get_VideoHeight(lHeight);
    {
    *  Speicher für Bitmapdateiheader und Bitmapinfoheader bereitstellen
    }
    FillChar(bmphdr, SizeOf(bmphdr), 0);
    FillChar(bmpinfo, SizeOf(bmpinfo), 0);
    {
    *  Den Bitmapdateiheader erstellen
    }
    bmphdr.bfType   := $4D42;
    bmphdr.bfSize   := sizeof(bmphdr) + sizeof(bmpinfo) + BufferSize;
    bmphdr.bfOffBits := sizeof(bmphdr) + sizeof(bmpinfo);
    {
    *  Den Bitmapinfoheader erstellen
    }
    bmpinfo.biSize    := sizeof(bmpinfo);
    bmpinfo.biWidth   := lwidth;
    bmpinfo.biHeight  := lheight;
    bmpinfo.biPlanes  := 1;
    bmpinfo.biBitCount := 32;
    {
    *  Dateierweiterung kontrollieren
    }
    if ExtractFileExt(LowerCase(Value)) <> '.bmp'
    then Value := ChangeFileExt(Value, '.bmp');
    {
    *  Die Datei schreiben
    }
    fh := CreateFile(PChar(Value), GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
    if fh <> INVALID_HANDLE_VALUE
    then begin
      WriteFile(fh, bmphdr, sizeof(bmphdr), nWritten, nil);
      WriteFile(fh, bmpinfo, sizeof(bmpinfo), nWritten, nil);
      WriteFile(fh, pDIBImage^, BufferSize, nWritten, nil);
    end
    else raise Exception.Create(GetLastError);
  finally
    CloseHandle(fh);
  end;
end;
Anstelle das Bild sofort zu speichern möchte ich lieber ein Bitmap zurück bekommen. Wenn ich einen TStream und anstelle WriteFile aStream.Write verwende, bekomme ich bei aBitmap.LoadFromStream nur einen Fehler. Als Alternative habe ich die Verwendung der GDI gefunden. Nach der Deklaration von

Delphi-Quellcode:
type
  {$EXTERNALSYM Status}
  Status = (
    Ok,
    GenericError,
    InvalidParameter,
    OutOfMemory,
    ObjectBusy,
    InsufficientBuffer,
    NotImplemented,
    Win32Error,
    WrongState,
    Aborted,
    FileNotFound,
    ValueOverflow,
    AccessDenied,
    UnknownImageFormat,
    FontFamilyNotFound,
    FontStyleNotFound,
    NotTrueTypeFont,
    UnsupportedGdiplusVersion,
    GdiplusNotInitialized,
    PropertyNotFound,
    PropertyNotSupported
  );
  TStatus = Status;
  GpStatus = TStatus;
  GpBitmap = Pointer;
  {$EXTERNALSYM GdipCreateBitmapFromGdiDib}
  function GdipCreateBitmapFromGdiDib(gdiBitmapInfo: PBitmapInfo; gdiBitmapData: Pointer; out bitmap: GPBITMAP): GPSTATUS; stdcall;
           external 'gdiplus.dll' name 'GdipCreateBitmapFromGdiDib';
erhalte ich dann mit
Delphi-Quellcode:
GdipCreateBitmapFromGdiDib(@bmpinfo, pDIBImage, pBitmap);
einen Pointer auf ein Bitmap. Ich weiß nun allerdings nicht, wie ich dann an das Bitmap herankomme.

erich.wanker 23. Okt 2009 15:04

Re: Screenshot von DirectX
 
Hallo Garfield,

ich hab grad ein kleines Programm (greift auf DirectX zu) funktionstüchtig, welches einen Videostream von einer Webcam abgreift und in einem Image (via Timer [intervall 100]) darstellt..

Das Bild kann dann via drag&Drop oder via jpegImg.SaveToFile abgespeichert werden..

würde dir das helfen ?

Garfield 23. Okt 2009 17:27

Re: Screenshot von DirectX
 
Hallo erich,

Dein IVideoWindow ist ein TImage und dieses wird dann als JPEG gespeichert?

Mein IVideoWindow ist ein TPanel. Hatte auch überlegt, ob man den Canvas kopieren kann. Eventuell stimmt dann der AspectRatio ohne weitere Bearbeitung, wobei dann wohl auch die verwendete Skalierung berücksichtigt wird. Deshalb wollte ich eine Kopie des Quellbildes machen. Eventuell mit Berücksichtigung des AspectRatio. Alternativ hatte ich es mit ISampleGrabber versucht. Das habe ich dann wieder gelöscht, weil kein Ergebnis herausgekommen war.

Garfield 24. Okt 2009 11:24

Re: Screenshot von DirectX
 
Mit der Funktion GdipCreateHBITMAPFromBitmap bekommt man das Handle zum Pointer des Bitmaps.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:11 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz