Net-Base Журнал

18.08.2026

VCL High-DPI: масштабування іконок під час виконання та запобігання піксельному розмиттю в TImageList

High-DPI у VCL — це не просто чекбокс, а ланцюжок налаштувань ImageList, подій зміни DPI та коректного рендерингу. У цьому практичному матеріалі показано, як під час виконання масштабувати іконки, уникати артефактів і відтворювано налагоджувати типові пастки TImageList.

18.08.2026

Від теми журналу до практики проєкту

Відповідні сторінки послуг і технічні сторінки до публікації

Коли запускають VCL-додатки на сучасних Windows-клієнтах, рано чи пізно натрапляють на один і той же симптом: іконки при 125a0%/150a0%/200a0% виглядають розмазаними, з потертостями на краях або отримують сірий контур. Саме тут тема VCL High-DPI Icons стає практичною: не тому, що High-DPI нове, а тому, що проблеми зазвичай виявляються в експлуатації — на термінальних серверах, при відключенні/підключенні док-станції ноутбука або коли для різних моніторів застосовуються різні DPI.

Ключова проблема майже ніколи не в тому, що PNG зіпсований, а в самій конвеєрній ланцюжку: звідки приходить іконка (ресурс, файл, SVG, шрифт), в якому розмірі вона надається, як потрапляє в TImageList і хто й коли її масштабує. У VCL з цим пов’язані кілька термінів, які необхідно розрізняти: Підтримка DPI (чи масштабує Windows додаток або додаток сам себе), Per-Monitor-DPI (кожен монітор може мати інший DPI) і ImageList-стратегія (тримати кілька роздільностей або раструвати в часі виконання).

У цьому матеріалі навмисно не йдеться про дискусії з UI-дизайну, а про акуратний, надійний у експлуатації підхід: масштабувати іконки під час виконання так, щоб вони не перетворювалися на «піксельний кашмар», щоб альфа-канали залишалися цілими і щоб зміни DPI відбувалися без мерехтіння або неправильних розмірів зображень. Додатково розглядаються підводні камені, поради для відладки та чесна оцінка того, коли додаткові зусилля виправдані.

Чому виникає розмазаність пікселів: розуміння ланцюга масштабування у VCL

Grafik zur Icon-Skalierung: Master-Icon wird in mehrere Zielgrf6dfen gerastert, doppelte Skalierung ffchrt zu Unsche4rfe
Одноразове масштабування з master-джерела контрольоване — подвійні кроки ресемплінгу швидко призводять до помітного розмиття.

Найпоширеніша причина нечітких іконок — це одноразове зменшення/збільшення у невідповідний момент. Класичний сценарій у legacy-VCL:

  • Додаток надає іконки лише в 16d716 або 24d724.
  • Windows або VCL масштабує до 20d720 / 32d732 / 48d748.
  • Скалер використовує інтерполяцію, яка для фотографій підходить, але для піксельної графіки розмиває краї.
  • Додатково прозорість (альфа) витискається в логіку маски або конвертується багаторазово.

Особливо підступно виходить, коли відбувається кілька масштабувань підряд: наприклад, коли ImageList вже повертає масштабоване бітове зображення, а Windows через відсутність підтримки DPI або через системний DPI масштабує його ще раз. Результат: подвійне розмиття.

Другий, у проектах недооцінений аспект — це момент масштабування. При Per-Monitor-DPI (PMv2, тобто Per-Monitor-DPI-Awareness v2) ефективний DPI може змінюватися, коли вікно переходить на інший монітор або коли клієнт віддаленого робочого столу динамічно підлаштовує DPI. Якщо при цьому TImageList або кеш не перебудовуються коректно, раптом бачимо іконки невірного розміру або з неправильним растром.

TImageList під High-DPI: типові пастки в реальних застосунках

Die TImageList ist historisch für kleine Bitmaps gedacht, mit festen Maßen, Indizes und relativ starrer Speicherlogik. Unter High-DPI ergeben sich daraus praxisnahe Fallen:

