Delphi write pixel colors to memo - windows

I Want to make a program, that can write my TImage pixels rgb color to a memo, the program don't know the resolution.
so how can i recover every pixel color to String variable (R,G,B)?
code
var
Image_width,Image_height,x,y,i,i2:integer;
Colors:TColor;
begin
Image_width:=Image1.Width;
Image_height:=Image1.Height;
memo1.text:='$image_width=*'+IntToStr(Image_Width)+
'$$image_height='+IntToStr(Image_Height)+'*$';
x:=1;
y:=1;
for i := 1 to Image_width do begin
for i2 := 1 to Image_height do begin
Colors:=Image1.Canvas.Pixels[x,y];
memo1.Text:=memo1.Text+ColorToString(Colors);
y:=y+1;
end;
x:=x+1
end;
end
|Edited|
procedure TForm1.Button2Click(Sender: TObject);
var
Image_width,Image_height,x,y:integer;
Colors:TColor;
s:string;
begin
Image_width:=Image1.Width;
Image_height:=Image1.Height;
memo1.text:='$image_width=*'+IntToStr(Image_Width)
+'*$ $image_height=*'+IntToStr(Image_Height)+'*$';
x:=0;
y:=0;
memo1.Lines.BeginUpdate;
for x := 0 to Image_width do begin
for y := 0 to Image_height do begin
Colors:=Image1.Canvas.Pixels[x,y];
memo1.Text:=Memo1.Text+ColorToString(Colors);
end;
memo1.Lines.EndUpdate;
end;
end;
It completes very slow, i think 19 second with a 640x480 picture.
And after the program ready, and it put to memo1, i see something in memo1 but the program "not responding" again..
I tried with the s variable, and the program do the same.

First correction, the pixels start from 0, 0. Not 1, 1 as you have. Replace the initial values before the for loops as follows:
x := 0; // not 1;
y := 0; // not 1;
Actually, assigning y at this point is not required as we will soon see.
Second correction, look closer at the inner for loop. i2 steps from 1 to Image_height and y is incremented in each round of the loop, which is ok. Then a visit to the outer loop increments x and we return to the inner loop. What happens with y? It continues from where it stopped previously, while it should first be reset to 0. The cure is to add a line as follows. This is also why the assignment above is redundant.
for i := 1 to Image_width do
begin
y := 0; // Add this line
for i2 := 1 to Image_height do
begin
Suggestions for improvement
It is unclear what you mean with resolution being unknown. If you mean color depth, or bits per pixel, it may be that your approach using pixels is more straight forward. Otherwise, as has been suggested in the comments, you could consider using scanline instead of pixels for faster access to the actual bitmap data . For an excellent article see: How to use ScanLine property for 24-bit bitmaps?
Repeatedly concatenating the color strings to the Text property is very slow. In fact it was so slow with a 64 x 64 pixel image that I couldn't wait for it to run to the end. To speed it up you can use a separate string variable to which you concatenate the color strings
Colors := Image1.Canvas.Pixels[x, y];
s := s + ColorToString(Colors);
and then after the loops concatenate to the Text property
Memo1.Text := Memo1.Text + s;
If your intention was to add each pixels colorstring as a new line to the memo you can instead use the Add method
Colors := Image1.Canvas.Pixels[x, y];
Memo1.Lines.Add(ColorToString(Colors));
Surrounding the for loops with Memo1.Lines.BeginUpdate; and Memo1.Lines.EndUpdate; further improves speed.
Finally, you could just as well, either use x and y as loop control variables or i and i2 as pixel indexes. I would ditch i and i2, and use x and y as both loop control variables and pixel indexes. But I leave that for you to decide.

Related

Change array type: 8bit type to 6bit type

