Самый быстрый способ получить данные изображения из изображения - это использовать LockBits
и Marshal.Copy
.
I настоятельно совет против использования GetPixel
.Смотрите, LockBits
работает, резервируя память для помещения байтов изображения и копирования туда байтов изображения.UnlockBits
затем очистит эту зарезервированную память.
Теперь проблема в том, что GetPixel
выполняет ту же самую операцию блокировки и разблокировки для каждого пикселя, к которому вы обращаетесь .Использование LockBits один раз довольно быстро, но использование его снова и снова для десятков тысяч пикселей действительно замедляет процесс.
Обратите внимание, что есть два способа использования LockBits
;либо вы получаете данные в исходном пиксельном формате, используя sourceImage.PixelFormat
, либо вы заставляете LockBits преобразовывать данные в нужный вам формат, задавая другой.В этом коде я вынуждаю вывод в формате пикселей Format32bppArgb
.
/// <summary>
/// Gets the raw bytes from an image.
/// </summary>
/// <param name="sourceImage">The image to get the bytes from.</param>
/// <returns>The raw bytes of the image</returns>
public static Byte[] GetImageDataAs32bppArgb(Bitmap sourceImage)
{
BitmapData sourceData = sourceImage.LockBits(
new Rectangle(0, 0, sourceImage.Width, sourceImage.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
Byte[] data = new Byte[sourceData.Stride * sourceImage.Height];
Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
sourceImage.UnlockBits(sourceData);
return data;
}
Stride
обычно может отличаться от width * bpp
, поскольку строки растровых изображений всегда выровнены с кратными 4 байтами, поэтому обычновам также нужно это вернуть и отследить, но, поскольку это 32-битный формат, его данные всегда выровнены до 4 байтов, поэтому здесь никакой реальной разницы нет.
Обратите внимание, в вашем вопросе никогда не указывается порядок , в котором вам нужны данные.Типичные данные ARGB на самом деле имеют порядок байтов B, G, R, A, потому что обычное целочисленное сохранение в архитектуре IBM PC имеет младший порядок, что означает, что фактические байты значения Int32 "FFEEDDCC" обращаются в памяти к [CC DDEE FF].Но ваш комментарий к другому ответу, приведенному здесь, похоже, указывает на то, что вы выбрали порядок байтов [RR, GG, BB, AA] или «ABGR», который, честно говоря, не является форматом, который я когда-либо видел до.Но если вам нужно изменить это, это просто дополнительный дополнительный цикл для замены красного и синего:
for (Int32 i = 0; i < data.Length; i += 4)
{
Byte b = data[i]; // save Blue
data[i] = data[i + 2]; // set first component to the Red value
data[i + 2] = b; // set third component to the Blue value
}