// This is related to http://stackoverflow.com/questions/7083853/simple-algorithm-to-crop-empty-borders-from-an-image-by-code
public static Rectangle MeasureImageCrop(Bitmap image)
{
// GDI+ still lies to us - the return format is BGR, NOT RGB.
var bmData = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
ImageLockMode.ReadWrite,
PixelFormat.Format24bppRgb);
var stride = bmData.Stride;
var scan0 = bmData.Scan0;
var cutLeft = 0;
var cutRight = 0;
var cutTop = 0;
var cutBottom = 0;
const int step = 1;
unsafe
{
var p = (byte*)(void*)scan0;
var refBlue = p[0];
var refGreen = p[1];
var refRed = p[2];
// --
// Top.
var wantBreak = false;
for (var y = 0; y < image.Height; y += step)
{
p = ((byte*)(void*)scan0) + stride * y;
for (var x = 0; x < image.Width; x += step)
{
var blue = p[0];
var green = p[1];
var red = p[2];
if (blue != refBlue || green != refGreen || red != refRed)
{
wantBreak = true;
break;
}
p += 3 * step;
}
if (wantBreak)
{
break;
}
cutTop += step;
}
// --
// Bottom.
wantBreak = false;
for (var y = image.Height - 1; y >= 0; y -= step)
{
p = ((byte*)(void*)scan0) + stride * y;
for (var x = 0; x < image.Width; x += step)
{
var blue = p[0];
var green = p[1];
var red = p[2];
if (blue != refBlue || green != refGreen || red != refRed)
{
wantBreak = true;
break;
}
p += 3 * step;
}
if (wantBreak)
{
break;
}
cutBottom += step;
}
// --
// Left.
p = (byte*)(void*)scan0;
wantBreak = false;
for (var x = 0; x < image.Width; x += step)
{
for (var y = 0; y < image.Height; y += step)
{
var blue = p[0];
var green = p[1];
var red = p[2];
if (blue != refBlue || green != refGreen || red != refRed)
{
wantBreak = true;
break;
}
p += stride * step;
}
if (wantBreak)
{
break;
}
cutLeft += step;
p -= stride * image.Height;
p += 3 * step;
}
// --
// Right.
p = (byte*)(void*)scan0;
p += (image.Width - 1) * 3;
wantBreak = false;
for (var x = image.Width - 1; x >= 0; x -= step)
{
for (var y = 0; y < image.Height; y += step)
{
var blue = p[0];
var green = p[1];
var red = p[2];
if (blue != refBlue || green != refGreen || red != refRed)
{
wantBreak = true;
break;
}
p += stride * step;
}
if (wantBreak)
{
break;
}
cutRight += step;
p -= stride * image.Height;
p -= 3 * step;
}
}
// --
image.UnlockBits(bmData);
return new Rectangle(
cutLeft,
cutTop,
image.Width - cutRight - cutLeft,
image.Height - cutBottom - cutTop);
}