PNG-Info


Terry  2024-04-21 09:10:47  No: 151459  IP: 192.*.*.*

低空飛行しながら車輪の再発明的なことが大好きな私ですm(_ _)m

PNG-Info を取得するのは Python で数行で出来たのですが Delphi でやってみようとして行き詰まってしまいました

最初 TMemoryStream で1バイトずつ読み込んでいたのですが TPngImage が TChunk で分かれていることを(今更)知り
TChunktEXt を使いましたが日本語が入っているとアドレス違反が起きます
(pngimage.pas の中の Text が AnsiString で扱われているから?)

そこで初心に戻り ChunktEXt 領域だけを取り出し System.Move するとエラーも出ず日本語も化けることなく取り出せました
(ここまでは1バイトずつ読み込んでいた時と同じ結果でした)

しかし「é」の様なアクセント文字が化けてしまいます
参照画像→https://files.catbox.moe/v9gotm.png
「Negative prompt: 3D, CGI, render, photo, text, watermark, low-quality, signature, moiré」

その部分は本来「C3 A9」になると思うのですが自分のコードで読んでもバイナリエディタ「edbin」で読んでも「E9」です
Delphi2009 だからか?と Delphi 11 CE でも試しましたが同じでした
Pythonプログラムや巷にあるウェブのPNG-Infoサービスでは問題なく表示出来ているので私の読み込み方が間違っているとは思うのですが
何かヒントがあればお教えください

編集 削除
AAAAA  2024-04-21 13:54:42  No: 151461  IP: 192.*.*.*

>その部分は本来「C3 A9」になると思うのですが自分のコードで読んでもバイナリエディタ「edbin」で読んでも「E9」です

UTF8 なら C3 A9 ですが E9 なので UNICODE 
https://0g0.org/unicode/00E9/


var
    I,J: Integer;
    PNG: TPNGImage;
    C: TChunk;
    T: TChunktEXt;
    U: UnicodeString;
begin
    PNG := TPngImage.Create;
    PNG.LoadFromFile('v9gotm.png');

    for I:=0 to PNG.Chunks.Count - 1 do
    begin
      C := PNG.Chunks.Item[I];
      if C is TChunkTEXT then
      begin
        T  := TChunktEXt(C);
        U := '';
        for J := 1 to ByteLength(T.Text) do
        begin
          U := U + Chr(Byte(T.TEXT[J]));
        end;
        Memo1.Lines.Add(U);
      end;
    end;
    PNG.Free;

編集 削除
Terry  2024-04-21 15:33:42  No: 151462  IP: 192.*.*.*

ありがとうございます
「é」もちゃんと取得出来ました

最初にてテストしていた日本語混じりの時が UTF8 だったので決めつけていました
その日本語混じりの画像の方
参照画像:https://files.catbox.moe/cbdhu3.png
では if C is TChunkTEXT then を通らなかったので調べると
こちらの Chunk.Name は 「iTXt」で iTXt チャンクという別物なのですね

取りあえず夜も更けてきましたのでやっつけで読み込めました
var
    I,J,K: Integer;
    PNG: TPNGImage;
    C: TChunk;
    T: TChunktEXt;
    U: UnicodeString;
    P: Char;
    PB:PByte;
    U8:UTF8String;
    B:TBytes;

        if C.Name ='tEXt' then
        begin
          T  := TChunktEXt(C);
          U := '';
          for J := 1 to ByteLength(T.Text) do
          begin
            U := U + Chr(Byte(T.TEXT[J]));
          end;
          Memo1.Lines.Add(U);
        end else
        if C.Name ='iTXt' then
        begin
          SetLength(B,C.DataSize);
          PB:=C.Data;
          for J := 1 to C.DataSize do
          begin
            if PB^<>$00 then//何故かヌル文字入ってる
            begin
              B[K]:= Byte(PB^);
              Inc(K);
            end;
            Inc(PB);
          end;

          Memo1.Text:=TEncoding.UTF8.GetString(B);
        end;
……ポインタは苦手です

編集 削除