Grayscale 8BPP bitmap for SharpDX.Direct2D1.Bitmap - c#

I am currently making a 2D application using SharpDX.Direct2D1.
Here is my setup for my 2D deviceContext that works correctly.
m_swapchaindesc = New SwapChainDescription()
With m_swapchaindesc
.BufferCount = 2
.ModeDescription =
New ModeDescription(control.Width, control.Height,
New Rational(60, 1), Format.R8G8B8A8_UNorm)
.IsWindowed = True
.OutputHandle = control.Handle
.SampleDescription = New SampleDescription(1, 0)
.SwapEffect = SwapEffect.Discard
.Usage = Usage.RenderTargetOutput
End With
SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport Or DeviceCreationFlags.Debug, m_swapchaindesc, m_device, m_swapChain)
Dim dxgiDevice As SharpDX.DXGI.Device = m_device.QueryInterface(Of SharpDX.DXGI.Device)()
m_2dDevice = New SharpDX.Direct2D1.Device(dxgiDevice)
m_d2dContext = New SharpDX.Direct2D1.DeviceContext(m_2dDevice, SharpDX.Direct2D1.DeviceContextOptions.None)
m_properties = New BitmapProperties(New SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.R8G8B8A8_UNorm, SharpDX.Direct2D1.AlphaMode.Premultiplied), 96, 96)
m_backBuffer = m_swapChain.GetBackBuffer(Of Surface)(0)
m_2dTarget = New SharpDX.Direct2D1.Bitmap(m_d2dContext, m_backBuffer, m_properties)
m_d2dContext.Target = m_2dTarget
My question : I want to draw 8bpp bitmap on a grayscale to my deviceContext, which means I don't need it to be 32bits per pixel which takes a loooot of memory. I would like for it to be only 8 bits for memory purpose. The problem when I do so, which means setting up my BitmapProperties, there is only a Format.R8_Unorm Or Format.A8_Unorm that seems interesting since I guess they only have 8bpp. However, when I put this format and I am trying to instantiate my SharpDX.Direct2D1.Bitmap, it returns an error message that says WRONGPIXELFORMAT.
I realised that only Format.R8G8B8A8_Unorm seems to work when creating bitmap, which I don't need.
Have any of you worked with 8bpp grayscale bitmap on SharpDX ?

You cannot use 8BPP bitmaps with SharpDX (DirectX). This is not a supported format by DirectX. To be able to display a grayscale image, You have to set all values of yours rgb to the same one, or apply a shaders to your image that converts all colors to gray.

Related

C# WinForm - SharpDX.Toolkit.Graphics draw 2D Texture

