Color to ARGB Convert - delphi

I have an integer color values like -16447153. And how to convert it ARGB?
In c#, he used color function,
Color.FromArgb(buf[buf_pos])
is there a function in delphi as like above otherwise how can i convert ?
I tried like this:
procedure TJP2RenderPreview.put_region(size : _Ckdu_coords; buf : array of Integer; offX, offY : Integer);
var
x, y : Integer;
width, height : Integer;
buf_pos : Integer;
RowPtr : PRGBQuad;
begin
width:= size.__property_get_x;
height:= size.__property_get_y;
buf_pos:=0;
for y := offY to offY + height - 1 do
begin
RowPtr:= formMain.imgPreview.Bitmap.ScanLine[y];
Inc(RowPtr, offX);
for x := 0 to width - 1 do
begin
RowPtr.rgbReserved:= (buf[buf_pos] div $1000000);
RowPtr.rgbRed:= ((buf[buf_pos] mod $1000000) div $10000);
RowPtr.rgbGreen:= ((buf[buf_pos] mod $10000) div $100);
RowPtr.rgbBlue:= (buf[buf_pos] mod $100);
Inc(RowPtr);
Inc(buf_pos);
end;
end;
formMain.imgPreview.Refresh;
formMain.imgPreview.Update;
end;
But this is not true, it seems grey :/

You appear to have got your channels mixed up. You are treating the input as RGBA when you say it is ARGB. In any case, your code using div and mod is inefficent. Bitwise shifting is the idiomatic way.
You can do it like this for ARGB input:
procedure ARGBtoColorChannels(ARGB: DWORD; out A, R, G, B: Byte);
begin
A := Byte(ARGB);
R := Byte(ARGB shr 8);
G := Byte(ARGB shr 16);
B := Byte(ARGB shr 24);
end;
Or if you start with RGBA then it goes like this:
procedure RGBAtoColorChannels(RGBA: DWORD; out A, R, G, B: Byte);
begin
R := Byte(RGBA);
G := Byte(RGBA shr 8);
B := Byte(RGBA shr 16);
A := Byte(RGBA shr 24);
end;
And these are little endian versions, since Delphi only targets on little endian machines, at the time of writing.
If you are looking for a function to convert ARGB to RGBA then you can make one like so:
function ARGBtoRGBA(ARGB: DWORD): DWORD;
var
A, R, G, B: Byte;
begin
ARGBtoColorChannels(ARGB, A, R, G, B);
Result := R or (G shl 8) or (B shl 16) or (A shl 24);
end;
And for completeness the reverse is:
function RGBAtoARGB(RGBA: DWORD): DWORD;
var
A, R, G, B: Byte;
begin
RGBAtoColorChannels(RGBA, A, R, G, B);
Result := A or (R shl 8) or (G shl 16) or (B shl 24);
end;
In order for you to know what to do, you need to understand what buf is. Is it ARGB or RGBA? Assuming it it ARGB, which seems likely given the content of your question, you are attempting to copy to RowPtr, which also appears to be ARGB. In which case you can blit the color like this:
PInteger(RowPtr)^ := buf[buf_pos];
I would also strongly recommend that you change the type of the buf parameter. An unsigned type is better here, because you may need to perform bitwise operations. What's more you are copying the entire array via the stack which is very inefficient. For large bitmaps you will suffer stack overflow. Instead that parameter should be:
const buf: array of DWORD;
or
const buf: array of Cardinal;
Using const means that a reference to the array is passed, rather than a copy.
You may as well avoid using PRGBQuad and declare RowPtr to be of type PCardinal, say.
Then you can assign like this:
RowPtr^ := buf[buf_pos];
At that point you don't need to do it pixel by pixel. You can copy an entire scanline with Move because this is a simply blit.
for y := offY to offY + height - 1 do
begin
RowPtr := formMain.imgPreview.Bitmap.ScanLine[y];
Inc(RowPtr, offX);
Move(buf[buf_pos], RowPtr^, width*SizeOf(RowPtr^));
Inc(buf_pos, width);
end;
Calling Refresh and Update seems pointless. I'm not sure you need to call either, but if you do, just call Invalidate instead!

Related

Is there anyway to use the property like behavior?

