user1641230
user1641230

Reputation: 71

Delphi TBitmap code to Python PIL

I am trying to convert some Delphi code to Python PIL. The problem is two pronged. First, I'm not a Delphi programmer. Second, I haven't used PIL before today so I may have problems in either area.

case PixelFormat of
  pf32bit: PixSize:=4;
  pf24bit: PixSize:=3;
  pf16bit: PixSize:=2;

end;
BitCounter:=0;
for i:=0 to Height-1 do begin
  Row:=ScanLine[i];
  PB:=@Row[PixSize-1];
  for j:=0 to Width-1 do begin 
    Ch[BitCounter] := (PB^ and 1);
    ....
    inc(BitCounter);
    inc(PB, PixSize);
end;

So I get that the PixelFormat attribute denotes the size of each pixel in bytes. I also get that the ScanLine method is supposed to get an array of pixels that represent the line. What I don't get is that I tend to visualize each pixel as an RGB value. I'm used to extracting the least significant bit of a color value. However, I don't think I'm even sure what the existing code is extracting. I have some python PIL code that will extract RGB values of each pixel in the same image, but I don't know how the tuple of RGB values compares to PB variable obtained in the earlier code. Based on some experiments I'm guessing that it doesn't compare at all.

Thanks in advance.

Upvotes: 0

Views: 590

Answers (2)

user1641230
user1641230

Reputation: 71

In case anyone is trying to do this later. Thanks to David for the help in clarifying what ScanLine was returning.

from PIL import Image
img = Image.open('picture.gif')
(width, height) = img.size
conv = img.convert("RGB").getdata()
bt = []
for h in range(height):
  for w in range(width):
    pixel = conv.getpixel((w, h))[0]    # getpixel returns a tuple (R,G,B)
    bt.append((pixel & 0x1))

Upvotes: 1

Glenn1234
Glenn1234

Reputation: 2582

It would help to show how the variables you are using are defined so we can see what you are trying to do with them. That said, the ScanLine property is an array representing the bytes representing the pixels. That said, you need a little function like your case statement to determine the number of bytes. But you need to pull each ScanLine off as a pointer to an array of bytes.

So the number of entries in the ScanLine array is Bitmap1.Height, which means you have that part right. But the rest is a little different. Let's say we define a variable named row to be a pointer. Then to find a specific pixel in the array, you have to set another pointer accordingly.

Not sure if this gets it since it's very lightly tested. I just used Longint to represent the pixel data I was pulling back. You'd use something more fitting for your needs to pull out the RGB data, but hopefully this demonstrates how to handle the ScanLine property to get the pixel data you need out of it:

var
  i, j: integer;
  row: pointer;
  pixel: pointer;
  pixelsize: integer;
  thepixel: longint;
begin
  for i := 0 to (Image1.Picture.Height - 1) do
    begin
      row := Image1.Picture.Bitmap.ScanLine[i];
      pixelsize := GetPixelSize(Image1.Picture.Bitmap.PixelFormat);
      pixel := row;
      for j := 0 to (Image1.Picture.Width - 1) do
        begin
          thepixel := Longint(Pixel^);
   //     Memo1.Lines.Add(IntToHex(thepixel, 12));
          Inc(Longint(Pixel), pixelsize);
        end;
     end;
end;

Upvotes: -1

Related Questions