Recent

Author Topic: [Solved] How to change the hue of a Tbitmap  (Read 6987 times)

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
[Solved] How to change the hue of a Tbitmap
« on: May 18, 2013, 12:46:38 pm »
hello,
i am beginner with graphics in Lazarus, i want to change only the hue of an image. This image (png with transparency)  is loaded in a Tpicture.  I don't want use the BGRAbitmap library because this library is too big for my purpose (growing size > 1Mb).
I have found a solution but i am sure that there is a better solution. And i have a problem with the transparency. here is my code (FPictureOn is a Tpicture : size 32x32)  :
Code: [Select]
  SetHue( hue : byte);
var  t: TLazIntfImage;
  px,py : integer;
  CurFPColor: TFPColor;
  CurColor: Tcolor;
  r,g,b,h,l,s : byte;
begin
  try
    t :=  FpictureON.Bitmap.CreateIntfImage;
    for py:=0 to t.Height-1 do begin
    for px:=0 to t.Width-1 do begin
    // Read and/or write to the pixels
    CurColor:= FPColorToTColor(t.Colors[px,py]); //lire la couleur source
    RedGreenBlue(CurColor,r,g,b);
    RGBtoHLS(r,g,b,h,l,s);
    HLStoRGB(hue,l,s,r,g,b);
    t.Colors[px,py]:=TColorToFPColor(RGBToColor(r,g,b));
    end;
    end;
    FpictureON.Bitmap.LoadFromIntfImage(t);
  finally
    t.Free;
  end;         
With this i can change the hue but i loose the transparency.  Optimization is not necessary because the image is very small.
Can you help me ?


« Last Edit: May 19, 2013, 04:25:31 pm by Jurassic Pork »
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
Re: How to change the hue of a Tbitmap
« Reply #1 on: May 18, 2013, 01:59:20 pm »
i have found a solution for the transparency :
Code: [Select]
  alpha :=  t.Colors[px,py].alpha;
    if alpha > 0 then
    begin
    CurColor:= FPColorToTColor(t.Colors[px,py]); //lire la couleur source
    RedGreenBlue(CurColor,r,g,b);
    RGBtoHLS(r,g,b,h,l,s);
    HLStoRGB(150,l,s,r,g,b);
    t.Colors[px,py]:=TColorToFPColor(RGBToColor(r,g,b));
    end; 
if i am in a transparent pixel (alpha = 0 -> invisible), i don't change the value of this pixel.
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: How to change the hue of a Tbitmap
« Reply #2 on: May 18, 2013, 02:07:52 pm »
You don't need to create a new image, but you can just edit the FpictureON directly.

This command
FpictureON.bitmap.Canvas.Colors[px,py]:=TColorToFPColor(RGBToColor(r,g,b));
is sure to abandon Alpha, but what if you individually set
FpictureON.bitmap.Canvas.Colors[px,py].red:=r; (i don't remember exact syntax)
or if there is RGBAToColor(r,g,b,a)

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: How to change the hue of a Tbitmap
« Reply #3 on: May 18, 2013, 02:12:18 pm »
1) alpha is transparent when 0 in some widgetsets and in other when it is 255, just for your information.
2) fpimage.TFpColor is a record type you can access the rgb values directly do not convert it to tcolor and then use an rgb convertion function. If you use the TFPcolor directly then the alpha value will be preserved. Remember to add fpimage in your uses clause.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
Re: How to change the hue of a Tbitmap
« Reply #4 on: May 18, 2013, 05:53:11 pm »
thanks for your help  but there are some "dark points"

1 - if i use FPictureON.Bitmap.Canvas.Colors[px,py] the alpha channel doesn't work ( read or write). For this i use always in my code the temporary TLazIntfImage.

2 - the members of the TFPColor are word not byte and if i affect for example the red member to a byte value r, this doesn't work . I must use TColorToFPColor to have the good values in the TFPColor

finally here is my code :
Code: [Select]
SetHue( hue : byte);
  t: TLazIntfImage;
  px,py : integer;
  CurColor: TColor;
  CurFPColor: TFPColor;
  r,g,b,h,l,s : byte;
  alpha : word;
begin
  try
    t :=  FpictureON.Bitmap.CreateIntfImage;
    for py:=0 to FPictureON.Bitmap.Height-1 do begin
    for px:=0 to FPictureON.Bitmap.Width-1 do begin
    curFPColor := t.Colors[px,py];
    RedGreenBlue(CurColor,r,g,b);
    alpha := curFPColor.alpha;
     RGBtoHLS(lo(curFPColor.red),lo(curFPColor.green),lo(curFPColor.blue),h,l,s);
     HLStoRGB(hue,l,s,r,g,b);
 //    curFPColor.red := r; //  doesn't work
     curFPColor := TColorToFPColor(RGBToColor(r,g,b));
     curFPColor.alpha := alpha;
      t.Colors[px,py] :=  curFPColor;
    end;
    end;
    FpictureON.Bitmap.LoadFromIntfImage(t);
  finally
    t.free;
  end;           

Friendly, J.P
« Last Edit: May 18, 2013, 05:56:00 pm by Jurassic Pork »
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: How to change the hue of a Tbitmap
« Reply #5 on: May 18, 2013, 07:28:43 pm »
To convert byte channel into word format, you can multiply it by 256. Or in opposite direction it is divided.

You didn't follow mine or taazz instructions. t.Colors[px,py] :=curFPColor; this is still a direct assignment. I meant something like:
Code: [Select]
t.Colors[px,py].red:=r;
t.Colors[px,py].green:=g;
t.Colors[px,py].blue:=b;

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1228
Re: How to change the hue of a Tbitmap
« Reply #6 on: May 19, 2013, 01:14:26 am »
For my first problem ( need to use a temporary TLazIntfImage  ) read this :
Quote
TLazIntfImage is a memory image. I can store transparency and 16-bit values for each channel. TBitmap is compatible with Delphi and use TColor type for pixels which do not contain alpha information. So TLazIntfImage is better suited for image processing. This component provide faster access to pixels because it is an array in memory like our TFastBitmap.

For direct assignment like this :
Code: [Select]
t.Colors[px,py].red:=r;i can't compile with this error :
Quote
.pas(133,22) Error: Argument can't be assigned to
look like this bug :  http://lists.lazarus.freepascal.org/pipermail/lazarus/2010-January/048371.html
to avoid this error i use a TFPColor variable

For the TFPColor to convert the r,v,b bytes i must multiply these values by 256 because :
Quote
The TFPColor record contains the Red, Green, Blue and Alpha channel values as left adjusted 16 bit words, with increasing intensity from 0 to $FFFF. Alpha=0 indicates transparent pixels.The internal representation uses the high order bits of these values, as specified by the color Depth of the image description.

finally my code (work for me) :
Code: [Select]
procedure SetHue (hue: byte) ;
var
  t: TLazIntfImage;
  px,py : integer;
  CurFPColor: TFPColor;
  r,g,b,h,l,s : byte;
  alpha : word;
begin
  try
    t :=  FpictureON.Bitmap.CreateIntfImage;
    for py:=0 to t.Height-1 do begin
    for px:=0 to t.Width-1 do begin
    curFPColor := t.Colors[px,py];
    RGBtoHLS(hi(curFPColor.red),hi(curFPColor.green),hi(curFPColor.blue),h,l,s);
    HLStoRGB(hue,l,s,r,g,b);
    curFPColor.red := r shl 8;
    curFPColor.green := g shl 8;
    curFPColor.blue := b shl 8;
    t.Colors[px,py] :=  curFPColor;
    end;
    end;
   FpictureON.Bitmap.LoadFromIntfImage(t);
  finally
    t.free;
  end;
end;
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

 

TinyPortal © 2005-2018