1) Fest verdrahtete Width/Height

Viele VCL-Formulare setzen ImageList.Width/Height zur Designzeit und lassen es dabei. Bei 150% möchte Windows aber z. B. aus 16×16 eher 24×24 machen. Wenn die Liste auf 16×16 bleibt, wird entweder geclippt oder skaliert an anderer Stelle — beides unschön.

2) PNG-Alpha und Maskenlogik

Je nach Delphi-Version und VCL-Controls landet man schnell in einem Mischbetrieb: PNGs mit Alpha werden intern teils als 32-bit Bitmap gehalten, teils als Mask+Color. Sobald du mehrfach konvertierst (PNG → Bitmap → ImageList → Draw), entstehen graue Halos oder harte Kanten. Der Effekt ist häufig backgroundsensitiv: Auf dunkler Toolbar sieht es schlimmer aus als auf einem hellen Panel.

3) DPI-Wechsel zur Laufzeit: Caches, Handles, OwnerDraw

Einige Controls cachen die Bilddarstellung oder übernehmen ImageList-Handles zu einem Zeitpunkt, wo die DPI noch nicht final ist. Besonders bei Toolbars, TreeViews/ListViews und OwnerDraw-Szenarien sieht man nach DPI-Wechseln sporadisch falsche Bildgrößen oder leere Icons, bis ein Repaint oder ein RecreateWnd passiert.

4) Terminalserver und Remote-Desktop als Realitätstest

Wenn die App über RDP genutzt wird, sind DPI-Wechsel und Session-Reconnects nicht exotisch. Genau dort fliegt dir eine unrobuste ImageList-Strategie um die Ohren: Der Benutzer sieht nach dem Reconnect verwaschene Icons oder falsch skalierte Symbolleisten, obwohl lokal alles ok war.

Sauberer Ansatz: Mehrere Auflösungen bereitstellen statt brutales Upscaling

Die wichtigste Entscheidung ist konzeptionell: Willst du Icons zur Laufzeit aus einer einzigen Basisgrafik hochskalieren (z. B. 16×16 → 32×32), oder stellst du mehrere native Auflösungen bereit und wählst je nach DPI die passende?

In der Praxis gewinnt fast immer die Variante mit mehreren Auflösungen. Upscaling kann man machen, wenn die Quelle vektorbasiert ist (SVG, Icon-Font) oder wenn du wirklich nur moderate Faktoren brauchst. Sobald du aus einem kleinen Rasterbild stark hochskalierst, verlierst du Kantenqualität, und das siehst du auf modernen Displays sofort.

In der VCL-Welt sind für diesen Ansatz heute zwei Bausteine relevant:

  • TImageCollection: Container für Bilder in mehreren Größen/Varianten.
  • TVirtualImageList: erzeugt daraus zur Laufzeit eine ImageList in der aktuell benötigten Größe und reagiert auf DPI-Änderungen.

Das nimmt dir nicht alle Probleme ab, aber es verschiebt das Problem an die richtige Stelle: Du definierst Bildquellen sauber, und die Skalierung/Selektion passiert konsistent.

VCL High-DPI Icons zur Laufzeit skalieren: Wann es sinnvoll ist (und wann nicht)

Es gibt legitime Gründe, Icons zur Laufzeit zu skalieren:

  • Du lädst Icons dynamisch (z. B. aus einem Plugin-Ordner, kundenspezifische Branding-Pakete, Konfigurationspakete).
  • Du willst eine einheitliche Pipeline für verschiedene Quellen (ICO, PNG, SVG) und möchtest nicht alle Varianten zur Build-Zeit binden.
  • Du erzeugst Icons programmgesteuert (Status-Badges, Overlays, zusammengesetzte Symbole).

