[delphi] stop met laden van jpeg

Pagina: 1
Acties:

  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
Jammer dat bij Delphi niet de source van het JPEG unit meegeleverd wordt (of ben ik gewoon scheel?), want ze zijn toch iets vergeten te implementeren: Het OnProgress event is prachtig om progressive JPEG's weer te geven, of om een progressbar mee te laten lopen wanneer je laadt vanaf een langzaam medium, maar wat ik wil is het kunnen stoppen met inladen.

Ik ben bezig met een simpele image-viewer, en als je van bestand naar bestand gaat, moet je niet eerst hoeven wachten tot de vorige ingeladen is, voordat je de volgende kan inladen.

Goed, het OnProgress event heeft dus geen parameter (of result) waarmee je em kan laten stoppen, en TJpegImage heeft ook niet een methode StopLoading ofzo.

Iemand enig idee hoe ik dit kan oplossen?

日本!🎌


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Een afgeleide maken van TStream and daar de progress code inzetten?

We adore chaos because we like to restore order - M.C. Escher


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
Hmm, op zich geen slecht idee. Dat zou dus betekenen dat als ie moet stoppen, dat de stream gewoon geen data meer geeft. Heeft wel een nadeeltje... Hij zou een exception kunnen geven, omdat de JPEG corrupted wordt.

En als ik het goed begrijp, zou mijn stream dus als een soort proxy werken. Een doorgeeftluik van een andere (echte) stream, een MemoryStream of FileStream, naar de LoadFromStream van TJpegImage.

Ik ga het iig ff proberen :)

日本!🎌


Verwijderd

Je kan ook (ieeekk! akkk! vies!!) het laden in een thread laten gebeuren. Als je ondertussen naar een andere file switcht, kun je naar keuze:

1) De thread afkappen: niet zo netjes, waarschijnlijk vragen om corruptie van gegevens hier of daar.
2) De thread lekker af laten laden maar verder negeren: dit zou potentieel veel geheugen/cpu kunnen gaan vreten, maar ik denk dat dat in de praktijk, met een mens achter het toetsenbord, nogal mee zal vallen.

  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
1) De thread afkappen: niet zo netjes, waarschijnlijk vragen om corruptie van gegevens hier of daar.
Onder welke voorwaarde? Als ik de thread afkap, moet die thread aan de TJpegImage vertellen dat hij ook moet stoppen, anders loopt ie gewoon door.
2) De thread lekker af laten laden maar verder negeren: dit zou potentieel veel geheugen/cpu kunnen gaan vreten, maar ik denk dat dat in de praktijk, met een mens achter het toetsenbord, nogal mee zal vallen.
Niet als je door afbeeldingen kunt browsen. Dan kunnen er vele in 1 seconde achter elkaar geprobeerd te laten te worden. En het kost niet alleen cpu/geheugen, maar ik had het over langzame media, dus het kost ook bandbreedte. Dus de volgende gaat alleen maar nog langzamer en de volgende nóg langzamer, enz ;)

日本!🎌


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 12:05

Tomatoman

Fulltime prutser

De source wordt wel degelijk meegeleverd - zie de map Info\Extras\Jpeg op de installatie-cd.

De code om de OnProgress events te genereren is wel degelijk aanwezig. Voor de
Hier is een stuk van de code die het comprimeren voor zijn rekening neemt. Zoals je ziet wordt de procedure Progress aangeroepen bij de start en bij het einde. De callback die helemaal aan het begin wordt geïnitialiseerd neemt de progress tijdens het comprimeren voor zijn rekening.
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
procedure TJPEGImage.Compress;

...

      jc.progress.progress_monitor := ProgressCallback;
      jc.progress.instance := Self;
      jc.common.progress := @jc.progress;

...

        Progress(Self, psStarting, 0, False, Rect(0,0,0,0), '');
        try
          jpeg_start_compress(jc.c, True);

          while (jc.c.next_scanline < jc.c.image_height) do
          begin
            LinesWritten := jpeg_write_scanlines(jc.c, @SrcScanline, 
              LinesPerCall);
            Inc(Integer(SrcScanline), PtrInc * LinesWritten);
          end;

          jpeg_finish_compress(jc.c);
        finally
          if ExceptObject = nil then
            PtrInc := 100
          else
            PtrInc := 0;
          Progress(Self, psEnding, PtrInc, False, Rect(0,0,0,0), '');
        end;
De callback triggert op zijn beurt OnProgress events.

Een dergelijk mechanisme is er ook voor het decomprimeren. Het probleem is dat veel JPEG's zijn gecomprimeerd als één lange scanline. Aangezien de callback na iedere scanline wordt aangeroepen, zit je al op 100% progress bij de eerste aanroep. De enige manier om hieraan te ontsnappen is de JPEG's zodanig te coderen dat er meer scanlines zijn (bijvoorbeeld door de beeldopbouw van onder naar boven te laten plaatsvinden - zie de codeeropties in je fotobewerkingsprogramma).

Concluderend: de implementatie van Delphi is wel degelijk volledig, maar als er maar één scanline per JPEG is, kunnen er door het JPEG-(de)compressiemechanisme geen progress events worden gegenereerd.

