Reputation: 359
I have a TImage placed on my Form and set a PNG image into it.
Is it possible to change the opacity of each pixel of the PNG image in runtime? I want to change the opacity according to specific actions in my application.
I'm using the following code to make a pixel darker, the idea is to apply that function to each pixel in the TImage:
function DarkerColor(thisColor: TColor; thePercent: Byte): TColor;
var
(* a TColor is made out of Red, Green and blue *)
cRed,
cGreen,
cBlue: Byte;
begin
(* get them individually *)
cRed := GetRValue(thisColor);
cGreen := GetGValue(thisColor);
cBlue := GetBValue(thisColor);
(* make them darker thePercent *)
(* we need a byte value but the "/" operator
returns a float value so we use Round function
because type mismatch *)
cRed := Round(cRed * thePercent / 100);
cGreen := Round(cGreen * thePercent / 100);
cBlue := Round(cBlue * thePercent / 100);
(* return them as TColor *)
Result := RGB(cRed, cGreen, cBlue);
end;
I have found how to access to each pixel in a BMP image. The thing is that I'm using a TImage with a PNG loaded in it.
Thanks!
Upvotes: 2
Views: 676
Reputation: 1068
Just use ScanLine
of your PNG
-image to make it darker before assign it to TImage
component. It should be faster then convert TBitmap
from TImage
to PNG
, perform actions and convert it back to TBitmap
and assign it to TImage
component again. Also, once you assigned PNG
to TBitmap
there is no way to get partial transparency of PNG
back. At least, all my trying in past weren't successful, that's why I prefer to store PNG
-files inside my small programs and change (sizing, blending etc.) their copy during run-time.
I changed your source code to exclude operations with floating point. It was replaced with MulDiv
function.
function DarkerColor(thisColor: TColor; thePercent: Byte): TColor;
var
(* a TColor is made out of Red, Green and blue *)
cRed,
cGreen,
cBlue: Byte;
begin
(* get them individually *)
cRed := GetRValue(thisColor);
cGreen := GetGValue(thisColor);
cBlue := GetBValue(thisColor);
(* make them darker thePercent *)
cRed := MulDiv(cRed, thePercent, 100);
cGreen := MulDiv(cGreen, thePercent, 100);
cBlue := MulDiv(cBlue, thePercent, 100);
(* return them as TColor *)
Result := RGB(cRed, cGreen, cBlue);
end;
Now you can go further and use ScanLine
of your PNG
-image:
procedure MakePNGDarker(APNGInOut: TPNGImage; AValue: Integer);
type
TRGBArray = Array [0..65535 - 1] of WinAPI.Windows.tagRGBTRIPLE;
PRGBArray = ^TRGBArray;
var
RowInOut: PRGBArray;
SourceColor: TColor;
ResultColor: TColor;
X: Integer;
Y: Integer;
begin
if not Assigned(APNGInOut) or (AValue < 0) then
Exit;
for Y:=0 to APNGInOut.Height - 1 do
begin
RowInOut := APNGInOut.ScanLine[Y];
for X:=0 to APNGInOut.Width - 1 do
begin
SourceColor := RGB(RowInOut[X].rgbtRed, RowInOut[X].rgbtGreen, RowInOut[X].rgbtBlue);
ResultColor := DarkerColor(SourceColor, AValue);
RowInOut[X].rgbtRed := GetRValue(ResultColor);
RowInOut[X].rgbtGreen := GetGValue(ResultColor);
RowInOut[X].rgbtBlue := GetBValue(ResultColor);
end;
end;
end;
Here is a result of the job that function done.
Fig. A stands for original image; Figures from B to F are present gradation of a modified images whose darkness was set with step of 25 through 0 to 100.
Note
Edges of colored images are blurred as these images were made with blurred edges. This is not a result of function work!
Useful resources
Upvotes: 4