Od teme magazina do projektne prakse
Povezane stranice usluga i tehnologije za članak
Ko koristi VCL-aplikacije na modernim Windows-klijentima, prije ili kasnije naiđe na isti simptom: ikone pri 125 %/150 %/200 % djeluju kao da su zamućene, narezane ili dobiju sivu ivicu. Upravo tu je tema VCL High-DPI Icons praktična: ne zato što je High-DPI novo, već zato što se problemi obično pokažu tek u svakodnevnoj upotrebi — na Terminalserverima, pri prebacivanju prijenosnika u dock ili čim se po monitoru koriste različiti DPI.
Osnovni problem gotovo nikad nije „PNG je pokvaren“, već pipeline: odakle dolazi ikona (resurs, datoteka, SVG, font), u kojoj veličini je isporučena, kako dospije u TImageList i ko skalira kada i kako. U VCL se tu skuplja više pojmova koje treba razdvojiti: DPI-Awareness (da li Windows ili aplikacija sama vrši skaliranje), Per-Monitor-DPI (svaki monitor može biti različit) i ImageList-Strategie (držati više rezolucija ili rasterizovati u runtime-u).
U ovom članku namjerno ne raspravljamo o UI-dizajnu, nego o čistom, operativno sigurnom pristupu: skalirati ikone u runtime-u, ali tako da ne postanu piksel-zujanje, da alfa-kanali ostanu netaknuti i da promjene DPI bez treperenja ili pogrešne veličine slike funkcioniraju. Uz to idu zamke, savjeti za debug i iskrena procjena kada se dodatni napor isplati.
Zašto nastaje pixel-mud: razumjeti lanac skaliranja u VCL
Najčešći razlog za neostrе ikone je jednokratni down-/upscaling u pogrešno vrijeme. Klasičan tok u legacy-VCL:
- Aplikacija isporučuje ikone samo u 16×16 ili 24×24.
- Windows ili VCL skalira na 20×20 / 32×32 / 48×48.
- Skalirač koristi interpolaciju koja je ok za fotografije, ali kod piksel-grafike zamagli rubove.
- Osim toga, prozirnost (alpha) je stisnuta u logiku maske ili više puta konvertovana.
Pogotovo je loše kada se dogode više skala jedna za drugom: na primjer kada ImageList već daje skalirani bitmap, a Windows zbog DPI-unaware ili sistemskog DPI ponovo skalira preko toga. Rezultat: dvostruko zamućivanje.
Druga, u projektima podcijenjena tačka je vrijeme skaliranja. Pri Per-Monitor-DPI (PMv2, odnosno Per-Monitor-DPI-Awareness v2) efektivni DPI se može promijeniti kada prozor mijenja monitor ili kada Remote-Desktop-klijent dinamički prilagodi DPI. Ako se tada TImageList ili cache ne rekonstruira ispravno, odjednom vidite ikone u pogrešnoj veličini ili s pogrešnim rasterom.
TImageList pod High-DPI: tipične zamke u realnim aplikacijama
TImageList je povijesno namijenjena za male bitmape, s fiksnim dimenzijama, indeksima i relativno krutom logikom pohrane. Pri High‑DPI pojavljuju se iz toga praktične zamke:
1) Fiksno vezani Width/Height
Mnogi VCL‑formulari postave ImageList.Width/Height u vrijeme dizajna i ostave to. Pri 150% Windows će, na primjer, htjeti iz 16 povećati na 24. Ako lista ostane na 16, slika će ili biti izrezana ili negdje drugdje skalirana — oba slučaja su neuredna.
2) PNG‑Alpha i logika maski
Ovisno o Delphi-verziji i VCL kontrolama, lako se nađeš u mješovitom režimu: PNG‑ovi s alfom interno se ponekad drže kao 32‑bitna bitmapa, ponekad kao maska+boja. Kad više puta konvertiraš (PNG → Bitmap → ImageList → Draw), nastaju sivi halo‑efekti ili oštri rubovi. Efekt je često osjetljiv na pozadinu: na tamnoj alatnoj traci izgleda gore nego na svijetlom panelu.
3) Promjene DPI za vrijeme rada: cache‑ovi, handles, OwnerDraw
Neke kontrole cache‑iraju prikaz slike ili preuzimaju ImageList handles u trenutku kad DPI još nije konačan. Posebno kod Toolbars, TreeViews/ListViews i OwnerDraw scenarija nakon promjene DPI‑ja povremeno se vide netočne veličine slika ili prazni ikon‑slotovi, sve dok se ne pokrene Repaint ili RecreateWnd.
4) Terminal server i Remote Desktop kao test stvarnosti
Ako se aplikacija koristi preko RDP‑a, promjene DPI‑ja i reconnect sessiona nisu rijetkost. Upravo tamo neodrživa ImageList‑strategija pokaže svoje slabosti: korisnik nakon reconnecta vidi zamućene ikone ili pogrešno skalirane alatne trake, iako je lokalno sve bilo u redu.
Pristup bez kompromisa: isporučiti više rezolucija umjesto brutalnog upscalinga
Najvažnija odluka je konceptualna: hoćeš li tijekom rada skalirati ikone iz jedne bazne grafike (npr. 16 → 32), ili pripremiš više nativnih rezolucija i prema DPI‑ju odabereš odgovarajuću?
U praksi gotovo uvijek pobjeđuje pristup „više rezolucija“. Upscaling je prihvatljiv kad je izvor vektorski (SVG, Icon‑Font) ili kad su potrebni samo umjereni faktori. Kad iz malog rastera snažno povećavaš, gubiš kvalitetu rubova — i to je na modernim zaslonima odmah vidljivo.
U VCL‑svijetu za taj pristup danas su relevantna dva sastavna dijela:
- TImageCollection: kontejner za slike u više veličina/varijanti.
- TVirtualImageList: kreira iz toga za vrijeme rada jednu ImageList u trenutno potrebnoj veličini i reagira na promjene DPI‑ja.
To ti ne rješava sve probleme, ali premješta ih na pravo mjesto: izvorne slike definiraš jasno, a skaliranje/selektiranje se događa dosljedno.
Skaliranje VCL High‑DPI ikona u runtimeu: kada ima smisla (a kada ne)
Postoje legitimni razlozi za skaliranje ikona tijekom rada:
- Učitavaš ikone dinamički (npr. iz plugin‑mape, korisničkih branding paketa, konfiguracijskih paketa).
- Želiš jedinstvenu pipeline za različite izvore (ICO, PNG, SVG) i ne želiš vezati sve varijante u build‑vremenu.
- Generiraš ikone programatski (status‑badževi, overlayi, sastavljeni simboli).
Skaliranje u vrijeme izvođenja nema smisla ako zapravo koristiš samo klasične ikone na alatnoj traci iz fiksnog skupa. Najmanje zahtjevan za održavanje pristup je: isporučiti više rezolucija uredno i dopustiti VCL-u da odabere.
Ako provodiš skaliranje u vrijeme izvođenja, učini to prema jasnim pravilima:
- Nikad ne skaliraj ponovno iz već skaliranog bitmapa. Uvijek polazi od master-izvora (po mogućnosti vektorski ili visoke rezolucije).
- Cache po ciljnoj veličini i DPI, inače ćeš pri svakom iscrtavanju skalirati iznova — to troši CPU i može uzrokovati trzaje.
- Sačuvati alpha kanal: Minimiziraj konverzije, koristi 32-bitni RGBA, pozadinu ne rasterizirati.
Pragmatična arhitektura: pipeline ikona kao vlastita komponenta
U većim aplikacijama isplati se ne razbacivati temu svugdje, nego izgraditi malu pipeline. To ne mora biti framework — prije jasno odgovorno područje:
- Izvor ikona: Odakle dolaze master-asseti (resursi, datoteke, baza podataka, API)?
- Rasterizer/Scaler: Kako se iz master-izvora generira ciljna veličina (interpolacija, eventualno SVG-render)?
- Cache: Ključ (Icon-ID, ciljni pikseli, DPI, tema) i životni ciklus (invalidirati pri promjeni DPI, promjeni teme, promjeni paketa).
- Consumer-Adapter: Kako rezultat dolazi u VCL-strukture (TImageList/TVirtualImageList, OwnerDraw, PaintBox)?
Prednost: DPI-bugove možeš reproducirati i debugirati na jednom mjestu, umjesto tražiti „gdje se još skalira“ kroz 40 formi.
Ispravno rukovanje promjenom DPI: događaji, ponovno stvaranje, ponovno iscrtavanje
Pod Windows su promjene DPI zaseban životni ciklus. U VCL-u postoji ovisno o verziji i DPI-awarenessu više događaja/mehanizama, ali osnovno pravilo ostaje:
- Ako se DPI prozora promijeni, resursi bazirani na slikama koji trebaju biti pikselno precizni moraju biti ponovno pripremljeni.
- Ako dinamički popunjavaš ImageList-e, često nije dovoljno samo Invalidate — trebaš ponovno izgraditi slike u novoj ciljnoj veličini.
Jedan praktičan obrazac je: na promjenu DPI (npr. Form-Scale/Monitorwechsel) invalidiraš cache ikona za tu DPI i ponovno gradiš pogođene ImageList-e. Važno je pri tome ne skalirati unutar Paint-događaja, nego u kontroliranom update-bloku (Toolbar.BeginUpdate/EndUpdate, isključi ListView-Redraw, pa ponovno uključi). Tako izbjegavaš treperenje i nedovršena stanja UI-a.
Zašto TImageList često postane nejasan: Interpolacija, zaokruživanje DPI, rubovi
Kada jednom shvatiš da problem nije samo DPI, već interpolacija plus zaokruživanje, mnogi efekti se mogu objasniti:
- DPI-zaokruživanje: 125% nije čist udvostručitelj. Iz 16 px nastane 20 px (16 * 1,25). Iz 24 px nastane 30 px. To su neravni brojevi koji otežavaju rubove piksela.
- Resampling-Filter: Bilinear/Bicubic čini rubove mekšim. To je za fotografije u redu, za ikone često nije.
- Subpixel-Effekte: Windows može, ovisno o render-potu, koristiti subpixel-antialiasing ili ne. Kod ikona želite kontrolisane rubove — i što je moguće manje višestrukih faza filtera.
Ako imate raster-ikone, u mnogim timovima je uobičajena praksa isporučiti zasebne PNG-ove po ciljnoj veličini (16/20/24/32/40/48). Zvuči kao puno, ali često je manje posla nego godinama debugirati „zašto ovo na tom monitoru izgleda čudno”.
Debugging: Reproducirati pixel-matsch umjesto popravljanja po osjećaju
High-DPI greške često djeluju slučajno. Sa par provjera postanu determinističke:
1) DPI i veličine ImageList logirati u runtime
Logirajte pri startu i pri promjeni DPI: CurrentPPI forme, Screen.PixelsPerInch (Pažnja: to može biti System-DPI), te ImageList.Width/Height pogođenih listi. Ako nakon promjene monitora i dalje vidite 16 px, iako očekujete 32, uzrok je jasan: nedostaje rebuild ili dolazi prekasno.
2) Ikone vizualno uvećati
Brzi test je privremeno postaviti toolbar-ikone na 48 px. Loša skaliranja odmah upadnu u oči. Dobre pipeline ostaju oštre i pri 48 px jer rasteriziraju iz odgovarajućeg izvora.
3) Testirati promjene teme i pozadine
Halo efekt na rubu su često problemi s alpha/premultiply. Testirajte na svijetlom/tamnom i na površinama s gradijentom. Ako rub ovisi o pozadini, obrada transparentnosti nije ispravna.
4) Remote Desktop / promjena monitora kao test-skript
Napišite kratak test-skript za QS: pokrenite aplikaciju na monitoru A (100%), premjestite prozor na monitor B (150%), vratite natrag, pa RDP reconnect. Ako je to stabilno, mnogo korisničkih problema je već riješeno.
Migracija u postojećim aplikacijama: postepeno umjesto Big Bang
U dozrijevajućim Delphi-VCL-aplikacijama logika ikona često je raspršena po mnogim mjestima: meniji, toolbari, ActionLists, TreeViews, statusni prikazi. Big-Bang preuređenje nosi rizik. Dokazano je sljedeće postupno pristupiti:
- Inventar: Koje ImageLists postoje? Koji Controls ih koriste? Koje veličine se očekuju?
- Prioritiziranje: Prvo najistaknutije površine (glavni toolbar, navigacija, kontekstni meniji).
- Jedinstveni izvor: Centralizirati ikone (ImageCollection ili vlastiti loader), umjesto da svaka forma učitava pojedinačne datoteke.
- Testiranje promjene DPI: Od prvog preuređenog modula dosljedno izvoditi DPI-promjenske testove.
Važno: Ako paralelno koristiš staru i novu pipeline, dokumentuj jasna pravila. Inače nastane mješoviti pejzaž u kojem su neki ikoni oštri, a drugi vidljivo zamućeni.
Performanse und Speicher: Laufzeit-Skalierung ohne Nebenwirkungen
Skaliranje košta CPU i memoriju. U poslovnom softveru to rijetko upada u oči u praznom hodu, ali pri povlačenju prozora na novi monitor ili pri pokretanju s mnogo formi može se javiti trzanje. Tri praktične smjernice:
- Cache-Größen begrenzen: Ne čuvaj svaku međufazu zauvijek. Ako ti trebaju samo 100% i 150%, predmemoriraj samo te nivoe.
- Lazy Build: Ikone rasteriziraj tek kada ih ekran zaista treba. Kod velikih menija to štedi vrijeme pokretanja.
- Batch-Rebuild: Pri promjeni DPI ne pokreći svaku kontrolu pojedinačno. Centralizirani Rebuild sprječava redundantno skaliranje.
Wenn du mit TVirtualImageList arbeitest, ist vieles davon bereits als Konzept enthalten, aber du musst trotzdem darauf achten, nicht zusätzlich noch eigene Skalierung oben drauf zu bauen.
Fallback-Strategien: Was tun, wenn nicht alle Icon-Größen vorliegen?
U stvarnosti često nemaš sve assete u svim veličinama. Treba ti jasna fallback-strategija da bi izbjegao slučajne rezultate:
- Prefer Downscale: Radije smanji sa 64 px na 32 px nego povećavaj sa 16 px na 32 px.
- Definiere Stufen: Odredi koje ciljane veličine stvarno podržavaš (npr. 16/20/24/32/40/48) i mapiraj DPI precizno na njih.
- Transparenz testen: Kod fallbackova obrati posebnu pažnju na alpha-kanal — upravo tamo nastaju halos.
Tipična greška je uzeti bilo koju najbližu veličinu. To uzrokuje varijacije u percipiranoj oštrini ovisno o ikoni. Bolje je imati strogo, dokumentovano mapiranje.
Wann lohnt sich der Aufwand wirklich?
Postoje tri jasna indikatora da se isplati uredna High-DPI-Icon-Pipeline:
- Tvoji korisnici rade s miješanim monitorima (laptop + eksterni) ili često preko RDP-a.
- Aplikacija je dugovječna i održava se godinama — percepcija UI-ja je dio prihvatanja.
- Ionako imaš planirane korake modernizacije (DPI-Awareness anheben, Controls tauschen, Toolbar-Layout überarbeiten).
Ako aplikacija radi samo na fiksnom kiosk-sistemu s identičnom rezolucijom, temu možeš držati minimalnom: isporuči odgovarajuću veličinu ikone, pravilno postavi DPI-Awareness i gotovo.
Fazit: High-DPI ist kein kosmetisches Detail, sondern eine Rendering-Entscheidung
Neoštre ikone u VCL-u rijetko su izolovana greška, već pokazatelj nečiste lanca izvora, skaliranja i keširanja. Najrobustniji put je pružiti ikone u više rezolucija i isporučivati ih konzistentno preko centralne pipeline (npr. ImageCollection/VirtualImageList ili vlastiti sloj ikona). Laufzeit-Skalierung ima smisla kada imaš dinamičke izvore ili sastavljene simbole, ali samo uz master-izvor, DPI-bazirani keš i jasna pravila za Rebuild.
Ako imaš konkretne simptome (DPI-Wechsel macht Icons kaputt, Halos am Rand, falsche Größen nach RDP), isplati se ciljano izolirati problem i tretirati ga kao mali arhitektonski modul umjesto gomilanja workarounda po formi. Ako trebaš podršku pri debugiranju ili pri postepenoj modernizaciji, naći ćeš odgovarajući ulaz ovdje: Kontakt za Net-Base Software GmbH.
Za ovu temu su također važni Timagelist High Dpi i Delphi Vcl Dpi-Awareness. Članak jasno razjašnjava ove aspekte i pokazuje na šta treba obratiti pažnju u svakodnevnom radu.
Razgovarajte o projektu ili modernizacijskom poduhvatu s Net-Base.
Sljedeći korak
Kada se tema pretvori u stvarni projekat, arhitektura, postojeći sistem i operacije trebaju se rano sagledati zajedno.
Pružamo podršku ne samo pri pojedinačnim pitanjima, već i kada iz fragmenata izvornog koda, naslijeđenih sistema ili ideja za portal treba nastati robustan poslovni projekat.
- Postojeće stanje, ciljno stanje i tehnički rizici procjenjuju se zajedno.
- REST, pristup podacima, portali i Rollout se ne odgađaju kao naknadne posljedice.
- Vi rano vidite koji je put ekonomski i operativno održiv.