create .bmp from ushort array - c#

I have several problem with creating a bitmap from a array. I have a camera and from this I get grayscale values in ushort format. But how to create a bitmap from this values? Only:
System.Drawing.Bitmap checks = new System.Drawing.Bitmap(10, 10);
.
.
checks.Save(#"C:\test.bmp", ImageFormat.Bmp);
will not work:(. I get an image and can open it with window tools, but when I will open the file with another graphic lib, I get alot of errors. So does anybody now how to create a correct bmp file with header etc? does anybody have some code example? this would help most.
thanks

You should create a Bitmap with the right dimensions (width, height), and use LockBits to get a handle to memory that you should write to. If your data is in a .NET supported PixelFormat, you can pass that to LockBits and simply copy data. If not, you might have to do some data conversion manually.
It all boils down to what format you receive data samples in, but the above description outlines the steps you need to take to generate your image.
Update: Since your data is 16 bits gray scale, there is a PixelFormat you can use directly, PixelFormat.16bppGrayScale.

public class(path,wid,height,boolean)
{
System.Drawing.Image myThumbnail150;
System.Drawing.Image.GetThumbnailImageAbort myCallback = new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback);
System.Drawing.Image imagesize = System.Drawing.Image.FromFile(pic.FilePath);
using (Bitmap bitmapNew = new Bitmap(imagesize))
{
double maxWidth = Convert.ToDouble(ConfigurationSettings.AppSettings["ImageWidth"]);
double maxHeight = Convert.ToDouble(ConfigurationSettings.AppSettings["ImageHeight"]);
int w = imagesize.Width;
int h = imagesize.Height;
// Longest and shortest dimension
int longestDimension = (w > h) ? w : h;
int shortestDimension = (w < h) ? w : h;
// propotionality
float factor = ((float)longestDimension) / shortestDimension;
// default width is greater than height
double newWidth = maxWidth;
double newHeight = maxWidth / factor;
// if height greater than width recalculate
if (w < h)
{
newWidth = maxHeight / factor;
newHeight = maxHeight;
}
myThumbnail150 = bitmapNew.GetThumbnailImage((int)newWidth, (int)newHeight, myCallback, IntPtr.Zero);
string name = pic.Name.Replace(Path.GetExtension(pic.Name), ".Bmp");
//Create a new directory name ThumbnailImage
//Save image in TumbnailImage folder
myThumbnail150.Save(yourpath+ name, System.Drawing.Imaging.ImageFormat.Bmp);
bitmapNew.Dispose();
}

Related

How to avoid bitmap out of memory when working on very large image for ie: 10.000.000 pixel and above

Currently i'm working on a system that load a very large image, with minimum width x heigh >= 10.000.000 pixel.
But the ratio of the user's upload image usually do not match our requirement ratio so i have to crop it to proper ratio, but when using System.Drawing bitmap to crop it, i always got SytemOutOfMemory exception.
I have try Bitmap.Clone and Graphic.DrawImage with correct RectangleF but no luck.
Is there anyways to do this without getting the outofmemory exception or are there any alternatives to System.Drawing library to get this task done easily ?
My code to load the image from user upload file:
var fileBinary = new byte[stream.Length];
stream.Read(fileBinary, 0, fileBinary.Length);
stream.Position = 0;
var fileExtension = Path.GetExtension(fileName);
using (Image image = Image.FromStream(stream, false, false))
{
//validation and check ratio
CropImage(image, PORTRAIT_RATIO, fileExtension);
}
And the CropImage function:
//Crop Image from center with predefine ratio
private byte[] CropImage(Image sourceImg, float ratio, string fileExtension)
var height = sourceImg.Height;
var width = sourceImg.Width;
var isPortrait = width < height;
RectangleF croppingRec = new RectangleF();
float positionX = 0;
float positionY = 0;
float cropHeight = (float)height;
float cropWidth = cropHeight * PORTRAIT_RATIO;
positionY = 0;
positionX = (width - cropWidth) / 2;
if (cropWidth > width)
{
cropWidth = width;
cropHeight = cropWidth * (1 / PORTRAIT_RATIO);
positionX = 0;
positionY = ((height - cropHeight) / 2);
}
croppingRec.Width = cropWidth;
croppingRec.Height = cropHeight;
croppingRec.X = positionX;
croppingRec.Y = positionY;
Bitmap bmpImage = sourceImg as Bitmap;
Bitmap bmpCrop = bmpImage.Clone(croppingRec, bmpImage.PixelFormat);
bmpCrop.Save("D:/test" + fileExtension, ImageFormat.Jpeg);
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(bmpCrop, typeof(byte[]));
}
}
You could convert the bitmap to a byte array. Try something like this (looks hackie but i don't know another way):
int pixelSize = 3;
int bytesCount = imgHeight * imgWidth * pixelSize;
byte[] byteArray= new byte[bytesCount];
BitmapData bitmapData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, imgWidth, imgHeight), ImageLockMode.ReadOnly, bitmap.PixelFormat);
Marshal.Copy(bitmapData.Scan0, byteArray, 0, bytesCount);
Each pixel in this array is represented by 3 bytes (this depends on the bitmap type). So you know that lenght of a bitmap line is 3 * imgWidth. Using this you could simply navigate in the byte array and copy just what you need into a new array.
You would then create a new bitmap with the desired final size, get the bitmap data and Marshal.Copy the new array into that:
Bitmap newBitmap = new Bitmap(Width, Height);
BitmapData newBitmapData = b.LockBits(BoundsRect,
ImageLockMode.WriteOnly,
newBitmap.PixelFormat);
Marshal.Copy(newByteArray, 0, newBitmapData.Scan0, newBytesCount);
Unlock the bitmaps at the end:
newBitmap.UnlockBits(newBitmapData );
bitmap.UnlockBits(bitmapData);
Hope this helps. Cheers.
Try using graphicsmagick.net library, then use the Crop method on MagickImage. It should still work well under asp.net, and handles huge image files using disk for scratch.

