Проблема с загрузкой png изображения из inifile

Я сохраняю PNG-изображение в Ini-файле со следующим кодом:

procedure TfrmParametres.SaveIni;
var
  IniFile: TIniFile;
  MS: TMemoryStream;
  PNG: TPngImage;
begin
  IniFile := TIniFile.Create(IniFileName);
  try
  PNG := TPngImage.Create;
  try
    PNG.LoadFromFile(edtLogo.Text);//edtlogo contain image file path
    MS  := TMemoryStream.Create;
    try
      PNG.SaveToStream(MS);
      MS.Seek(0, 0);
      IniFile.WriteBinaryStream('REPORT_HEADER', 'LOGO', MS);
    finally
      MS.Free;
    end;
  finally
    PNG.Free;
  end;
finally
  FreeAndNil(IniFile);
end;
end;

и чтобы показать картинку в другой форме события OnShow я использовал тот же подход:

  1. Загрузить данные в объект TMemoryStream
  2. Загрузить данные из MemoryStream в объект TPngImage
  3. Показать картинку в компоненте TImage

    procedure TfrmLoadPicture.FormShow(Sender: TObject);
    var
      IniFile: TIniFile;
      MS: TMemoryStream;
      PNG: TPngImage;
    begin
      IniFile:= TIniFile.Create(frmParametres.IniFileName);
      try
        MS:= TMemoryStream.Create;
        try
          IniFile.ReadBinaryStream('REPORT_HEADER', 'LOGO', MS);
          PNG := TPngImage.Create;
          try
            MS.Seek(0, 0);
            PNG.LoadFromStream(MS);
            Image.Picture.Assign(PNG);
          finally
            PNG.Free;
          end;
        finally
          MS.Free;
        end;
      finally
        IniFile.Free;
      end;
    end;
    

однако я всегда получаю ошибку исключения:

2 ответа

Решение

TIniFile имеет жестко ограниченный размер любого значения, которое он может прочитать, частично из-за того, что в основе лежит API Windows (GetPrivateProfileString и друзья) не позволяет запрашивать размер сохраненного значения. IMO TIniFile должно действительно вызывать исключение при попытке записать большее значение, но независимо от того, если вы используете TMemIniFile вместо TIniFile у вас должно быть все в порядке (я только что попробовал).

Крис ответил на прямой вопрос, который вы задали. У меня есть некоторые другие комментарии.

Нет необходимости декодировать PNG для передачи его в INI-файл

Вы можете скопировать файл напрямую, без декодирования PNG и последующей перекодировки.

Stream := TFileStream.Create(FileName, fmOpenRead);
try
  IniFile.WriteBinaryStream('REPORT_HEADER', 'LOGO', Stream);
finally
  Stream.Free;
end;

Шестнадцатеричное кодирование неэффективно

WriteBinaryStream не очень эффективный способ кодировать двоичный файл как текст. Фактически вы используете base16, и было бы более обычным и эффективным использовать base64.

Я предлагаю вам закодировать поток двоичных файлов в строку base64 и записать эту строку в файл INI.

INI-файлы не подходят для двоичных данных

Файлы INI никогда не предназначались для хранения больших двоичных двоичных объектов. При первом осмотре может показаться странным, что вы пытаетесь вставить PNG-изображение в INI-файл.

Другие вопросы по тегам