I have two types and two arrays of that types in file.ads
type Ebit is mod 2**8;
type Sbit is mod 2**6;
type Data_Type is array (Positive range <>) of Ebit;
type Changed_Data_Type is array (Positive range <>) of Sbit;
and function:
function ChangeDataType (D : in Data_Type) return Changed_Data_Type
with
Pre => D'Length rem 3 = 0 and D'Last < Positive'Last / 4,
Post => ChangeDataType'Result'Length = 4 * (D'Length / 3)
Ok i can understand all of this.
For example we have arrays of:
65, 66, 65, 65, 66, 65 in 8bit values function should give to us 16, 20, 9, 1, 16, 20, 9, 1 in 6bit values.
I dont know how i can build a 6bit table from 8 bit table.
My idea of sollutions is for example taking bit by bit from type:
fill all bites in 6bit type to 0 (propably default)
if first bit (2**1) is 1 set bit (2**1) in 6bit type to 1;
and do some iterations
But i dont know how to do this, always is a problem with types. Is this good idea or i can do this with easier way? I spend last nigt to try write this but without success.
Edit:
I wrote some code, its working but i have problem with array initialization.
function ChangeDataType (D: in Data_Type) return Changed_Data_Type
is
length: Natural := (4*(D'Length / 3));
ER: Changed_Data_type(length);
Temp: Ebit;
Temp1: Ebit;
Temp2: Ebit;
Actual: Ebit;
n: Natural;
k: Natural;
begin
n := 0;
k := 0;
Temp := 2#00000000#;
Temp1 := 2#00000000#;
Temp2 := 2#00000000#;
Array_loop:
for k in D'Range loop
case n is
when 0 =>
Actual := D(k);
Temp1 := Actual / 2**2;
ER(k) := Sbit(Temp1);
Temp := Actual * ( 2**4);
n := 2;
when 2 =>
Actual := D(k);
Temp1 := Actual / 2**4;
Temp2 := Temp1 or Temp;
ER(k) := Sbit(Temp2);
Temp := Actual * ( 2**2);
n := 4;
when 4 =>
Actual := D(k);
Temp1 := Actual / 2**6;
Temp2 := Temp1 or Temp;
ER(k) := Sbit(Temp2);
n := 6;
when 6 =>
Temp1 := Actual * ( 2**2);
Temp2 := Actual / 2**2;
ER(k) := Sbit(Temp2);
n := 0;
when others =>
n := 0;
end case;
end loop Array_Loop;
return ER;
end;
IF I understand what you're asking... it's that you want to re-pack the same 8-bit data into 6-bit values such that the "leftover" bits of the first EBit become the first bits (highest or lowest?) of the second Sbit.
One way you can do this - at least for fixed size arrays, e.g. your 6 words * 8 bits, 8 words * 6 bits example, is by specifying the exact layout in memory for each array type, using packing, and representation aspects (or pragmas, before Ada-2012) which are nicely described here.
I haven't tested the following, but it may serve as a starting point.
type Ebit is mod 2**8;
type Sbit is mod 2**6;
for Ebit'Size use 8;
for Sbit'Size use 6;
type Data_Type is array (1 .. 6) of Ebit
with Alignment => 0; -- this should pack tightly
type Changed_Data_Type is array (1 .. 8) of Sbit
with Alignment => 0;
Then you can instantiate the generic Unchecked_Conversion function with the two array types, and use that function to convert from one array to the other.
with Ada.Unchecked_Conversion;
function Change_Type is new Ada.Unchecked_Conversion(Data_Type, Changed_Data_Type);
declare
Packed_Bytes : Changed_Data_Type := Change_Type(Original_Bytes);
begin ...
In terms of code generated, it's not slow, because Unchecked_Conversion doesn't do anything, except tell the compile-time type checking to look the other way.
I view Unchecked_Conversion like the "I meant to do that" look my cat gives me after falling off the windowledge. Again...
Alternatively, if you wish to avoid copying, you can declare Original_Bytes as aliased, and use a similar trick with access types and Unchecked_Access to overlay both arrays on the same memory (like a Union in C). I think this is what DarkestKhan calls "array overlays" in a comment below. See also section 3 of this rather dated page which describes the technique further. It notes the overlaid variable must not only be declared aliased but also volatile so that accesses to one view aren't optimised into registers, but reflect any changes made via the other view. Another approach to overlays is in the Ada Wikibook here.
Now this may be vulnerable to endian-ness considerations, i.e. it may work on some platforms but not others. The second reference above gives an example of a record with exact bit-alignment of its members : we can at least take the Bit_Order aspect, as in with Alignment => 0, Bit_Order => Low_Order_First; for the arrays above...
-- code stolen from "Rationale" ... see link above p.11
type RR is record
Code: Opcode;
R1: Register;
R2: Register;
end record
with Alignment => 2, Bit_Order => High_Order_First;
for RR use record
Code at 0 range 0 .. 7;
R1 at 1 range 0 .. 3;
R2 at 1 range 4 .. 7;
end record;
One thing that's not clear to me is if there's a formulaic way to specify the exact layout of each element in an array, as is done in a record here - or even if there's a potential need to. If necessary, one workaround would be to replace the arrays above with records. But I'd love to see a better answer if there is one.

Array Tally Chart

I'm trying to create a Tally Chart based on values stored in array.
I know it is possible to do this in Python, but is there a way to do this in Pascal by keeping the amount of coding to a minimum?
var numbers:array [0..9] of integer;
Sum,aNumber, count,count2:integer;
Average:real=0;
begin
randomize;
// Put 10 Random numbers into an array
for count:= 0 to 9 do
begin
aNumber:=Random(10)+1;
numbers[count]:=aNumber
end;
// Show a Tally
begin
for count:= 0 to 9 do
writeln(numbers[count] * '£');
writeln;
end;
readln;
end.
I simply want to present the outcome of the array by showing all possible values. E.g. If my array had the following random values between 1 and 10: 3,3,8,8,9 it should show:
1-
2-
3- II
4-
..
8- II
9- I
10-
Thanks.
The obvious way would be another for loop:
for count := 0 to 9 do
begin
for i := 1 to numbers[count] do
write('£');
writeln;
end
If you can settle for just one character at the right position, you could use something like:
for count := 0 to 9 do
writeln('£' : numbers[count]);
Think it works now... i created a Function to return the number of instances in each element. That result helps me to know the no. of iterations for each number.
Function TallyCount(x:integer):integer;
var i,TotalCount:integer;
begin
i:=0;
TotalCount:=0;
for i := 0 to 9 do
begin
if numbers[i] = x then
TotalCount:=TotalCount +1;
end;
result:=Totalcount;
end;

Most repeated character in a row

My task is to show most used letter in a row. For example if you put in aabbbbccbbb most repeated character is B and it is used 4 times. There was a very similar topic about the same task, but i didnt understand the code. Most repeating character in a string
Program Task;
var s:string;
i,k,g,count:integer;
c:char;
begin
Readln(s);
g:=0;
while Length(s) > 0 do
begin
c := s[1];
i:=1;
while i<= Length(s) do
begin
If (c=s[i]) then
delete(s,i,1)
else
Inc(i);
If (c=s[i]) then
Inc(g);
end;
end;
Writeln(g);
Readln;
end.
There are many problems i face. First is i dont know how to show which character is most used and second is i dont know how compare which one of repeating characters is most used.
For example if i write aaaabbbc it will give me answer of 7 because there is 4xa and 3xb.
All the help is most appreciated.
If it's just about english characters, you might just allocate an array to keep a count per character. In that case, the code could look like this.
I wrote this using Delphi. I hope it works as well in your flavour of Pascal.
program Task;
{$APPTYPE CONSOLE} // For Delphi
var
s: string[50];
i: Integer;
Counters: array[Char] of Integer;
Highest: Char;
begin
// Initialize counters.
for i := 0 to 255 do
Counters[Char(i)] := 0;
s := 'aabbbbccbbb';
// Count the characters.
for i := 1 to Length(s) do
Inc(Counters[s[i]]);
// Find out which one is highest.
Highest := #0;
for i := 0 to 255 do
if Counters[Char(i)] > Counters[Highest] then
Highest := Char(i);
// Output that character and its count.
WriteLn('The highest character is ', Highest, ' with ', Counters[Highest], ' occurrences.');
ReadLn;
end.
In less academic setups, using an array like this might not be the most efficient, because it contains a counter for every possible character, including those that don't occur in the string at all. That means, if you want to use this exact code for every possible character in the unicode table, your array would be a couple of megabytes large (still not really a problem on modern computers, but still).
You can improve this code by using a kind of dictionary or list to keep track of the items, so you need only to add those items you find, but if you have to write that yourself, it will make your program quite a bit larger.
EDIT:
As per request in comment: Counting the longest subsequent range of characters:
program Task;
{$APPTYPE CONSOLE} // For Delphi
var
s: String;
i: Integer;
Longest: Integer;
Current: Integer;
LongestChar: Char;
begin
s := 'aabbbbccbbb';
Longest := 0;
Current := 0;
// Count the characters.
for i := 1 to Length(s) do
begin
Inc(Current);
// If it's the last char or the next char is going to be different, restart the counting.
if (i = Length(s)) or (s[i] <> s[i+1]) then
begin
if Current > Longest then
begin
Longest := Current;
LongestChar := s[i];
end;
Current := 0;
end;
end;
// Output that character and its count.
WriteLn('The highest character is ', LongestChar, ' with ', Longest, ' occurrences.');
ReadLn;
end.
Current > Longest makes sure the first longest sequence is returned in case multiple character sequences have the same length. Change to Current >= Longest if you want the last sequence instead.

Pascal: Got to subtract 1 from length to get right size

I've got a piece of code like this:
for I := 0 to Self.EventQueue.Count do
Dispose(Self.EventQueue[I]);
It bugs out when the Count is 0, because it tries to Dispose a nonexisting element. When I change it to
for I := 0 to Self.EventQueue.Count-1 do
Dispose(Self.EventQueue[I]);
All works fine. Is there any elegant way to get around this or is this common practice?
This is absolutely normal behavior, and is documented in the help for every list and container class in Delphi/FreePascal. The reason is pretty clear - if you have three items in the list, and the first item is at index 0, then you have items 0, 1, 2 but a Count of 3, right?
for i := 0 to StringList.Count - 1 do // TStringList
for i := 0 to List.Count - 1 do // TList
for i := 0 to StringGrid1.ColCount do // TStringGrid
The alternative isn't as clear (and to me is worse to type):
for i := 0 to Pred(StringList.Count) do
Dynamic arrays start at index 0 as well.
var
IntArray: array of Integer;
i: Integer;
begin
SetLength(IntArray, 10);
for i := Low(IntArray) to High(IntArray) do // loop is 0..9
//
end;
The only things that aren't 0 based in FPC/Delphi are string types, which start at 1, and non-dynamic arrays (ones that are declared with a fixed size in code), which can start at almost any index you want. For instance, this is perfectly legal:
var
IntArray: array[-10..10] of Integer;
i: Integer;
begin
for i := Low(IntArray) to High(IntArray) do // loop is -10..10
//
end;
Just as an aside, any time you do anything in your loop that will reduce the number of items in your list, you should iterate backwards:
for i := List.Count - 1 downto 0 do
Otherwise, you'll iterate beyond the end of the list, because the Count is only evaluated at the time the loop starts.
Omg. That's because in cycle from 0 to Self.EventQueue.Count you iterate through Self.EventQueue.Count + 1 items.
I prefere to use
for I := 1 to Self.EventQueue.Count do
Dispose(Self.EventQueue[I-1]);
That way it is clear that nothing happens if the count is zero and the correction of the index happens at the place where it matters

Short VHDL for loop code i dont understand

I do understand how to convert a binary number into a decimal number but the following code thats supposed to do that doesnt make sense. I mean lets sat we have a binary number 10, then v(i) would be 0, so result stays 0. Upon the next iteration v(i) will be 1 so result will be 0 + 1 . The loop stops and the function will return the value of result which is 1 and not 2 which is the value of the binary number put into the function. Could someone tell me why I am wrong? This code comes with a university assignment so it should be correct. Thanks. :)
-------------------------------------------------------------------------------
-- convert std_logic vector v to natural
-------------------------------------------------------------------------------
FUNCTION s2n(v: std_logic_vector)
RETURN natural IS
VARIABLE result: natural := 0;
BEGIN
FOR i IN v'range LOOP
result := result * 2;
IF v(i) = '1' THEN
result := result + 1;
END IF;
END LOOP;
RETURN result;
END s2n;
The 'range loop works from left to right. The convention is for the most-significant bit to be on the left
By decoding that first, the *2 operation gets run most times on the MSB as you'd expect.
(BTW, if you want the range to go the other way for some reason, you can use the 'reverse_range attribute)

Resources