Converting Bitmap PixelFormats in C# - c#

I need to convert a Bitmap from PixelFormat.Format32bppRgb to PixelFormat.Format32bppArgb.
I was hoping to use Bitmap.Clone, but it does not seem to be working.
Bitmap orig = new Bitmap("orig.bmp");
Bitmap clone = orig.Clone(new Rectangle(0,0,orig.Width,orig.Height), PixelFormat.Format24bppArgb);
If I run the above code and then check clone.PixelFormat it is set to PixelFormat.Format32bppRgb. What is going on/how do I convert the format?

Sloppy, not uncommon for GDI+. This fixes it:
Bitmap orig = new Bitmap(#"c:\temp\24bpp.bmp");
Bitmap clone = new Bitmap(orig.Width, orig.Height,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (Graphics gr = Graphics.FromImage(clone)) {
gr.DrawImage(orig, new Rectangle(0, 0, clone.Width, clone.Height));
}
// Dispose orig as necessary...

For some reason if you create a Bitmap from a file path, i.e. Bitmap bmp = new Bitmap("myimage.jpg");, and call Clone() on it, the returned Bitmap will not be converted.
However if you create another Bitmap from your old Bitmap, Clone() will work as intended.
Try something like this:
using (Bitmap oldBmp = new Bitmap("myimage.jpg"))
using (Bitmap newBmp = new Bitmap(oldBmp))
using (Bitmap targetBmp = newBmp.Clone(new Rectangle(0, 0, newBmp.Width, newBmp.Height), PixelFormat.Format32bppArgb))
{
// targetBmp is now in the desired format.
}

using (var bmp = new Bitmap(width, height, PixelFormat.Format24bppArgb))
using (var g = Graphics.FromImage(bmp)) {
g.DrawImage(..);
}
Should work like that. Maybe you want to set some parameters on g to define the interpolation mode for quality etc.

Related

cannot convert from 'System.Drawing.Bitmap' to 'byte[*,*,*]'

Bitmap bitmap = (Bitmap)eventArgs.Frame.Clone();
Image<Bgr, byte> grayImage = new Image<Bgr, byte>(bitmap);
Rectangle[] rectangles = cascadeclassifier.DetectMultiScale(grayImage, 1.2, 1);
foreach(Rectangle rectangle in rectangles)
{
using (Graphics graphics = Graphics.FromImage(bitmap))
{
using (Pen pen = new Pen(Color.OrangeRed,1))
{
graphics.DrawRectangle(pen, rectangle);
}
}
}
i have problem at code here:
Image<Bgr, byte> grayImage = new Image<Bgr, byte>(bitmap);
the error is at (bitmap)
the error is :
Error CS1503 Argument 1: cannot convert from 'System.Drawing.Bitmap' to 'byte[*,*,*]'
For Version 4.3, use:
var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb);
Image<Bgr, Byte> img1 = bmp.ToImage<Bgr, byte>();
Are you sure the frame you get from eventArgs is actually a bitmap? Just because you cast it as such it is not converted to one if its not.
Try using:
eventArgs.Frame.Clone() as Bitmap
and check it for null.
Also, please post the Frame grabbing method for reference.
Downgrade to EmguCV 4.1.1.3497 for the following code!
I had the same issue after using the latest library (4.4.0.4099).Here is what I did to solve my problem instead of downgrading.
// Create The Bitmap Object From EventArgs.
using (Bitmap bitmap = (Bitmap)eventArgs.Frame.Clone())
{
// Define A File Path.
string filePath = Path.Combine(Path.GetTempPath(), DateTime.Now.ToString("ddmmyyyyhhmmssfff") + ".jpg");
// Lock The Bits In Memory.
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
// Create OpenCV Image<TColor,TDepth> Object And Add The bitmapData Properties Like So.
using (Image<Bgr, byte> grayImage = new Image<Bgr, byte>(bitmap.Width, bitmap.Height, bitmapData.Stride, bitmapData.Scan0))
{
// Get The Rectangles That Should Be Detected From The Training Data.
Rectangle[] rectangles = CascadeClassifier.DetectMultiScale(image: grayImage, scaleFactor: 1.2, minNeighbors: 1);
// Unlock The Bits So We Can Draw To It.
bitmap.UnlockBits(bitmapData);
// Loop Each Rectange In The Retanges Collection.
foreach (Rectangle rectangle in rectangles)
{
// Create Graphics Object And Load The Bitmap From The Beginning
using (Graphics graphics = Graphics.FromImage(bitmap))
// Create A Pen, Choose Any Colour
using (Pen pen = new Pen(Brushes.Red))
{
// Draw The Rectange Onto The Bitmap.
graphics.DrawRectangle(pen, rectangle);
}
}
// Create A File Stream And Save The Modified Bitmap
// We're Using The Above FilePath.
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite))
{
bitmap.Save(fs, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
// Open The Saved Image That Should Contain The Drawn Rectangle.
System.Diagnostics.Process.Start(filePath);
}

Convert Bitmap to unindexed pixelformat without compression/qualityloss

Is it possible to convert a indexed Bitmap to a unindexed without losing any quality?
I currently use this code to convert:
public Bitmap CreateNonIndexedImage(Image src)
{
Bitmap newBmp = new Bitmap(src.Width, src.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics gfx = Graphics.FromImage(newBmp))
{
gfx.DrawImage(src, 0, 0);
}
return newBmp;
}
Here is the indexed bitmap: http://puu.sh/6VO1N.png
And this is the converted image: http://puu.sh/6VO2Q.png
I need the unindexed to be exactly the same as the indexed but I donĀ“t know what to do.
The image was resampled. That's normally a Good Thing, it helps to get rid of the dithering artifacts in the original image. But you don't like it so you have to turn interpolation off. You also should use the DrawImage() overload that prevents rescaling due to the resolution of the original image. Not actually a problem with the image you've got but it could be one with another. Thus:
public static Bitmap CreateNonIndexedImage(Image src) {
Bitmap newBmp = new Bitmap(src.Width, src.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (Graphics gfx = Graphics.FromImage(newBmp)) {
gfx.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.None;
gfx.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
gfx.DrawImage(src, new Rectangle(0, 0, src.Width, src.Height));
}
return newBmp;
}

What's the most efficient way to generate thumbnails?

I am developing a graphical application, and I need to keep a thumbnail for each page.
The challenge is how to generate a thumbnail file without loosing performance ??
Currently here is my code to do it:
VisualBrush VisualBrush = new VisualBrush(pageToGenerateThumbnailFor);
UIVisual.Background = VisualBrush;
RenderTargetBitmap = new RenderTargetBitmap((int)UIVisual.ActualWidth, (int)UIVisual.ActualHeight, 96, 96, PixelFormats.Pbgra32);
rtb.Render(UIVisual);
using (FileStream outStream = new FileStream(ThumbFileFullPath, FileMode.OpenOrCreate,
System.IO.FileAccess.ReadWrite))
{
PngBitmapEncoder pngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(BitmapFrame.Create(rtb));
pngEncoder.Save(outStream);
}
So, Is there a faster way to generate a thumbnail for a given Visual ?
Thanks
I did a bit of research recently for generating Image Thumbnails on the fly for an eCommerce site. I started off doing this myself generating a bitmap and then resizing etc. similar to the answer above. After problems with image size on disc and quality I looked in to http://imageresizing.net/ and I haven't looked back since. It can generate images from byte(), streams and physicals files all very quickly with one line of code:
ImageBuilder.Current.Build(New MemoryStream(bImage), sImageLocation + sFullFileName, New ResizeSettings("maxwidth=214&maxheight=238"))
I would definitely recommend this component rather than trying to reinvent the wheel...
The following class from a utility library that I've written performs well for me and produces good clear quality thumbnails...
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Threading;
namespace Simple {
public static class ThumbnailCreator {
private static readonly object _lock = new object();
public static Bitmap createThumbnail(Stream source, Int32 width, Int32 height) {
Monitor.Enter(_lock);
Bitmap output = null;
try {
using (Bitmap workingBitmap = new Bitmap(source)) {
// Determine scale based on requested height/width (this preserves aspect ratio)
Decimal scale;
if (((Decimal)workingBitmap.Width / (Decimal)width) > ((Decimal)workingBitmap.Height / (Decimal)height)) {
scale = (Decimal)workingBitmap.Width / (Decimal)width;
}
else {
scale = (Decimal)workingBitmap.Height / (Decimal)height;
}
// Calculate new height/width
Int32 newHeight = (Int32)((Decimal)workingBitmap.Height / scale);
Int32 newWidth = (Int32)((Decimal)workingBitmap.Width / scale);
// Create blank BitMap of appropriate size
output = new Bitmap(newWidth, newHeight, PixelFormat.Format32bppArgb);
// Create Graphics surface
using (Graphics g = Graphics.FromImage(output)) {
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
Rectangle destRectangle = new Rectangle(0, 0, newWidth, newHeight);
// Use Graphics surface to draw resized BitMap to blank BitMap
g.DrawImage(workingBitmap, destRectangle, 0, 0, workingBitmap.Width, workingBitmap.Height, GraphicsUnit.Pixel);
}
}
}
catch {
output = null;
}
finally {
Monitor.Exit(_lock);
}
return output;
}
}
}
it also retains the original image's aspect ratio.

Resizing Image From Graphics?

I'm trying to resize my image after copying it from the screen, and can't figure out how to do it. The tutorials I've been reading recommend using Graphics.DrawImage to resize the image, but when I run this code, it doesn't resize.
Bitmap b = new Bitmap(control.Width, control.Height);
Graphics g = Graphics.FromImage(b);
g.CopyFromScreen(control.Parent.RectangleToScreen(control.Bounds).X, control.Parent.RectangleToScreen(control.Bounds).Y, 0, 0, new Size(control.Bounds.Width, control.Bounds.Height), CopyPixelOperation.SourceCopy);
g.DrawImage(b, 0,0,newWidth, newHeight);
Any help would be appreciated, thanks!
Try this. Graphics won't "replace" the image when you use DrawImage - it draws the input image on its source, which is the same as the the image you're trying to draw to it.
Probably a more concise way to do this but.....
Bitmap b = new Bitmap(control.Width, control.Height);
using (Graphics g = Graphics.FromImage(b)) {
g.CopyFromScreen(control.Parent.RectangleToScreen(control.Bounds).X,
control.Parent.RectangleToScreen(control.Bounds).Y, 0, 0,
new Size(control.Bounds.Width, control.Bounds.Height),
CopyPixelOperation.SourceCopy);
}
Bitmap output = new Bitmap(newWidth, newHeight);
using (Graphics g = Graphics.FromImage(output)) {
g.DrawImage(b, 0,0,newWidth, newHeight);
}
Is there any reason why you can't just use a PictureBox control? That control takes care of stretching for you.

Alpha channel transparency and resizing image files

I'm using the following code to resize a tif. The tif has an alpha channel set for transparency. I'm trying to resize this image and honour the transparency but at the moment it's coming out with a black background. Any ideas?
public static void ResizeImage(string OriginalImagePath, string NewImagePath, int Width, int Height)
{
Size NewSize = new Size(Width, Height);
using (Image OriginalImage = Image.FromFile(OriginalImagePath))
{
//Graphics objects can not be created from bitmaps with an Indexed Pixel Format, use RGB instead.
PixelFormat Format = OriginalImage.PixelFormat;
if (Format.ToString().Contains("Indexed"))
Format = PixelFormat.Format24bppRgb;
using (Bitmap NewImage = new Bitmap(NewSize.Width, NewSize.Height, OriginalImage.PixelFormat))
{
using (Graphics Canvas = Graphics.FromImage(NewImage))
{
Canvas.SmoothingMode = SmoothingMode.AntiAlias;
Canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
Canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
Canvas.DrawImage(OriginalImage, new Rectangle(new Point(0, 0), NewSize));
NewImage.Save(NewImagePath, OriginalImage.RawFormat);
}
}
}
}
}
Try this:
if (Format.ToString().Contains("Indexed"))
Format = PixelFormat.Format32bppArgb;
Format32bppArgb specifies an alpha channel in the pixel format.
And I think you meant to do this:
using (Bitmap NewImage = new Bitmap(NewSize.Width, NewSize.Height, Format))
EDIT:
Actually, try just forcing the pixel format on the NewImage to Format32bppArgb like so:
using (Bitmap NewImage = new Bitmap(NewSize.Width, NewSize.Height,
PixelFormat.Format32bppArgb))
Canvas.Clear(Color.Transparent)
before you blit.
I actually found out that due to the way the transparency is stored in the tiff format with photoshop it was better to create png's by automating photoshop and then crunching off the resulting png.

Categories

Resources