Од теме часописа до пројектне праксе
Одговарајуће странице услуга и техничке странице за чланак
Ко покреће VCL-програме на модерним Windows-клијентима, пре или касније наилази на исти симптом: иконице на 125%/150%/200% делују као да су замућене, нарушених ивица или добијају сиви обрис. Управо овде тема VCL High-DPI Icons постаје практична: не зато што је High‑DPI нов, већ јер се проблеми обично појаве тек у пракси — на терминал серверима, при пребацивању ноутбука у док или када су по монитору различите DPI вредности.
Кључни проблем ретко када гласи „PNG је покварен“, већ је у путањи обраде: одакле долази иконица (ресурс, фајл, SVG, фонт), у којој величини се испоручује, како стиже у TImageList и ко и када врши скалирање. У VCL се у игру укључује неколико појмова које треба разdвојити: DPI-Awareness (да ли Windows скалира апликацију или апликација сама себе), Per-Monitor-DPI (сваки монитор може имати своју вредност) и ImageList-Strategie (одржавање више резолуција или растеризација при извршавању).
У овом тексту намерно не расправљамо UI-дизајн, већ представљамо чист, оперативно поуздан приступ: скалирати иконе у време извршавања, али тако да не постану замућене, да алфа-канали остану нетакнути и да смене DPI не доводе до треперења или погрешних димензија слика. Прате и замке, савети за дебаговање и реална процена када се додатни напор исплати.
Зашто настаје замућење пиксела: разумевање ланца скалирања у VCL
Најчешћи разлог за неоштре иконе је једнократно смањивање/повећање у погрешном тренутку. Класичан ток у Legacy‑VCL:
- Апликација испоручује иконе само у 16×16 или 24×24.
- Windows или VCL скалира на 20×20 / 32×32 / 48×48.
- Скалер користи интерполацију која је поуздана за фотографије, али за пикселску графику замагљује ивице.
- Поред тога, прозирност (алфа) се притисне у логику маске или се више пута конвертује.
Посебно непријатно постаје када се догоди више скала узастопно: на пример када ImageList већ даје скалирани bitmap, а Windows због DPI‑Unaware или системске DPI поново прескалира. Резултат: двоструко замућење.
Други, у пројектима често потцењен аспект је тренутак скалирања. Код Per‑Monitor‑DPI (PMv2, тј. Per‑Monitor‑DPI‑Awareness v2) ефективна DPI вредност може да се промени када прозор промени монитор или када RDP клијент динамички прилагоди DPI. Ако се онда TImageList или кеш не реконструишу исправно, изненада се виде иконе у погрешној величини или са погрешним растром.
TImageList под High‑DPI: типичне замке у реалним апликацијама
TImageList је историјски намијењена за мале битмапе, са фиксним мјерама, индексима и релативно крутом логиком складиштења. При високим DPI-јевима то доноси практичне замке:
1) Чврсто везани Width/Height
Многи VCL формулари подесе ImageList.Width/Height у време дизајна и оставе тако. При 150% Windows жели, нпр., да уместо 16×16 користи 24×24. Ако листа остане на 16×16, слика ће или бити исечена (geclippt) или ће се негде другде скалирати — оба случаја су неуређена.
2) PNG-Alpha и логика маски
У зависности од Delphi-верзије и VCL контроле, брзо се заврши у мешовитом режиму: PNG-ови са алфа каналом се интерно понекад чувају као 32-bit bitmapа, понекад као Mask+Color. Кад више пута конвертујеш (PNG -> Bitmap -> ImageList -> Draw), појављују се сиви хало ефекти или оштре ивице. Ефекат је често зависан од позадине: на тамној тулбар траци изгледа горе него на светлом панелу.
3) Промене DPI у току извршавања: кешеви, Handles, OwnerDraw
Неки контролери кеширају приказ слика или преузимају ImageList-handles у тренутку када DPI још није коначни. Посебно код Toolbars, TreeViews/ListViews и OwnerDraw сценарија, након промена DPI-а повремено се виде погрешне величине слика или празни икони, све док се не деси Repaint или RecreateWnd.
4) Terminalserver и Remote-Desktop као тест реалности
Ако се апликација користи преко RDP-а, промене DPI и поновна повезивања сесија нису ретки. Управо тамо неотпорна ImageList-стратегија се поквари: корисник види замућене иконе или погрешно скалиране траке са иконама након reconnect-а, иако је локално све било у реду.
Чист приступ: обезбедити више резолуција уместо бруталног упскејлинга
Најважнија одлука је концептуална: да ли желиш иконице у току извршавања скалирати из једне базне графике (нпр. 16×16 -> 32×32), или обавештаваш више нативних резолуција и бираш одговарајућу у зависности од DPI-а?
У пракси готово увек побеђује приступ с више резолуција. Upscaling има смисла ако је извор векторски (SVG, Icon-Font) или ако су потребни само умерени фактори. Кад јако скалираш из мале растер слике, губиш квалитет ивица и то се на модерним дисплејима одмах види.
У VCL свету за овај приступ данас су релевантна два грађевна камена:
- TImageCollection: контејнер за слике у више величина/варијанти.
- TVirtualImageList: из тога током извршавања генерише ImageList у тренутно потребној величини и реагује на DPI-измене.
То ти не решава све проблеме, али помера проблем на право место: дефинишеш изворе слика чисто, а скалирање/селекција се дешава доследно.
Скалирaње VCL High-DPI иконица у току извршавања: када има смисла (а када не)
Постоје легитимни разлози да се иконице скалирају у runtime-у:
- Учитаваш иконе динамички (нпр. из фолдера плагина, купачких пакетa за брендирање, конфигурационих пакета).
- Желиш један заједнички пайплајн за различите изворе (ICO, PNG, SVG) и не желиш да све варијанте везујеш при изградњи.
- Генериш иконе програмски (статус беџеви, оверлеји, састављени симболи).
Није смислено користити скалирање у току рада ако заправо имаш само класичне toolbar-иконе из фиксног сета. Тада је најмање захтевно за одржавање решење: испоручити више резолуција и препустити VCL да бира.
Ако радиш скалирање у току рада, онда са јасним правилима:
- Никада скалирати поново из већ скалираног bitmap-а. Увек полазити од master-извора (идеално векторски или високе резолуције).
- Cache по циљној величини и DPI, у супротном ћеш скалирати при сваком Paint-у — то троши CPU и може да запиње.
- Сачувати алфа канал: минимизирати конверзије, поставити на 32-bit RGBA, позадину не растеризовати.
Pragmatische Architektur: Icon-Pipeline als eigener Baustein
У већим апликацијама исплати се не распршивати тему по целом коду, већ израдити малу pipeline. То не мора бити framework — пре је јасно дефинисано подручје одговорности:
- Icon-Quelle: Одакле долазе master-assets (ресурси, фајлови, база података, API)?
- Rasterizer/Scaler: Како се из master извора генерише циљна величина (интерполација, евентуално SVG-render)?
- Cache: Кључ (Icon-ID, циљни пиксели, DPI, Theme) и животни циклус (invalidirati при промени DPI, промени теме, промени пакета).
- Consumer-Adapter: Како резултат стиже у VCL-структуре (TImageList/TVirtualImageList, OwnerDraw, PaintBox)?
Предност: можеш репродуковати DPI-багове и дебаговати их на једном месту, уместо да тражиш по 40 Forms где се поново скалира.
DPI-Wechsel korrekt behandeln: Ereignisse, Rebuild, Repaint
Под Windows су промене DPI посебан животни циклус. У VCL-у постоје, у зависности од верзије и DPI-Awareness, различити догађаји/механизми, али основни принцип остаје:
- Ако се DPI прозора промени, ресурси засновани на сликама који треба да буду пиксел-прецизни морају се поново обезбедити.
- Ако динамички пуните ImageLists, често није довољно просто Invalidate — треба вам Rebuild слика у новој циљној величини.
Пракснај примерак је: при промени DPI (нпр. Form-Scale/прелазак монитора) invalidирајте Icon-Cache за ту DPI и реконструишите погођене ImageLists. Важно је при том не скалирати у Paint-догађајима, већ у контролисаном update-блоку (Toolbar.BeginUpdate/EndUpdate, ListView-Redraw искључити, па поново укључити). Тако избегавате треперење и недовршена UI-стaња.
Warum TImageList so oft unscharf wird: Interpolation, DPI-Rundung, Kanten
Када једном схватиш да проблем није сам по себи DPI, већ интерполација плус заокруживање, многи ефекти се могу објаснити:
- Заокруживање DPI: 125% није чист удвостручујући фактор. Од 16 px добијаш 20 px (16 * 1,25). Од 24 px добијаш 30 px. То су некоректни бројеви који отежавају ивице пиксела.
- Ресемплинг филтери: Bilinear/Bicubic размуте ивице. То је у реду за фотографије, често није за иконе.
- Субпиксел ефекти: Windows може у зависности од пута рендеровања да користи Subpixel-Antialiasing или не. За иконе желиш контролисане ивице и, по могућности, што мање вишеструких нивоа филтера.
Ако имаш растерске иконе, у многим тимовима је уобичајена пракса да се по циљној величини испоруче појединачни PNG-ови (16/20/24/32/40/48). Звучи као много посла, али често је мање напорно него годинама дебаговати „зашто на овом монитору то изгледа чудно”.
Debugging: учинити зamuћење пиксела репродуктивним уместо поправљања по осећају
High-DPI bagovi често делују случајно. Са неколико провера постају детерминистички:
1) DPI und ImageList-Größe zur Laufzeit loggen
Логуј при покретању и при промени DPI: CurrentPPI des Forms, Screen.PixelsPerInch (пажња: то може бити системски DPI), као и ImageList.Width/Height погођених листа. Ако после промене монитора још видиш 16, иако очекујеш 32, узрок је јасан: недостаје Rebuild или долази прекасно.
2) Icons sichtbar vergrößern
Брз тест је привремено поставити toolbar-иконе на 48 px. Лоша скалa се тада одмах примети. Добри процеси остају оштри и на 48 px јер растеришу из адекватног извора.
3) Theme- und Hintergrundwechsel testen
Халои на ивици су често проблеми са alpha/premultiply. Тестирај на светлом/тамном и на површинама са градијентом. Ако ивица изгледа другачије у зависности од позадине, третман транспарентности није исправан.
4) Remote Desktop / Monitorwechsel als Testskript
Направи кратак тест-скрипт за QS: покрени апликацију на монитор A (100%), премести прозор на монитор B (150%), врати назад, онда RDP reconnect. Ако то стоји стабилно, многи кориснички проблеми су решени.
Migration in bestehenden Anwendungen: Schrittweise statt Big Bang
У нараслој Delphi-VCL апликацији логика икона често је распоређена по многим местима: Menüs, Toolbars, ActionLists, TreeViews, status барови. Big-Bang реконструкција носи ризик. Показао се као успешан постепен приступ:
- Inventur: Које ImageLists постоје? Која контрола их користи? Које величине се очекују?
- Priorisieren: Прво највидљивији делови (главна тулбар, навигација, контекстни менији).
- Einheitliche Quelle: Централизовати иконе (ImageCollection или сопствени loader), уместо да се по форме учитавају појединачне датотеке.
- DPI-Wechsel testen: Од првог преуређеног модула доследно изводити тестове промене DPI.
Важно: Ако паралелно водиш стару и нову пајплајн, документуј јасна правила. У супротном настаје мешовито окружење у коме су неке иконе оштре, а друге видљиво неоштре.
Перформансе и меморија: скалирање у време извршавања без нежељених ефеката
Скалирање троши CPU и меморију. У бизнис софтверу се то ретко примећује у празном ходу, али при превлачењу прозора на нови монитор или при покретању са много форма може доћи до заостајања. Три практичне смернице:
- Ограничи величину кеша: Немој чувати сваку међуфазу у недоглед. Ако ти требају само 100% и 150%, кеширај само њих.
- Lazy Build: Иконе раструј тек када их екран заиста захтева. Код великих менија то штеди време покретања.
- Batch-Rebuild: При промени DPI не покрећи сваки контрол појединачно. Централизовани Rebuild спречава редундантно скалирање.
Ако радиш са TVirtualImageList, много тога је већ као концепт присутно, али ипак мораш пазити да не додајеш још сопствено скалирање преко тога.
Fallback-Strategien: Šta raditi kada nisu dostupne sve veličine ikona?
У реалности не увек имаш све assets у свим величинама. Тада ти треба јасна fallback-стратегија да би се избегли насумични резултати:
- Prefer Downscale: Боље је смањити са 64 px на 32 px него појачавати са 16 px на 32 px.
- Дефиниши нивое: Одреди које циљне величине заиста подржаваш (нпр. 16/20/24/32/40/48) и мапирај DPI на њих прецизно.
- Тестирај транспарентност: При fallback-има посебно обрати пажњу на алфа-канал — баш тамо настају халои.
Типична грешка је узети било коју следећу величину. То доводи до варијације перципиране оштрине у зависности од иконе. Боље је имати строг, документован мапинг-план.
Када се улог заиста исплати?
Постоје три јасна индикатора да се чиста High-DPI-икона-пајплајн заиста исплати:
- Твоји корисници раде са мешовитим мониторима (лаптоп + екстерни) или често преко RDP.
- Апликација је дуговечна и одржаваће се годинама — перцепција UI је део прихватања.
- Имати ћеш у плану кораке модернизације (подизање DPI-Awareness, замену Controls, прераду Toolbar-Layout-а).
Ако апликација ради само на фиксном киоск-систему са идентичном резолуцијом, тему можеш држати на минимуму: достави одговарајућу величину икона, DPI-Awareness правилно подеси и готово.
Закључак: High-DPI није козметички детаљ, већ одлука о рендеровању
Неоштре иконе у VCL ретко су изолованa грешка, већ показатељ нечистог ланца извора, скалирања и кеширања. Најробустнији пут је обезбедити иконе у више резолуција и достављати их конзистентно преко централне пајплајн (нпр. ImageCollection/VirtualImageList или сопствени слој икона). Скалирање у време извршавања има смисла када имаш динамичке изворе или састављене симболе — али само уз master-извор, DPI-базирани кеш и јасна правила за Rebuild.
Ако имаш конкретне симптоме (промена DPI оштећује иконе, халои на ивицама, погрешне величине након RDP), вреди тему систематски изоловати и третирати је као мали архитектонски елемент уместо нагомилавања workaround-ова по формама. Ако ти треба подршка при дебаговању или при постепеној модернизацији, овде ћеш наћи прави увод: Контакт за Net-Base Software GmbH.
За ову тему су такође важни Timagelist High Dpi и Delphi Vcl Dpi-Awareness. Чланак их јасно ставља у контекст и показује на шта је у пракси важно обратити пажњу.
Разговарајте о пројекту или плану модернизације са Net-Base.
Следећи корак
Када из теме настане реалан пројекат, архитектуру, постојеће стање и операције треба рано разматрати заједно.
Подржавамо не само у појединачним питањима, већ и када из исечака изворног кода, застарелих тема или идеја за портале треба да настане поуздан корпоративни пројекат.
- Постојеће стање, циљано стање и технички ризици оцењују се заједно.
- REST, приступ подацима, портали и увођење неће бити одложени за касније фазе.
- Ви рано увидите који пут је економски и оперативно одржив.