Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
How can I apply blur effect on an image in C# without using a library?
Updated code (now much faster, requires use of UNSAFE keyword)
static void Main(string[] args)
{
Bitmap bitmap = new Bitmap("C:\\Users\\erik\\test.png");
bitmap = Blur(bitmap, 10);
bitmap.Save("C:\\Users\\erik\\test2.png");
}
private static Bitmap Blur(Bitmap image, Int32 blurSize)
{
return Blur(image, new Rectangle(0, 0, image.Width, image.Height), blurSize);
}
private unsafe static Bitmap Blur(Bitmap image, Rectangle rectangle, Int32 blurSize)
{
Bitmap blurred = new Bitmap(image.Width, image.Height);
// make an exact copy of the bitmap provided
using (Graphics graphics = Graphics.FromImage(blurred))
graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);
// Lock the bitmap's bits
BitmapData blurredData = blurred.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, blurred.PixelFormat);
// Get bits per pixel for current PixelFormat
int bitsPerPixel = Image.GetPixelFormatSize(blurred.PixelFormat);
// Get pointer to first line
byte* scan0 = (byte*)blurredData.Scan0.ToPointer();
// look at every pixel in the blur rectangle
for (int xx = rectangle.X; xx < rectangle.X + rectangle.Width; xx++)
{
for (int yy = rectangle.Y; yy < rectangle.Y + rectangle.Height; yy++)
{
int avgR = 0, avgG = 0, avgB = 0;
int blurPixelCount = 0;
// average the color of the red, green and blue for each pixel in the
// blur size while making sure you don't go outside the image bounds
for (int x = xx; (x < xx + blurSize && x < image.Width); x++)
{
for (int y = yy; (y < yy + blurSize && y < image.Height); y++)
{
// Get pointer to RGB
byte* data = scan0 + y * blurredData.Stride + x * bitsPerPixel / 8;
avgB += data[0]; // Blue
avgG += data[1]; // Green
avgR += data[2]; // Red
blurPixelCount++;
}
}
avgR = avgR / blurPixelCount;
avgG = avgG / blurPixelCount;
avgB = avgB / blurPixelCount;
// now that we know the average for the blur size, set each pixel to that color
for (int x = xx; x < xx + blurSize && x < image.Width && x < rectangle.Width; x++)
{
for (int y = yy; y < yy + blurSize && y < image.Height && y < rectangle.Height; y++)
{
// Get pointer to RGB
byte* data = scan0 + y * blurredData.Stride + x * bitsPerPixel / 8;
// Change values
data[0] = (byte)avgB;
data[1] = (byte)avgG;
data[2] = (byte)avgR;
}
}
}
}
// Unlock the bits
blurred.UnlockBits(blurredData);
return blurred;
}
Took 2.356 seconds to process 256x256 image with blur value 10.
Original Code (from Github - slightly altered)
static void Main(string[] args)
{
Bitmap bitmap = new Bitmap("C:\\Users\\erik\\test.png");
bitmap = Blur(bitmap, 10);
bitmap.Save("C:\\Users\\erik\\test2.png");
}
private static Bitmap Blur(Bitmap image, Int32 blurSize)
{
return Blur(image, new Rectangle(0, 0, image.Width, image.Height), blurSize);
}
private static Bitmap Blur(Bitmap image, Rectangle rectangle, Int32 blurSize)
{
Bitmap blurred = new Bitmap(image.Width, image.Height);
// make an exact copy of the bitmap provided
using (Graphics graphics = Graphics.FromImage(blurred))
graphics.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);
// look at every pixel in the blur rectangle
for (int xx = rectangle.X; xx < rectangle.X + rectangle.Width; xx++)
{
for (int yy = rectangle.Y; yy < rectangle.Y + rectangle.Height; yy++)
{
int avgR = 0, avgG = 0, avgB = 0;
int blurPixelCount = 0;
// average the color of the red, green and blue for each pixel in the
// blur size while making sure you don't go outside the image bounds
for (int x = xx; (x < xx + blurSize && x < image.Width); x++)
{
for (int y = yy; (y < yy + blurSize && y < image.Height); y++)
{
Color pixel = blurred.GetPixel(x, y);
avgR += pixel.R;
avgG += pixel.G;
avgB += pixel.B;
blurPixelCount++;
}
}
avgR = avgR / blurPixelCount;
avgG = avgG / blurPixelCount;
avgB = avgB / blurPixelCount;
// now that we know the average for the blur size, set each pixel to that color
for (int x = xx; x < xx + blurSize && x < image.Width && x < rectangle.Width; x++)
for (int y = yy; y < yy + blurSize && y < image.Height && y < rectangle.Height; y++)
blurred.SetPixel(x, y, Color.FromArgb(avgR, avgG, avgB));
}
}
return blurred;
}
Took 7.594 seconds to process 256x256 image with blur value 10.
Orignal Image
Blurred Image (blur level 10)
Image from: https://www.pexels.com/search/landscape/
If you are using XAML check it from Microsoft. Also study this code it your problem can be solved.
Related
See: Save a 32-bit Bitmap as 1-bit .bmp file in C#
Listing #1
public static Bitmap BitmapTo1Bpp(Bitmap source)
{
int Width = source.Width;
int Height = source.Height;
Bitmap dest = new Bitmap(Width, Height, PixelFormat.Format1bppIndexed);
BitmapData destBmpData = dest.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
byte[] destBytes = new byte[(Width + 7) / 8];//19 bytes
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
Color c = source.GetPixel(x, y);
if (x % 8 == 0)
{
destBytes[x / 8] = 0;
}
if (c.GetBrightness() >= 0.5)
{
destBytes[x / 8] |= (byte)(0x80 >> (x % 8));
}
}
Marshal.Copy(destBytes, 0, (IntPtr)((long)destBmpData.Scan0 + destBmpData.Stride * y), destBytes.Length);
}
dest.UnlockBits(destBmpData);
return dest;
}
Listing #2
public static Bitmap BitmapTo1Bpp222(Bitmap source)
{
int Width = source.Width;
int Height = source.Height;
Bitmap dest = new Bitmap(Width, Height, PixelFormat.Format1bppIndexed);
BitmapData destBmpData = dest.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
int destStride = destBmpData.Stride;
int destSize = Math.Abs(destStride) * Height;
byte[] destBytes = new byte[destSize];
for (int y = 0; y < Height; y++)
{
for (int x = 0; x < Width; x++)
{
Color c = source.GetPixel(x, y);
if (x % 8 == 0)
{
destBytes[x*y / 8] = 0;
}
if (c.GetBrightness() >= 0.5)
{
destBytes[x*y / 8] |= (byte)(0x80 >> (x % 8));
}
}
}
Marshal.Copy(destBytes, 0, destBmpData.Scan0, destBytes.Length);
dest.UnlockBits(destBmpData);
return dest;
}
See the position of Marshal.Copy().
Why does the Listing #1 work, but Listing #2 doesn't?
What modification can make the Listing #2 work?
Both of these are overly complicated. LockBits can convert data to 1bpp. Just open the source as 1bpp, copy its data into the new 1bpp image, and you're done.
I'm also quite baffled by the combination of GetPixel and LockBits. Usually, using LockBits means you realized that GetPixel is a horribly slow waste of time that performs a LockBits internally on every call.
public static Bitmap BitmapTo1Bpp(Bitmap source)
{
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
Bitmap dest = new Bitmap(rect.Width, rect.Height, PixelFormat.Format1bppIndexed);
dest.SetResolution(source.HorizontalResolution, source.VerticalResolution);
BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed);
BitmapData targetData = dest.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format1bppIndexed);
Int32 actualDataWidth = (rect.Width + 7) / 8;
Int32 h = source.Height;
Int32 origStride = sourceData.Stride;
Int32 targetStride = targetData.Stride;
// buffer for one line of image data.
Byte[] imageData = new Byte[actualDataWidth];
Int64 sourcePos = sourceData.Scan0.ToInt64();
Int64 destPos = targetData.Scan0.ToInt64();
// Copy line by line, skipping by stride but copying actual data width
for (Int32 y = 0; y < h; y++)
{
Marshal.Copy(new IntPtr(sourcePos), imageData, 0, actualDataWidth);
Marshal.Copy(imageData, 0, new IntPtr(destPos), actualDataWidth);
sourcePos += origStride;
destPos += targetStride;
}
dest.UnlockBits(targetData);
source.UnlockBits(sourceData);
return dest;
}
Do note that conversion of data to indexed formats should be avoided in cases where your result is not 1bpp for pure black and white. Indexed formats are paletted, and doing it this way will not do any kind of reduction to an optimised palette approaching the image colours; it will just change the colours on the image to their closest match on the standard palette for this bit depth. For 1bpp this is just black and white, which is perfect, but for 4bpp and 8bpp it will give pretty bad results.
Also note that for some reason you can't convert from a higher to a lower indexed pixel format; it will throw an exception. Since you can convert a bitmap to 32-bit using the new Bitmap(Bitmap) constructor, this problem can easily be avoided by calling the code like this:
public static Bitmap ConvertTo1Bpp(Bitmap source)
{
PixelFormat sourcePf = source.PixelFormat;
if ((sourcePf & PixelFormat.Indexed) == 0 || Image.GetPixelFormatSize(sourcePf) == 1)
return BitmapTo1Bpp(source);
using (Bitmap bm32 = new Bitmap(source))
return BitmapTo1Bpp(bm32);
}
I have written a code that converts image to grayscale. but the code only convert partial of it.
I am trying to convert this code to a Parallel computation. I end up with bugs that I can not get my head around them. Any suggestion?
private void button2_Click(object sender, EventArgs e)
{
Bitmap bmp = (Bitmap)pictureBox1.Image;
unsafe {
//get image dimension
//int width = bmp.Width;
//int height = bmp.Height;
BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
//define variable
int bpp = System.Drawing.Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8;
int hip = bitmapData.Height;
int wib = bitmapData.Width + bpp;
//point to first pixel
byte* PtrFirstPixel = (byte*)bitmapData.Scan0;
//color of pixel
// Color p;
//grayscale
Parallel.For(0, hip, y =>
{
byte* currentLine = PtrFirstPixel + (y * bitmapData.Stride);
for (int x = 0; x < wib; x = x + bpp)
{
//get pixel value
//p = bmp.GetPixel(x, y);
//extract pixel component ARGB
//int a = p.A;
//int r = p.R;
//int g = p.G;
// int b = p.B;
int b = currentLine[x];
int g = currentLine[x + 1];
int r = currentLine[x + 2];
//find average
int avg = (r + g + b) / 3;
//set new pixel value
// bmp.SetPixel(x, y, Color.FromArgb(a, avg, avg, avg));
currentLine[x] = (byte)avg;
currentLine[x + 1] = (byte)avg;
currentLine[x + 2] = (byte)avg;
}
});
bmp.UnlockBits(bitmapData);
//load grayscale image in picturebox2
//pictureBox2.Image = bmp;
}
pictureBox2.Image = bmp;
}
my out put image
int wib = bitmapData.Width + bpp;
should be:
int wib = bitmapData.Width * bpp;
You want the number of bytes which requires a multiply, not an add. There may be other issues, but this is definitely incorrect.
The following routine is to sharpen an 8 bit indexed grayscale only.
This code seems to have no effect on the input image. That is, what is going in, the same is coming out.
If I increase the value of strength the image seems to be getting darker, but, never filtered.
What could be possibly going wrong?
I am using the following kernel,
double[,] _numericalKernel = new double[,]
{ { -1, -1, -1, },
{ -1, 9, -1, },
{ -1, -1, -1, }, };
The following is my source code for sharpening,
public static Bitmap NonfftSharpen(Bitmap image, double[,] mask, double strength)
{
Bitmap bitmap = (Bitmap)image.Clone();
if (bitmap != null)
{
int width = bitmap.Width;
int height = bitmap.Height;
if (mask.GetLength(0) != mask.GetLength(1))
{
throw new Exception("_numericalKernel dimensions must be same");
}
// Create sharpening filter.
int filterSize = mask.GetLength(0);
double[,] filter = (double[,])mask.Clone();
int channels = sizeof(byte);
double bias = 1.0 - strength;
double factor = strength / 16.0;
int halfOfFilerSize = filterSize / 2;
byte[,] result = new byte[bitmap.Width, bitmap.Height];
// Lock image bits for read/write.
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite,
PixelFormat.Format8bppIndexed);
// Declare an array to hold the bytes of the bitmap.
int memorySize = bitmapData.Stride * height;
byte[] memory = new byte[memorySize];
// Copy the RGB values into the local array.
Marshal.Copy(bitmapData.Scan0, memory, 0, memorySize);
int rgb;
// Fill the color array with the new sharpened color values.
for (int y = halfOfFilerSize; y < height - halfOfFilerSize; y++)
{
for (int x = halfOfFilerSize; x < width - halfOfFilerSize; x++)
{
for (int filterY = 0; filterY < filterSize; filterY++)
{
double grayShade = 0.0;
for (int filterX = 0; filterX < filterSize; filterX++)
{
int imageX = (x - halfOfFilerSize + filterX + width) % width;
int imageY = (y - halfOfFilerSize + filterY + height) % height;
rgb = imageY * bitmapData.Stride + channels * imageX;
grayShade += memory[rgb + 0] * filter[filterX, filterY];
}
rgb = y * bitmapData.Stride + channels * x;
int b = Math.Min(Math.Max((int)(factor * grayShade + (bias * memory[rgb + 0])), 0), 255);
result[x, y] = (byte)b;
}
}
}
// Update the image with the sharpened pixels.
for (int x = halfOfFilerSize; x < width - halfOfFilerSize; x++)
{
for (int y = halfOfFilerSize; y < height - halfOfFilerSize; y++)
{
rgb = y * bitmapData.Stride + channels * x;
memory[rgb + 0] = result[x, y];
}
}
// Copy the RGB values back to the bitmap.
Marshal.Copy(memory, 0, bitmapData.Scan0, memorySize);
// Release image bits.
bitmap.UnlockBits(bitmapData);
return bitmap;
}
else
{
throw new Exception("input image can't be null");
}
}
I've changed your function a bit to make it work.
Take care that the strength parameter has no effect in my function. You can play with the bias and factor values to get different results in brightness and so on.
public static Bitmap NonfftSharpen(Bitmap image, double[,] mask, double strength)
{
Bitmap bitmap = (Bitmap)image.Clone();
if (bitmap != null)
{
int width = bitmap.Width;
int height = bitmap.Height;
if (mask.GetLength(0) != mask.GetLength(1))
{
throw new Exception("_numericalKernel dimensions must be same");
}
// Create sharpening filter.
int filterSize = mask.GetLength(0);
double[,] filter = (double[,])mask.Clone();
int channels = sizeof(byte);
double bias = 0.0; // 1.0 - strength;
double factor = 1.0; // strength / 16.0;
byte[,] result = new byte[bitmap.Width, bitmap.Height];
// Lock image bits for read/write.
BitmapData bitmapData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, width, height),
ImageLockMode.ReadWrite,
System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
// Declare an array to hold the bytes of the bitmap.
int memorySize = bitmapData.Stride * height;
byte[] memory = new byte[memorySize];
// Copy the RGB values into the local array.
Marshal.Copy(bitmapData.Scan0, memory, 0, memorySize);
int pixel;
// Fill the color array with the new sharpened color values.
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
double grayShade = 0.0;
for (int filterY = 0; filterY < filterSize; filterY++)
{
for (int filterX = 0; filterX < filterSize; filterX++)
{
int imageX = (x - filterSize / 2 + filterX + width) % width;
int imageY = (y - filterSize / 2 + filterY + height) % height;
pixel = imageY * bitmapData.Stride + channels * imageX;
grayShade += memory[pixel] * filter[filterX, filterY];
}
int newPixel = Math.Min(Math.Max((int)(factor * grayShade + bias), 0), 255);
result[x, y] = (byte)newPixel;
}
}
}
// Update the image with the sharpened pixels.
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
pixel = y * bitmapData.Stride + channels * x;
memory[pixel] = result[x, y];
}
}
// Copy the values back to the bitmap.
Marshal.Copy(memory, 0, bitmapData.Scan0, memorySize);
// Release image bits.
bitmap.UnlockBits(bitmapData);
return bitmap;
}
else
{
throw new Exception("input image can't be null");
}
}
I hope this gets you going :)
Regards
I'm trying to implement a cropping method myself,using the unsafe code and pointer to speed up the whole process.
This is my code:
private unsafe void Cut(Bitmap bmp, Rectangle r) {
Bitmap result = new Bitmap(r.Width, r.Height, bmp.PixelFormat);
BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, bmp.PixelFormat);
BitmapData bmData2 = result.LockBits(new Rectangle(0, 0, result.Width, result.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, result.PixelFormat);
IntPtr scan0 = bmData.Scan0;
IntPtr scan02 = bmData2.Scan0;
int stride = bmData.Stride;
int stride2 = bmData2.Stride;
int x = r.X;
int y = r.Y;
int width = r.Width;
int height = r.Height;
for (; y < height; y++) {
byte * p = (byte * ) scan0.ToPointer();
p += y * stride;
byte * p2 = (byte * ) scan02.ToPointer();
p2 += y * stride2;
for (; x < width; x++) {
p2[0] = p[0];
p2[1] = p[1];
p2[2] = p[2];
p2[3]=p[3];
p += 4;
p2 += 4;
}
}
result.Save("a.png");
}
And the call to this method:
Bitmap b = (Bitmap)Bitmap.FromFile(#"C:\Users\itapi\Desktop\1.png");
Rectangle r = new Rectangle(200, 500, 300, 450);
Cut(b, r);
When i run the code,i just get a black rectangle as result...not the pixels i wanted to copy from the intial image.
The image from the example above is in32bpprgb format
I'm not sure what i'm doing wrong..i'll appreciate any help.
Thanks.
On the result, you chose "System.Drawing.Imaging.ImageLockMode.ReadOnly" I think you want ReadWrite or WriteOnly.
When I ran through debugger, this statement: for (; y < height; y++) condition failed immediately on my rather large image. So your loop logic is incorrect for running through the lines... Use a debugger :)
EDIT I ran it through the debugger, and your Y and X logic is wrong. I did a quick fix on the Y logic, and got it too crop. You'll have to do something similar to the X to get the correct crop point.
Try this, it cropped and saved a file:
int x = r.X;
int y = r.Y;
int width = r.Width;
int height = r.Height;
int newY = 0;
for (y = r.Y; y < height+r.Y; y++) //For each line in the old image
{
byte* p = (byte*)scan0.ToPointer();
p += y * stride;
byte* p2 = (byte*)scan02.ToPointer();
p2 += newY * stride2;
for (x=r.X; x < width+r.X; x++)
{
p2[0] = p[0];
p2[1] = p[1];
p2[2] = p[2];
p2[3] = p[3];
p += 4;
p2 += 4;
}
newY++;
}
result.Save("\\a.png");
im looking for a way to resize a Bitmap, without losing its actually shape, while having in mind that the new size is musn't be proportional to the original image dimensions.
To be exact I want to resize a image of a upright eight (40x110) to a 29x29 Bitmap and im looking for a function to convert the original proportions relativ to its new image, while filling the new created space (in width) with white and having the same side clearance from the actually eight to its white baselines.
Unfortunately this hasn't satisfy my requirements:
public static Bitmap ResizeImage(Image image, int width, int height)
{
var destRect = new Rectangle(0, 0, width, height);
var destImage = new Bitmap(width, height);
destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
Update 1:
New function for proportional resizing:
public static Bitmap ResizeImageProportional(Bitmap bitmap, int width, int height)
{
Bitmap destImage;
Rectangle destRect;
int destH, destW, destX, dextY;
if (bitmap.Height > bitmap.Width)
{
destH = height;
destW = bitmap.Width / bitmap.Height * height;
destX = (width - destW) / 2;
dextY = 0;
}
else if (bitmap.Height < bitmap.Width)
{
destH = bitmap.Height / bitmap.Width * width;
destW = width;
destX = 0;
dextY = (height - destH) / 2;
}
else
// if (bitmap.Width == bitmap.Height)
{
destH = height;
destW = width;
destX = 0;
dextY = 0;
}
destRect = new Rectangle(destX, dextY, destW, destH);
destImage = new Bitmap(width, height);
destImage.SetResolution(bitmap.HorizontalResolution, bitmap.VerticalResolution);
using (var graphics = Graphics.FromImage(destImage))
{
graphics.CompositingMode = CompositingMode.SourceCopy;
graphics.CompositingQuality = CompositingQuality.HighQuality;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
using (var wrapMode = new ImageAttributes())
{
wrapMode.SetWrapMode(WrapMode.TileFlipXY);
graphics.DrawImage(bitmap, destRect, 0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, wrapMode);
}
}
return destImage;
}
Unfortunately I always get a empty bitmap with this solution. I first crop the original bitmap to a rect in which the element of my bitmap does precisely fit in. Otherwise put the left baseline of the bitmap itself is also the baseline of the graphics element in it, while the whole background is white.
Then I put this bitmap (approx. 40x80) in to the "ResizeImageProportional" (original post edit.) function with a width and height value of 29.
If you want to keep the proportion you need to calculate the destination rectnagle.
Here are the measures, off the top of my head:
destH = height;
destW = image.Width / image.Height * height;
destX = (width - destW) / 2;
dextY = 0;
You should clear the background to the color you want before: Graphics.Clear(someColor);
If you don't you use the bounds of the source and the destination images, thereby distorting the image. Which is what you seem to have.., no?
In that case there is no new space, of course.
When calculating, use float if necessary..
Update:
Maybe you want to analyze the original image and preserve or remove the spaces from the foreground to its edges. That means either looking into the pixels or maybe going one step back to how the original was created..
For the example I have added the bounds of the figure.
Here is a simple cropping function; it assumes the top left corner to hold the background color and returns a cropping rectangle:
public static Rectangle CropBounds(Image image)
{
Bitmap bmp = (Bitmap)image;
int x0 = 0;
int x1 = bmp.Width - 1;
int y0 = 0;
int y1 = bmp.Height - 1;
Color c = bmp.GetPixel(0, 0);
while (x0==0)
{ for (int x = 0; x < x1; x++)
if ((x0==0)) for (int y = 0; y < y1; y++)
if ( bmp.GetPixel(x,y)!= c) {x0 = x-1; break;} }
while (x1 == bmp.Width - 1)
{
for (int x = bmp.Width - 1; x > 0; x--)
if ((x1 == bmp.Width - 1)) for (int y = 0; y < y1; y++)
if (bmp.GetPixel(x, y) != c) { x1 = x + 1; break; } }
while (y0 == 0)
{
for (int y = 0; y < y1; y++)
if ((y0 == 0)) for (int x = 0; x < bmp.Width; x++)
if (bmp.GetPixel(x, y) != c) { y0 = y - 1; break; }
}
while (y1 == bmp.Height - 1)
{
for (int y = bmp.Height - 1; y > 0; y--)
if ((y1 == bmp.Height - 1)) for (int x = 0; x < bmp.Width; x++)
if (bmp.GetPixel(x, y) != c) { y1 = y + 1; break; }
}
return new Rectangle(x0, y0, x1 - x0, y1 - y0);
}
Now you can change your code to use it like this:
graphics.DrawImage(image, destRect, CropBounds(image) , GraphicsUnit.Pixel);
If you really need to flip, simply store the rectangle and change to the appropriate format..!
Update 2:
There was a reason why I wrote When calculating, use float if necessary..:
In your ResizeImageProportional function you need to avoid integer precision loss! Change the divisions to:
destW = (int) (1f * bitmap.Width / bitmap.Height * height);
and
destH = (int) (1f *bitmap.Height / bitmap.Width * width);