Een goede grap mag vrienden kosten.


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
tomatoman, wat jij uitlegt, zijn volgens mij progressive jpegs. Maar op zich ging het me niet om het progressief weergeven van jpegs, maar om het decompressen op een willekeurig moment te stoppen. Dus als je een non-progressive jpeg hebt, zou het OnProgress event niet werken zelfs áls ie een parameter had om een stop te signaleren.

日本!🎌


  • Tomatoman
  • Registratie: November 2000
  • Laatst online: 12:05

Tomatoman

Fulltime prutser

Nog een tamelijk belangrijke aanvulling. ProgressCallback ziet er als volgt uit:
Delphi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
procedure ProgressCallback(const cinfo: jpeg_common_struct);
  {$IFDEF LINUX} cdecl; export; {$ENDIF}
var
  Ticks: Integer;
  R: TRect;
  temp: Integer;
begin
  if (cinfo.progress = nil) or (cinfo.progress^.instance = nil) then
    Exit;
  with cinfo.progress^ do
  begin
    Ticks := GetTickCount;
    if (Ticks - last_time) < 500 then Exit;
    temp := last_time;
    last_time := Ticks;
    if temp = 0 then Exit;

...

    instance.Progress(instance, psRunning, temp, 
      (R.Bottom - R.Top) >= 4, R, '');
  end;
end;
Als ik deze code goed begrijp (cinfo.progress^.last_time is nergens goed uitgelegd) zorgen de eerste paar regels ervoor dat er pas OnProgress events worden gegenereerd telkens als er minstens 500 milliseconden verstreken zijn. Op een snelle computer zie je daardoor natuurlijk nooit OnProgress events anders dan psStarting en psEnding.

[Edit]
Ik zie dat ik je vraag niet goed begrepen heb. Om alsnog een goed antwoord te geven: het daadwerkelijke decomprimeren doet een externe DLL. Er is daardoor geen mogelijkheid om in een OnProgress event het decomprimeren op een nette manier te stoppen. De callback heeft daar eenvoudigweg de mogelijkheid niet voor.

[ Voor 20% gewijzigd door Tomatoman op 26-07-2004 17:52 ]

Een goede grap mag vrienden kosten.


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
LordLarry, jouw oplossing lijkt ook niet te werken. De eerste de beste Read() leest gewoon de hele file in een keer in, dus geen manier om de toevoer van data voortijdig te stoppen...

日本!🎌


  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

kan je niet gewoon minder bytes teruggeven? Of gaat ie dan over de zeik denk je? Als ie het netjes doet kan het goed gaan.

We adore chaos because we like to restore order - M.C. Escher


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
Nee, als ik minder bytes teruggeef dan dat hij verwacht, dan denkt ie dat de file aan z'n eind zit. Hij probeert naderhand niet verder te lezen.

De source van het jpeg unit verklapt dit ook: de hele file wordt naar een memorystream gekopiëerd en deze wordt vervolgens ingeladen. Ik zie ff niet wat de filosofie hierachter is, maar erg geheugen-efficient is het niet.

日本!🎌


  • MerijnB
  • Registratie: Oktober 2000
  • Laatst online: 19:10
ws wil jij http://g32.org

A software developer is someone who looks both left and right when crossing a one-way street.


  • _Thanatos_
  • Registratie: Januari 2001
  • Laatst online: 15-05 14:44

_Thanatos_

Ja, en kaal

Topicstarter
Graphics32 :? :?

Geef maar es een voorbeeldje dan, hoe je daarmee een JPEG zonder delphi's jpeg unit kan inladen.

日本!🎌


Verwijderd

_Thanatos_ schreef op 26 juli 2004 @ 19:30:
Nee, als ik minder bytes teruggeef dan dat hij verwacht, dan denkt ie dat de file aan z'n eind zit. Hij probeert naderhand niet verder te lezen.

De source van het jpeg unit verklapt dit ook: de hele file wordt naar een memorystream gekopiëerd en deze wordt vervolgens ingeladen. Ik zie ff niet wat de filosofie hierachter is, maar erg geheugen-efficient is het niet.
Kan je dit stuk dan niet vervangen door code die de file stukje voor stukje inlaad?
Ik heb geen idee hoe een progressive jpeg inelkaar stukt, ik neem aan een of andere header met pointers naar de opeenvolgende stukken die gedecodeerd worden. (heb gister wel ff gekeken ivm met exif info etc. en het leek me op het eerste zich dat het ongeveer zoiets was), ben namelijk zelf ook bezig met een image framer,thumbnailer, gallery maker.

Heb ff op Torry gekeken, en met een snelle look in de code lijkt het erop dat deze:
http://www.torry.net/vcl/graphics/jpg/jpgimg.zip

wel OnProgress (met progressive) ondersteund. (zie jpgimg.pas zoeken op FOnprogress)

[edit]
Ook niet, ook hier wordt eerst de gehele file ingelezen

[ Voor 16% gewijzigd door Verwijderd op 26-07-2004 21:23 ]

Pagina: 1