delphibitmaptbitmap

How to copy a gray-scale bitmap via ScanLine


I want to copy pixels from BMP1 to BMP2 but the copied image is gabbled. Why?

Note: The input image is pf8bit;

TYPE
  TPixArray = array[0..4095] of Byte;
  PPixArray = ^TPixArray;

procedure Tfrm1.CopyImage;
VAR
  BMP1, BMP2: TBitmap;
  y, x: Integer;
  LineI, LineO: PPixArray;
begin
 BMP1:= TBitmap.Create;
 BMP2:= TBitmap.Create;
 TRY
   BMP1.LoadFromFile('test.bmp');

   BMP2.SetSize(BMP1.Width, BMP1.Height);   
   BMP2.PixelFormat:= BMP1.PixelFormat;

   for y:= 0 to BMP1.Height -1 DO
    begin
     LineI := BMP1.ScanLine[y];
     LineO := BMP2.ScanLine[y];

     for x := 0 to BMP1.Width -1 DO
        LineO[x]:= LineI[x];
    end;

  //BMP2.SaveToFile('out.bmp');
  imgOut.Picture.Assign(BMP2); //TImage
 FINALLY
   FreeAndNil(BMP2);
   FreeAndNil(BMP1);
 END;
end;

For the saved image, a graphic editor says "Pixel depth/colors: indexed, 256 color palette".


Solution

  • It might be worth pointing out that an 8-bit bitmap isn't necessarily greyscale.

    Instead, it is a bitmap with a "colour table" consisting of up to 256 entries, and each pixel refers to an entry in this table. So if a pixel's value is 185, this means that it should use the colour at location 185 in the bitmap's "colour table". Hence, an 8-bit bitmap works entirely different compared to a 16-, 24- or 32-bit bitmap, which does not have a colour table, but instead has actual RGB(A) values at each pixel.

    The problem in your case is likely that the target pixmap doesn't have the same colour table as the source bitmap.

    I have actually never worked with 8-bit bitmaps and palettes before, but I think it is this simple:

    var
      s, t: TBitmap;
      y: Integer;
      sp, tp: PByte;
      x: Integer;
    begin
    
      s := TBitmap.Create;
      try
        s.LoadFromFile('C:\Users\Andreas Rejbrand\Desktop\bitmap.bmp');
        Assert(s.PixelFormat = pf8bit);
    
        t := TBitmap.Create;
        try
    
          t.PixelFormat := pf8bit;
          t.SetSize(s.Width, s.Height);
          t.Palette := s.Palette;        // <-- Let the new image have the same colour table
    
          for y := 0 to s.Height - 1 do
          begin
            sp := s.ScanLine[y];
            tp := t.ScanLine[y];
            for x := 0 to s.Width - 1 do
              tp[x] := sp[x];
          end;
    
          t.SaveToFile('C:\Users\Andreas Rejbrand\Desktop\bitmap2.bmp');
    
        finally
          t.Free;
        end;
    
      finally
        s.Free;
      end;