Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Звук, графика и видео > GDI+: Загрузка PNG из потока


Автор: JohnJ2 21.4.2009, 11:36
Здравствуйте! Не могу разобраться в следующей ситуации:
Загружаю картинку из потока:
Код

procedure TTestGDIP.GDIPLoadImage(aStream: TStream);
var imgFile: TGPImage; 
    aptr: IStream;
begin
  aStream.Seek(0, soFromBeginning);
  aptr := TStreamAdapter.Create(aStream, soReference) as IStream;
  imgFile := TGPImage.Create(aptr); //создаем класс используя поток
  GDIPLoadTGPImage(imgFile);
  imgFile.Free;//уничтожаем класс изображения
end;

Поток получаю от TIdHTTP.Get, которому задаю адрес любой картинки PNG (например: http://nigma.ru/themes/nigma/img/nigma-logo-small.png), и передаю в вышеприведённую процедуру.
Такой вариант работает, но! На строке "imgFile := TGPImage.Create(aptr);" появляется окошко с ассемблеровским кодом с заголовком "CPU". Содержимое выделенной строки (если как-то поможет) "7С90120F C3 ret". Чуть выше строчка "{ntdll.DbgBreakPoint}". Когда я закрываю это ассемблеровское окошко и нажимаю F9, то картинка рисуется как ни в чём не бывало. Если из потока сохранять сначала в файл и потом загружать из файла в TGPImage, то всё работает без проблем. А почему тут такая фигушка?
P.S.: Пробовал aptr создавать так: 
aptr := TStreamAdapter.Create(aStream, soReference);
Ничего не изменилось. 
Другие форматы картинок (bmp, jpg, gif) открываются без проблем, а при png возникает такое вот "прерывание".
Саму технологию загрузки в TGPImage изучал по статье: http://forum.vingrad.ru/faq/topic-157721.html
Нашёл, что и у других были подобные проблемы с png: http://www.rsdn.ru/Forum/Message.aspx?mid=386854, и найдено решение, но ссылка на приведённое решение не грузится.
Я плохо разбираюсь в английском, поэтмоу не понял, эта статья по теме или нет, но что-то тоже с проблемами png и gdi: http://lummie.co.uk/tstreamadapter-and-images/
Цитата
When trying to load / save PNG Images from a stream using GDI+ routines to load and save from IStream, there were problems, it turns out with the date/time information returned in the Istream Stats.

И если по теме, то как мне это можно использовать? smile
Заранее благодарен за Вашу помощь.

Автор: JohnJ2 21.4.2009, 12:21
Нашёл ответ, точнее мне помогли в другом месте.
Публикую решение сюда:
Как я понял, функция Stat у TStreamAdapter неправильно определяет дату и время png-файла. Чтобы это исправить, мы её перепишем:
Код

interface

type TMyStreamAdapter = class(TStreamAdapter)
      public
       function Stat(out statstg: TStatStg; grfStatFlag: longint): HResult; override; stdcall;
     end;

implementation

function TMyStreamAdapter.Stat(out statstg: TStatStg; grfStatFlag: Longint): HResult;

 function DateTimeToFileTime(DateTime: TDateTime): TFileTime;
  const FileTimeBase = - 109205.0;
        FileTimeStep: extended = 24.0 * 60.0 * 60.0 * 1000.0 * 1000.0 * 10.0; // 10 наносекунд в день
  var E: extended;
      F64: int64;
 begin
   E := (DateTime - FileTimeBase) * FileTimeStep;
   F64 := Round(E);
   Result := TFileTime(F64);
 end;

begin
  Result := S_OK;
  try
   if (@statstg <> nil) then
    with statstg do
     begin
       FillChar(statstg, sizeof(statstg), 0);
       dwType := STGTY_STREAM;
       cbSize := Stream.Size;
       mTime := DateTimeToFileTime(now);
       cTime := DateTimeToFileTime(now);
       aTime := DateTimeToFileTime(now);
       grfLocksSupported := LOCK_WRITE;
     end;
  except
   Result := E_UNEXPECTED;
  end;
end;

Не смотря на то, что я не понимаю назначения практически ни одной строчки вышеприведённого кода, это работает.
Использовать, в моём случае, так:
Код

procedure TTestGDIP.GDIPLoadImage(aStream: TStream);
var imgFile: TGPImage; 
    aptr: IStream;
begin
  aStream.Seek(0, soFromBeginning);
  aptr := TMyStreamAdapter.Create(aStream, soReference) as IStream;
  imgFile := TGPImage.Create(aptr); //создаем класс используя поток
  GDIPLoadTGPImage(imgFile);
  imgFile.Free;//уничтожаем класс изображения
end;

Что очень важно, остальные форматы картинок, которые поддерживались и ранее (jpg, bmp, gif) точно также открываются без ошибок, как и png сейчас.

Автор: Alexeis 21.4.2009, 13:40
Цитата(JohnJ2 @  21.4.2009,  11:21 Найти цитируемый пост)
Как я понял, функция Stat у TStreamAdapter неправильно определяет дату и время png-файла. Чтобы это исправить, мы её перепишем:

  Она просто не может ее определить, потому что такая информация не хранится. Тут похоже косяк в самом GDI+, который неправильно анализирует полученную информацию о дате. Просто нулевые значения его не устраивают, поэтому вместо нулевых туда записали текущие. 
  Хорошо что решился вопрос. Можно было поискать обновления библиотеки GDIPlus.dll

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)