Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как быстро загрузить и отобразить JPEG ? [D7]


Страницы:   1 2

alexandr-m ©   (2005-08-09 18:15:00) 

Все примеры которые были найдены в сети - медленные. Картинка JPEG с современного фотоаппарата размером 5Мб грузится и отображается минимум 1.5-2 секунды. Хочется сделать этот процесс моментальным.
Скажем фоновая подгрузка следующей картинки для последующего моментального отображения.


Alexander Panov   (2005-08-15 18:28:00) [1]

   PJ.Release;
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
   s: String;
   fr: TFileRecArray;
   i: Integer;
begin
  s := DirSelect('e:\data\photo');
  if s='' then Exit;
  GetFilesSimple(s,fr);
  lb.Items.Clear;
  for i := Low(fr) to High(fr) do
  begin
   lb.Items.Add(fr[i].FilePath);
  end;
  lb.ItemIndex := 0;
  LastIndex := 0;
  if (PJ.FStatus<>psProcess) and (lb.Items.Count>1) then PJ.Load(lb.Items[1]);
end;

procedure TForm1.lbClick(Sender: TObject);
var
   Index: Integer;
begin
   Index := lb.ItemIndex;
   if Index=LastIndex then
   begin
       if PJ.FStatus=psComplete then im.Picture.Assign(PJ.JpegImage);
       Exit;
   end;
   if PJ.FStatus=psComplete then im.Picture.Assign(PJ.JpegImage);
   if PJ.FStatus=psNone then
   begin
       PJ.Load(lb.Items[Index],pwWait);
       im.Picture.Assign(PJ.JpegImage);
   end;
   if Index>LastIndex then
   begin
       if Index+1<lb.Items.Count then
       begin
           LastIndex := Index;
           Index := Index+1;
           PJ.Load(lb.Items[Index]);
       end;
   end
   else
   begin
       if Index-1>=0 then
       begin
           LastIndex := Index;
           Index := Index-1;
           PJ.Load(lb.Items[Index]);
       end;
   end;
end;

end.


Как должен работать - смотри по коду, разбирайся.
Я отлаживать до конца не стал, но общая идея, работа с потоком понятна.

Вот ссылка на проект:
ftp://ftp.almar.net.ru/pub/pload/pload.zip


Alexander Panov   (2005-08-15 18:28:00) [2]

Вот написал примерный код:


{$WARN UNIT_PLATFORM OFF}
{$WARN SYMBOL_PLATFORM OFF}

unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, ComCtrls, Buttons, ExtCtrls, StdCtrls, ToolWin, JPeg,FIleCtrl;