Не має сенсу виконувати масштабування під час виконання, якщо у вас насправді лише класичні іконки панелі інструментів з фіксованого набору. У такому випадку найменш витратний з точки зору підтримки підхід: постачати кілька роздільностей і дозволяти VCL обирати.

Якщо ви робите масштабування під час виконання, робіть це за чіткими правилами:

  • Ніколи не масштабувати повторно з уже масштабованого бітмапу. Завжди виходьте з master-джерела (бажано векторного або високої роздільності).
  • Кеш для кожного цільового розміру та DPI, інакше при кожному Paint відбуватиметься повторне масштабування — це навантажує CPU і може спричиняти ривки у відтворенні.
  • Зберігайте альфа-канал: мінімізуйте конвертації, використовуйте 32-bit RGBA; не раструйте фон у формат без альфа.

Pragmatische Architektur: Icon-Pipeline als eigener Baustein

У більших застосунках має сенс не розпорошувати цю логіку по всьому коду, а побудувати невеликий конвеєр. Це не обов’язково має бути фреймворк — скоріше чітка зона відповідальності:

  • Icon-Quelle: Звідки надходять master-ресурси (ресурси, файли, база даних, API)?
  • Rasterizer/Scaler: Як з master утворюється цільовий розмір (інтерполяція, за потреби SVG-рендер)?
  • Cache: Ключ (Icon-ID, цільові пікселі, DPI, Theme) та життєвий цикл (інвалідовувати при зміні DPI, зміні теми, зміні пакета).
  • Consumer-Adapter: Як результат потрапляє у VCL-структури (TImageList/TVirtualImageList, OwnerDraw, PaintBox)?

Перевага: ви зможете відтворювати DPI-баги в одному місці замість того, щоб шукати «де ще раз масштабується» у 40 формах.

DPI-Wechsel korrekt behandeln: Ereignisse, Rebuild, Repaint

Notebook mit zwei Monitoren unterschiedlicher DPI, Fensterwechsel zeigt unterschiedliche Icon-Grf6dfen in einer Desktop-App
Per-Monitor-DPI ist der Realitätstest: Beim Monitorwechsel muss die Icon-Pipeline neu rastern, nicht nur neu zeichnen.

Unter Windows sind DPI-Wechsel ein eigener Lebenszyklus. In der VCL gibt es je nach Version und DPI-Awareness mehrere Ereignisse/Mechanismen, aber das Grundprinzip bleibt:

  • Wenn sich die DPI des Fensters ändert, müssen bildbasierte Ressourcen, die pixelgenau sein sollen, neu bereitgestellt werden.
  • Wenn du ImageLists dynamisch füllst, reicht ein bloßes Invalidate oft nicht — du brauchst ein Rebuild der Images in der neuen Zielgröße.

Ein praxistaugliches Muster ist: Auf DPI-Änderung (z. B. Form-Scale/Monitorwechsel) invalidierst du den Icon-Cache für diese DPI und baust die betroffenen ImageLists neu auf. Wichtig ist, dabei nicht in Paint-Events zu skalieren, sondern in einem kontrollierten Update-Block (Toolbar.BeginUpdate/EndUpdate, ListView-Redraw aus, dann wieder an). So vermeidest du Flackern und halbfertige UI-Zustände.

Warum TImageList so oft unscharf wird: Interpolation, DPI-Rundung, Kanten

Wenn du einmal verstanden hast, dass nicht die DPI das Problem ist, sondern Interpolation plus Rundung, lassen sich viele Effekte erklären:

  • Округлення DPI: 125% — це не точне подвоєння. З 16 px виходить 20 px (16 * 1,25). З 24 px — 30 px. Це непрості значення, що ускладнюють межі пікселів.
  • Resampling-Filter: Bilinear/Bicubic робить краї м’якішими. Для фото це зазвичай ок, для іконок часто — ні.
  • Subpixel-Effekte: Windows kann je nach Renderpfad Subpixel-Antialiasing nutzen oder nicht. Bei Icons willst du kontrollierte Kanten — und möglichst keine mehrfachen Filterstufen.

