Recent

Author Topic: [SOLVED] What's Wrong With ScanLine on Linux.  (Read 4236 times)

Xor-el

  • Sr. Member
  • ****
  • Posts: 404
[SOLVED] What's Wrong With ScanLine on Linux.
« on: October 25, 2018, 10:04:39 am »
Hi,
This is another question that erupted from my previous question http://forum.lazarus.freepascal.org/index.php/topic,42965.msg300289/topicseen.html

Why does BitMap.ScanLine which works beautifully on Windows produce Skewed Images on Linux?

Attached below is the demo code and the images on both platforms.

Thanks.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, LCLIntf, Dialogs, StdCtrls,
  9.   ExtCtrls;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     procedure Button1Click(Sender: TObject);
  18.   private
  19.  
  20.   public
  21.  
  22.   end;
  23.  
  24. var
  25.   Form1: TForm1;
  26.  
  27. implementation
  28.  
  29. {$R *.lfm}
  30.  
  31. function GetRandom32BitMap(aX, aY: integer): TBitMap;
  32. type
  33.   TRGBTriple = packed record
  34.     B, G, R: byte;
  35.   end;
  36.  
  37. type
  38.   PRGBTripleArr = ^TRGBTripleArr;
  39.   TRGBTripleArr = packed array [0 .. MaxInt div SizeOf(TRGBTriple) - 1] of TRGBTriple;
  40. var
  41.   LinePixs: PRGBTripleArr;
  42.   X, Y: integer;
  43. var
  44.   color: TColor;
  45. begin
  46.   Result := Tbitmap.Create;
  47.   Result.Pixelformat := pf24bit;
  48.   Result.SetSize(aX, aY);
  49.   color := TColor($00A5FF);
  50.   for Y := 0 to aY - 1 do
  51.   begin
  52.     LinePixs := Result.ScanLine[Y];
  53.     for X := 0 to aX - 1 do
  54.     begin
  55.       LinePixs^[X].B := GetBValue(color);
  56.       LinePixs^[X].G := GetGValue(color);
  57.       LinePixs^[X].R := GetRValue(color);
  58.     end;
  59.   end;
  60. end;
  61.  
  62. procedure TForm1.Button1Click(Sender: TObject);
  63. var
  64.   bmp: TBitmap;
  65.   png: TPortableNetworkGraphic;
  66.   jpg: TJPEGImage;
  67. begin
  68.   png := TPortableNetworkGraphic.Create();
  69.   jpg := TJPEGImage.Create;
  70.   bmp := GetRandom32BitMap(100, 100);
  71.  
  72.   try
  73.     Canvas.Draw(0, 0, bmp);
  74.     bmp.SaveToFile('bmp.bmp');
  75.  
  76.     try
  77.       png.Assign(bmp);
  78.       Canvas.Draw(110, 0, png);
  79.       png.SaveToFile('png.png');
  80.     finally
  81.       png.Free;
  82.     end;
  83.  
  84.     try
  85.       jpg.Assign(bmp);
  86.       Canvas.Draw(220, 0, jpg);
  87.       jpg.SaveToFile('jpg.jpg');
  88.     finally
  89.       jpg.Free;
  90.     end;
  91.  
  92.   finally
  93.     bmp.Free;
  94.   end;
  95. end;
  96.  
  97.  
  98. end.
  99.  

« Last Edit: October 25, 2018, 04:49:22 pm by Xor-el »

zeljko

  • Hero Member
  • *****
  • Posts: 1686
    • http://wiki.lazarus.freepascal.org/User:Zeljan
Re: What's Wrong With ScanLine on Linux.
« Reply #1 on: October 25, 2018, 11:10:47 am »
What widgetset on linux ?

Xor-el

  • Sr. Member
  • ****
  • Posts: 404
Re: What's Wrong With ScanLine on Linux.
« Reply #2 on: October 25, 2018, 11:13:14 am »

Handoko

  • Hero Member
  • *****
  • Posts: 5382
  • My goal: build my own game engine using Lazarus
Re: What's Wrong With ScanLine on Linux.
« Reply #3 on: October 25, 2018, 11:24:54 am »
It works correctly on my Linux GTK2, if I add the line #5 and modify the line #18:

Code: Pascal  [Select][+][-]
  1. function GetRandom32BitMap(aX, aY: integer): TBitMap;
  2. type
  3.   TRGBTriple = packed record
  4. //    B, G, R: byte;
  5.     R, G, B: byte;
  6.   end;
  7.  
  8. type
  9.   PRGBTripleArr = ^TRGBTripleArr;
  10.   TRGBTripleArr = packed array [0 .. MaxInt div SizeOf(TRGBTriple) - 1] of TRGBTriple;
  11. var
  12.   LinePixs: PRGBTripleArr;
  13.   X, Y: integer;
  14. var
  15.   color: TColor;
  16. begin
  17.   Result := Tbitmap.Create;
  18.   Result.Pixelformat := pf32bit;
  19.   Result.SetSize(aX, aY);
  20.   color := TColor($00A5FF);
  21.   for Y := 0 to aY - 1 do
  22.   begin
  23.     LinePixs := Result.ScanLine[Y];
  24.     for X := 0 to aX - 1 do
  25.     begin
  26.       LinePixs^[X].B := GetBValue(color);
  27.       LinePixs^[X].G := GetGValue(color);
  28.       LinePixs^[X].R := GetRValue(color);
  29.     end;
  30.   end;
  31. end;

Why does it work? I don't know. Just my lucky day. :D

Xor-el

  • Sr. Member
  • ****
  • Posts: 404
Re: What's Wrong With ScanLine on Linux.
« Reply #4 on: October 25, 2018, 11:34:31 am »
It works correctly on my Linux GTK2, if I add the line #5 and modify the line #18:

Code: Pascal  [Select][+][-]
  1. function GetRandom32BitMap(aX, aY: integer): TBitMap;
  2. type
  3.   TRGBTriple = packed record
  4. //    B, G, R: byte;
  5.     R, G, B: byte;
  6.   end;
  7.  
  8. type
  9.   PRGBTripleArr = ^TRGBTripleArr;
  10.   TRGBTripleArr = packed array [0 .. MaxInt div SizeOf(TRGBTriple) - 1] of TRGBTriple;
  11. var
  12.   LinePixs: PRGBTripleArr;
  13.   X, Y: integer;
  14. var
  15.   color: TColor;
  16. begin
  17.   Result := Tbitmap.Create;
  18.   Result.Pixelformat := pf32bit;
  19.   Result.SetSize(aX, aY);
  20.   color := TColor($00A5FF);
  21.   for Y := 0 to aY - 1 do
  22.   begin
  23.     LinePixs := Result.ScanLine[Y];
  24.     for X := 0 to aX - 1 do
  25.     begin
  26.       LinePixs^[X].B := GetBValue(color);
  27.       LinePixs^[X].G := GetGValue(color);
  28.       LinePixs^[X].R := GetRValue(color);
  29.     end;
  30.   end;
  31. end;

Why does it work? I don't know. Just my lucky day. :D

thanks for replying.
while it does looks like it did work, it didn't.
take a look at the output image files (not the drawn canvas), they are still skewed.  :(

circular

  • Hero Member
  • *****
  • Posts: 4369
    • Personal webpage
Re: What's Wrong With ScanLine on Linux.
« Reply #5 on: October 25, 2018, 12:03:46 pm »
For me Handoko version works as well. That's surprising because pf32bit is supposed to mean 4 bytes, but matches 3 bytes RGB values.

The problem is that the PixelFormat property is not reliable. That's a bit why I wrote BGRABitmap library in the first place.

There are some surprising things about the pixel formats. It can be ARGB, BGRA or RGBA and you don't have much control over it. So you are better of leaving the PixelFormat to the default value (it is pfDevice but you don't need to set it) and detect what format you have:

Code: Delphi  [Select][+][-]
  1. function GetRandom32BitMap(aX, aY: integer): TBitMap;
  2. var
  3.   bytesPerPixel, redOffset, greenOffset, blueOffset: byte;
  4.   LinePixs: PByte;
  5.   X, Y: integer;
  6.   color: TColor;
  7. begin
  8.   Result := Tbitmap.Create;
  9.   Result.SetSize(aX, aY);
  10.   bytesPerPixel := Result.RawImage.Description.BitsPerPixel div 8;
  11.   redOffset := Result.RawImage.Description.RedShift div 8;
  12.   greenOffset := Result.RawImage.Description.GreenShift div 8;
  13.   blueOffset := Result.RawImage.Description.BlueShift div 8;
  14.   {$IFNDEF ENDIAN_LITTLE}
  15.   redOffset := bytesPerPixel - 1 - redOffset;
  16.   greenOffset := bytesPerPixel - 1 - greenOffset;
  17.   blueOffset := bytesPerPixel - 1 - blueOffset;
  18.   {$ENDIF}
  19.  
  20.   color := TColor($00A5FF);
  21.   for Y := 0 to aY - 1 do
  22.   begin
  23.     LinePixs := Result.RawImage.GetLineStart(Y);
  24.     for X := 0 to aX - 1 do
  25.     begin
  26.       (LinePixs+blueOffset)^ := GetBValue(color);
  27.       (LinePixs+greenOffset)^ := GetGValue(color);
  28.       (LinePixs+redOffset)^ := GetRValue(color);
  29.       inc(LinePixs, bytesPerPixel);
  30.     end;
  31.   end;
  32. end;
Conscience is the debugger of the mind

Xor-el

  • Sr. Member
  • ****
  • Posts: 404
Re: What's Wrong With ScanLine on Linux.
« Reply #6 on: October 25, 2018, 04:48:42 pm »
For me Handoko version works as well. That's surprising because pf32bit is supposed to mean 4 bytes, but matches 3 bytes RGB values.

The problem is that the PixelFormat property is not reliable. That's a bit why I wrote BGRABitmap library in the first place.

There are some surprising things about the pixel formats. It can be ARGB, BGRA or RGBA and you don't have much control over it. So you are better of leaving the PixelFormat to the default value (it is pfDevice but you don't need to set it) and detect what format you have:

Code: Delphi  [Select][+][-]
  1. function GetRandom32BitMap(aX, aY: integer): TBitMap;
  2. var
  3.   bytesPerPixel, redOffset, greenOffset, blueOffset: byte;
  4.   LinePixs: PByte;
  5.   X, Y: integer;
  6.   color: TColor;
  7. begin
  8.   Result := Tbitmap.Create;
  9.   Result.SetSize(aX, aY);
  10.   bytesPerPixel := Result.RawImage.Description.BitsPerPixel div 8;
  11.   redOffset := Result.RawImage.Description.RedShift div 8;
  12.   greenOffset := Result.RawImage.Description.GreenShift div 8;
  13.   blueOffset := Result.RawImage.Description.BlueShift div 8;
  14.   {$IFNDEF ENDIAN_LITTLE}
  15.   redOffset := bytesPerPixel - 1 - redOffset;
  16.   greenOffset := bytesPerPixel - 1 - greenOffset;
  17.   blueOffset := bytesPerPixel - 1 - blueOffset;
  18.   {$ENDIF}
  19.  
  20.   color := TColor($00A5FF);
  21.   for Y := 0 to aY - 1 do
  22.   begin
  23.     LinePixs := Result.RawImage.GetLineStart(Y);
  24.     for X := 0 to aX - 1 do
  25.     begin
  26.       (LinePixs+blueOffset)^ := GetBValue(color);
  27.       (LinePixs+greenOffset)^ := GetGValue(color);
  28.       (LinePixs+redOffset)^ := GetRValue(color);
  29.       inc(LinePixs, bytesPerPixel);
  30.     end;
  31.   end;
  32. end;

I used your example and it worked beautifully.
Thanks a lot.

circular

  • Hero Member
  • *****
  • Posts: 4369
    • Personal webpage
Re: [SOLVED] What's Wrong With ScanLine on Linux.
« Reply #7 on: October 25, 2018, 06:15:46 pm »
You're welcome  :)
It's a pleasure to share  8-)
Conscience is the debugger of the mind

 

TinyPortal © 2005-2018