Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.01.22;
Скачать: CL | DM;

Вниз

Как быстро загрузить и отобразить JPEG ?   Найти похожие ветки 

 
alexandr-m ©   (2005-08-09 18:15) [0]

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


 
Eraser ©   (2005-08-09 20:28) [1]

alexandr-m ©   (09.08.05 18:15)

Скорее всего быстрее вряд ли получится. Скорость ограничена ресурсами конкретного компьютера. А декодирование jpeg картинки достаточно "процессороёмкий" процесс.


 
alexandr-m ©   (2005-08-09 23:22) [2]

а нельзя ли этот  "процессороёмкий" процесс проводить в фоновом режиме подгружая следующую картинку пока юзер смотрит на ту которая загрузилась?


 
Eraser ©   (2005-08-09 23:52) [3]

alexandr-m ©   (09.08.05 23:22) [2]

Можно! А какие проблемы в реализации этого?


 
programania ©   (2005-08-10 03:52) [4]

Для ускорения загрузки Jpeg можно ещеTJPEGScale = (jsFullSize, jsHalf, jsQuarter, jsEighth);грузить сначала не jsFullSize и показывать все равно большая картинка в экран не влезета потом jsFullSize уже незаметно пока что-то не нажмути вначале делать масштабирование не качественно но быстро, а потом уже улучшено.А для картинок больше 1mb лучше заранее сделать миниатюры.


 
miek ©   (2005-08-10 09:09) [5]

В принципе, 2 секунды на такой файл это много, ACDSEE распаковывает значительно быстрее. Значит, надо искать в сети более быстрый модуль для декодирования. Или библиотеку. IJL (Intel JPEG Library) здесь первый кандидат.


 
WondeRu ©   (2005-08-10 15:30) [6]

miek ©   (10.08.05 9:09) [5]
ACDSEE распаковывает значительно быстрее

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


 
Ландграф Павел ©   (2005-08-10 20:16) [7]

И куда он их кеширует? имхо такой же бред, что, всю папку в 2 гега jpg`ов можно прокешировать? Специально провел тест и именно 2 гега скопировал всех моих картинок из разных папок в одну и все файлы переименовал, открывается ТАКЖЕ БЫСТРО!


 
Alexander Panov ©   (2005-08-10 20:38) [8]

Ландграф Павел ©   (10.08.05 20:16) [7]

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


 
Ландграф Павел ©   (2005-08-10 21:57) [9]

Ну в принципе я так думал, что в отдельном потоке обрабатываются след. картинка по списку, ну и библиотека загрузки думаю тоже не малую роль вносит... на асме будет веселее чем на языках высокого уровня


 
miek ©   (2005-08-11 09:50) [10]

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

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

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


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

Загрузка на 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


 
alexandr-m ©   (2005-08-11 20:09) [12]

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

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


 
alexandr-m ©   (2005-08-11 20:12) [13]

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

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

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


 
alexandr-m ©   (2005-08-11 20:21) [14]

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

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


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

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

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


 
Alexander Panov ©   (2005-08-11 21:25) [16]

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


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


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

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

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

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

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

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

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


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

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


 
Jeer ©   (2005-08-12 12:27) [19]

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


 
alexandr-m ©   (2005-08-14 16:07) [20]

test


 
alexandr-m ©   (2005-08-14 16:27) [21]

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

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

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

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

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

Undeclared Indetifier Form1


 
alexandr-m ©   (2005-08-14 17:13) [22]

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

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 17:22) [23]

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

Synchronize(UpdateCaption);

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

ошибка missing operator.

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


 
miek ©   (2005-08-15 10:56) [24]

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


 
alexandr-m ©   (2005-08-15 15:34) [25]

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


 
Alexander Panov ©   (2005-08-15 15:47) [26]

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


 
alexandr-m ©   (2005-08-15 16:04) [27]

http://delphimaster.net/view/8-1124107398/

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


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

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


{$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


 
Alexander Panov ©   (2005-08-15 18:28) [29]

   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



Страницы: 1 вся ветка

Текущий архив: 2006.01.22;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.045 c
2-1136673586
KvORubin
2006-01-08 01:39
2006.01.22
Мастера ХЕЛП !!! Как получить список имён файлов из каталога???


2-1135865632
Dyakon_Frost
2005-12-29 17:13
2006.01.22
Найти среднее геометрическое!


2-1136561798
Dot
2006-01-06 18:36
2006.01.22
найти и удалить текст


8-1124134643
Никита
2005-08-15 23:37
2006.01.22
Как залить замкнутый участок в Canvas каким либо цветом


9-1123882414
Будулай
2005-08-13 01:33
2006.01.22
Почему А* не всегда ищет оптимальный путь ? И как поправить ?