Crop a bitmap and expand the size if necessary - c#

I want to crop a bitmap with this function but the bitmap could be smaller then the crop area so I want to get the bitmap bigger in that case.
As example I have a bitmap which is 200x250 and if I use the CropBitmap method with 250x250 I get an out of memory error. It should return a bitmap with 250x250 where the missing left 50px are filled with white.
How can I achieve that?
public Bitmap CropBitmap(Bitmap bitmap, int cropX, int cropY, int cropWidth, int cropHeight)
{
var rect = new Rectangle(cropX, cropY, cropWidth, cropHeight);
if(bitmap.Width < cropWidth || bitmap.Height < cropHeight)
{
// what now?
}
return bitmap.Clone(rect, bitmap.PixelFormat);
}

Create a new Bitmap with the appropriate size. Then get a System.Drawing.Graphics and use it to create the white area and to insert the source image. Something like this:
if (bitmap.Width < cropWidth && bitmap.Height < cropHeight)
{
Bitmap newImage = new Bitmap(cropWidth, cropHeight, bitmap.PixelFormat);
using (Graphics g = Graphics.FromImage(newImage))
{
// fill target image with white color
g.FillRectangle(Brushes.White, 0, 0, cropWidth, cropHeight);
// place source image inside the target image
var dstX = cropWidth - bitmap.Width;
var dstY = cropHeight - bitmap.Height;
g.DrawImage(bitmap, dstX, dstY);
}
return newImage;
}
Note, that I replaced the || in the outer if expression with &&. To make it work with ||, you have to calculate the source region and use another overload of Graphics.DrawImage

Related

automatically add transparent on resize overflow

So I have this code to crop images
private static Image Crop(Image img, Rectangle cropArea)
{
Bitmap bmpImage = (Bitmap)img.Clone();
var part = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
return part;
}
However, cropArea is occasionally out of bounds in the image, sometimes the crop extends outside the image and I want to fill these with transparent color, how do I achieve this?
Use Graphics object against the destination image and draw the original image at translated point.
private static Image Crop(Image img, Rectangle cropArea)
{
//Bitmap bmpImage = (Bitmap)img.Clone();
//var part = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
//return part;
Bitmap part = new Bitmap(cropArea.Width, cropArea.Height, img.PixelFormat);
using (var graphics = Graphics.FromImage(part))
{
graphics.DrawImage(img, -cropArea.X, -cropArea.Y);
}
return part;
}

Custom bitmap object isn't displaying correctly in PictureBox

I'm trying to generate a custom Bitmap through code at a very small size and display it to a PictureBox, upscaled to fit said PictureBox. I am using the graphics object to do this in order to use NearestNeighbor interpolation to upscale single pixels perfectly.
I'm using the graphics object of a temporary default image that is in the PictureBoxs "Image" component on Form.Load, which is sized to be the perfect width and height to maintain the correct aspect ratio from the original Bitmap.
Here is the relevant code:
private void Form1_Load(object sender, EventArgs e)
{
bmp = new Bitmap(16, 9, PixelFormat.Format24bppRgb);
rnd = new Random();
GenerateImage();
}
private void GenerateImage()
{
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
int num = rnd.Next(2);
if (num == 0)
{
bmp.SetPixel(x, y, Color.White);
}
else
{
bmp.SetPixel(x, y, Color.Gold);
}
}
}
Bitmap image = new Bitmap(picOutput.Image);
grp = Graphics.FromImage(image);
grp.InterpolationMode = InterpolationMode.NearestNeighbor;
grp.DrawImage(
bmp,
new Rectangle(0, 0, image.Width, image.Height),
0,
0,
bmp.Width,
bmp.Height,
GraphicsUnit.Pixel
);
grp.Dispose();
picOutput.Image = image;
}
The problem is that the Bitmap seems to be drawn incorrectly. About half a pixel from the original Bitmap is cut off on the left and top edges of the Bitmap when displayed through the PictureBox, and that roughly half a pixel shows up as the original default image on the right and bottom edges. It's almost like the Bitmap was offset up and to the left while being drawn by the graphics object, it doesn't perfectly cover up the original default image like it was supposed to.
My first thought was the PictureBoxs SizeMode, which is still set to "Normal," but none of them change the problem at all. Here is a picture of the problem. The black edges on the right and bottom are part of the temporary default image (the image I used graphics from), which is completely black and covers the entire PictureBox area.
Can anyone offer some insight?
As user Jimi pointed out in a comment, grp.PixelOffsetMode = PixelOffsetMode.Half from this post solved the issue.

Image resizing in C# with alignment of a logo and text in the image to the top

