TBitMap.PixelFormat = pf1bit/pf4bit/pf15bit时如何通过ScanLine得到某个像素的值(100分)

  • 主题发起人 主题发起人 陈冲伟
  • 开始时间 开始时间

陈冲伟

Unregistered / Unconfirmed
GUEST, unregistred user!
好像 ScanLine只能在24bit时用
 
to lha: 胡说!
ScanLine返回的是一行像素的内容,PixelFormat决定每个像素的大小。
当每个像素的大小不是8的整数倍时,就需要自己编程来处理。
比如 PixelFormat=pf1bit ,就是每个像素一个bit。
那么:
var
IwantknowPixel: byte; //我要知道的像素的值
IwantKnow: Integer; //我要知道第几个像素
P : PByteArray; //保存ScanLine的数组
begin
P := BitMap.ScanLine[y];
IwantknowPixel := P[IwantKnow shr 3];

IwantknowPixel := IwantknowPixel shl (IwantKnow mod 8);
IwantknowPixel := IwantknowPixel shr 7;
end;
大概是这样子吧,未经测试,有错莫怪:p
 
to DoubleWood:

呵呵,谢谢提醒。
我想 ScanLine返回的是指定行第一个像素的指针。
 

基本同意DoubleWood,只是最后两行可这样写:

IwantknowPixel :=( IwantknowPixel shr (7-IwantKnow mod 8) and 1;


 
如果TBitmap.PixelFormat = pf16Bit / pf24Bit,则可以直接通过TBitmap.ScanLine获得
图象中某一行象素的颜色值数组。
否则,使用TBitmap.ScanLine只能获得图象中某一行象素颜色索引值数组,通过颜色索引去
查图象的调色板方可获得对应点的颜色值。
 
to JohnsonGuo:
能否具体一点,如何访问调色版得到象素信息?
 
各位打虾,我写的一个程序:
for i:=1 to image1.height-1 do
begin
p:=image1.picture.bitmap.scanline;
for j:=1 to image1.width-1 do
begin
……
end;
end;
可是大循环没有结束就出现scanline 的越界错误。( scanline index out of rang);
是什么原因?
 
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

但愿对朋友们有所帮助,^_^






 
to 斑竹:
〉〉pf15bit位图 影象装置/影象驱动器的限制
是啥意思??
是不是和机器显卡有关?
 
TBitmap.ScanLine只能用于较低的象素要求。
 
听课中....
 
受益非浅呀
 
后退
顶部