Этот код проверяет стандартную 8-битную шкалу серого, где значения пикселей соответствуют их яркости. Это более или менее стандарт для градаций серого, но он действительно не будет соответствовать оптимизированным палитрам или чему-то в этом роде.
Я не уверен, почему вы исключили бы 1bpp. Это индексированный формат, как и любой другой, и на самом деле он имеет цветовую палитру, такую как 8bpp, что означает, что он даже не ограничивается чисто черным и белым. Это версия этого попугая в оттенках серого размером 1 п.н. с двумя значениями серого в его палитре:
![1bpp gray Parrot](https://i.stack.imgur.com/I2QFR.png)
Самый простой способ проверить проиндексированные изображения - это действительно пройти по палитре и выполнить тест R = G = B, но технически даже тогда вы можете утверждать, что изображение является серым, если на нем не серые цвета. палитра на самом деле не используется на изображении.
Верный способ, вероятно, состоит в том, чтобы заставить LockBits преобразовать изображение в 32bppARGB, а затем проверить R, G и B на этом. Но даже там вам придется делать выбор ... сделать 100% прозрачных пикселей, которые не соответствуют R = G = B, сделать изображение "не в градациях серого" ?
В любом случае, вот какой метод я бы использовал:
public static Boolean IsGrayscale(Bitmap cur)
{
// Indexed format, and no non-gray colours in the images palette: immediate pass.
if ((cur.PixelFormat & PixelFormat.Indexed) == PixelFormat.Indexed
&& cur.Palette.Entries.All(c => c.R == c.G && c.R == c.B))
return true;
// Quick indexed check failed; actually check image data.
// Get bytes out of the image, converted to 32bpp ARGB
BitmapData curBitmapData = cur.LockBits(new Rectangle(0, 0, cur.Width, cur.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
Int32 stride = curBitmapData.Stride;
Byte[] data = new Byte[stride * cur.Height];
Marshal.Copy(curBitmapData.Scan0, data, 0, data.Length);
cur.UnlockBits(curBitmapData);
// Go over all bytes per block of four.
Int32 curRowOffs = 0;
for (Int32 y = 0; y < cur.Height; y++)
{
// Set offset to start of current row
Int32 curOffs = curRowOffs;
for (Int32 x = 0; x < cur.Width; x++)
{
Byte b = data[curOffs];
Byte g = data[curOffs + 1];
Byte r = data[curOffs + 2];
Byte a = data[curOffs + 3];
// Increase offset to next colour
curOffs += 4;
if (a == 0)
continue;
if (r != g || r != b)
return false;
}
// Increase row offset
curRowOffs += stride;
}
return true;
}