Якщо у вас растрові іконки, у багатьох командах звичайна практика — постачати окремі PNG під кожний цільовий розмір (16/20/24/32/40/48). Звучить багато, але часто це менше зусиль, ніж роками відлагоджувати «чому на цьому моніторі це виглядає дивно».

Налагодження: зробити піксельні артефакти відтворюваними замість виправлень за відчуттями

Arbeitsplatz mit Debug-Notizen ffcr Icon-Skalierung und Hintergrundtests zur Alpha-Kante
Добрі DPI-рутину налагодження перевіряють Größen, Hintergründe und Rebuild-Zeitpunkte — не тільки перший скріншот.

Проблеми High-DPI часто здаються випадковими. Декількома перевірками їх можна зробити детерміністичними:

1) Логувати DPI і розміри ImageList під час виконання

Логуй при старті й при зміні DPI: CurrentPPI форми, Screen.PixelsPerInch (увага: це може бути системний DPI), а також ImageList.Width/Height відповідних списків. Якщо після переключення монітора ти все ще бачиш 16, хоча очікував 32, причина зрозуміла: відсутній Rebuild або він відбувається занадто пізно.

2) Візуально збільшити іконки

Швидкий тест — тимчасово встановити іконки панелі інструментів на 48 px. Погана масштабування відразу кинеться в очі. Добрі пайплайни залишаються чіткими навіть при 48 px, бо вони растеризуються з відповідного джерела.

3) Тестувати зміни теми та фону

Гало на краях часто пов’язане з проблемами Alpha/Premultiply. Тестуйте на світлому і темному тлі та на ділянках з градієнтом. Якщо край виглядає по-різному залежно від фону, обробка прозорості некоректна.

4) Remote Desktop / Monitorwechsel як тестовий сценарій

Створіть короткий тестовий скрипт для QS: запустити додаток на моніторі A (100%), перемістити вікно на монітор B (150%), повернути назад, потім перепідключити RDP. Якщо це стабільно, багато клієнтських проблем вже буде вирішено.

Міграція в існуючих застосунках: поступово замість Big Bang

У дорослих Delphi-VCL-застосунках логіка іконок часто розпорошена по багатьох місцях: меню, тулбари, ActionLists, TreeViews, індикатори статусу. Капітальний одноразовий перебудова несе ризики. Досвід показує ефективність поетапного підходу:

  • Інвентаризація: Які ImageLists існують? Які контролі їх використовують? Яких розмірів очікують?
  • Пріоритизація: Спочатку найпомітніші ділянки (головна тулбар, навігація, контекстні меню).
  • Уніфіковане джерело: Централізувати іконки (ImageCollection або власний Loader), замість завантаження окремих файлів для кожної форми.
  • Тестування зміни DPI: Від першого переробленого модуля послідовно виконувати тести при зміні DPI.

Важливо: якщо ви одночасно підтримуєте старий і новий пайплайн, задокументуйте чіткі правила. Інакше виникне змішане середовище, в якому одні іконки будуть різкими, а інші помітно розмитими.

Продуктивність і пам’ять: масштабування в рантаймі без побічних ефектів

Масштабування коштує CPU і пам’яті. У бізнес‑програмі це рідко помітно в просте, але при перетягуванні вікна на інший монітор або при старті з великою кількістю форм може з’явитися ривок. Три практичні орієнтири:

  • Обмежити розміри кешу: не тримайте кожну проміжну ступінь вічно. Якщо вам потрібні тільки 100% і 150%, кешуйте саме ці розміри.
  • Відкладена побудова: раструйте іконки лише коли екран їх дійсно потребує. На великих меню це економить час запуску.
  • Пакетне відновлення: при зміні DPI не тригерьте кожний Control окремо. Центральний ребілд запобігатиме надмірному повторному масштабуванню.

