![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как быстро загрузить и отобразить JPEG ? [D7]
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 сек много.