(转贴)
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[i] := 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[i] := <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[i] := RGB
END; Image1.Picture.Graphic := Bitmap
FINALLY
Bitmap.Free
END
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[i] := 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[i] := <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[i] := RGB
END; Image1.Picture.Graphic := Bitmap
FINALLY
Bitmap.Free
END
// 若想改变色深,可以通过算法把颜色换算成四位,这样 P[x] 就可以存储两个象素了/////////////////////////////////////////////////////
var
x,y : Integer;
BitMap : TBitMap;
P : PByteArray;
begin
BitMap := TBitMap.create;
try
BitMap.LoadFromFile('..\256color\user.bmp');
for y := 0 to BitMap.height -1 do
begin
P := BitMap.ScanLine[y];
for x := 0 to BitMap.width -1 do
begin
// 这时的 p[x] 为 8Bit ,可以处理成大于 8Bit或小于 8Bit
// p[x] 纯粹就是对位图内存直接换算修改
end finally
BitMap.free;
end;
end;
我是不知道如何设置图像的色深,
如何保证一位2色图(PixelFormat = pif1bit)转换成256色图后,
黑色点的像素值为0,白色点的像素值为255,
如果直接用PixelFormat := pf8bit; 转换,白色点的值为19,非255,那么白色点的值一定为19吗?
看过一些资料,说对256色图像,WINDOWS会保留20种颜色作为系统调色板,19是否就是其中最后一种?我怎么处理其它236种颜色?
你说得对!
8位图的白色被索引到19,通过二进制文件也可以看到,第19项调色板,它对应$00FFFFFF,就是系统调色板的白色; 可是你后面的话我看不懂, 如何检索调色板?
如何存贮原先的两色?
如何转换?
如何找到?
如何赋值?
不好意思,实在搞不懂。