2
votes

Using this (test) code to read a tEXt chunk from a PNG:

procedure TForm1.Button1Click(Sender: TObject);
var
  PngVar: TPngImage;
  n: Integer;
begin
  PngVar := TPNGImage.Create;
  PngVar.LoadFromFile('C:\test.png');
  for n := 0 to pred(PngVar.Chunks.count) do
  if PngVar.Chunks.item[n].Name='tEXt' then
  with PngVar.Chunks.item[n] as TChunkTEXT do
  memo1.lines.add(KeyWord+'='+Text);
end;

The code is from an example by the original author of the TPNGObject and was downloaded from embercardo's website. KeyWord contains the value of what the tEXt chunk is, in this case comment. Text contains the text we need. It is an AnsiString and should have breaks in them but when casting from AnsiString to unicode they are lost and it becomes one string with not even a space between the end and start of a line.

Stepping through the debugger I noticed It had each line in single quotes and between the lines it has #$A which I assume if I check in hex are some form of control character.

comment=PunkBuster Screenshot (ñ) BF3 Levels/MP_017/MP_017'#$A'1135998 31.204.131.11:25530 GoTBF3.nl #4 | 32p | TDM Canals Only | 500 Tickets'#$A'geawtaw46y4w63a46a34643a BorislavFatsolka'#$A'Attempted: w=320 X h=240 at (x=50%,y=50%)'#$A'Resulting: w=320 X h=200 sample=1'

Sample Image http://www.pbbans.com/pbss_evidence/bf3/31.204.131.11:25530/5d00a95d22fae4a287bd510c076db1bf-2e36c3b4.png Here is the sample. What I am doing is reading data off punkbuster images to make them searchable in our communities database. But I also display the information next to the image and id like to have the line breaks and or know when the line ends.

When placed into memo or string list directly it comes out all one line like:

comment=PunkBuster Screenshot (ñ) BF3 Levels/MP_017/MP_0171135998 31.204.131.11:25530 GoTBF3.nl #4 | 32p | TDM Canals Only | 500 Tickets*geawtaw46y4w63a46a34643a* BorislavFatsolkaAttempted: w=320 X h=240 at (x=50%,y=50%)Resulting: w=320 X h=200 sample=1

Question

What is the best way to handle this ansistring which is what it is from the original image and or TPNGImage no real choice there. Putting it into a memo, rich edit or string list with the breaks intact.

The first thing that comes to mind is probably inefficient and thats just to throw it into a byte array or the like and read it byte by byte cutting each line at the end of line marks.

More Data from the example You should be able to see this by downloading the example image but, this is how it looks in a hex editor (First part of the file intact, png header, tEXt chunk header keyword etc.

‰PNG........IHDR...Ž...2.....ûŒÆ$....tEXtcomment.PunkBuster Screenshot (ñ) BF3  Levels/MP_017/MP_017.1135998 31.204.131.11:25530 GoTBF3.nl #4 | 32p | TDM Canals Only | 500 Tickets.*geawtaw46y4w63a46a34643a* BorislavFatsolka.Attempted: w=320 X h=240 at (x=50%,y=50%).Resulting: w=320 X h=200 sample=1.

89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 00 00 02 8E 00 00 01 32 08 02 00 00 00 FB 8C C6 24 00 00 01 03 74 45 58 74 63 6F 6D 6D 65 6E 74 00 50 75 6E 6B 42 75 73 74 65 72 20 53 63 72 65 65 6E 73 68 6F 74 20 28 F1 29 20 42 46 33 20 20 4C 65 76 65 6C 73 2F 4D 50 5F 30 31 37 2F 4D 50 5F 30 31 37 0A 31 31 33 35 39 39 38 20 33 31 2E 32 30 34 2E 31 33 31 2E 31 31 3A 32 35 35 33 30 20 47 6F 54 42 46 33 2E 6E 6C 20 23 34 20 7C 20 33 32 70 20 7C 20 54 44 4D 20 43 61 6E 61 6C 73 20 4F 6E 6C 79 20 7C 20 35 30 30 20 54 69 63 6B 65 74 73 0A 2A 67 65 61 77 74 61 77 34 36 79 34 77 36 33 61 34 36 61 33 34 36 34 33 61 2A 20 42 6F 72 69 73 6C 61 76 46 61 74 73 6F 6C 6B 61 0A 41 74 74 65 6D 70 74 65 64 3A 20 77 3D 33 32 30 20 58 20 68 3D 32 34 30 20 61 74 20 28 78 3D 35 30 25 2C 79 3D 35 30 25 29 0A 52 65 73 75 6C 74 69 6E 67 3A 20 77 3D 33 32 30 20 58 20 68 3D 32 30 30 20 73 61 6D 70 6C 65 3D 31 0A

Other Findings If I dump the Chunk (PngVar.Chunks.item[n].SaveToStream) it gives me basically what we find in the hex editor. The control characters are 0A. I am not sure if the #$A is a before or after conversion effect maybe even being caused by the pngimage code.

2
what is s and what do you mean by "returns the data"?Igor
The code is from the example by the author who did TPNGObject/TPNGImage originally as downloaded from embercardo. S represents a TStringList in that example. In my test code I had it as Memo1.Lines.Add. I lost the example i had going because it was not saved. In the end anything this is going into is using unicode strings. Explaining what I mean by returns the data will not do anything for you. It returns the data we request. The data is an ansistring which has line breaks but they are lost.Brian Holloway
I will edit to add some more code if someone wants to try it out and add an image from pbbans that is public in a few minutes here.Brian Holloway
#$0A is the same as #10, chr(10), or chr($A) also known as CR (Carriage Return). In windows that's half line break, since the line break is a CR+LF pair (LF is #$0D or #13). If you save it to a file, the notepad will show it also without the line breaks. Usually Delphi manages it for you in a transparent way. You may be confused also for the $ notation, which is equivalent to c 0x, meaning the following number is represented in hexadecimal. so, $0A is the same as 0x0A, or simply, 10.jachguate
Other Delphi notation is #, which represent a character by its ASCII value, and it's mostly used to show non printable characters. For example #65 is 'A'. You can combine both notations like #$41 to represent the same 'A' character.jachguate

2 Answers

2
votes

Try:

memo1.lines.add(KeyWord+'='+StringReplace(Text,#10,sLineBreak,[rfReplaceAll]));
1
votes

Another approach would be Jedi CodeLib

sl := TJclStringList.Create;
sl.Split(Text, #10);
sl[0] := 'Keyword=' +sl[0]
memo1.lines.AddStrings(sl);
sl.Free;