I would like to implement hardware acceleration for a C # WinForms application. Reason is that i have to draw 150 x 720p images and the 5 picturebox control's takes too long (scaling+drawing of images) and therefore are problems with disposing and reloading.
So I dealt with ShapeDX.
But now I 'm stuck and do not know how to draw the 2D Texture. To test the code i just have a Test Button and one PictureBox.
When I run the code in the PictureBox also DirectX ( Draw or 3D ) is loaded. I acknowledge the black background. But I do not understand how the Texture must be drawn.
String imageFile = "Image.JPG";
Control TargetControl = this.pictureBoxCurrentFrameL;
int TotalWidth = TargetControl.Width;
int TotalHeight = TargetControl.Height;
SharpDX.Direct3D11.Device defaultDevice = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware, SharpDX.Direct3D11.DeviceCreationFlags.Debug);
SharpDX.Toolkit.Graphics.GraphicsDevice graphicsDevice = SharpDX.Toolkit.Graphics.GraphicsDevice.New(defaultDevice);
SharpDX.Toolkit.Graphics.PresentationParameters presentationParameters = new SharpDX.Toolkit.Graphics.PresentationParameters();
presentationParameters.DeviceWindowHandle = this.pictureBoxCurrentFrameL.Handle;
presentationParameters.BackBufferWidth = TotalWidth;
presentationParameters.BackBufferHeight = TotalHeight;
SharpDX.Toolkit.Graphics.SwapChainGraphicsPresenter swapChainGraphicsPresenter = new SharpDX.Toolkit.Graphics.SwapChainGraphicsPresenter(graphicsDevice, presentationParameters);
SharpDX.Toolkit.Graphics.Texture2D texture2D = SharpDX.Toolkit.Graphics.Texture2D.Load(graphicsDevice, imageFile);
//Now i should draw. But how?
swapChainGraphicsPresenter.Present();/**/
Using Microsoft Visual Studio Community 2015 (.Net 4, C# WinForm) on Windows 10 an SharpDX-SDK-2.6.3!
Thank you for assistance.
I solved the problem by simply switching to SlimDX (SlimDX Runtime .NET 4.0 x64 January 2012.msi, .Net4, Win10, MS Visual Studio Community 2015, Winforms App.). There are several useful tutorials .
to use SlimDX just link the only one DLL to ur project! after installing SlimDX u will find this SlimDX.dll file somewhere on ur C Drive.
it is important to understand that you need at least one factory and an render target for Direct2D . The RenderTarget points to the object to be used ( Control / form / etc ) and takes over the drawing.
a swap chain is not needed. probable used by the render target internally. the biggest part is to convert an bitmap into usefull Direct2D Bitmap (for drawing). Otherwise, you can process the bitmap data also from a MemoryStream .
For Those Who are looking for a solution too:
Control targetControl = this.pictureBoxCurrentFrameL;
String imageFile = "Image.JPG";
//Update control styles, works for forms, not for controls. I solve this later otherwise .
//this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
//this.SetStyle(ControlStyles.Opaque, true);
//this.SetStyle(ControlStyles.ResizeRedraw, true);
//Get requested debug level
SlimDX.Direct2D.DebugLevel debugLevel = SlimDX.Direct2D.DebugLevel.None;
//Resources for Direct2D rendering
SlimDX.Direct2D.Factory d2dFactory = new SlimDX.Direct2D.Factory(SlimDX.Direct2D.FactoryType.Multithreaded, debugLevel);
//Create the render target
SlimDX.Direct2D.WindowRenderTarget d2dWindowRenderTarget = new SlimDX.Direct2D.WindowRenderTarget(d2dFactory, new SlimDX.Direct2D.WindowRenderTargetProperties() {
Handle = targetControl.Handle,
PixelSize = targetControl.Size,
PresentOptions = SlimDX.Direct2D.PresentOptions.Immediately
});
//Paint!
d2dWindowRenderTarget.BeginDraw();
d2dWindowRenderTarget.Clear(new SlimDX.Color4(Color.LightSteelBlue));
//Convert System.Drawing.Bitmap into SlimDX.Direct2D.Bitmap!
System.Drawing.Bitmap bitmap = (System.Drawing.Bitmap)Properties.Resources.Image_720p;//loaded from embedded resource, can be changed to Bitmap.FromFile(imageFile); to load from hdd!
SlimDX.Direct2D.Bitmap d2dBitmap = null;
System.Drawing.Imaging.BitmapData bitmapData = bitmap.LockBits(new Rectangle(new Point(0, 0), bitmap.Size), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);//TODO: PixelFormat is very important!!! Check!
SlimDX.DataStream dataStream = new SlimDX.DataStream(bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, true, false);
SlimDX.Direct2D.PixelFormat d2dPixelFormat = new SlimDX.Direct2D.PixelFormat(SlimDX.DXGI.Format.B8G8R8A8_UNorm, SlimDX.Direct2D.AlphaMode.Premultiplied);
SlimDX.Direct2D.BitmapProperties d2dBitmapProperties = new SlimDX.Direct2D.BitmapProperties();
d2dBitmapProperties.PixelFormat = d2dPixelFormat;
d2dBitmap = new SlimDX.Direct2D.Bitmap(d2dWindowRenderTarget, new Size(bitmap.Width, bitmap.Height), dataStream, bitmapData.Stride, d2dBitmapProperties);
bitmap.UnlockBits(bitmapData);
//Draw SlimDX.Direct2D.Bitmap
d2dWindowRenderTarget.DrawBitmap(d2dBitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));/**/
d2dWindowRenderTarget.EndDraw();
//Dispose everything u dont need anymore.
//bitmap.Dispose();//......
So it is super simple to use Direct2D, all the code can be compressed to 2 main Lines + drawing:
SlimDX.Direct2D.Factory d2dFactory = new SlimDX.Direct2D.Factory(SlimDX.Direct2D.FactoryType.Multithreaded, SlimDX.Direct2D.DebugLevel.None);
SlimDX.Direct2D.WindowRenderTarget d2dWindowRenderTarget = new SlimDX.Direct2D.WindowRenderTarget(d2dFactory, new SlimDX.Direct2D.WindowRenderTargetProperties() { Handle = targetControl.Handle, PixelSize = targetControl.Size, PresentOptions = SlimDX.Direct2D.PresentOptions.Immediately });
d2dWindowRenderTarget.BeginDraw();
d2dWindowRenderTarget.Clear(new SlimDX.Color4(Color.LightSteelBlue));
d2dWindowRenderTarget.DrawRectangle(new SlimDX.Direct2D.SolidColorBrush(d2dWindowRenderTarget, new SlimDX.Color4(Color.Red)), new Rectangle(20,20, targetControl.Width-40, targetControl.Height-40));
d2dWindowRenderTarget.EndDraw();