I have the following formula
X := X + F*(1-i div n);
Where
X, F, i, n: integer;
The code I'm using is this
F := 7; // the initial speed with no friction.
n := 10; // the animation number of steps.
Hn := n * 2 ;
X := 0; // first Pos
i := 1;
J := 1;
while J < Hn do
begin
X := X + F * (1 - i div n);
if X > Xmax then X := 0; <-- line (1).
if i >= n then Dec(i)
else Inc(i);
Inc(J);
end;
If it was possible I would like to use this but without class/record implementation(not inside a class/record implementation/method).not the exact syntax, just the same principle, instead of direct assignment to X the SetX is called then the result is assigned to X.
X: integer write SetX; // This is not a correct delphi syntax. I added it to explain the behavior I want.
function SetX(aValue: integer): integer;
const
Xmax: SomeIntegerValue;
begin
if aValue > Xmax then result := 0
else result := aValue;
end;
So I could omit Line (1). If this was possible, all the lines after the formula would be omitted and the while loop would look like this
while J < Hn do // J will be incremented each time the loop wants to read it.
begin
X := X + F * (1 - i div n);
end;
Is there anyway to use the property like behavior?
Note: I'm looking for a way to alter the assignment and reading ways of a variable like you do in a property of a record/class.
Is there anyway to use the property like approach outside a class/record?
No, property getters and setters can only be implemented in records and classes.
You can use local function like
procedure YourProcedure;
var
X: Integer;
LJ: Integer;
function J: Integer;
begin
Inc(LJ);
Result := LJ;
end;
procedure SetX(const AValue: Integer);
const
Xmax: SomeIntegerValue;
begin
if aValue > Xmax then X := 0
else X := aValue;
end;
//...
begin
while J < Hn do // J will be incremented each time the loop wants to read it.
begin
SetX(X + F * (1 - i div n));
end
end.
I found a way to do what I wanted. I know that overloading the := operator is not possible, However forcing the compiler to produce the same behavior as the overloaded operator would behave is possible.
The overloading would not let me control the LSA (Left Side Argument). but it gave full control to implicitly convert any TType (in my case it is an integer) to TXinteger. So all I had to do is make sure that every operator would result in a TType which will force the compiler to implicitly convert that to a TXinteger.
Forcing the compiler to use my implicit operator every time it wants to assign something to TXinteger means I control the assignment Hence I overloaded the := operator.
the following is a test example that makes omitting Line(1) possible.
program Project4;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
type
TXinteger = record
X: integer;
class operator Add(a, b: TXinteger): integer;
class operator Add(a: TXinteger; b:integer): integer;
class operator Add(a: integer; b:TXinteger): integer;
class operator Implicit(a: Integer): TXinteger;
class operator Implicit(a: TXinteger): Integer;
end;
// Example implementation of Add
class operator TXinteger.Add(a, b: TXinteger): integer;
begin
result := a.X + b.X;
end;(**)
class operator TXinteger.Add(a: TXinteger; b:integer): integer;
begin
result := a.X + b;
end;
class operator TXinteger.Add(a: integer; b:TXinteger): integer;
begin
result := a + b.X;
end;
class operator TXinteger.Implicit(a: Integer): TXinteger;
const
Xmax: integer = 10;
begin
if a > Xmax then result.X := 0 else result.X := a;
end;
class operator TXinteger.Implicit(a: TXinteger): Integer;
begin
result := a.X;
end;
var
X: TXinteger;
Hn, F, i,J, n: integer;
begin
try
F := 7;
n := 10;
Hn := n * 2 ;
X := 0;
i := 1;
J := 1;
while J < Hn do
begin
X := X + F * (1 - i div n);
// Line (1) is gone now.
if i >= n then Dec(i)
else Inc(i);
Inc(J);
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Note: for this case it is pointless to do all of this just to omit one line of code. I wanted to share this because it gives an idea of how one could overload the := operator.
What I wanted is this:
Alter how X:Integer is read (value read from the variable x's storage).
Alter how X:Integer is assigned.
by overloading all the operators that use the value of X, I completed the first.
And by forcing the compiler as explained above, I completed the second.
Thank you all for your help.

Reading Pixels and finding specific RGB

I would like to load an image, and read pixels to find a certain RGB, but then check the next pixels across to make sure they match, and i am at the right position of the bitmap.
I know the below code is wrong, but i am not sure how to go about correcting it. I also know Pixels is not the fastest way to read pixels.
Thanks guys!
procedure RGB(Col: TColor; var R, G, B: Byte);
var
Color: $0..$FFFFFFFF;
begin
Color := ColorToRGB(Col);
R := ($000000FF and Color);
G := ($0000FF00 and Color) Shr 8;
B := ($00FF0000 and Color) Shr 16;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
x,y : Integer;
ColorN: TColor;
R, G, B: Byte;
begin
for Y := 0 to Image1.Picture.Bitmap.Height -1 do
begin
for X := 0 to Image1.Picture.Bitmap.Width -1 do
begin
inc(i);
ColorN := Image1.Canvas.Pixels[x, y];
RGB(ColorN, R, G, B);
//Memo1.Lines.Append('Line: '+IntToStr(i)+' Y: '+IntToStr(Y)+' X: '+IntToStr(X)+' R: '+IntToStr(R)+' G: '+IntToStr(G)+' B: '+IntToStr(B));
if (IntToStr(R) = '235') and (IntToStr(G) = '235') and (IntToStr(B) = '235') then //Y: 500 X: 587
begin
//Image1.Canvas.MoveTo(X,Y);
//Image1.Canvas.LineTo(X,Y);
ColorN := Image1.Canvas.Pixels[x +1, y];
RGB(ColorN, R, G, B);
end;
if (IntToStr(R) = '232') and (IntToStr(G) = '232') and (IntToStr(B) = '232') then //RGB:232,232,232 Y: 500 X: 588
begin
ColorN := Image1.Canvas.Pixels[x +1, y];
RGB(ColorN, R, G, B);
ShowMessage('Test1');
end;
if (IntToStr(R) = '231') and (IntToStr(G) = '231') and (IntToStr(B) = '231') then //RGB: 231,231,231 Y: 500 X: 589
begin
ColorN := Image1.Canvas.Pixels[x +1, y];
RGB(ColorN, R, G, B);
ShowMessage('Test2');
end;
if (IntToStr(R) = '230') and (IntToStr(G) = '230') and (IntToStr(B) = '230') then //RGB: 230,230,230 Y: 500 X: 590
begin
ShowMessage('Test3');
end;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
b: TBitmap;
begin
Image1.Picture.LoadFromFile('E:\Delphi Projects\Detect(XE6)\screen\1.png');
b := TBitmap.Create;
b.Assign(Image1.Picture.Graphic);
Image1.Picture.bitmap := b;
FreeAndNil(b);
end;
There are several big issues in this code:
Instead of IntToStr(R) = '235' it would be much faster to just check R=235
Instead of checking R, G and B individually, it would be easier to just check if ColorN=C_Gray235 where C_Gray235 = #00EBEBEB;
For the application as a whole I'd use a single if:
if (GetPixel(x, y) = C_Gray235) and
(GetPixel(x+1, y) = C_Gray232) and
(GetPixel(x+2, y) = C_Gray231) and
(GetPixel(x+3, y) = C_Gray230) then
begin
//do stuff here
end;
please note that the for-loop should be for x := 0 to myBitmap.Width - 4 (there's no way for the if to succeed once you have less than 4 pixels left on the line. Actually you may even get an AV if you try to access them, depending on the way you get the pixels).
Now if the bitmap already is a 24-bit or 32-bit bitmap, you can improve the performance quite a bit by using Bitmap.ScanLine[iLine]...

How to convert HSB to RGB

I having one Delphi XE2 Project to change Label01 Font Color using Timer04. So I have written the following codes:
procedure TMainForm.FormCreate(Sender: TObject);
begin
Timer04.Enabled := true;
end;
..
..
..
..
..
procedure TMainForm.Timer04Timer(Sender: TObject);
var
StartColor, RedColor, GreenColor, BlueColor: integer;
begin
StartColor := ColorToRGB(Label01.Font.Color);
RedColor := GetRValue(StartColor);
GreenColor := GetGValue(StartColor);
BlueColor := GetBValue(StartColor);
if RedColor <= 251 then Inc(RedColor, 1) else RedColor := 1;
if GreenColor <= 252 then Inc(GreenColor, 2) else GreenColor := 2;
if BlueColor <= 253 then Inc(BlueColor, 3) else BlueColor := 3;
Label01.Font.Color := RGB(RedColor, GreenColor, BlueColor);
end;
This codes work perfectly. Label01 Font Color changes between different colors.
Now I am trying to implement that Label02 Color will be fixed (say Green) and the value of brightnees will be increase from 0 to 100. If the value reaches to 100 it will be decreased to 0 and it will be continuous to a loop.
For my case I have chosen HUE=135, SATURATION=85 and BRIGHTNESS=50. The value of BRIGHTNESS will be increased from 50 to 100 and then will be decreased from 100 to 0 and it will be continued.
But the problem is that there is no such Function available to convert HSB to RGB and vice versa in Delphi XE2. I have Gooled it. But I have found any Function as HSBToRGB. Only some Delphi Unit is availabe. I have read their revoews and found that every one is having some bugs.
Here is a Delphi a translation of C code found here: http://www.cs.rit.edu/~ncs/color/t_convert.html
function RGBFP(R, G, B: Double): TColor;
const
RGBmax = 255;
begin
Result := RGB(Round(RGBmax * R), Round(RGBmax * G), Round(RGBmax * B));
end;
function HSVtoRGB(H, S, V: Double): TColor;
var
i: Integer;
f, p, q, t: Double;
begin
Assert(InRange(H, 0.0, 1.0));
Assert(InRange(S, 0.0, 1.0));
Assert(InRange(V, 0.0, 1.0));
if S = 0.0 then
begin
// achromatic (grey)
Result := RGBFP(V, V, V);
exit;
end;
H := H * 6.0; // sector 0 to 5
i := floor(H);
f := H - i; // fractional part of H
p := V * (1.0 - S);
q := V * (1.0 - S * f);
t := V * (1.0 - S * (1.0 - f));
case i of
0:
Result := RGBFP(V, t, p);
1:
Result := RGBFP(q, V, p);
2:
Result := RGBFP(p, V, t);
3:
Result := RGBFP(p, q, V);
4:
Result := RGBFP(t, p, V);
else
Result := RGBFP(V, p, q);
end;
end;
I've given this minimal testing. Please do feel free to double check it.
For Firemonkey it's HSLtoRGB from System.UIConsts.pas
It's similar to HSB (=HSV). All you can do with HSB you can do with HSL
function HSLtoRGB(H, S, L: Single): TAlphaColor;
It returns FMX TAlphaColor - that is RGB.
For VCL you need TColor, that is BGR.
So use RGBtoBGR in the same unit.
function RGBtoBGR(const C: TAlphaColor): TAlphaColor;
Then just do
Color := TColor(MyAlphaColorVariable);
AFAIK there is no HSB function in standard units.

How change the alpha value of a specific color in a 32 bit TBitmap?

I need to change the value of the alpha component when a pixel contains a specific color for a TBitmap of 32 bits, I know about the ScanLine property to access the bitmap data, but i can't figure out how change the alpha component of each pixel.
This is a basic implementation
First you need define a record to hold the ARGB structure
TRGB32 = record
B, G, R, A: byte;
end;
Then you must define a array of TRGB32 to cast the Scanline and get and set the values.
Check this sample method
procedure SetAlphaBitmap(const Dest: TBitmap;Color : TColor;Alpha:Byte);
type
TRGB32 = record
B, G, R, A: byte;
end;
PRGBArray32 = ^TRGBArray32;
TRGBArray32 = array[0..0] of TRGB32;
var
x, y: integer;
Line, Delta: integer;
ColorRGB : TColor;
begin
if Dest.PixelFormat<>pf32bit then exit;
ColorRGB:=ColorToRGB(Color);
Line := integer(Dest.ScanLine[0]);
Delta := integer(Dest.ScanLine[1]) - Line;
for y := 0 to Dest.Height - 1 do
begin
for x := 0 to Dest.Width - 1 do
if TColor(RGB(PRGBArray32(Line)[x].R, PRGBArray32(Line)[x].G, PRGBArray32(Line)[x].B))=ColorRGB then
PRGBArray32(Line)[x].A := Alpha;
Inc(Line, Delta);
end;
end;
Also you can take a look to this unit that i wrote to manipulate 32 bit bitmaps
For each 32 bits pixel the highest byte contains the alpha value.
var
P: Cardinal;
Alpha: Byte;
...
begin
...
P := bmp.Canvas.Pixels[x, y]; // Read Pixel
P := P and $00FFFFFF or Alpha shl 24; // combine your desired Alpha with pixel value
bmp.Canvas.Pixels[x, y] := P; // Write back
...
end;
I would make the following tweaks to RRUZ's answer:
procedure SetAlphaBitmap(Dest: TBitmap; Color: TColor; Alpha: Byte);
type
TRGB32 = packed record
B, G, R, A: Byte;
end;
PRGBArray32 = ^TRGBArray32;
TRGBArray32 = array[0..0] of TRGB32;
var
x, y: Integer;
Line: PRGBArray32;
ColorRGB: Longint;
Red, Green: Blue: Byte;
begin
if Dest.PixelFormat <> pf32bit then Exit;
ColorRGB := ColorToRGB(Color);
Red := GetRValue(ColorRGB);
Green := GetGValue(ColorRGB);
Blue := GetBValue(ColorRGB);
for y := 0 to Dest.Height - 1 do
begin
Line := PRGBArray32(Dest.ScanLine[y]);
for x := 0 to Dest.Width - 1 do
begin
with Line[x] do
begin
if (R = Red) and (G = Green) and (B = Blue) then
A := Alpha;
end;
end;
end;
end;

Improve speed on Crc16 calculation

I need to calculate Crc16 checksums with a $1021 polynom over large files, below is my current implementation but it's rather slow on large files (eg a 90 MB file takes about 9 seconds).
So my question is how to improve my current implementation (to make it faster), I have googled and looked at some samples implementing a table lookup but my problem is that I don't understand how to modify them to include the polynom (probably my math is failing).
{ based on http://miscel.dk/MiscEl/CRCcalculations.html }
function Crc16(const Buffer: PByte; const BufSize: Int64;
const Polynom: WORD=$1021; const Seed: WORD=0): Word;
var
i,j: Integer;
begin
Result := Seed;
for i:=0 to BufSize-1 do
begin
Result := Result xor (Buffer[i] shl 8);
for j:=0 to 7 do begin
if (Result and $8000) <> 0 then
Result := (Result shl 1) xor Polynom
else Result := Result shl 1;
end;
end;
Result := Result and $FFFF;
end;
If you want this to be fast, you need to implement a table-lookup CRC algorithm.
See chapter 10 of A PAINLESS GUIDE TO CRC ERROR DETECTION ALGORITHMS INDEX V3.00 (9/24/96)
Look for CRC routines from jclMath.pas unit of Jedi Code Library. It uses CRC lookup tables.
http://jcl.svn.sourceforge.net/viewvc/jcl/trunk/jcl/source/common/
Your Result variable is a Word, which means there are 64k possible values it could have upon entry to the inner loop. Calculate the 64k possible results that the loop could generate and store them in an array. Then, instead of looping eight times for each byte of the input buffer, simply look up the next value of the checksum in the array. Something like this:
function Crc16(const Buffer: PByte; const BufSize: Int64;
const Polynom: Word = $1021; const Seed: Word = 0): Word;
{$J+}
const
Results: array of Word = nil;
OldPolynom: Word = 0;
{$J-}
var
i, j: Integer;
begin
if (Polynom <> OldPolynom) or not Assigned(Results) then begin
SetLength(Results, 65535);
for i := 0 to Pred(Length(Results)) do begin
Results[i] := i;
for j := 0 to 7 do
if (Results[i] and $8000) <> 0 then
Results[i] := (Results[i] shl 1) xor Polynom
else
Results[i] := Results[i] shl 1;
end;
OldPolynom := Polynom;
end;
Result := Seed;
for i := 0 to Pred(BufSize) do
Result := Results[Result xor (Buffer[i] shl 8)];
end;
That code recalculates the lookup table any time Polynom changes. If that parameter varies among a set of values, then consider caching the lookup tables you generate for them so you don't waste time calculating the same tables repeatedly.
If Polynom will always be $1021, then don't even bother having a parameter for it. Calculate all 64k values in advance and hard-code them in a big array, so your entire function is reduced to just the last three lines of my function above.
Old thread, i know. Here is my implementation (just one loop):
function crc16( s : string; bSumPos : Boolean = FALSE ) : Word;
var
L, crc, sum, i, x, j : Word;
begin
Result:=0;
L:=length(s);
if( L > 0 ) then
begin
crc:=$FFFF;
sum:=length(s);
for i:=1 to L do
begin
j:=ord(s[i]);
sum:=sum+((i) * j);
x:=((crc shr 8) xor j) and $FF;
x:=x xor (x shr 4);
crc:=((crc shl 8) xor (x shl 12) xor (x shl 5) xor x) and $FFFF;
end;
Result:=crc+(Byte(bSumPos) * sum);
end;
end;
Nice thing is also that you can create an unique id with it, for example to get an unique identifier for a filename, like:
function uniqueId( s : string ) : Word;
begin
Result:=crc16( s, TRUE );
end;
Cheers,
Erwin Haantjes

Resources