How to resize an image maintaining the aspect ratio in C#

I need to know of a way to resize an image to fit in a box without the image stretching too much. The box has set width and height and I want the image to fill as much of the box as possible but maintain the aspect ratio it originally had.
//calculate the ratio
double dbl = (double)image.Width / (double)image.Height;
//set height of image to boxHeight and check if resulting width is less than boxWidth,
//else set width of image to boxWidth and calculate new height
if( (int)((double)boxHeight * dbl) <= boxWidth )
{
resizedImage = new Bitmap(original, (int)((double)boxHeight * dbl), boxHeight);
}
else
{
resizedImage = new Bitmap(original, boxWidth, (int)((double)boxWidth / dbl) );
}
The formula for scaling with the same ratio is:
newWidth = (int)((double)boxHeight * dbl)
or
newHeight = (int)((double)boxWidth / dbl)
A Math.Max could simplify the problem:
double ratio = Math.Max((double)image.width / (double)box.width , (double)image.height / (double)box.height);
image.width = (int)(image.width / ratio);
image.height = (int)(image.height / ratio);
Bitmap original,resizedImage;
try
{
using (FileStream fs = new System.IO.FileStream(imageLabel.Text, System.IO.FileMode.Open))
{
original = new Bitmap(fs);
}
int rectHeight = BOXWIDTH;
int rectWidth = BOXWIDTH;
//if the image is squared set it's height and width to the smallest of the desired dimensions (our box). In the current example rectHeight<rectWidth
if (original.Height == original.Width)
{
resizedImage = new Bitmap(original, rectHeight, rectHeight);
}
else
{
//calculate aspect ratio
float aspect = original.Width / (float)original.Height;
int newWidth, newHeight;
//calculate new dimensions based on aspect ratio
newWidth = (int)(rectWidth * aspect);
newHeight = (int)(newWidth / aspect);
//if one of the two dimensions exceed the box dimensions
if (newWidth > rectWidth || newHeight > rectHeight)
{
//depending on which of the two exceeds the box dimensions set it as the box dimension and calculate the other one based on the aspect ratio
if (newWidth > newHeight)
{
newWidth = rectWidth;
newHeight = (int)(newWidth / aspect);
}
else
{
newHeight = rectHeight;
newWidth = (int)(newHeight * aspect);
}
}
resizedImage = new Bitmap(original, newWidth, newHeight);
}
}
catch (Exception ex)
{
MessageBox.Show( ex.Message);
}
}
The accepted answer probably works but I stared at it for a long time and could not understand exactly how, so I thought I would share what I came up with: shrink height first, then check width and shrink again if needed, always preserving the aspect ratio.
I used SixLabors.ImageSharp because it's compatible with Linux, but you can easily swap out the resizing function once you have the newHeight and newWidth.
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
public class ImageSharpService : IImageService
{
public async Task ShrinkAndSaveAsync(Stream stream, string savePath, int maxHeight, int maxWidth)
{
using Image image = Image.Load(stream);
// check if resize is needed
if (ResizeNeeded(image.Height, image.Width, maxHeight, maxWidth, out int newHeight, out int newWidth))
// swap this part out if not using ImageSharp
image.Mutate(x => x.Resize(new ResizeOptions
{
Size = new Size(newWidth, newHeight)
}));
await image.SaveAsync(savePath);
}
private bool ResizeNeeded(int height, int width, int maxHeight, int maxWidth, out int newHeight, out int newWidth)
{
// first use existing dimensions
newHeight = height;
newWidth = width;
// if below max on both then do nothing
if (height <= maxHeight && width <= maxWidth) return false;
// naively check height first
if (height > maxHeight)
{
// set down to max height
newHeight = maxHeight;
// calculate what new width would be
var heightReductionRatio = maxHeight / height; // ratio of maxHeight:image.Height
newWidth = width * heightReductionRatio; // apply ratio to image.Width
}
// does width need to be reduced?
// (this will also re-check width after shrinking by height dimension)
if (newWidth > maxWidth)
{
// if so, re-calculate height to fit for maxWidth
var widthReductionRatio = maxWidth / newWidth; // ratio of maxWidth:newWidth (height reduction ratio may have been applied)
newHeight = maxHeight * widthReductionRatio; // apply new ratio to maxHeight to get final height
newWidth = maxWidth;
}
// if we got here, resize needed and out vars have been set
return true;
}
}
I believe that if you only change the height or only the width it will remain in better ratios and the width/height will change with it. So you can try that

