我有这个类适用于 8 bpp 位图到 pcx,但我无法让它适用于 1 bpp。
图像开始是这样的:
但是在第 27 行之后生成的 PCX 是黑色的,如 IrfanView 中所示:
谁能帮我发现明显的错误?
顺便说一句,用法是Pcx.SavePCX("AOut.pcx", new Bitmap("A.bmp"));
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
namespace Imaging
{
public sealed class Pcx
{
private static void WriteWord(Stream stream, int data)
{
stream.WriteByte((byte) (data & 0xFF));
stream.WriteByte((byte) ((data >> 8) & 0xFF));
}
public static void SavePCX(Stream pcxStream, Bitmap bmp)
{
if (bmp.PixelFormat != PixelFormat.Format1bppIndexed)
{
throw new Exception("Can only PCX bitmaps that are 1bpp indexed");
}
var data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat);
try
{
{
//header
pcxStream.WriteByte(10); // char manufacturer;
pcxStream.WriteByte(5); //char version;
pcxStream.WriteByte(1); //char encoding;
pcxStream.WriteByte(1); // char bpp;
pcxStream.WriteByte(0);
pcxStream.WriteByte(0); //char xmin[2];
pcxStream.WriteByte(0);
pcxStream.WriteByte(0); //char ymin[2];
WriteWord(pcxStream, bmp.Width - 1); // char xmax[2];
WriteWord(pcxStream, bmp.Height - 1); //char ymax[2];
WriteWord(pcxStream, 72); //word(pcx->hdpi, 72);
WriteWord(pcxStream, 72); // word(pcx->vdpi, 72);
for (var i = 0; i < 16*3; i++) //4bpp palette
{
pcxStream.WriteByte(0);
}
pcxStream.WriteByte(0); // pcx->res = 0;
pcxStream.WriteByte(1); // pcx->nplanes = 1;
WriteWord(pcxStream, bmp.Width); // word(pcx->bytesperline, width / 2);
WriteWord(pcxStream, 0); //word(pcx->palletteinfo, 0);
WriteWord(pcxStream, 0); //word(pcx->hscrn, 0);
WriteWord(pcxStream, 0); //word(pcx->vscrn, 0);
for (var i = 0; i < 54; i++) //memset(pcx->filler, 0, 54);
{
pcxStream.WriteByte(0);
}
} //end of header
{
//read all bytes to an array
var baseLine = data.Scan0;
// Declare an array to hold the bytes of the bitmap.
var byteLength = bmp.Width*bmp.Height;
var bytes = new byte[byteLength];
// Copy the RGB values into the array.
for (var y = 0; y < data.Height; y++)
{
var lineOffset = y*data.Stride;
Debug.WriteLine("Y={0}, Offset={1}", y, lineOffset);
for (var x = 0; x < data.Width; x++)
{
bytes[y*bmp.Width + x] = Marshal.ReadByte(baseLine, lineOffset + x);
}
}
var baseIdx = 0;
var end = byteLength;
var run = 0;
var ldata = -1;
byte ld;
while (baseIdx < end)
{
//if it matches, increase the run by 1 up to max of 63
if ((bytes[baseIdx] == ldata) && (run < 63)) run++;
else
{
//write data
if (run != 0) //not first run
{
ld = (byte) ldata;
if ((run > 1) || (ld >= 0xC0)) pcxStream.WriteByte((byte) (0xC0 | run));
pcxStream.WriteByte(ld);
}
run = 1;
}
ldata = bytes[baseIdx];
baseIdx++;
}
ld = (byte) ((ldata >> 4) | (ldata << 4));
if ((run > 1) || (ld >= 0xC0)) pcxStream.WriteByte((byte) (0xC0 | run));
pcxStream.WriteByte(ld);
}
}
finally
{
bmp.UnlockBits(data);
}
}
public static void SavePCX(string fileName, Bitmap bbp1Bmp)
{
using (var fstest = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
SavePCX(fstest, bbp1Bmp);
}
}
}
}