Unsupported Pixel Format of source or template image. AForge Imaging

I am getting the following Exception at ProcessImage(bitmap1, bitmap2);
Unsupported Pixel Format of source or template image
and this is my code:
public static double FindComparisonRatioBetweenImages(
System.Drawing.Image one, System.Drawing.Image two)
{
Bitmap bitmap1 = new Bitmap(one);
Bitmap bitmap2 = new Bitmap(two);
ExhaustiveTemplateMatching tm = new ExhaustiveTemplateMatching(0);
TemplateMatch[] matchings = null;
matchings = tm.ProcessImage(bitmap1, bitmap2); // Exception occurs here!
return matchings[0].Similarity;
}
I have also passed managedImage from the below code into the method, but it still gives error:
UnmanagedImage unmanagedImageA = UnmanagedImage.FromManagedImage(bitmap1);
Bitmap managedImageA = unmanagedImageA.ToManagedImage();
UnmanagedImage unmanagedImageB = UnmanagedImage.FromManagedImage(bitmap2);
Bitmap managedImageB = unmanagedImageB.ToManagedImage();
I have passed Images randomly from my computer, they all give exception.
I have passed Blank Image edited in paint into the method,it still give exception.
Also checked, jpeg, png, bmp formats, nothing work.
Try ExhaustiveTemplateMatching:
The class implements exhaustive template matching algorithm, which performs complete scan of source image, comparing each pixel with corresponding pixel of template.
The class processes only grayscale 8 bpp and color 24 bpp images.
So, those are the image formats you must use.
As requested, to convert to a specific pixel format, you can do this:
public static Bitmap ConvertToFormat(this Image image, PixelFormat format)
{
Bitmap copy = new Bitmap(image.Width, image.Height, format);
using (Graphics gr = Graphics.FromImage(copy))
{
gr.DrawImage(image, new Rectangle(0, 0, copy.Width, copy.Height));
}
return copy;
}
The one you would use is System.Drawing.Imaging.PixelFormat.Format24bppRgb.

image quality is blurry

I have a situation where I want to convert some XAML to an image, so I created a RichTextBox and then took the image of it. Now problem is that words in image is blurred, any idea how I might be able to fix it?
public System.Drawing.Bitmap ConvertXamltoImage(string XamlString, int Width, int Height)
{
RichTextBox AdContentRichTextBox = new RichTextBox() { Width = Width, Height = Height };
AdContentRichTextBox.BorderThickness = new Thickness(0);
XmlReader _XmlReader = XmlReader.Create(new StringReader(XamlString));
AdContentRichTextBox.Document = XamlString;
var size = new Size(Width, Height);
AdContentRichTextBox.Measure(size);
AdContentRichTextBox.Arrange(new Rect(size));
RenderTargetBitmap bmp = new RenderTargetBitmap(Width, Height, 300, 300, PixelFormats.Pbgra32);
bmp.Render(AdContentRichTextBox);
DrawingVisual _drawingVisual = new DrawingVisual();
using (DrawingContext _drwaingContext = _drawingVisual.RenderOpen())
{
VisualBrush _visualBrush = new VisualBrush(AdContentRichTextBox);
}
PngBitmapEncoder _png = new PngBitmapEncoder();
_png.Frames.Add(BitmapFrame.Create(bmp));
System.Drawing.Bitmap _tempBitmap = null;
using (Stream _fileStream = new MemoryStream())
{
_png.Save(_fileStream);
_tempBitmap = new System.Drawing.Bitmap(_fileStream);
_fileStream.Flush();
}
return _tempBitmap;
}
Hmmmm..there could be lots of things all interacting here:
1st
"Grayscale fall back - if ClearType is disabled or one is rendering text in certain situations where the ClearType algorithm cannot be run, WPF will use a grayscale rendering algorithm to antialias the rendered text."
Rendering Text to a RenderTargetBitmap seems to be one of those situations....(the renderer switches from a hardware to a software path).
2nd
In addition NET 4 switched the default scaling algorithm from high-quality (Fant) to low-quality (Bi-Linear).....now that shouldn't come into play here as it doesn't look like you are scaling the bitmap in any way...but you never know what's going on inside. It's possible to switch the scaler back to the higher quality one.
http://www.olsonsoft.com/blogs/stefanolson/post/Workaround-for-low-quality-bitmap-resizing-in-WPF-4.aspx
3rd
You may need to take into account the parent container of the RichTextBox...see last link below, mentions it can distort the font rendering.
Problems with rendering text as bitmaps using WPF
Some ideas on how to work around this are:
render the RichTextBox at a higher resolution e.g. 600dpi, and then scale down the bitmap (probably will make no difference)
capture the screen....difficult or not practical if your visual is offscreen/obscured, etc.
See related links:
http://windowsclient.net/wpf/white-papers/wpftextclarity.aspx
WPF RenderTargetBitmap downscaling text ClearType to GreyScale
WPF RenderTargetBitmap downscaling TextRenderMode to GreyScale
WPF text rendering inconsistencies

Problems with loading a BitmapPalette from image file

I want to load a palette from a bitmap file I have created. The file is 256 px wide and 1 px high.
I use
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri("image.bmp", UriKind.RelativeOrAbsolute);
image.EndInit();
myPalette = new BitmapPalette(image, 256);
The strange thing is, that the Count property of myPalette.Colors is only 244!
Is there something wrong with my code?
There is nothing wrong with your code - BitmapPalette returns up to the number of colors specified. From here: http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmappalette.aspx
Initializes a new instance of the BitmapPalette class based on the
specified BitmapSource. The new BitmapPalette is limited to a
specified maximum color count.
I created a test bitmap with the same dimensions and a single color, and myPalette.Colors.Count returned 1.
Note however that you may actually want to use Bitmap from System.Drawing, much simpler and this returns the full palette list (256) even if they are all the same:
var test = new Bitmap("image.bmp");
Console.WriteLine(test.Palette.Entries.Length);
With the same test as above, that returns 256 entries

Bitmap.Clone creates an image that is 4x Larger in output size than original

So, I have an app that takes an original image, gets the new new cropped region, and then saves the cropped version of the image as a new file. It works perfectly with one major drawback. The new image is, on average, 4x larger than the original image. In my test, I have a photograph that has a size on disk of ~4.5MB, and the cropped version (which is properly cropped and looks fine) is ~21MB on disk. The code is as follows:
var originalImage = new Bitmap(imagePath);
var fWidth = originalImage.PhysicalDimension.Width;
var fHeight = originalImage.PhysicalDimension.Height;
float calculatedWidth = GetCroppedWidth();
float calculatedHeight = GetCroppedHeight();
//Draw the image by centering the cropped region on the original
var heightOffset = (fHeight - calculatedHeight) / 2;
var widthOffset = (fWidth - calculatedWidth) / 2;
var sourceRectF = new RectangleF(widthOffset, heightOffset, calculatedWidth, calculatedHeight);
var croppedImage = originalImage.Clone(sourceRectF, originalImage.PixelFormat);
//Save the image
croppedImage.Save(croppedFileName);
It sounds like the image you are loading is some other format than BMP (e.g. PNG or JPG).
Use another overload of Bitmap.Save that specified an ImageFormat
Look at the Bitmap.Save overload that lets you choose the output format.
By default, it is Bmp i guess, which has no compression.
so, in your case use
croppedImage.Save(croppedFileName, originalImage.RawFormat);

Categories

Resources