create an empty BitmapSource in C# - c#

What is the fastest (few lines of code and low resource usage) way to create an empty (0x0 px or 1x1 px and fully transparent) BitmapSource instance in c# that is used when nothing should be rendered.

Thanks to Arcutus hint I have this now (wich works fine):
var i = BitmapImage.Create(
2,
2,
96,
96,
PixelFormats.Indexed1,
new BitmapPalette(new List<Color> { Colors.Transparent }),
new byte[] { 0, 0, 0, 0 },
1);
If I make this image smaller I get an ArgumentException. I have no clue why I can't create a smaller image that 2x2px.

Use the Create method.
Example stolen from MSDN: :)
int width = 128;
int height = width;
int stride = width/8;
byte[] pixels = new byte[height*stride];
// Try creating a new image with a custom palette.
List<System.Windows.Media.Color> colors = new List<System.Windows.Media.Color>();
colors.Add(System.Windows.Media.Colors.Red);
colors.Add(System.Windows.Media.Colors.Blue);
colors.Add(System.Windows.Media.Colors.Green);
BitmapPalette myPalette = new BitmapPalette(colors);
// Creates a new empty image with the pre-defined palette
BitmapSource image = BitmapSource.Create(
width, height,
96, 96,
PixelFormats.Indexed1,
myPalette,
pixels,
stride);

The way to create such an image without allocating a big managed byte array is to use TransformedBitmap.
var bmptmp = BitmapSource.Create(1,1,96,96,PixelFormats.Bgr24,null,new byte[3]{0,0,0},3);
var imgcreated = new TransformedBitmap(bmptmp, new ScaleTransform(width, height));

The most minimal BitmapSource can be generated like this:
public static BitmapSource CreateEmptyBitmap()
{
return BitmapSource.Create(1, 1, 1, 1, PixelFormats.BlackWhite, null, new byte[] {0}, 1);
}

Another way is to create an instance of a BitmapImage class which is derived from BitmapSource:
BitmapSource emptySource = new BitmapImage();

Just take a look at this. It works for any Pixelformat
public static BitmapSource CreateEmtpyBitmapSource(int width, int height, PixelFormat pixelFormat)
{
PixelFormat pf = pixelFormat;
int rawStride = (width * pf.BitsPerPixel + 7) / 8;
var rawImage = new byte[rawStride * height];
var bitmap = BitmapSource.Create(width, height, 96, 96, pf, null, rawImage, rawStride);
return bitmap;
}

Related

