does any one know how to initilize directX using hdc? the problem is i want to draw my stuff in a component inside a window and these things usualy only have HDC but DX gets HWND which is assigned to a window.
You can create an invisible window using CreateWindow with 0 width and 0 height and use that hwnd to create the device. Then you can render the images to a texture, retreive the raw buffer from it and pass it to the application where the image is copied to the window. You do no need the HDC too.
HDC represents your rendering device, while HWND represents your window.
You can get get an HDC representing the Window's rendering target with GetDC (don't forget to ReleaseDC it when you're done).
Hope that helps?
Related
In addition to drawing GDI+ onto a control canvas via TGPGraphics (which has been working fine), I'm also trying to draw onto a TBitmap using GDI+ as well, and then drawing that bitmap to the control canvas. However, nothing actually appears to get drawn.
The following code is within the WM_PAINT message handler, which again works for the actual control canvas, but when creating an equivalent TGPGraphics object and passing this TBitmap handle, nothing gets drawn:
FBitmapCanvas:= CreateGPCanvas(FBitmap.Handle);
try
FBitmapCanvas.DrawLine(FSomePen, P1, P2); //Same pen used to successfully draw to control canvas
finally
FreeAndNil(FBitmapCanvas);
end;
Canvas.Draw(0, 0, FBitmap); //Draw this bitmap to control canvas
CreateGPCanvas looks like so, and is used for both this bitmap and the control:
function CreateGPCanvas(const DC: HDC): TGPGraphics;
begin
Result:= TGPGraphics.Create(DC);
Result.SetInterpolationMode(InterpolationMode.InterpolationModeHighQuality);
Result.SetSmoothingMode(SmoothingMode.SmoothingModeHighQuality);
Result.SetCompositingQuality(CompositingQuality.CompositingQualityHighQuality);
end;
On the other hand, if I don't try to use the TGPGraphics and instead draw a line directly via the TBitmap.Canvas property, it works fine (but of course looks ugly because it's not GDI+). So I know the actual bitmap gets drawn correctly to the control canvas.
FBitmap.Canvas.MoveTo(P1.X, P1.Y);
FBitmap.Canvas.LineTo(P2.X, P2.Y);
What am I doing wrong here, and how do I make the TGPGraphics work on this bitmap canvas?
PS - The only reason I'm using a TBitmap at all is because what I'm actually writing needs to "remember" a portion of what was previously drawn and retain it, rather than repainting it over and over.
Just figured out the problem, and it was a silly mistake.
When creating a TGPGraphics object, instead of passing FBitmap.Handle, it should rather be FBitmap.Canvas.Handle.
You need the handle of the bitmap's canvas, not of the bitmap itself.
So I've filled a canvas on my printer object and it prints perfectly. Now I need to save to a file that same canvas that's filled in the printer.canvas. I know I can save a bitmap object and I thought I could just instantiate a bitmap and assign it the printer canvas, but alas, its read-only. This is the line with the error. Anyone has any idea?
bitmapAGuardar.Canvas := Printer.Canvas;
This isn't how to do it, and in fact what you ask can't be done.
Write a function that receives a canvas as its parameter. Have that function perform the necessary drawing. When you need to print to a printer call the function passing the printer canvas. When you need to save to a bitmap, call the function passing the bitmap canvas.
You'll likely need to account for the fact that the printer canvas resolution will be much greater than the resolution you want for the bitmap.
I have a form that is higher than the screen, and when I try to simulate the printscreen key with
keybd_event(VK_SNAPSHOT, 1, 0, 0);
of course, the form gets cropped.
So I tried to do the following on the active form:
Clipboard.Assign(GetFormImage);
but still, even in this case, the bitmap gets cropped too.
There was an old Delphi component, BDPrint, that was available here:
http://www.efg2.com/Lab/Library/Delphi/Printing/
but it's not available anymore, that was able to print a form creating a temporary tImage and then printing it, even the off screen portion, but I do not have the source code of it anymore.
How can I generate a bitmap of the active form, with the off screen portion too, and store it in the clipboard? Thank you
Off the top of my head, I could search around some more if I had the time:
fist get the handle of the window (with FindWindow or somesuch)
GetwindowDC
BitBlt onto a TBitmap's Canvas.Handle of your own (or StretchBlt or a personal favorite PlgBlt)
You don't need to involve the clipboard, or otherwise capture the screen. Try passing the form's Handle property to PrintWindow(), or send a WM_PRINT message directly to the Form. Either one will let you specify an HDC (such as the one from the TBitmap.Canvas.Handle property) for the window to draw itself onto.
Preambule:
I'm working with Black Magic Design (BMD) Decklink input card to acquire HD video signal. They provide C++ Sample with their SDK. I've successfully translated the c++ sample into Delphi (VCL). I've also isolated the API call in a TDecklink witch I want it to be available to the Delphi community. It work very well in VCL (I can provide the TDecklnk with a demo app to use it if requested).
Now I need to acquire the signal in a FMX form (but not crosscompile to other platform than Windows). I've tried to modify the TDecklink to be usable in FMX without success.
Core Question:
In my VCL version, I pass a TPaintBox refference to my TDecklink. The TPaintBox is used by the GraphBuilder as area to display the live video.
Here is some line of code I use in the VCL version to assign the TPaintBox to the GraphBuilder:
pWnd := WindowFromDC(FpboxPreview.Canvas.Handle); //WindowFromDC retreive HWND from HDC
hr:= pIVMRWindowlessCtrl.SetVideoClippingWindow(pWnd); // set the bounds of the video to the preview window
if hr = S_OK then
begin
previewRect.Left := FpboxPreview.Left;
previewRect.Right := FpboxPreview.Width;
previewRect.Top := FpboxPreview.Top;
previewRect.Bottom := FpboxPreview.Height;
hr:= pIVMRWindowlessCtrl.SetVideoPosition(nil, #previewRect); // show the whole of the source frame in the whole of the client area of the control
hr:= pIVMRWindowlessCtrl.SetAspectRatioMode(VMR_ARMODE_LETTER_BOX); // maintain the aspect ratio of the video
hr:= pIVMRWindowlessCtrl.SetBorderColor(GetSysColor(COLOR_BTNFACE)); // set the colour of the letter or pillar boxed area
Where PWnd is a HWND
In FMX, what is the best component and parameter to use to provide what the GraphBuilder expect to receive ?
In VCL, TPaintBox is a TGraphicControl descendant that draws onto the HDC of its Parent control's HWND. When the Parent control receives a WM_PAINT message, it draws itself onto the provided HDC as needed, and then temporarily gives that same HDC to each child TGraphicControl when drawing them, clipping the HDC to each child's coordinates and rectangle accordingly. If you try to draw onto a TGraphicControl.Canvas from outside of its Parent control's WM_PAINT handler (which you should never do), TCanvas will temporarily grab the Parent control's HDC using the Win32 API GetDC() function.
Thus, this statement:
pWnd := WindowFromDC(FpboxPreview.Canvas.Handle);
Is effectively the same as this:
pWnd := FpboxPreview.Parent.Handle;
So, you are actually putting your video on the window of the TPaintBox.Parent control, not on the TPaintBox itself. If you want the video associated with its own control, consider using TPanel instead, as it is a TWinControl descendant with its own HWND.
FireMonkey, on the other hand, has no concept of TGraphicControl and TWinControl. Every control is a TControl descendant with an overridden Paint() method to handle any custom drawing onto a TCanvas that is provided by either the parent TForm or the caller of the TControl.PaintTo() method. FireMonkey does not even create an HWND for each control. Only the parent TForm has its own HWND (so it can interact with the OS). Child controls are drawn directly onto that window, adjusting the drawing coordinates and clipping rectangle accordingly as they go along (under the hood, FireMonkey uses DirectX (Windows) or OpenGL (other platforms) for all of its drawing).
So, if you really need an HWND for your video class to display on, you will have to either:
use the HWND of a TForm, which you can get by either passing its Handle property to the
FMX.Platform.Win.WindowHandleToPlatform() function (or the FMX.Platform.Win.FmxHandleToHWND() function on older FireMonkey versions):
uses
..., FMX.Platform.Win;
pWnd := WindowHandleToPlatform(Form1.Handle);
Or passing the TForm itself to the FMX.Platform.Win.FormToHWND() function:
uses
..., FMX.Platform.Win;
pWnd := FormToHWND(Form1);
use the Win32 API directly to create your own HWND as needed and then embed it inside the HWND of a TForm.
Otherwise, you will have to re-think your video UI in FireMonkey. For instance, assuming the video class can provide you with images of the video frames, you can draw them onto the TPaintBox.Canvas from within the TPaintBox.OnPaint event (which is how TPaintBox is meant to be used in the first place, in both VCL and FireMonkey). Or maybe derive your own custom TControl that pulls images from the video class in its own overridden Paint() method. I don't know what your GraphBuilder class is capable of, but BMD provides an SDK for controlling video recording/playback hardware and accessing video data (see this PDF).
I would like to know width and height of canvas but I know only its HDC.
I've tried with this code:
procedure TForm92.Button1Click(Sender: TObject);
var
hBitmap: HGDIOBJ;
Header: TBitmapInfoHeader;
begin
hBitmap := GetCurrentObject(PaintBox1.Canvas.Handle, OBJ_BITMAP);
GetObject(hBitmap, sizeof(TBitmapInfoHeader), #Header);
ShowMessage(IntToStr(Header.biWidth));
end;
However it does not return me the dimensions of PaintBox1's Canvas, instead I am getting the dimensions of the form on which the PaintBox1 is placed.
What am I doing wrong?
Given only a handle to a device context, it's not generally possible to determine the dimensions of a TCanvas object associated with it. Descendants of TGraphicControl all share the DC of their parent control because only windowed controls can have device contexts, and TGraphicControl objects aren't windowed controls.
When a TGraphicControl descendant (including TPaintBox) needs a canvas, TControlCanvas calls back to the control's GetDeviceContext method. That method returns the DC handle of the parent control, but before returning, it modifies the DC a little:
Result := Parent.GetDeviceContext(WindowHandle);
SetViewportOrgEx(Result, Left, Top, nil);
IntersectClipRect(Result, 0, 0, Width, Height);
That is, it shifts the origin to match the upper left corner of the current control, and it updates the clipping region to exclude anything outside the current control's borders.
In some circumstances, you might be able to determine the canvas's dimensions by inspecting the DC's clipping region (with GetClipRgn), but that's only if the region hasn't been adjusted in any other ways. The clipping region might be smaller than the control's dimensions. (It will never be larger because of the call to IntersectClipRect shown above.)
As you can see, you need more than just the DC handle to get the information you want. Ideally, that will include a TControl reference; then you can just read its Height and Width properties to know the control's and the canvas's dimensions.
The handle of a TCanvas points to a Windows device context (DC). Assuming a display device context (rather then a printer, memory, or information DC), then the logical size of that DC is equal to the (total) screen resolution, as obtainable by GetDeviceCaps or GetSystemMetrics. (Although you can paint beyond that dimensions, output will be cut).
The maximum visible part of a display device context is limited by its associated window size, which is obtainable by WindowFromDC and GetClientRect.
The current visible part may be limited by either the current framework (such as TPaintBox from the Delphi VCL which does not have a window handle and instead depends on the framework to translate the dimensions to the control's size within the parent's DC, which is obtainable by inspecting the control's dimensions) or by the current set clipping region, which is obtainable by GetClipRgn.