type

 PFileRec=^TFileRec;
 TFileRec=record
   FilePath: String;
   FullFileName: String;
   FileName: String;
   FileExt: String;
   FileSize: Integer;
   isDir: Boolean;
 end;
 TFileRecArray=array of TFileRec;

 EErrorJpeg=Exception;
 TPreloadStatus=(psNone,psProcess,psComplete);
 TPreloadWait=(pwWait);
 TCompleteProc=procedure(const FilePath: String) of  object;

 TPreloadJpeg=class(TThread)
 private
   FFilePath: String;
   FJpeg: TJpegImage;
   FComplete: TCompleteProc;
   FStatus: TPreloadStatus;

   procedure FOnComplete;
   function GetJpegImage: TJpegImage;

 protected
   procedure Execute; override;
 public
   constructor Create;
   destructor Destroy; override;
   procedure Release;

   procedure Load(const FilePath: String); overload;
   procedure Load(const FilePath: String;aWait: TPreloadWait); overload;

   property OnComplete: TCompleteProc read FCOmplete write FComplete;
   property Status: TPreloadStatus read FStatus;
   property JpegImage: TJpegImage read GetJpegImage;

 end;

 TForm1 = class(TForm)
   sb: TStatusBar;
   ToolBar1: TToolBar;
   lb: TListBox;
   im: TImage;
   SpeedButton1: TSpeedButton;
   procedure FormCanResize(Sender: TObject; var NewWidth,
     NewHeight: Integer; var Resize: Boolean);
   procedure FormCreate(Sender: TObject);
   procedure FormClose(Sender: TObject; var Action: TCloseAction);
   procedure SpeedButton1Click(Sender: TObject);
   procedure lbClick(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

function DirSelect(const RootDir: String): String;

var
 Form1: TForm1;
 PJ: TPreloadJpeg;
 LastIndex: Integer;

implementation

{$R *.dfm}
function GetFileName(const FullFileName: String): String;
var
 i: Integer;
begin
 Result := FullFileName;
 for i := Length(FullFileName) downto 1 do
 begin
   if FullFileName[i]='.' then
   begin
     Result := Copy(FullFileName,1,i-1);
     Break;
   end;
 end;
end;

function GetFileExt(const FullFileName: String): String;
var
 i: Integer;
begin
 Result := '';
 for i := Length(FullFileName)-1 downto 1 do
 begin
   if FullFileName[i]='.' then
   begin
     Result := Copy(FullFileName,i+1,Length(FullFileName)-i);
     Break;
   end;
 end;
end;

procedure GetFilesSimple(const aPath: String;var FileArr: TFileRecArray);
var
 SR: TSearchRec;
 tPath: String;
begin
 tPath := IncludeTrailingBackSlash(aPath);
 if FindFirst(tPath+'\*.*',faAnyFile,SR)=0 then
 begin
   try
     repeat
       if (SR.Name='.') or (SR.Name='..') then Continue;
       if (SR.Attr and faDirectory)<>0 then
       begin
           Continue;
         SetLength(FileArr,Length(FileArr)+1);
         FileArr[High(FileArr)].FilePath := tPath+SR.Name;
         FileArr[High(FileArr)].FullFileName := SR.Name;
         FileArr[High(FileArr)].FileName := GetFileName(SR.Name);
         FileArr[High(FileArr)].FileName := GetFileExt(SR.Name);
         FileArr[High(FileArr)].isDir := True;
         GetFilesSimple(tPath+SR.Name,FileArr);
       end;
       if UpperCase(GetFileExt(SR.Name))='JPG' then
       begin
           SetLength(FileArr,Length(FileArr)+1);
           FileArr[High(FileArr)].FilePath := tPath+SR.Name;
           FileArr[High(FileArr)].FullFileName := SR.Name;
           FileArr[High(FileArr)].FileName := GetFileName(SR.Name);
           FileArr[High(FileArr)].FileExt := GetFileExt(SR.Name);
           FileArr[High(FileArr)].FileSize := SR.Size;
           FileArr[High(FileArr)].isDir := False;
       end;
     until FindNext(SR)<>0;
   finally
     Sysutils.FindClose(SR);
   end;
 end;
end;

procedure TForm1.FormCanResize(Sender: TObject; var NewWidth,
 NewHeight: Integer; var Resize: Boolean);
begin
   sb.Panels[0].Width := Form1.ClientWidth-30;
end;

function DirSelect(const RootDir: String): String;
var
 Dir: String;
begin
 Dir := RootDir;
 if SelectDirectory(
      Dir,
      [sdAllowCreate, sdPerformCreate, sdPrompt],
      0)
   then Result := Dir
   else Result := '';
end;

{ TPreloadJpeg }

constructor TPreloadJpeg.Create;
begin
   inherited Create(True);
   FreeOnTerminate := True;
   FJpeg := TJpegImage.Create;
   FStatus := psNone;
   Resume;
end;

destructor TPreloadJpeg.Destroy;
begin
 FJpeg.Free;
 inherited;
end;

procedure TPreloadJpeg.Execute;
begin
   while not Terminated do
   begin
       Suspend;
       if Terminated then Break;
       try
           FJpeg.LoadFromFile(FFilePath);
           Synchronize(FOnComplete);
       except
           fStatus := psNone;
       end;
   end;
end;

procedure TPreloadJpeg.FOnComplete;
begin
   FStatus := psComplete;
   if Assigned(FComplete) then FComplete(FFilePath);
end;

function TPreloadJpeg.GetJpegImage: TJpegImage;
begin
 if FStatus = psProcess then raise EErrorJpeg.Create('Не закончена загрузка рисунка');
 if FStatus = psNone then REsult := nil else Result := FJpeg;
end;

procedure TPreloadJpeg.Load(const FilePath: String);
begin
   if FStatus = psProcess then raise EErrorJpeg.Create('Не закончена загрузка предыдущего рисунка');
   fStatus := psProcess;
   If FilePath=FFilePath then Exit;
   FFilePath := FilePath;
   Resume;
end;

procedure TPreloadJpeg.Load(const FilePath: String; aWait: TPreloadWait);
begin
   Load(FilePath);
   while FStatus<>psComplete do Sleep(1);
end;

procedure TPreloadJpeg.Release;
begin
   Terminate;
   Resume;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
   PJ := TPreloadJpeg.Create;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin


alexandr-m   (2005-08-15 16:04:00) [3]

http://www.delphimaster.ru/cgi-bin/forum.pl?id=1124107398&n=7

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


Alexander Panov   (2005-08-15 15:47:00) [4]

Ты бы код потока привел лучше.


alexandr-m   (2005-08-15 15:34:00) [5]

уже прописал, я же написал выше.
В обоих модулях пропиши uses друг друга.


miek   (2005-08-15 10:56:00) [6]

В обоих модулях пропиши uses друг друга.


alexandr-m   (2005-08-14 17:22:00) [7]

по идее должно вызываться типа

Synchronize(UpdateCaption);

пишу Synchronize(unit1.LoadNextImage(execute));

ошибка missing operator.

как блин вызвать эту процедуру с потоком?


alexandr-m   (2005-08-14 17:13:00) [8]

С этим разобрался надо было прописать

implementation

uses unit1;

теперь не могу вызвать эту процедуру прописанную в другом юните:

procedure LoadNextImage.execute;
begin
 SetName;
 { Place thread code here }

Form1.Image3.Picture.LoadFromFile('c:\1YPB290681.JPG');

end;

пишу в первой форме:
unit1.LoadNextImage(execute);

ошибка: Undeclared Indetifier Form1


alexandr-m   (2005-08-14 16:27:00) [9]

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

>Загружай в отдельном потоке с пониженным приоритетом.

Именно это и хочу сделать. Создал новый поток, но не могу из него вызвать компонент из первой формы, на попытку

Form1.Image2.Picture.LoadFromFile('c:\1YPB290680.JPG');

из нового Unit1.pas в котором создался этот Thread пишет:

Undeclared Indetifier Form1


alexandr-m   (2005-08-14 16:07:00) [10]

test


Jeer   (2005-08-12 12:27:00) [11]

P-IV 2G
jpg 96% 4M 3000x3000 310 ms


Sapersky   (2005-08-12 11:41:00) [12]

Понял в чём дело - IJL быстрее при выключенном Smoothing (для качественной картинки он и не нужен).
В TBumpForm.LoadImage:
LoadJPGFile(Tmp,FileName,False);


Sapersky   (2005-08-12 11:10:00) [13]

Значит качественную картинку в 5 метров с цифровика с хорошим качеством IJL: 820 мс *2= 1640 мс т.е. 1.5 секунды - это уже тормозззззззззз

820 мс - это результат весьма престарелого по нынешним временам процессора... (P3-667)

загрузка 5-меировой картинки те же 1.5 сек что и у делфийского TImage

Странно. У меня IJL стабильно быстрее (протестировал ещё с 7 мб файлом). Или - как посмотреть - TImage/KOLJpegObj медленнее (думал на версию Дельфи - но в 5 и 7, во всяком случае, всё практически одинаково, 7 даже несколько медленнее).

Процессор не Athlon? Может, IntelJpeg Library с ним принципиально не хочет быстро работать.

Ещё зависит от типа файла. Прогрессивные JPG, например, грузятся медленнее, и IJL на них даёт меньшее ускорение (но оно есть - в 1.5 раза).


Alexander Panov   (2005-08-11 21:25:00) [14]

alexandr-m ©   (11.08.05 20:09) [12]
Это я и хочу сделать, но во время загрузки следующей картинки прога висит


Загружай в отдельном потоке с пониженным приоритетом.


alexandr-m   (2005-08-11 20:21:00) [15]

> http://prdownloads.sourceforge.net/skinner/FastLib.zip?download

загрузка 5-меировой картинки те же 1.5 сек что и у делфийского TImage


alexandr-m   (2005-08-11 20:21:00) [16]

> http://prdownloads.sourceforge.net/skinner/FastLib.zip?download

загрузка картинки 1.5 метра те же 1.5 сек что и у делфийского TImage


alexandr-m   (2005-08-11 20:12:00) [17]

>Та же картинка с хорошим качеством (2.5 мб):

>KOLJpegObj: 3000 мс
>IJL: 820 мс

Значит качественную картинку в 5 метров с цифровика с хорошим качеством IJL: 820 мс *2= 1640 мс т.е. 1.5 секунды - это уже тормозззззззззз. Пробовал проги которые пользуют IJL именно такое время у них и уходит на это. Да и ACDCEE не чемпион при больших картинках так же тормозит.


alexandr-m   (2005-08-11 20:09:00) [18]

>ACDSee используется не кэширование, а предзагрузка. Т.е. при >последовательном просмотре рисунков программа предварительно >загружает следующий по списку файл в отдельный буфер и >обрабатывает его. При переходе пользователем на след. рисунок >загруженный рисунок уже не загружается, а лишь отображается на >экране.

Это я и хочу сделать, но во время загрузки следующей картинки прога висит, так как идёт процесс считывания с винта этих 5 Мб. Отображается потом моментально, а вот как сделать этот процесс загрузки низкоприоритетным чтобы он не вешал всё остальное и можно было жмакать на кнопки и т п.


Sapersky   (2005-08-11 10:42:00) [19]

Загрузка на P3-667 картинки 4096 * 4096, ужатой до 500 кб:

KOLJpegObj (аналог стандартного jpeg.pas): 2700 мс
IJL: 710 мс

Та же картинка с хорошим качеством (2.5 мб):

KOLJpegObj: 3000 мс
IJL: 820 мс

Единственный недостаток IJL - относительно большой размер (DLL в 370 кб, тот же JpegObj - около 70 кб). Хотя и 370 кб по современным меркам немного.

Пример использования:
http://prdownloads.sourceforge.net/skinner/FastLib.zip?download


miek   (2005-08-11 09:50:00) [20]

>ACDSEE - кеширует! так что Ваше предположение - бред!

Одно другому не мешает. Да, кэширует.

Но даже если картинки нет в кэше, он работает быстро. Тут, правда, есть одно "но" - какой номинальный размер у картинки? 800x600 или 3000x3000? И то и другое можно сжать в 5МБ. Для первого случая 1,5 сек много.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо