// 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); }