How to Crop Image without changing the aspect ratio

I need to crop an image without changing its aspect ratio. I am taking picture from CANON1100D using EDSDK. Captured image:
Width = 1920 and Height=1280
Aspect ratio is 1.5. But I need picture which aspect ratio will be 1.33.
// convert into processing resolution (1600,1200)
Image<Bgr, byte> runtime_frm = new Image<Bgr, byte>(frame.ToBitmap(1600,1200));
// also in bitmap processing
// Bitmap a = new Bitmap(runtime_frm.ToBitmap());
// Bitmap b = new Bitmap(a, new Size(1600,1200));
It's resizing the image, so the aspect ratio of image is changed, but it creates stress in image. I'd like to crop the image (1920x1280) to (1600x1200) in runtime.
How can I do this programmatically?
public void Crop(Bitmap bm, int cropX, int cropY,int cropWidth,int cropHeight)
{
var rect = new System.Drawing.Rectangle(cropX,cropY,cropWidth,cropHeight);
Bitmap newBm = bm.Clone(rect, bm.PixelFormat);
newBm.Save("image2.jpg");
}
Maybe something like that?
source
this is my solution for centered cropping.
Bitmap CenterCrop(Bitmap srcImage, int newWidth, int newHeight)
{
Bitmap ret = null;
int w = srcImage.Width;
int h = srcImage.Height;
if ( w < newWidth || h < newHeight)
{
MessageBox.Show("Out of boundary");
return ret;
}
int posX_for_centerd_crop = (w - newWidth) / 2;
int posY_for_centerd_crop = (h - newHeight) / 2;
var CenteredRect = new Rectangle( posX_for_centerd_crop,
posY_for_centerd_crop, newWidth, newHeight);
ret = srcImage.Clone(imageCenterRect, srcImage.PixelFormat);
return ret;
}

Display small image catalog in asp

Hi I want to put products to a catalog, How i can crop the picture to small and save the small and the orginal?
Try look here:
C# Thumbnail Image With GetThumbnailImage
or here:
Convert Bitmap to Thumbnail
Create thumbnail and reduce image size
Create thumbnail image
update
For example you can save the image to a folder and then you can do something like this:
var filename = "sourceImage.png";
using(var image = Image.FromFile(filename))
{
using(var thumbnail = image.GetThumbnailImage(20/*width*/, 40/*height*/, null, IntPtr.Zero))
{
thumbnail.Save("thumb.png");
}
}
update
to resize proportionally try something like this:
public Bitmap ProportionallyResizeBitmap (Bitmap src, int maxWidth, int maxHeight)
{
// original dimensions
int w = src.Width;
int h = src.Height;
// Longest and shortest dimension
int longestDimension = (w>h)?w: h;
int shortestDimension = (w<h)?w: h;
// propotionality
float factor = ((float)longestDimension) / shortestDimension;
// default width is greater than height
double newWidth = maxWidth;
double newHeight = maxWidth/factor;
// if height greater than width recalculate
if ( w < h )
{
newWidth = maxHeight / factor;
newHeight = maxHeight;
}
// Create new Bitmap at new dimensions
Bitmap result = new Bitmap((int)newWidth, (int)newHeight);
using ( Graphics g = Graphics.FromImage((System.Drawing.Image)result) )
g.DrawImage(src, 0, 0, (int)newWidth, (int)newHeight);
return result;
}

ASP.Net MVC Image Upload Resizing by downscaling or padding

A user will be able to upload an image. If the image is greater than a set size I want to downsize it to that size. Obviously it doesn't have to match exactly due to ratios, the width would be the key size so the height would be variable.
If the image is smaller than the set size I would like to create a new image to the set size with a background of a defined colour and then centre the uploaded image into it therefore the result is the original with paddded colour.
Any code examples or links greatly appreciated
Here's a snippet of code I quickly knocked up for resizing it based on the width. I'm sure you could figure out how to add a background color to the Bitmap. It's not complete code but just an idea of how to do things.
public static void ResizeLogo(string originalFilename, string resizeFilename)
{
Image imgOriginal = Image.FromFile(originalFilename);
//pass in whatever value you want for the width (180)
Image imgActual = ScaleBySize(imgOriginal, 180);
imgActual.Save(resizeFilename);
imgActual.Dispose();
}
public static Image ScaleBySize(Image imgPhoto, int size)
{
int logoSize = size;
float sourceWidth = imgPhoto.Width;
float sourceHeight = imgPhoto.Height;
float destHeight = 0;
float destWidth = 0;
int sourceX = 0;
int sourceY = 0;
int destX = 0;
int destY = 0;
// Resize Image to have the height = logoSize/2 or width = logoSize.
// Height is greater than width, set Height = logoSize and resize width accordingly
if (sourceWidth > (2 * sourceHeight))
{
destWidth = logoSize;
destHeight = (float)(sourceHeight * logoSize / sourceWidth);
}
else
{
int h = logoSize / 2;
destHeight = h;
destWidth = (float)(sourceWidth * h / sourceHeight);
}
// Width is greater than height, set Width = logoSize and resize height accordingly
Bitmap bmPhoto = new Bitmap((int)destWidth, (int)destHeight,
PixelFormat.Format32bppPArgb);
bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution);
Graphics grPhoto = Graphics.FromImage(bmPhoto);
grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(imgPhoto,
new Rectangle(destX, destY, (int)destWidth, (int)destHeight),
new Rectangle(sourceX, sourceY, (int)sourceWidth, (int)sourceHeight),
GraphicsUnit.Pixel);
grPhoto.Dispose();
return bmPhoto;
}
You can just load the file into a bitmap object:
http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.aspx
Then just check the width on the object. For the second part of your problem, I would recommend using a tool like ImageMagick
http://www.imagemagick.org/script/index.php
to accurately resize the first image or to create the background image and merge the two images together.

Categories

Resources