to 陈冲伟:
关于你的问题,我想详细讨论一下。
>pf1bit的位图
如果你只需要每个像素只有一位就可以了的话,你可以节省许多内存空间,但在Delphi中
你如果要访问这样一个像素点,你必须要位操作了。在每个像素点只有一位信息的情况下,
pf1bit的位图中通常出现的颜色就是黑色和白色。也就是说,它定义了一个只有两种颜色的调色板。
我们用在Delphi的SysUtils.pas unit里定义的TByteArray来访问一个pf1bit Scanline:
pByteArray = ^ByteArray;
TByteArray = ARRAY[0..32767] OF BYTE;
如果宽度是8的倍数的话,pf1bit Scanline的字节宽度是Bitmap.width DIV 8。
如果不是8的倍数,用1+(Bitmap.width - 1) DIV 8来计算字节长度。
用SysUtils定义的TByteArray限制了一个pf1bit的位图不会大于32768*32768个像素,
这样大的位图超过了现在windows系统有效的内存存储能力(一幅位图123MB,实在太大了),
Borland的解决方法是用有范围检测的数组来实现的,范围检测要求没有的变化,所有我
更加喜欢上面这种结构。
procedure TFormPf1bit.ButtonTagFillClick(Sender: TObject);
VAR
Bitmap: TBitmap;
i : INTEGER;
j : INTEGER;
Row : pByteArray;
Value : BYTE;
begin
// Value = $00 = 00000000 binary for black
// Value = $FF = 11111111 binary for white
// Value = $55 = 01010101 binary for black & white stripes
Value := (Sender AS TButton).Tag;
Bitmap := TBitmap.Create;
TRY
WITH Bitmap DO
BEGIN
Width := 32;
Height := 32;
// Unclear why this must follow width/height to work correctly.
// If PixelFormat precedes width/height, bitmap will always be black.
PixelFormat := pf1bit;
IF CheckBoxPalette.Checked
THEN Bitmap.Palette := GetTwoColorPalette
END;
FOR j := 0 TO Bitmap.Height-1 DO
BEGIN
Row := pByteArray(Bitmap.Scanline[j]);
FOR i := 0 TO (Bitmap.Width DIV BitsPerPixel)-1 DO
BEGIN
Row := Value
END
END;
ImageBits.Picture.Graphic := Bitmap
FINALLY
Bitmap.Free
END
end;
>pf4bit的位图
操作pf4bit的位图比较复杂。每个像素只占部分的字节。所以就像pf1bit位图一样,
pf4bit位图也需要位操作。每个像素有4位,可以表示16种颜色。在标准的16色VGA还经常
被使用的情况下,它的调色板可能会更加复杂一些。
>pf8bit的位图
操作pf8bit位图是很容易的,因为他的每个像素正好占一字节,能够在TByteArray中直接访问。
VAR
i : INTEGER;
j : INTEGER;
Row: pByteArray
. . .
FOR j := 0 TO BitmapBase.Height-1 DO
BEGIN
Row := BitmapBase.ScanLine[j];
FOR i := 0 TO BitmapBase.Width-1 DO
BEGIN
Row := <pixel value 0..255>; // assign palette index
END
END;
ImageShow.Picture.Graphic := BitmapBase;
虽然用Scanline来操作8位的位图是简单的。但是分配给Scanline的描述像素颜色的字节值
却是间接的。Scanline的值表示的是调色板上颜色的索引。调色板上包含了确切的R,G,B色。
>pf15bit位图
不是所有的PixelFormats在每台机器上都是有效的。就像pf15bit位图在一些机器上会受
影象装置/影象驱动器的限制。
BEGIN
bitmap := TBitmap.Create;
TRY
bitmap.Width := 32;
bitmap.Height := 32;
bitmap.PixelFormat := pf15Bit;
IF bitmap.PixelFormat <> pf15bit
THEN ShowMessage('Not pf15bit);
...
如果你对你的操作有什么怀疑,你可以证明一下PixelFormat是否被正确建立了。
如果PixelFormat不被支持,它显然会被分配给pfcustom。
用pWordArray来访问pf15bit和pf16bit像素的Scanline,pWordArray已经在Sysutils中定义了。
这种方式也限制了位图的大小不会超过16384*16384个像素,但这也难保会不会用尽系统资源。
pf15bit像素有5位红色,5位绿色和5位兰色。
VAR
Bitmap: TBitmap;
i : INTEGER;
j : INTEGER;
R : 0..31; // each RGB component has 5 bits
G : 0..31;
B : 0..31;
RGB : WORD;
Row : pWordArray; // from SysUtils
...
Bitmap := TBitmap.Create;
TRY
Bitmap.Width := Image1.Width;
Bitmap.Height := Image1.Height;
Bitmap.PixelFormat := pf15bit;
R := 31; // Max Red
G := 31; // Max Green
B := 0; // No Blue
// "FillRect" using Scanline
// The bits in each pixel (WORD) are as follows:
// 0rrrrrgggggbbbbb. The high order bit is ignored.
RGB := (R SHL 10) OR (G SHL 5) OR B; // "yellow"
FOR j := 0 TO Bitmap.Height-1 DO
BEGIN
Row := Bitmap.Scanline[j];
FOR i := 0 TO Bitmap.Width-1 DO
Row := RGB
END;
Image1.Picture.Graphic := Bitmap
FINALLY
Bitmap.Free
END
但愿对朋友们有所帮助,^_^