Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Image Preview


Автор: z-END 15.8.2004, 21:34
Имеется ли какая-нить возможность получить превью картинки?
Я делаю это очень коряво, т.е. загружаю картинку целиком, а затем ужимаю то необходимого размера, но при больших размерах картинок (по несколько тыс. пискелей)а также их большом количестве этот процесс занимает огромную уйму времени, напорядок больше чем в ACDSee.

Автор: El Guapo 15.8.2004, 21:49
Не загрузив картинку целиком - нельзя, конечно. Откуда же тогда взять превью? Этого изображения больше нигде нет.

Но что вы называете "ужимаю"? Процедуру StretchDraw? Она конечно, медленнее. А если просто установить свойства Stretch и Proportional у TImage в true, то получается вовсе не медленней ACDSee. Во всяком случае, у меня на машине так.

Автор: z-END 15.8.2004, 22:04
Proportional я и ставлю...
Расскажу поподробней: имеется компонент типа TreeView к которому прицеплен ImageList (100x100) далее есть процедура которая проходит по заданному дереву каталогов и строит его в TreeView, и соответсвенно добавляет картинку в ImageList, но добавляется она так:
Создается (runtilme) TImage в которое загружается картинка, затем его размеры меняю на 100х100 и Proportional:=true; после чего создаю (runtime) TBitmap куда копирую (CopyRect) TImage.Graphic и уже этот TBitmap добавляю в ImageList.
Собственно эта часть мне больше всего и ненравится... Вот я и подумал что можно попроще как-то сделать

Автор: p0s0l 15.8.2004, 23:31
Тут день назад Illusion Dolphin что-то творил с превьюингом картинок. Как я понял, он работал с большим количеством картинок (4000), тоже ужимал их до 100x100. Может он с тобой поделится опытом ?...

Автор: El Guapo 15.8.2004, 23:45
Нет, менять размеры TImage вовсе не нужно! Нужно его Graphic "перерисовать" в TBitmap с помощью StretchDraw

Код

B:=TBitmap.Create;

try
  B.Width := 100;
  B.Height:= 100;
  B.Canvas.StretchDraw( B.Canvas.Cliprect, Image1.Picture.Graphic );
  ImageList1.Add(B,nil);
finally
  B.free;
end;


У меня получилось. Попробуйте, будет ли так быстрее?


Автор: Dynamic 16.8.2004, 07:53
Посмотрите этот http://www.delphipages.com/edit/count.cfm?ID=3795
Описание:
Цитата
TPrintPreview это наследник TScrollBox и имеет свойства классов TScrollBox control и TPrinter. Основные возможности TPrintPreview:
Поддержка всех режимов отображения
Автоподстройка под размер и ориетнтацию страницы во время печати
Страницы предпросмотра могут масштабироваться
Страницы могут быть сохранены и считаны с диска
Каждая страница доступна как изображение Windows MetaFile
Независимо от количества просматриваемых страниц и их сложности, занята небольшая часть ресурсов Windows
Имеет несколько методов для простого отображения rtf и изображений
Имеет полный набор событий

ЗЫ. Сам не пользовался (пока).

Автор: GRU 30.8.2004, 11:21
mne eta tema tozhe aktualna. V Photoshop'e FileBrowser ochen bystro pakazyvaet preview'u kartinki. Interesno po kakomu prinsipu on rabotaet. Ved sperva sasdaiot bystro ochen malenkie grubye kartinki, i tolko patom, pavtorno, ix "utachnaet", atkryvaet uzhe normalnovo kachestvo.

Автор: Illusion Dolphin 30.8.2004, 12:35
Долго бился над проблемой, чтобы добится результата не намного хуже, чем в специализированных программах. Делал почти то же самое, что и nJIaKca.spb и сразу скажу вот что...
Цитата
компонент типа TreeView к которому прицеплен ImageList (100x100)

