Show A D3DImage With SharpDX - c#

I intend to develop an application to get an image from a file and show it with Directx9 . I have used this code but I got the Error on SetBackBuffer Method!!
System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
private void d3dImage_IsFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (d3dImage.IsFrontBufferAvailable)
{
// (Re)initialization:
Bitmap b = new Bitmap(#"C:\Users\newuser\Desktop\3.jpg");
IntPtr Mysurface = b.GetHbitmap();
if (Mysurface != IntPtr.Zero)
{
d3dImage.Lock();
//Error occurred this line
d3dImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, Mysurface);
d3dImage.Unlock();
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
}
else
{
// Cleanup:
CompositionTarget.Rendering -= CompositionTarget_Rendering;
//Sample.Cleanup();
}
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// Now that we can get an HWND for the Window, force the initialization
// that is otherwise done when the front buffer becomes available:
d3dImage_IsFrontBufferAvailableChanged(this,
new DependencyPropertyChangedEventArgs());
}
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
if (d3dImage.IsFrontBufferAvailable)
{
d3dImage.Lock();
//Sample.Render();
// Invalidate the whole area:
d3dImage.AddDirtyRect(new Int32Rect(0, 0,
d3dImage.PixelWidth, d3dImage.PixelHeight));
d3dImage.Unlock();
}
}
actually I want show an image in d3dimage in a WPF project. Can any one help me? I could not find good resources about Directx and C#!!!
Edited Using Sharpdx and Got new Error "'HRESULT: [0x8876086C], Module: [SharpDX.Direct3D9], ApiCode: [D3DERR_INVALIDCALL/InvalidCall], "
s = new SharpDX.Direct3D9.Surface(IntPtr.Zero);
SharpDX.Direct3D9.Surface.FromFile(s, #"C:\Users\newuser\Desktop\3.jpg", SharpDX.Direct3D9.Filter.None, 1);

You're setting the back buffer to a Bitmap. You cannot do this. The back buffer must be of type IDirect3DSurface9. This is noted in the documentation for the SetBackBuffer method.
In order to use DirectX9 (unmanaged) from C# (managed), you need to use a wrapper library. Are you using one? If not, there are several available. SlimDX and SharpDX seem to be the most popular. Using any of the wrapper libraries, you can create a IDirect3DSurface9that you render to with a IDirect3DDevice9, and attach that surface to your WPF control. Your rendered content will then appear in the control.
I think using DirectX may be overkill for what you need, but I'm not sure what the entire scope of your project is.
Solution using SharpDX
I put together a working example that uses SharpDX to display an image within a D3DImage. This is very basic and doesn't include proper error handling. It's just meant to get you going in the right direction.
Step 1 - Create D3D9 device
To create the necessary surfaces, you will need a Direct3D 9 Device. The following code will create a Device using SharpDX.
//Create the d3d interface.
Direct3D d3d = new Direct3D();
//Get a handle to the WPF window. This is required to create a device.
IntPtr windowHandle = new WindowInteropHelper(this).Handle;
//Create a device. Using standard creation param.
//Width and height have been set to 1 because we wont be using the backbuffer.
//Adapter 0 = default adapter.
PresentParameters presentationParams = new PresentParameters(1,1);
Device d3dDevice = new Device(d3d, 0, DeviceType.Hardware, windowHandle, CreateFlags.HardwareVertexProcessing, presentationParams);
Step 2 - Create the image surface
Create a surface to hold the image data.
//Create an empty offscreen surface. Use SystemMemory to allow for surface copying.
Surface imageSurface = Surface.CreateOffscreenPlain(d3dDevice, ImageWidthPixels, ImageHeightPixels, Format.A8R8G8B8, Pool.SystemMemory);
//Fill the surface with the image data.
Surface.FromFile(imageSurface, "dx.jpg", Filter.None, 0);
Step 3 - Create the render target surface
Create the surface that acts as a render target. This is the type of surface required by D3DImage.
//Create the surface that will act as the render target.
//Set as lockable (required for D3DImage)
Surface target = Surface.CreateRenderTarget(d3dDevice, ImageWidthPixels, ImageHeightPixels, Format.A8R8G8B8, MultisampleType.None, 0, true);
Step 4 - Copy the image surface to the render target.
The image surface can be copied into the render target surface using the Device.UpdateSurfaces method. Note that in the previous steps, both surfaces were created with the same format (A8R8G8B). Watch out for this. It's necessary for surface copies.
//Copy the image surface contents into the target surface.
d3dDevice.UpdateSurface(imageSurface, target);
Step 5 - Attach the surface to D3DImage
You now have a surface that contains your image and that can be used with 'D3DImage`. Make sure you use the target surface, not the image source surface.
this.wpfImageSource.Lock();
this.wpfImageSource.SetBackBuffer(D3DResourceType.IDirect3DSurface9, target.NativePointer);
this.wpfImageSource.AddDirtyRect(new Int32Rect(0, 0, wpfImageSource.PixelWidth, wpfImageSource.PixelHeight));
this.wpfImageSource.Unlock();
Results
The image appears!

Related

Unknown Error Cause While Debugging WPF - 'System.AccessViolationException' occurred in SkiaSharp.dll

I am incredibly new to C# (my knowledge comes exclusively from YouTube tutorials), so please keep this in mind when viewing my novice code! I apologize in advance.
I am trying to develop a WPF desktop application using VS2022. Without going into extensive detail, the application needs to be capable of loading and displaying SVG files, as well as storing the path data. For this, I am using the SkiaSharp and Skia.Svg nuget packages.
As in the title, when the program tries to run the 'draw' function, it gives the following error:
An unhandled exception of type 'System.AccessViolationException' occurred in SkiaSharp.dll
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
The following are how I initialized the canvas, as well as the 'draw' function itself:
canvas:
SKCanvas canvas;
public void CreateCanvas()
{
SKImageInfo info = new SKImageInfo(1920, 1080);
SKSurface surface = SKSurface.Create(info);
canvas = surface.Canvas;
canvas.Clear(SKColors.Empty);
}
//not actually sure if this is an initializer oop...
public MainWindow()
{
InitializeComponent();
CreateCanvas();
}
draw function:
private void draw(string path, SKCanvas canvas)
{
var svg = new SKSvg();
svg.Load(path);
canvas.DrawPicture(svg.Picture);
}
The "path" string is simply the filepath for the desired svg. The one I've been feeding it for debug purposes is on my desktop, and I am running VS as admin. Again, I'm new to this, so I'm not sure where the error lies or what really causes it. Seeking help in determining the root cause!

C# System.Drawing.Image.get_Width() throws exception on WinForms form is maximized

I writing Windows Forms Application application which should show image on the PictureBox control.
To retrieve this image from DICOMDIR file I use fo-dicom library (driven by this guide):
....
private void MainForm_Load(object sender, EventArgs e)
{
ImageManager.SetImplementation(WinFormsImageManager.Instance);
}
....
// this function is just for example
// real function is bit complicated
private void ShowImage()
{
// Getting DICOM file, retrieving all info from it
// Getting dicomDataset instance
....
var id = dicomDataset.Get<string>(DicomTag.ReferencedFileID, -1);
var dicomImage = new DicomImage(id);
var bitmap = dicomImage.RenderImage().AsBitmap();
pictureBox.Image = bitmap ?? pictureBox.ErrorImage;
}
When image is retrieving all works fine. But as soon as I maximize my MainForm, I got System.ArgumentException with Parameter is not valid message:
It looks like this is a .NET Framework bug, but maybe there is a way to fix it by overrideing OnPaint() method of PictureBox control?
Have anyone see this bug previously?
Thanks in advance.
P.S. During development this project I use following software:
Windows 10 x64
Visual Studio 2017 Community Edition
.NET Framework 4.5.1
fo-dicom version 3.0.2
EDIT #1
The same issue with Panel instead of PictureBox:
You are facing a known and already fixed bug in fo-dicom 3.0.2. See also https://github.com/fo-dicom/fo-dicom/issues/634.
For performance reason the Bitmap, that DicomImage.RenderImage().AsBitmap() returns, does not have its own pixel data, but has a pointer to the bytes of DicomImage. So the AsBitmap() does not duplicate all the pixel data in memory.
But if you instanciate the DicomImage in a local variable and save the Bitmap in the control, then the DicomImage is disposed at the end of the method and the pixel data gets garbace collected. The next time, the Bitmap tries to access the pixel data this exception happens.
The next release will have two methods: AsSharedBitmap() - the same as now but more obvious to the user - and AsClonedBitmap().
The workaround now is, to copy the pixel data manually by calling:
var bitmap = dicomImage.RenderImage().AsBitmap().Clone();

DevExpress Map Control not Loading - Windows Service

I am using the DevExpress XtraMap MapControl within a windows service with the intention of generating the maps, saving them as images and adding them to reports. I have this setup working well when using it through a WinForms project, but when I copy the same code to a Windows Service it fails to save the image. Code in the WinForms project:
MapControl map;
public void Form1_Load_1(object sender, EventArgs e)
{
// Create a map control.
map = new MapControl();
// Create an image tiles layer and add it to the map.
ImageTilesLayer tilesLayer = new ImageTilesLayer();
tilesLayer.DataLoaded += Map_DataLoaded;
map.Layers.Add(tilesLayer);
BingMapDataProvider prov = new BingMapDataProvider();
prov.BingKey = "MY_BING_KEY";
tilesLayer.DataProvider = prov;
map.ZoomLevel = 2;
map.CenterPoint = new GeoPoint(38, -100);
map.ResumeRender();
this.Controls.Add(map);
}
private void Map_DataLoaded(object sender, EventArgs e)
{
var loc = #"C:\0Temp\Map\" + DateTime.Now.Ticks.ToString() + ".png";
map.ExportToImage(loc, System.Drawing.Imaging.ImageFormat.Png);
}
This code when run in a Windows service fails to save the image. The only difference being, in the Windows Service, the following line is removed:
this.Controls.Add(map);
When removing that line from the winforms project, it also fails to load/save. I can only assume that there is an event being triggered/monitored that adding this control to a form triggers that I am not aware of?
I believe, the Map Control is not intended to be used without showing it (or at least without creating it's handle). So when accessing to Bing Maps from Windows-service, I suggest you to use the Bing Imagery API directly.
p.s. Microsoft Bing Maps Terms of Use do not allow to
3.2 (b) Copy, store, archive, or create a database of the Content ...

CAD insert block with thumbnail under mouse

I need to insert an external DWG into an AutoCAD drawing via C# plugin.
I need to "ask" to the user the insertion point and rotation of the inserted block.
Until now I've always used a lisp function that calls the command "._-insert" which gives a thumbnail of the block under the mouse, allows the user to click into the drawing to set the insertion point and from that point allows the user to click one more time to set the rotation.
Now I want to avoid the use of Lisp or the use of low level API of AutoCAD because I need a solution that runs over various CAD environments.
What I found is something like this:
public static void InsertDwg(string dwgName)
{
CADAPI.ApplicationServices.Document doc = CADAPI.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
CADDB.Database db = doc.Database;
CADAPI.EditorInput.Editor ed = doc.Editor;
CADDB.ObjectId ObjId;
using (CADDB.Transaction trx = db.TransactionManager.StartTransaction())
{
CADDB.BlockTable bt = db.BlockTableId.GetObject(CADDB.OpenMode.ForRead) as CADDB.BlockTable;
CADDB.BlockTableRecord btrMs = bt[CADDB.BlockTableRecord.ModelSpace].GetObject(CADDB.OpenMode.ForWrite) as CADDB.BlockTableRecord;
using (CADDB.Database dbInsert = new CADDB.Database(false, true))
{
dbInsert.ReadDwgFile(dwgName, CADDB.FileOpenMode.OpenForReadAndAllShare, true, string.Empty);
ObjId = db.Insert(Path.GetFileNameWithoutExtension(dwgName), dbInsert, true);
}
CADAPI.EditorInput.PromptPointOptions ppo = new CADAPI.EditorInput.PromptPointOptions("\nInsertion Point");
CADAPI.EditorInput.PromptAngleOptions ppa = new CADAPI.EditorInput.PromptAngleOptions("\nInsert Rotation");
CADAPI.EditorInput.PromptPointResult ppr;
ppr = ed.GetPoint(ppo);
CADAPI.EditorInput.PromptDoubleResult ppd = ed.GetAngle(ppa);
if (ppr.Status == CADAPI.EditorInput.PromptStatus.OK)
{
CADGEOM.Point3d insertPt = ppr.Value;
CADDB.BlockReference bref = new CADDB.BlockReference(insertPt, ObjId);
btrMs.AppendEntity(bref);
trx.AddNewlyCreatedDBObject(bref, true);
trx.Commit();
}
}
}
But here I have two problems:
The main one is that there is no preview under the mouse.
The second is that the user needs to click 3 times instead of 2 to set both the insertion point and the rotation.
Is there any way that doesn't use some kind of SendCommand and does all of this stuff?
TIA
It seems Jigging is the way to go to allow the preview. I have three links for you.
Jigging multiple entities with the DrawJig
Using a jig to rotate an AutoCAD entity via .NET
Using transient graphics to simulate AutoCAD’s MOVE command using .NET
The first is an example of creating a simple jig with polylines - you could extend this to a block.
The second link is similar but applies rotation to the mix. This is applied to a rectangle but again could be modified to accomodate a block.
The third link describes a different method - AutoCADs transient graphics interface. You must be using AutoCAD 2009 or later to use this method.
The last two links are from the Through the Interface blog, where you may find some more examples and is a very good starting point if you have problems, especially for coding C#.
You will want to use the AcEdJig class. It provides the preview. You will have to write the code to collect the insert point and rotation and to transform the block accordingly.
Here is the first link from my google search for example usage code.

Gtk#: How to convert a Gtk.Image in a Gdk one?

I would like to write a simple 2D game in Mono/Gtk#with MonoDevelop 2.4. My first interest was to display a PNG image for the player character in the Window canvas (later I will respond to keyboard events in order to move it). However, I have found out a disturbing problem here: while I get a Gtk.Image object for the player character, the DrawImage method of the Gdk Window needs a Gdk image. How could I convert the first one to the latter?
public static void ShowImage(Gdk.Window w, Gtk.Image image)
{
w.DrawImage( Style.ForegroundGC( StateType.Normal ),
image, // ERROR
0, 0, image.Pixbuf.Width, image.Pixbuf.Height,
image.Pixbuf.Width, image.Pixbuf.Height
);
}
This is might appear simplistic, but honestly I haven't found the answer yet.
Gtk.Image.ImageProp is a property holding the Gdk.Image held in the Gtk.Image widget.
public static void ShowImage(Gdk.Window w, Gtk.Image image)
{
w.DrawImage( Style.ForegroundGC( StateType.Normal ),
image.ImageProp, // TRY THIS
0, 0, image.Pixbuf.Width, image.Pixbuf.Height,
image.Pixbuf.Width, image.Pixbuf.Height
);
}
Here is a link to the GTK# documentation.
Gtk.Image is a widget (or a control in winforms terminology).
see: http://library.gnome.org/devel/gtk/unstable/GtkImage.html
From your problem description I don't think you want to be using a Gtk.Image, but a Gdk.Image.
IE. change your ShowImage method to: public static void ShowImage(Gdk.Window w, Gdk.Image image)

Categories

Resources