我一直在研究位图解码器,但我处理像素数据的算法似乎不太正确:
public IntPtr ReadPixels(Stream fs, int offset, int width, int height, int bpp)
{
IntPtr bBits;
int pixelCount = bpp * width * height;
int Row = 0;
decimal value = ((bpp*width)/32)/4;
int RowSize = (int)Math.Ceiling(value);
int ArraySize = RowSize * Math.Abs(height);
int Col = 0;
Byte[] BMPData = new Byte[ArraySize];
BinaryReader r = new BinaryReader(fs);
r.BaseStream.Seek(offset, SeekOrigin.Begin);
while (Row < height)
{
Byte ReadByte;
if (!(Col >= RowSize))
{
ReadByte = r.ReadByte();
BMPData[(Row * RowSize) + Col] = ReadByte;
Col += 1;
}
if (Col >= RowSize)
{
Col = 0;
Row += 1;
}
}
bBits = System.Runtime.InteropServices.Marshal.AllocHGlobal(BMPData.Length);
System.Runtime.InteropServices.Marshal.Copy(BMPData, 0, bBits, BMPData.Length);
return bBits;
}
我只能处理单色位图,而在某些位图上,部分位图处理得很好。没有被压缩,它们被颠倒并翻转。我真的可以帮上这个。
答案 0 :(得分:3)
decimal value = ((bpp*width)/32)/4;
int RowSize = (int)Math.Ceiling(value);
这是不正确的。您的 RowSize 变量实际上称为“stride”。你这样计算:
int bytes = (width * bitsPerPixel + 7) / 8;
int stride = 4 * ((bytes + 3) / 4);
答案 1 :(得分:3)
你忽视了这一步。
图像行可以用另外的字节填充到左边,使它们的大小除以一个数字,例如(1 =没有填充,2,4,8 =许多图像的默认值,16,......)。
此外,图像可以是较大图像中的矩形区域,使得较小图像中的线之间的“填充”甚至更大(因为步幅是较大图像的步幅)。 - 在这种情况下,图像也可以在缓冲区中具有其起始点的偏移量。
更好的做法是:
// Overload this method 3 time for different bit per SUB-pixel values (8, 16, or 32)
// = (byte, int, float)
// SUB-pixel != pixel (= 1 3 or 4 sub-pixels (grey or RGB or BGR or BGRA or RGBA or ARGB or ABGR)
unsafe
{
byte[] buffer = image.Buffer;
int stride = image.buffer.Length / image.PixelHeight;
// or int stride = image.LineSize; (or something like that)
fixed (float* regionStart = (float*)(void*)buffer) // or byte* or int* depending on datatype
{
for (int y = 0; y < height; y++) // height in pixels
{
// float* and float or byte* and byte or int* and int
float* currentPos
= regionStart + offset / SizeOf(float) + stride / SizeOf(float) * y;
for (int x = 0; x < width; x++) // width in pixels
{
for (int chan = 0; chan < channel; chan++) // 1, 3 or 4 channels
{
// DO NOT USE DECIMAL - you want accurate image values
// with best performance - primative types
// not a .NET complex type used for nice looking values for users e.g. 12.34
// instead use actual sub pixel type (float/int/byte) or double instead!
var currentValue = value;
currentPos++;
}
}
}
}
}
答案 2 :(得分:0)
我发现了一些我不理解的东西:
decimal value = ((bpp*width)/32)/4;
int RowSize = (int)Math.Ceiling(value);
在我看来,RowSize应该是(bpp*width) / 8 + (bpp%8==0?0:1)