Text ueber Bild flimmerfrei zeichnen (ohne Backbuffer)

01/06/2011 - 00:37 von Ulrich Korndoerfer | Report spam
Hallo NG,

in einem Anzeigefenster wird ganzflàchig ein Bild(ausschnitt) angezeigt.
An einer Stelle wird über dem Bild Text ausgegeben. Nun wird der
anzuzeigende Bildausschnitt geàndert (Panning). Dazu muß der
Bildausschnitt neu ausgegeben werden. Dann muß der Text an der gleichen
Stelle wieder hergestellt werden. Das flimmert, da (wenn auch nur sehr
kurz) der Text beim Neuzeichnen des Bildes verschwindet und nach dem
Neuzeichnen wieder hergestellt wird.

Der Text wird per DrawShadowText aus der V6 der CommonControls direkt
auf den DC der Anzeigeflàche (PictureBox) ausgegeben.

Ich möchte das nach Möglichkeit ohne DoubleBuffering lösen.

Interessanterweise geht das Pannen flimmerfrei:

- zuerst wird die vorhandene Anzeige per ScrollDC gescrollt
Dadurch entstehen in der Anzeige Lücken in der Hintergrundfarbe
des Anzeigefensters.
- anschließend werden die Lücken durch Neuzeichnen der entsprechenden
Bildausschnitte gefüllt.

Da flimmert rein gar nichts. Vorher hatte ich fürs Scrollen noch
ScrollWindow verwendet: da hats geflimmert. Es scheint so, als ob die am
DC (bzw. genauer an der zugehörigen Bitmap) vorgenommenen Änderungen
erst angezeigt werden, nachdem alle Operationen abgeschlossen wurden. Es
wird übrigens das Panning außerhalb des Paint-Events durchgeführt (der
Paint Event wird gar nicht ausgelöst).

Was ich bràuchte wàre eine Windows-API, mit der man das sofortige
Anzeigen von Änderungen eines DCs unterbinden kann:

- Update der DC Anzeige unterbinden
- den Hintergrund der Textanzeigestelle ausgeben
- den Text ausgeben
- das Update der DC Anzeige wieder einschalten

Gibts sowas? Oder wie könnte es sonst gehen?

PS

Ich möchte hier kurz eine Lanze für StretchDIBits brechen: das Ding ist
einfach fantastisch! Ich rufe StretchDIBits immer mit dem *ganzen* Bild
als Quelle auf, die Angaben für das Ziel variieren: die angegebenen
Werte für die Breite und Höhe des Zieles geben den Zoomfaktor vor, die
Werte für X und Y bestimmen die Lage des anzuzeigenden Ausschnittes. Das
geht ratz-fatz, selbst bei Bildern mit 50 Megapixeln. StretchDIBits
bearbeitet dabei anscheinend nur genausoviele Quellpixel, wie für das
Füllen der Clippingregion des Anzeigefensters benötigt werden.

Anfangs hatte ich befürchtet, daß StretchDIBits die komplette Quelle
bearbeitet und das Ergebnis clipped. Das würde spàtestens bei 50
Megapixel großen Bildern quàlend langsam werden. Da es aber schnell
geht, scheint StretchDIBits wohl nur die unbedingt benötigten Quellpixel
zu bearbeiten.

Obige Vorgehensweise macht es recht einfach, einen "Pictureviewer" mit
Zoom und Pan zusammenzubasteln, da die nötigen Berechnungen für die
Zieldaten einfach sind.

ZB ist für einen Stretchfill DstX = DstY = 0 und DstH=DispH und
DstW=DispW zu setzen (DispH ist die Scaleheight des Viewports etc).
Einfacher gehts nimmer.

Oder für einen 2fach Zoom DstW = 2 * PicW und DstH = 2 * PicH. Mit DstX
und DstY kann man dann die Anzeige beliebig plazieren. Ergibt sich eine
gezoomte Bildgröße, die größer als der Viewport ist, werden zur
Plazierung DstX und DstY mit negativen Werten belegt.

Und das visuelle Ergebnis, gerade bei Zoomfaktoren > 1, ist
hervorragend. Als Vergleichsquelle habe ich den FastStone ImageViewer
mit eingeschaltetem Lanczos-Smoothing hergenommen. Da gefallen mir die
Ergebnisse von StretchDIBits fast besser ;-)

Ulrich Korndoerfer

VB tips, helpers, solutions -> http://www.prosource.de/Downloads/
MS Newsgruppen Alternativen -> http://www.prosource.de/ms-ng-umzug.html
 

Lesen sie die antworten

#1 Thorsten Albers
01/06/2011 - 02:01 | Warnen spam
Ulrich Korndoerfer schrieb im Beitrag
<is3qju$u22$...
Da flimmert rein gar nichts. Vorher hatte ich fürs Scrollen noch
ScrollWindow verwendet: da hats geflimmert. Es scheint so, als ob die am
DC (bzw. genauer an der zugehörigen Bitmap) vorgenommenen Änderungen
erst angezeigt werden, nachdem alle Operationen abgeschlossen wurden. Es
wird übrigens das Panning außerhalb des Paint-Events durchgeführt (der
Paint Event wird gar nicht ausgelöst).



Eventuell spielt
LockWindowUpdate()
dabei eine Rolle.
Und auch GdiFlush() etc. könnte vielleicht in so einem Zusammenhang zur
Anwendung kommen.

Thorsten Albers

gudea at gmx.de

Ähnliche fragen