Тут есть подводные грабли exclamation.gif Попробуй загрузи больше чем 1200 картинок... Что получишь? А ничего хорошего! После 1000-какой-то у тебя добавляться в ImageList ничего не будер tounge.gif. Решение - убирай ImageList и делай массив битмапок плюс делай собственную прорисовку. Если будут проблемы - могу дать свой код прорисовки. Дальше по сабжу. При генерации предпросмотров для JPEG есть одна хитрость, которую я прочитал как-то, и которая не часто афишируется... Вот функция, которой я обрабатываю на всякий случай загружаемые изображения:
Код

procedure JPEGScale(Graphic : TGraphic; Width, Height: Integer);
Var
 ScaleX, ScaleY, Scale :Extended;
begin
If (Graphic Is TJpegImage) Then
begin
 ScaleX:=Graphic.Width/Width;
 ScaleY:=Graphic.Height/Height;
 Scale:=Min(ScaleX,ScaleY);
 If Scale<2 then
 (Graphic As TJpegImage).Scale:=jsFullSize;
 If (Scale>=2) and (Scale<4) then
 (Graphic As TJpegImage).Scale:=jsHalf;
 If (Scale>=4) and (Scale<8) then
 (Graphic As TJpegImage).Scale:=jsQuarter;
 If Scale>=8 then
 (Graphic As TJpegImage).Scale:=jsEighth;
end;
end;