I have an image 3519 X 2495 with some logo and text next to it. When the image is opened, i see the logo and the text next to it in the center. I would like to resize the image to 768 X 1004 and want both the logo and the text next to it to appear on the top. When I resize the image I get the logo and text next to it in the center.
Is there a good way to achieve this in c#.
I tried the below code
Image image = Image.FromFile(#"D:\SSH\Automation\ImageResize\Diageo.jpg");
Bitmap bitmap = new Bitmap(768, 1004);
Graphics graphics = Graphics.FromImage(bitmap);
graphics.DrawImage(image, 0, 0, 768, 1004);
bitmap.Save(#"D:\SSH\Automation\ImageResize\Diageo.png");
graphics.Dispose();
To resize an image and keep its initial aspect ratio use the following code:
Note that I use usings from the IDisposable interface instead of calling Dispose myself as this is considered best practice and is safer.
int maxWidth = 768;
int maxHeight = 1004;
using (Bitmap bitmap = new Bitmap(filePath))
{
int width = (int)(bitmap.Width * (maxHeight / (float)bitmap.Height));
int height = maxHeight;
if (bitmap.Height * (maxWidth / (float)bitmap.Width) <= maxHeight)
{
width = maxWidth;
height = (int)(bitmap.Height * (maxWidth / (float)bitmap.Width));
}
using (Bitmap resizedBitmap = new Bitmap(width, height))
{
resizedBitmap.SetResolution(bitmap.HorizontalResolution, bitmap.VerticalResolution);
using (Graphics g = Graphics.FromImage(resizedBitmap))
{
g.DrawImage(bitmap, 0, 0, resizedBitmap.Width, resizedBitmap.Height);
}
//Use resizedBitmap here
}
}

Fill / append rectangle on bottom of image c#

I need to fill an rectangle on bottom of my image, but not over the image, so it should be a kind of append a rectangle to bottom of image.
What I have for now:
private void DrawRectangle()
{
string imageFilePath = #"c:\Test.jpg";
Bitmap bitmap = (Bitmap)Image.FromFile(imageFilePath);
using (Graphics graphics = Graphics.FromImage(bitmap))
{
using (Image img = Image.FromFile(imageFilePath))
{
SolidBrush brush = new SolidBrush(Color.Black);
int width = img.Width;
int height = img.Height - 350;
graphics.FillRectangle(brush, 0, height, width, 350);
}
}
bitmap.Save(#"c:\Test1.jpg");
}
But this is over the image.
Any idea's?
Thank you.
You need to know the dimensions of your original image in order to set the size of the new bitmap, which must be larger to accommodate the rectangle.
private void DrawRectangle()
{
string imageFilePath = #"c:\Test.jpg";
int rectHeight = 100;
using (Image img = Image.FromFile(imageFilePath)) // load original image
using (Bitmap bitmap = new Bitmap(img.Width, img.Height + rectHeight)) // create blank bitmap of desired size
using (Graphics graphics = Graphics.FromImage(bitmap))
{
// draw existing image onto new blank bitmap
graphics.DrawImage(img, 0, 0, img.Width, img.Height);
SolidBrush brush = new SolidBrush(Color.Black);
// draw your rectangle below the original image
graphics.FillRectangle(brush, 0, img.Height, img.Width, rectHeight);
bitmap.Save(#"c:\Test1.bmp");
}
}
take a look at the FillRectangle() method overloads.. it has one with the following definition: FillRectangle(Brush brush, int PositionX, int PositionY, int Width, int Height)
your problem most likely stems on using an improper overload for what you're doing.

C#: Draw one Bitmap onto Another, with Transparency

I have two Bitmaps, named largeBmp and smallBmp. I want to draw smallBmp onto largeBmp, then draw the result onto the screen. SmallBmp's white pixels should be transparent. Here is the code I'm using:
public Bitmap Superimpose(Bitmap largeBmp, Bitmap smallBmp) {
Graphics g = Graphics.FromImage(largeBmp);
g.CompositingMode = CompositingMode.SourceCopy;
smallBmp.MakeTransparent();
int margin = 5;
int x = largeBmp.Width - smallBmp.Width - margin;
int y = largeBmp.Height - smallBmp.Height - margin;
g.DrawImage(smallBmp, new Point(x, y));
return largeBmp;
}
The problem is that the result winds up transparent wherever smallBmp was transparent! I just want to see through to largeBmp, not to what's behind it.
CompositingMode.SourceCopy is the problem here. You want CompositingMode.SourceOver to get alpha blending.
Specify the transparency color of your small bitmap. e.g.
Bitmap largeImage = new Bitmap();
Bitmap smallImage = new Bitmap();
--> smallImage.MakeTransparent(Color.White);
Graphics g = Graphics.FromImage(largeImage);
g.DrawImage(smallImage, new Point(10,10);
Winform copy image on top of another
private void timerFFTp_Tick(object sender, EventArgs e)
{
if (drawBitmap)
{
Bitmap bitmap = new Bitmap(_fftControl.Width, _fftControl.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
_fftControl.DrawToBitmap(bitmap, new Rectangle(0, 0, _fftControl.Width, _fftControl.Height));
if (!fDraw)
{
bitmap.MakeTransparent();
Bitmap fftFormBitmap = new Bitmap(_fftForm.BackgroundImage);
Graphics g = Graphics.FromImage(fftFormBitmap);
g.DrawImage(bitmap, 0, 0);
_fftForm.BackgroundImage = fftFormBitmap;
}
else
{
fDraw = false;
_fftForm.Width = bitmap.Width + 16;
_fftForm.Height = bitmap.Height + 48;
_fftForm.BackgroundImage = bitmap;
}
}
}

Categories

Resources