Якщо ви працюєте з TVirtualImageList, багато з цього вже закладено в концепт, але ви все одно повинні стежити, щоб не нашаровувати власні додаткові механізми масштабування.

Fallback‑стратегії: що робити, коли не всі розміри іконок наявні?

На практиці не завжди є всі ассети у всіх розмірах. Тому потрібна чітка стратегія fallback, щоб уникнути випадкових результатів:

  • Віддавайте перевагу зменшенню: краще зменшити з 64 px до 32 px, ніж збільшувати з 16 px до 32 px.
  • Визначте ступені: зафіксуйте, які цільові розміри ви реально підтримуєте (наприклад 16/20/24/32/40/48) і коректно відобразіть на них DPI.
  • Перевіряйте прозорість: при fallback особливо звертайте увагу на альфа‑канал — саме там з’являються ореоли.

Типова помилка — просто взяти будь‑який найближчий розмір. Через це сприйнята різкість іконок буде відрізнятися. Краще мати твердий, задокументований план відображення.

Коли витрати виправдані насправді?

Є три чіткі індикатори того, що варто реалізувати якісну High‑DPI‑іконну пайплайн:

  • Ваші користувачі працюють на змішаних моніторах (ноутбук + зовнішній) або часто використовують RDP.
  • Додаток довговічний і буде підтримуватися роками — сприйняття UI є частиною прийняття.
  • У вас заплановані кроки модернізації (підвищення підтримки DPI, заміна контролів, переробка макета тулбару).

Якщо ж застосунок працює виключно на фіксованій kiosk‑системі з ідентичною роздільною здатністю, тему можна тримати мінімальною: надати відповідний розмір іконок, коректно встановити DPI‑налаштування — і цього достатньо.

Висновок: High‑DPI — це не косметика, а рішення рендерингу

Розмиті іконки в VCL рідко є ізольованою проблемою; це ознака некоректної ланцюжка джерел, масштабування і кешування. Найстійкіший шлях — надавати іконки в кількох роздільностях і послідовно доставляти їх через центральну пайплайн (наприклад ImageCollection/VirtualImageList або власний шар іконок). Масштабування в рантаймі має сенс, якщо у вас динамічні джерела або складені символи, але тільки за умови наявності master‑джерела, кешу на основі DPI і чітких правил ребілду.

Якщо у вас є конкретні симптоми (зміна DPI ламає іконки, ореоли по краю, неправильні розміри після RDP), варто ізолювати проблему і розглядати її як невеликий архітектурний модуль, замість нагромадження воркараундів по кожній формі. Якщо потрібна підтримка при відлагодженні або поетапній модернізації, ви знайдете відповідний вступ тут: Kontakt zur Net-Base Software GmbH.

Для цієї теми також важливі Timagelist High Dpi та Delphi Vcl Dpi-Awareness. У статті ці аспекти чітко пояснено та показано, на що потрібно звертати увагу в повсякденній роботі.

Обговорити проєкт або плани модернізації з Net-Base.

Наступний крок

Якщо тема перетворюється на реальний проєкт, архітектуру, наявні системи та експлуатацію слід розглядати разом на ранньому етапі.

Ми підтримуємо не лише в окремих питаннях, а й тоді, коли з уривків вихідного коду, питань, пов’язаних із legacy, або ідей порталу має вирости надійний корпоративний проєкт.

  • Поточний стан, цільова архітектура та технічні ризики оцінюються спільно.
  • REST, доступ до даних, портали та Rollout не відсуваються на пізніший етап.
  • Ви заздалегідь бачите, який шлях є економічно та операційно життєздатним.

Поділитися дописом

Поділитися цим дописом безпосередньо

LinkedIn, X, XING, Facebook, WhatsApp та E‑Mail доступні негайно. Для Instagram ми безпосередньо готуємо посилання та короткий текст.

Електронна пошта

Instagram відкривається в новій вкладці. Посилання та короткий текст попередньо копіюються у буфер обміну.