我遵循了这里描述的TGA规范(页面末尾的信息是该方法的基础),并编写了一种方法,该方法获取TGA文件的像素数据部分,并在其中创建位图。
它很有效,但是代码看起来很草率。特别是当我在读字节的时候。您会注意到,为了重复地将相同的字节添加到数组中,我执行了一些奇怪的foreach循环。
这是读取像素的方法。它返回一个表示像素的字节数组。
是否有一种方法可以让我重写128情况下的内部循环,而不使用foreach来将相同的字节序列设置为数组?我想我会经常将字节放入数组中,如果知道其他方法会更好。
private byte[] getImageType10()
{
// header stores total bits per pixel
int bytesPerPixel = header.bpp / 8;
int total = header.width * header.height * bytesPerPixel;
// number of bytes we've read so far
int count = 0;
int repeat;
byte packetHdr;
int packetType;
// temp storage
byte[] bytes;
byte[] pixData = new byte[total];
while (count < total)
{
packetHdr = inFile.ReadByte();
packetType = packetHdr & (1 << 7);
// RLE packet
if (packetType == 128)
{
// packet stores number of times following pixel is repeated
repeat = (packetHdr & ~(1 << 7)) + 1;
bytes = inFile.ReadBytes(bytesPerPixel);
for (int j = 0; j < repeat; j++)
{
foreach (byte b in bytes)
{
pixData[count] = b;
count += 1;
}
}
}
// raw packet
else if (packetType == 0)
{
// packet stores number of pixels that follow
repeat = ((packetHdr & ~(1 << 7)) + 1) * bytesPerPixel;
for (int j = 0; j < repeat; j++)
{
pixData[count] = inFile.ReadByte();
count += 1;
}
}
}
return pixData;
}发布于 2012-08-11 03:57:38
这128种情况可以优化如下:
if (packetType == 128)
{
// packet stores number of times following pixel is repeated
repeat = (packetHdr & ~(1 << 7)) + 1;
bytes = inFile.ReadBytes(bytesPerPixel);
for (int j = 0; j < repeat; j++)
{
bytes.CopyTo(pixData, count);
count += bytes.Length;
}
} 0的情况可以优化如下:
if (packetType == 0)
{
// packet stores number of pixels that follow
repeat = ((packetHdr & ~(1 << 7)) + 1) * bytesPerPixel;
bytes = inFile.ReadBytes(repeat);
bytes.CopyTo(pixData, count);
count += bytes.Length;
} 发布于 2012-08-13 19:14:53
我的回答很大程度上是基于@WouterH,所以如果你投我的票,那么你必须投两次票。我所做的是提供一个“完整”的代码列表,清理一些变量名称和注释(在使用了正确的变量名之后删除了许多注释),为图像标题添加了一个类,并添加了用于错误检查的占位符。我对神奇常数positiveMask不太满意,因为我不完全理解它的作用。您可以替换例外情况下的代码契约,以减少程序集的使用。通过预计算ImageHeader类中的一些变量,您可以稍微加快代码的速度。其他的改进是可能的,但是我们还没有看到您的全部代码,所以很难说。我还会把这个文件分成两个不同的文件--每个班级一个。
namespace TGAImageParser
{
using System;
using System.Diagnostics.Contracts;
using System.IO;
// Using a class like this helps to avoid http://c2.com/cgi/wiki?DataEnvy
internal class TGAImageHeader
{
public const int BitsInByte = 8; // const is ok over readonly here since this will not change in the future, right?
public readonly int BytesPerPixel;
public readonly int Width;
public readonly int Height;
public TGAImageHeader(int bytesPerPixel, int width, int height)
{
// Check the inputs thoroughly here.
Contract.Requires(width > 0, "Image must be at least one pixel wide."); // Or is it zero pixels wide?
// ... and so on.
this.BytesPerPixel = bytesPerPixel;
this.Width = width;
this.Height = height;
}
public int BitsPerPixel
{
get
{
return this.BytesPerPixel * BitsInByte;
}
}
// If this gets called often, then pre-compute it once.
public int TotalBytes
{
get
{
return this.BytesPerPixel * this.TotalPixels;
}
}
// If this gets called often, then pre-compute it once.
public int TotalPixels
{
get
{
return this.Width * this.Height;
}
}
}
public class TGAImageParser
{
public const int RLEPacketType = 128;
public const int RawPacketType = 0;
private const byte positiveMask = 1 << 7; // TODO: Come up with a better name! What does it do?
public static byte[] GetImageType10Bytes(BinaryReader inFile, TGAImageHeader imageHeader)
{
int numBytesReadSoFar = 0;
int numTimesPixelIsRepeated;
byte packetHeaderByte;
int packetType;
byte[] tempStorageBuffer;
byte[] pixData = new byte[imageHeader.TotalBytes];
while (numBytesReadSoFar < imageHeader.TotalBytes)
{
packetHeaderByte = inFile.ReadByte();
packetType = packetHeaderByte & positiveMask;
if (packetType == RLEPacketType)
{
numTimesPixelIsRepeated = (packetHeaderByte & ~positiveMask) + 1;
tempStorageBuffer = inFile.ReadBytes(imageHeader.BytesPerPixel);
for (int i = 0; i < numTimesPixelIsRepeated; i++)
{
tempStorageBuffer.CopyTo(pixData, numBytesReadSoFar);
numBytesReadSoFar += tempStorageBuffer.Length;
}
continue;
}
if (packetType == RawPacketType)
{
numTimesPixelIsRepeated = ((packetHeaderByte & ~positiveMask) + 1) * imageHeader.BytesPerPixel;
tempStorageBuffer = inFile.ReadBytes(numTimesPixelIsRepeated);
tempStorageBuffer.CopyTo(pixData, numBytesReadSoFar);
numBytesReadSoFar += tempStorageBuffer.Length;
continue;
}
// TODO: report an error here?
}
return pixData;
}
}
}https://codereview.stackexchange.com/questions/14593
复制相似问题