Displaying TIF image using byte array to writeable bitmap(C#)

I've a byte array of a tiff image. I want to form 3 images from it,that i'll do later but the problem is i'm not able to display the original image as it is.
Here is my xaml:
<Image Grid.Row="0" Grid.Column="0" Name="ReferenceImage"/>
xaml.cs code:
public MainWindow()
{
InitializeComponent();
ImagePath = #"G:\TiffImage\Test.TIF"
DisplayAllImages();
}
private void DisplayAllImages()
{
byte[] imageSize = File.ReadAllBytes(ImagePath);
ReferenceImage.Source = DisplayAllImages(imageSize, 64, 64);
}
private WriteableBitmap DisplayAllImages(byte[] imageData,int height,int width)
{
if (imageData != null)
{
PixelFormat format = PixelFormats.Gray8;
WriteableBitmap wbm = new WriteableBitmap(height, width, 96, 96, format, null);
wbm.WritePixels(new Int32Rect(0, 0, height, width), imageData, 1*width, 0);
return wbm;
}
else
{
return null;
}
}
My main aim is to display image using byte array like this way only, so that i can extract byte array to form other image as per requirements.
The image file contains encoded bitmap data. In order to access the raw pixels you would first have to decode the bitmap:
BitmapSource bitmap;
using (var fileStream = new FileStream(ImagePath, FileMode.Open, FileAccess.Read))
{
bitmap = BitmapFrame.Create(
fileStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
Now you would get the raw pixels by calling the CopyPixels method of the BitmapSource:
var width = bitmap.PixelWidth;
var height = bitmap.PixelHeight;
var stride = (width * bitmap.Format.BitsPerPixel + 7) / 8;
var imageData = new byte[height * stride];
bitmap.CopyPixels(imageData, stride, 0);
I'm not getting the expected images.Although i'm able to generate images which is matching almost 75% but not completely.

Save as 8bit PNG

I am creating placeholder images in certain sizes that will be used as Data URIs
Bitmap bitmap = new Bitmap(16, 10);
I have done some research, but can't find a good way of saving this bitmap as the smallest possible filesize, which is why I want an 8bit PNG.
My question is: How can I save this bitmap into a file/bytearray/stream as an 8bit PNG? Any good libraries?
You can do this with nQuant (which you can install with nuget, or see references below). The following example converts an image on disk and would be readily adapted to meet your needs.
public static bool TryNQuantify(string inputFilename, string outputFilename)
{
var quantizer = new nQuant.WuQuantizer();
var bitmap = new Bitmap(inputFilename);
if (bitmap.PixelFormat != System.Drawing.Imaging.PixelFormat.Format32bppArgb)
{
ConvertTo32bppAndDisposeOriginal(ref bitmap);
}
try
{
using (var quantized = quantizer.QuantizeImage(bitmap))
{
quantized.Save(outputFilename, System.Drawing.Imaging.ImageFormat.Png);
}
}
catch
{
return false;
}
finally
{
bitmap.Dispose();
}
return true;
}
private static void ConvertTo32bppAndDisposeOriginal(ref Bitmap img)
{
var bmp = new Bitmap(img.Width, img.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (var gr = Graphics.FromImage(bmp))
gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height));
img.Dispose();
img = bmp;
}
For more information see:
https://github.com/mcychan/nQuant.cs
https://code.msdn.microsoft.com/windowsdesktop/Convert-32-bit-PNGs-to-81ef8c81
I like the FreeImage project, it is light weight and easy to use. Below is an example of creating a transparent png. You could easily wrap this in a method and set the width and height and transparency value.
//create a new bit map
FIBITMAP dib = new FIBITMAP();
//allocate a 16x10 bitmap with 8bit depth
dib = FreeImage.Allocate(16, 10, 8);
//set the transpareny
byte[] Transparency = new byte[1];
Transparency[0] = 0x00;
FreeImage.SetTransparencyTable(dib, Transparency);
//save the bitmap
FreeImage.Save(FREE_IMAGE_FORMAT.FIF_PNG, dib, "C:\\temp\\tp.png", FREE_IMAGE_SAVE_FLAGS.DEFAULT);
If all you need is a small transparent image, why stop at 8 bit? You can go straight down to 1 bit! You only need one colour anyway, and it'll be even smaller.
In fact, you don't even need to do anything special for that. Since the pixels on a new indexed bitmap will all default to 0, meaning they reference its first palette colour, all you need to do is make a new 1bpp image, and set that first palette colour to transparent:
public static Bitmap MakePlaceholderImage(Int32 width, Int32 height)
{
Bitmap bm = new Bitmap(width, height, PixelFormat.Format1bppIndexed);
// This colour can't be assigned directly since the .Palette getter actually makes a copy of the palette.
ColorPalette pal = bm.Palette;
pal.Entries[0] = Color.Transparent;
bm.Palette = pal;
return bm;
}
I experimented a bit with this, and, saved as png, the end result seemed to consistently be 8 times smaller than the result of the same code executed with 8bpp. For a 5000x5000 image, the file size as png was barely over 3 KiB.
Google search led me to a 6 year old thread and I can't find my solution. It should've been possible 6 years as well, as it uses the System.Drawing Libraray of the .Net Framework.
This example code should help anyone who want to write an 8 bit indexed png.
static class SaveImages
{
public static void SaveGrayImage(Bitmap srcImg, string name)
{
Bitmap grayImg = new Bitmap(srcImg.Width, srcImg.Height, PixelFormat.Format8bppIndexed);
var pal = grayImg.Palette;
foreach (int i in Enumerable.Range(0, 256))
pal.Entries[i] = Color.FromArgb(255, i, i, i);
grayImg.Palette = pal;
var data = grayImg.LockBits(new Rectangle(0, 0, srcImg.Width, srcImg.Height), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
var bytes = new byte[data.Stride * data.Height];
foreach (int y in Enumerable.Range(0, srcImg.Height))
{
foreach (int x in Enumerable.Range(0, srcImg.Width))
{
var colour = srcImg.GetPixel(x, y);
var c = (int)colour.R + (int)colour.G + (int)colour.B;
c /= 3;
bytes[data.Stride * y + x] = (byte)c;
}
}
Marshal.Copy(bytes, 0, data.Scan0, bytes.Length);
grayImg.Save(name, ImageFormat.Png);
}
}
Edit: To add transparency dabble with the color palette.
1) Create your bitmap with 8 bit per pixel format:
Bitmap bmp = new Bitmap(20, 20, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
See PixelFormat for more formats.
2) Draw to the bitmap ...
3) Then save it as PNG:
bmp.Save(#"c:\temp\xyz.png", System.Drawing.Imaging.ImageFormat.Png);
The created file will have the same pixel format as bmp (8 bit)

How to create 1024x1024 RGB bitmap image of white?

It's embarrassing to ask this question but can't find an answer.
I tried this in vain.
Image resultImage = new Bitmap(image1.Width, image1.Height, PixelFormat.Format24bppRgb);
using (Graphics grp = Graphics.FromImage(resultImage))
{
grp.FillRectangle(
Brushes.White, 0, 0, image1.Width, image1.Height);
resultImage = new Bitmap(image1.Width, image1.Height, grp);
}
I basically want to fill a 1024x1024 RGB bitmap image with white in C#. How can I do that?
You almost had it:
private Bitmap DrawFilledRectangle(int x, int y)
{
Bitmap bmp = new Bitmap(x, y);
using (Graphics graph = Graphics.FromImage(bmp))
{
Rectangle ImageSize = new Rectangle(0,0,x,y);
graph.FillRectangle(Brushes.White, ImageSize);
}
return bmp;
}
You are assigning a new image to resultImage, thereby overwriting your previous attempt at creating a white image (which should succeed, by the way).
So just remove the line
resultImage = new Bitmap(image1.Width, image1.Height, grp);
Another approach,
Create a unit bitmap
var b = new Bitmap(1, 1);
b.SetPixel(0, 0, Color.White);
And scale it
var result = new Bitmap(b, 1024, 1024);
Graphics.Clear(Color)
Bitmap bmp = new Bitmap(1024, 1024);
using (Graphics g = Graphics.FromImage(bmp)){g.Clear(Color.White);}
Depending on your needs, a BitmapSource might suit. You can quickly fill a byte array with the 0xff (i.e. white) using Enumerable.Repeat().
int w = 1024;
int h = 1024;
byte[] pix = Enumerable.Repeat((byte)0xff, w * h * 4).ToArray();
SomeImage.Source = BitmapSource.Create(w, h, 96, 96, PixelFormats.Pbgra32, null, pix, w * 4);

Rendering out camera images to a WPF Image control

I have a uEye camera and I take snapshots of images at a 1000ms interval and I want to render them in a WPF Image Control like so
Bitmap MyBitmap;
// get geometry of uEye image buffer
int width = 0, height = 0, bitspp = 0, pitch = 0, bytespp = 0;
long imagesize = 0;
m_uEye.InquireImageMem(m_pCurMem, GetImageID(m_pCurMem), ref width, ref height, ref bitspp, ref pitch);
bytespp = (bitspp + 1) / 8;
imagesize = width * height * bytespp; // image size in bytes
// bulit a system bitmap
MyBitmap = new Bitmap(width, height, PixelFormat.Format24bppRgb);
// fill the system bitmap with the image data from the uEye SDK buffer
BitmapData bd = MyBitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
m_uEye.CopyImageMem(m_pCurMem, GetImageID(m_pCurMem), bd.Scan0);
MyBitmap.UnlockBits(bd);
I am trying to put these bitmaps in to an Image control at the rate of 1 second. How can I get Bitmap to appear in the Image control and disposing them as soon as I'm done to leave minimal memory footprint to be a good little programmer :) ?
Here the way we do (for me it works at 200fps without loading CPU (about 5%)):
private WriteableBitmap PrepareForRendering(VideoBuffer videoBuffer) {
PixelFormat pixelFormat;
if (videoBuffer.pixelFormat == PixFrmt.rgb24) {
pixelFormat = PixelFormats.Rgb24;
} else if (videoBuffer.pixelFormat == PixFrmt.bgra32) {
pixelFormat = PixelFormats.Bgra32;
} else if (videoBuffer.pixelFormat == PixFrmt.bgr24) {
pixelFormat = PixelFormats.Bgr24;
} else {
throw new Exception("unsupported pixel format");
}
var bitmap = new WriteableBitmap(
videoBuffer.width, videoBuffer.height,
96, 96,
pixelFormat, null
);
_imgVIew.Source = bitmap;
return bitmap;
}
private void DrawFrame(WriteableBitmap bitmap, VideoBuffer videoBuffer, double averangeFps) {
VerifyAccess();
if (isPaused) {
return;
}
bitmap.Lock();
try {
using (var ptr = videoBuffer.Lock()) {
bitmap.WritePixels(
new Int32Rect(0, 0, videoBuffer.width, videoBuffer.height),
ptr.value, videoBuffer.size, videoBuffer.stride,
0, 0
);
}
} finally {
bitmap.Unlock();
}
fpsCaption.Text = averangeFps.ToString("F1");
}

C# - Convert WPF Image.source to a System.Drawing.Bitmap

I've found loads of people converting a BitmapSource to a Bitmap, but what about ImageSource to Bitmap? I am making an imaging program and I need to extract bitmaps from the image displayed in the Image element. Does anyone know how to do this?
EDIT 1:
This is a function for converting the BitmapImage to a Bitmap. Remember to set the 'unsafe' option in the compiler preferences.
public static System.Drawing.Bitmap BitmapSourceToBitmap(BitmapSource srs)
{
System.Drawing.Bitmap btm = null;
int width = srs.PixelWidth;
int height = srs.PixelHeight;
int stride = width * ((srs.Format.BitsPerPixel + 7) / 8);
byte[] bits = new byte[height * stride];
srs.CopyPixels(bits, stride, 0);
unsafe
{
fixed (byte* pB = bits)
{
IntPtr ptr = new IntPtr(pB);
btm = new System.Drawing.Bitmap(width, height, stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, ptr);
}
}
return btm;
}
Next is now to get a BitmapImage:
RenderTargetBitmap targetBitmap = new RenderTargetBitmap(
(int)inkCanvas1.ActualWidth,
(int)inkCanvas1.ActualHeight,
96d, 96d,
PixelFormats.Default);
targetBitmap.Render(inkCanvas1);
MemoryStream mse = new MemoryStream();
System.Windows.Media.Imaging.BmpBitmapEncoder mem = new BmpBitmapEncoder();
mem.Frames.Add(BitmapFrame.Create(targetBitmap));
mem.Save(mse);
mse.Position = 0;
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = mse;
bi.EndInit();
Next is to convert it:
Bitmap b = new Bitmap(BitmapSourceToBitmap(bi));
Actually you don't need to use unsafe code. There's an overload of CopyPixels that accepts an IntPtr:
public static System.Drawing.Bitmap BitmapSourceToBitmap2(BitmapSource srs)
{
int width = srs.PixelWidth;
int height = srs.PixelHeight;
int stride = width * ((srs.Format.BitsPerPixel + 7) / 8);
IntPtr ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(height * stride);
srs.CopyPixels(new Int32Rect(0, 0, width, height), ptr, height * stride, stride);
using (var btm = new System.Drawing.Bitmap(width, height, stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, ptr))
{
// Clone the bitmap so that we can dispose it and
// release the unmanaged memory at ptr
return new System.Drawing.Bitmap(btm);
}
}
finally
{
if (ptr != IntPtr.Zero)
Marshal.FreeHGlobal(ptr);
}
}
That example worked for me:
public static Bitmap ConvertToBitmap(BitmapSource bitmapSource)
{
var width = bitmapSource.PixelWidth;
var height = bitmapSource.PixelHeight;
var stride = width * ((bitmapSource.Format.BitsPerPixel + 7) / 8);
var memoryBlockPointer = Marshal.AllocHGlobal(height * stride);
bitmapSource.CopyPixels(new Int32Rect(0, 0, width, height), memoryBlockPointer, height * stride, stride);
var bitmap = new Bitmap(width, height, stride, PixelFormat.Format32bppPArgb, memoryBlockPointer);
return bitmap;
}
Are your ImageSource not a BitmapSource? If your loading the images from files they should be.
Reply to your comment:
Sounds like they should be BitmapSource then, BitmapSource is a subtype of ImageSource. Cast the ImageSource to BitmapSource and follow one of those blogposts.
You don't need a BitmapSourceToBitmap method at all. Just do the following after creating your memory stream:
mem.Position = 0;
Bitmap b = new Bitmap(mem);

Categories