(转贴)
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

解决方案 »

  1.   

    设置 PixelFormat 属性可以有许多的值,比如:pf1bit, pf4bit, pf8bit, pf16bit 等,当然每次设置不同的值都会有不同的效果。如果原先是一个 32bit 的位图,那么值 pf8bit 就只能显示 8 位了,如果是 pf1bit 那就纯粹只有一种颜色。ScanLine 属性则提供了处理每个象素的能力
      

  2.   

    // 位图是 256 色的情况,变址 P[x] 则代表了一个象素,但这时可以进行处理
    // 若想改变色深,可以通过算法把颜色换算成四位,这样 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;
      

  3.   

    根据不同的PixelFormat来读取象素我能理解,
    我是不知道如何设置图像的色深,
    如何保证一位2色图(PixelFormat = pif1bit)转换成256色图后,
    黑色点的像素值为0,白色点的像素值为255,
    如果直接用PixelFormat := pf8bit; 转换,白色点的值为19,非255,那么白色点的值一定为19吗?
    看过一些资料,说对256色图像,WINDOWS会保留20种颜色作为系统调色板,19是否就是其中最后一种?我怎么处理其它236种颜色?
      

  4.   

    这样的,原先为2色图,则黑色点的像素值为0,白点的象素值为1,但是转换以后系统调色板上0还是代表黑色,而1就不是白色了,白色被索引到了15(大概估计)。要使图象被复原,可以试试这样:通过 ScanLine 转换,使每个象素都转换。这时要检索调色板, TBitmap.Palette ,可以先进行存贮(原先的两色),转换后新的 Palette 可以用函数找到原先较为匹配的颜色,找到后赋值即可。 原先 Palette 句柄用于 Windows API 中的 GetNearesPaletteIndex 函数,具体看看 Windows API
      

  5.   

    torble(elbrot)兄:
        你说得对!
        8位图的白色被索引到19,通过二进制文件也可以看到,第19项调色板,它对应$00FFFFFF,就是系统调色板的白色;    可是你后面的话我看不懂,    如何检索调色板?
        如何存贮原先的两色?
        如何转换?
        如何找到?
        如何赋值?
            不好意思,实在搞不懂。