При загрузке JPEG файлов теперь времени тратится будет во мнооого раз меньше. С BMP и другими так не проходит 8(. Остальные файлы придётся всё равно грузить сначала полностью, прорисовывать на битмапе и потом уменьшать. В связи с этим вот ешё несколько функций для "качественного уменьшения":

Код

procedure StretchCool(Width, Height : integer; var S,D : TBitmap);
var
 i, j, h, k, p, w : Integer;
 p1 : PARGB;
 col, r, g, b, Sheight1, MSh : Integer;
 Sh, Sw : Extended;
 pk,pp: PInteger;
 Xp : array of PARGB;
begin
If Width=0 then exit;
If Height=0 then exit;
S.PixelFormat:=pf24bit;
D.PixelFormat:=pf24bit;
D.Width:=Width;
D.Height:=Height;
Sh:=S.height/height;
Sw:=S.width/width;
Sheight1:=S.height-1;
SetLength(Xp,S.height);
for i:=0 to Sheight1 do
Xp[i]:=s.ScanLine[i];
for i:=0 to Height-1 do
begin
 p1:=D.ScanLine[i];
 for j:=0 to Width-1 do
 begin
  col:=0;
  r:=0;
  g:=0;
  b:=0;
  for k:=Round(Sh*i) to Min(Round(Sh*(i+1))-1,Sheight1) do
  begin
   for p:=Round(Sw*j) to Min(Round(Sw*(j+1))-1,S.Width-1) do
   begin
    inc(col);
    inc(r,Xp[k,p].r);
    inc(g,Xp[k,p].g);
    inc(b,Xp[k,p].b);
   end;
  end;
  if col<>0 then
  begin
   p1[j].r:=r div col;
   p1[j].g:=g div col;
   p1[j].b:=b div col;
  end;
 end;
end;
end;

procedure QuickReduce(NewWidth, NewHeight : integer; BmpIn, BmpOut : TBitmap);
var
x, y, xi1, yi1, xi2, yi2, xx, yy, lw1 : integer;
bufw, bufh, outw, outh : integer;
sumr, sumb, sumg, pixcnt : dword;
adrIn, adrOut, adrLine0, deltaLine, deltaLine2 : DWORD;
begin
BmpOut.Width := NewWidth;
BmpOut.Height := NewHeight;
BmpIn.PixelFormat := pf24bit;
BmpOut.PixelFormat := pf24bit;
bufw := BmpIn.Width;
bufh := BmpIn.Height;
outw := BmpOut.Width;
outh := BmpOut.Height;
adrLine0 := DWORD(bmpIn.ScanLine[0]);
deltaLine := DWORD(BmpIn.ScanLine[1]) - adrLine0;
yi2 := 0;
for y := 0 to outh-1 do
begin
  adrOut := DWORD(BmpOut.ScanLine[y]);
  yi1 := yi2 {+ 1};
  yi2 := ((y+1) * bufh) div outh - 1;
  if yi2 > bufh-1 then yi2 := bufh;
  xi2 := 0;
  for x := 0 to outw-1 do
  begin
    xi1 := xi2 {+ 1};
    xi2 := ((x+1) * bufw) div outw - 1;
    if xi2 > bufw-1 then xi2 := bufw-1; //
    lw1 := xi2-xi1+1;
    deltaLine2 := deltaLine - lw1*3;
    sumb := 0;
    sumg := 0;
    sumr := 0;
    adrIn := adrLine0 + yi1*deltaLine + xi1*3;
    for yy := yi1 to yi2 do
    begin
      for xx := 1 to lw1 do
      begin
        Inc(sumb, PByte(adrIn+0)^);
        Inc(sumg, PByte(adrIn+1)^);
        Inc(sumr, PByte(adrIn+2)^);
        Inc(adrIn, 3);
      end;
      Inc (adrIn, deltaLine2);
    end;
    pixcnt := (yi2-yi1+1)*lw1;
    if pixcnt<>0 then
    begin
     PByte(adrOut+0)^ := sumb div pixcnt;
     PByte(adrOut+1)^ := sumg div pixcnt;
     PByte(adrOut+2)^ := sumr div pixcnt;
    end;
    Inc(adrOut, 3);
  end;
end;
end;



Первая хороша при небольших размерах картинки, там лучше происходит уменьшение и по быстродействию она не отличается от второй (при малых картинках, т.е. до 1000х1000). Вторая хороша при большом коэффициенте уменьшения и быстрее на больших картинках (при маленьких происходит значительное размытие конечной картинки). Поэтому в конце концов я это использовал практически так:

Код

Procedure QuickReduceWide(Width, Height : integer; Var S,D : TBitmap);
begin
if S.Width div Width>=8 then
QuickReduce(Width,Height,S,D) else
StretchCool(Width,Height,S,D)
end;


Прошу ваши комментарии и поправки.
Добавлено @ 12:36
Да:

Код

Type
   ARGB=array [0..1] of TRGB;
   PARGB=^ARGB;

Автор: z-END 30.8.2004, 22:08
Illusion Dolphin спасибо код твой потом посмотрю, ща времени нет.
Но вот что хочу заметить
Цитата(Illusion @ 30.8.2004, 12:35)
Попробуй загрузи больше чем 1200 картинок

я использовал JEDI (TJvImageList) 150x150x24bit в нем 1600 (с копейками) картинок+к этому этот ImageList сохранял и загружал все работаетsmile.gif (правда сам файл под 200 Метров весит и открыается жутко долго, но все же.
ЗЫ еще че заметил, при добавлении заранее извесного кол-ва картинок очеь стоит AllocBy уставить равному этому кол-ву (тогда добавлеется все намного быстрее)

Автор: Illusion Dolphin 30.8.2004, 22:48
Цитата
я использовал JEDI (TJvImageList)

Такого не слышал, если честно, да и стараюсь посторонние компоненты у себя в проектах не использовать... Поэтому про жутко долго не знаю ничего, да и AllocBy мне не к чему... всё сдулал ручками biggrin.gif.

Автор: z-END 31.8.2004, 10:12
Illusion Dolphin ссори за небольшой офф-топ, но JEDI это не сторонние компоненты, это комопненты созданные независимыми програмиствами под руководством Borland, для примера можешь в Дельфях нахать хелп, и удерживая Alt набери JEDI и видишь все самsmile.gif

Автор: Illusion Dolphin 2.9.2004, 16:14
А где взять JEDI (TJvImageList)?

Автор: z-END 2.9.2004, 22:06
Illusion Dolphin отдельно его взять наверно неполучится, компонент является частью пакета JEDI, сам он халявно скачивается, есть много где, например http://sourceforge.net/projects/jvcl
правда с установокой я бился пару суток, но поверь это того стоит=)

Автор: GRU 6.9.2004, 20:00
a как класс TQuickPixels?

Автор: Guest 6.9.2004, 20:10
GRU:
Цитата
a как класс TQuickPixels?

Если я не ошибаюсь, то его аналог дан в моём примере StretchCool, а ещё более быстрая работа - в QuickReduce

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