AWARE [SYSTEMS] | ||||||||

TechTalks / Unused color | ||||||||

AWare Systems on-line
Home Languages
Contact
Information: info@awaresystems.be |
## How to calculate an unused color from a Delphi VCL TBitmap
I take it that this TBitmap is pf24bit or pf32bit? Any bitdepth smaller than that cannot cause a significant problem, since you can simply - setup a bit array, one bit for each possible color value
- clear the bit array
- scan through the bitmap
- for each pixel color value, set the appropriate bit in the bit array
- scan through the bit array, until you find an unset bit
- return the index of this unset bit as unused color value.
For example, in a pf16bit TBitmap, this would look like...
BitArray: Pointer; ma: PByte; mb: Integer; mc: Integer; md: PWord; na: Integer; nb: Integer; nba: PByte; nbb: Integer; oaa: PByte; oab: Integer; ob, oc: Integer;
GetMem(BitArray, 8192); ZeroMemory(BitArray, 8192);
ma := a.Scanline[0]; mb := Integer(a.Scanline[1])-Integer(a.Scanline[0]);
md := PWord(ma);
nb := md^; Inc(md);
nba := PByte(Cardinal(BitArray)+Cardinal(nb nbb := (128
nba^ := (nba^
Inc(ma, mb);
oaa := BitArray;
ob := 0; oc := 128; while True
Inc(ob); oc := (oc
Result := ((oab FreeMem(BitArray, 8192); exit;
Inc(oaa);
FreeMem(BitArray, 8192); Result := -1;
This function returns either an unused 16bit color value, or -1 if all colors are used. Note that it's still up to you to interpret the 16bit color value, whatever way you need to interpret it, the function simply returns it as it is stored in a pf16bit bitmap. Also note that we don't abuse the stack by declaring an 8Kb bit array in the var section, but separately allocate this, since it is not good practice to use the stack for blocks of this magnitude. Note also that we don't use nonsense like TBitArray and such, since we do not want our users to grow a beard waiting for this function to complete... The problem grows more complex when dealing with pf24bit or pf32bit TBitmap's. Using exactly the same algorithm design to get at an unused color would involve a bit array of 2^24 bits, being 2 meg. 8 kilobyte fits into every user's processor cache, nowadays, but 2 meg does not. Randomly accessing 2 meg for each pixel in a TBitmap is extremely bad practice, at best. The easiest solution is to go hunting for an unused combination of R and G values, given some fixed B value. If the algorithm finds one, then these R and G values, together with the fixed B value, is an unused color, for sure. If it does not, then the same algorithm can be repeated, searching for an unused combination of R and G values, given the next B value. Thus, this solution still needs a bit array of only 2^16 bits, at the expense of potentially scanning through the TBitmap multiple times. This multiple scanning is not half as bad as maintaining a 2^24 bits array, and is furthermore not very likely to occur. Most of the time, the first pass will already yield an unused color. Here's some code implementing the proposed solution, for pf24bit bitmaps.
BitArray: Pointer; p: Integer; ma: PByte; mb: Integer; mc: Integer; md: PByte; na: Integer; nb: Integer; nba: PByte; nbb: Integer; oaa: PByte; oab: Integer; ob, oc: Integer; o: Integer;
GetMem(BitArray, 8192);
ZeroMemory(BitArray, 8192);
ma := a.Scanline[0]; mb := Integer(a.Scanline[1])-Integer(a.Scanline[0]);
md := ma;
Inc(md); nb := (md^ Inc(md); nb := (nb Inc(md);
nba := PByte(Cardinal(BitArray)+Cardinal(nb nbb := (128
nba^ := (nba^
Inc(md, 3);
Inc(ma, mb);
oaa := BitArray;
ob := 0; oc := 128; while True
Inc(ob); oc := (oc
o := ((oab
FreeMem(BitArray, 8192); Result := RGB((o exit;
Inc(oaa);
FreeMem(BitArray, 8192); Result := TColor(-1);
This function returns either an unused TColor, or TColor(-1) if all colors are used. Please drop us a line drop us a line if you wish to be kept informed about changes and additions to this page. |