Du thème du magazine à la pratique des projets
Pages de services et techniques pertinentes pour l'article
Qui exploite des applications VCL sur des clients Windows modernes se heurte tôt ou tard au même symptôme : les icônes paraissent floutées, effilochées ou présentent un contour gris à 125%/150%/200%. C’est précisément là que le sujet VCL High-DPI Icons devient concret : pas parce que le High-DPI serait nouveau, mais parce que les problèmes se manifestent généralement au quotidien — sur des Terminalserver, lors du branchement/débranchement d’un dock de portable ou dès qu’il y a des DPI différents par moniteur.
Le problème central n’est presque jamais « le PNG est corrompu », mais la pipeline : d’où provient l’icône (ressource, fichier, SVG, police), dans quelle résolution elle est fournie, comment elle atterrit dans la TImageList et qui la redimensionne et quand. Dans la VCL, plusieurs notions se combinent qu’il faut distinguer : DPI-Awareness (si Windows met l’application à l’échelle ou si l’application se met à l’échelle elle-même), Per-Monitor-DPI (chaque moniteur peut être différent) et ImageList-Strategie (conserver plusieurs résolutions ou rasteriser à l’exécution).
Cet article ne traite délibérément pas des débats de design d’interface, mais d’une approche propre et opérationnelle : mettre les icônes à l’échelle à l’exécution, de sorte qu’elles ne deviennent pas du « pixel-mélange », que les canaux alpha restent intacts et que les changements de DPI fonctionnent sans scintillement ni tailles d’image incorrectes. S’y ajoutent des pièges, des conseils de débogage et une évaluation honnête du moment où l’effort supplémentaire en vaut la peine.
Pourquoi le flou pixelisé apparaît : comprendre la chaîne de mise à l’échelle dans la VCL
La raison la plus fréquente des icônes floues est un redimensionnement unique (down-/upscaling) effectué au mauvais moment. Processus classique dans la VCL héritée :
- L’application fournit les icônes uniquement en 16×16 ou 24×24.
- Windows ou la VCL met à l’échelle vers 20×20 / 32×32 / 48×48.
- L’algorithme d’interpolation utilisé convient pour les photos, mais il brouille les contours des images pixelisées.
- De plus, la transparence (alpha) est compressée en une logique de masque ou convertie plusieurs fois.
Cela devient particulièrement sournois quand plusieurs mises à l’échelle se succèdent : par exemple si l’ImageList fournit déjà un bitmap mis à l’échelle et que Windows le re-redimensionne à nouveau parce que l’application n’est pas DPI-aware ou en raison du DPI système. Résultat : double floutage.
Un deuxième point, sous-estimé dans les projets, est le moment de la mise à l’échelle. Avec le Per-Monitor-DPI (PMv2, c.-à-d. Per-Monitor-DPI-Awareness v2) l’échelle effective peut changer lorsqu’une fenêtre change de moniteur ou lorsqu’un client Remote Desktop ajuste dynamiquement le DPI. Si alors une TImageList ou un cache n’est pas reconstruit correctement, on voit soudainement des icônes à une taille incorrecte ou avec une rasterisation inadaptée.
TImageList sous High-DPI : pièges typiques dans des applications réelles
La TImageList a été historiquement conçue pour de petites bitmaps, avec des dimensions fixes, des indices et une logique de stockage relativement rigide. En High-DPI, cela engendre des pièges pratiques :
1) Width/Height codés en dur
Beaucoup de formulaires VCL définissent ImageList.Width/Height au design-time et n’y reviennent pas. À 150% Windows voudra par exemple passer d’un 16×16 à un 24×24. Si la liste reste sur 16×16, l’image est soit découpée, soit mise à l’échelle ailleurs — les deux étant inesthétiques.
2) PNG-Alpha et logique de masque
Selon la version de Delphi et les contrôles VCL, on se retrouve rapidement dans un mode mixte : les PNG avec canal alpha sont parfois conservés en interne en tant que bitmap 32 bits, parfois comme mask+color. Dès que vous effectuez plusieurs conversions (PNG → Bitmap → ImageList → Draw), apparaissent des halos gris ou des bords durs. L’effet dépend souvent de l’arrière-plan : sur une barre d’outils sombre c’est pire que sur un panneau clair.
3) Changement de DPI à l’exécution : caches, handles, OwnerDraw
Certaines controls mettent en cache la représentation des images ou prennent en charge les ImageList-Handles à un moment où le DPI n’est pas encore finalisé. Particulièrement pour les Toolbars, TreeViews/ListViews et les scénarios OwnerDraw, on observe après un changement de DPI des tailles d’images incorrectes ou des icônes vides de manière sporadique, jusqu’à ce qu’un repaint ou un RecreateWnd survienne.
4) Terminalserver et Remote-Desktop comme test de réalité
Si l’application est utilisée via RDP, les changements de DPI et les reconnexions de session ne sont pas rares. C’est précisément là qu’une stratégie ImageList peu robuste se révèle : l’utilisateur voit après la reconnexion des icônes floues ou des barres d’outils mal mises à l’échelle, alors qu’en local tout semblait correct.
Approche propre : fournir plusieurs résolutions plutôt que d’upscaling brutal
La décision la plus importante est conceptuelle : voulez-vous mettre à l’échelle des icônes à l’exécution à partir d’un seul fichier source (p. ex. passer de 16×16 à 32×32), ou fournissez-vous plusieurs résolutions natives et choisissez-vous celle qui convient selon la DPI ?
En pratique, la solution multi-résolutions l’emporte presque toujours. L’upscaling est acceptable si la source est vectorielle (SVG, Icon-Font) ou si vous n’avez besoin que de facteurs modérés. Dès que vous augmentez fortement la taille d’une petite image matricielle, vous perdez la qualité des contours, et cela se voit immédiatement sur les écrans modernes.
Dans l’écosystème VCL, deux composants sont aujourd’hui pertinents pour cette approche :
- TImageCollection : conteneur pour des images en plusieurs tailles/variantes.
- TVirtualImageList : génère à l’exécution une ImageList avec la taille nécessaire et réagit aux changements de DPI.
Cela ne résout pas tous les problèmes, mais déplace le point d’attention au bon endroit : vous définissez proprement les sources d’images, et la mise à l’échelle/sélection se fait de manière cohérente.
Mettre à l’échelle les icônes VCL en High-DPI à l’exécution : quand c’est pertinent (et quand non)
Il existe des raisons légitimes de mettre à l’échelle les icônes à l’exécution :
- Vous chargez des icônes dynamiquement (p. ex. depuis un dossier de plugins, des packs de branding client, des paquets de configuration).
- Vous souhaitez une pipeline unifiée pour différentes sources (ICO, PNG, SVG) et ne voulez pas lier toutes les variantes à la compilation.
- Vous générez des icônes par programme (badges d’état, overlays, icônes composées).
La mise à l’échelle à l’exécution n’a pas de sens si vous n’avez en réalité que des icônes de barre d’outils classiques provenant d’un ensemble fixe. Dans ce cas, la solution la moins coûteuse en maintenance est : fournir proprement plusieurs résolutions et laisser la VCL choisir.
Si vous faites de la mise à l’échelle à l’exécution, appliquez des règles claires :
- Jamais redimensionner à nouveau un bitmap déjà mis à l’échelle. Partir toujours d’une source maître (idéalement vectorielle ou en haute résolution).
- Cache par taille cible et DPI — sinon vous redimensionnez à chaque paint, ce qui coûte du CPU et peut provoquer des saccades.
- Conserver l’alpha : minimiser les conversions, utiliser 32-bit RGBA, ne pas rasteriser l’arrière-plan.
Architecture pragmatique : Icon-Pipeline comme composant dédié
Dans les applications de plus grande taille, il vaut la peine de ne pas disperser le sujet partout, mais de construire une petite pipeline. Ce n’est pas forcément un framework — plutôt un domaine de responsabilité clair :
- Source des icônes : d’où proviennent les assets maîtres (ressources, fichiers, base de données, API) ?
- Rasterizer/Scaler : comment la taille cible est-elle générée à partir de la source maître (interpolation, éventuel rendu SVG) ?
- Cache : clé (Icon-ID, pixels cibles, DPI, thème) et cycle de vie (invalidation lors du changement de DPI, du thème, ou du paquet).
- Adaptateur consommateur : comment le résultat est-il intégré dans les structures VCL (TImageList/TVirtualImageList, OwnerDraw, PaintBox) ?
Avantage : vous pouvez déboguer les bugs liés au DPI de façon reproductible en un seul endroit, au lieu de chercher « où est-ce qu’on redimensionne encore » dans 40 Forms.
DPI-Wechsel korrekt behandeln: Ereignisse, Rebuild, Repaint
Sous Windows, les changements de DPI constituent un cycle de vie à part. Dans la VCL, selon la version et le niveau de DPI-awareness, il existe plusieurs événements/mécanismes, mais le principe de base reste :
- Quand le DPI de la fenêtre change, les ressources basées sur des images qui doivent être exactes au pixel doivent être regénérées.
- Si vous remplissez dynamiquement des ImageLists, un simple Invalidate ne suffit souvent pas — vous avez besoin d’un Rebuild des images à la nouvelle taille cible.
Un modèle pragmatique est : lors d’un changement de DPI (p. ex. mise à l’échelle du formulaire / changement de moniteur), vous invalidez le cache d’icônes pour ce DPI et reconstruisez les ImageLists concernées. Il est important de ne pas scaler dans les événements de paint, mais dans un bloc de mise à jour contrôlé (Toolbar.BeginUpdate/EndUpdate, ListView-Redraw désactivé puis réactivé). Ainsi, vous évitez les scintillements et les états d’UI incomplets.
Pourquoi TImageList est si souvent flou : interpolation, arrondi lié au DPI, bords
Une fois que vous avez compris que le problème n’est pas le DPI en soi, mais l’interpolation et l’arrondi, de nombreux effets s’expliquent :
- Arrondi DPI : 125 % n’est pas un double propre. 16 px deviennent 20 px (16 * 1,25). 24 px deviennent 30 px. Ce sont des valeurs non entières qui compliquent les bords de pixels.
- Filtres de rééchantillonnage : Bilinear/Bicubic adoucit les contours. C’est acceptable pour les photos, souvent inadapté pour les icônes.
- Effets sous-pixel : Windows peut, selon le chemin de rendu, activer ou non l’anticrénelage subpixel. Pour les icônes vous voulez des bords contrôlés — et, autant que possible, pas de filtrage en plusieurs étapes.
Si vous utilisez des icônes matricielles, il est courant dans de nombreuses équipes de fournir des PNGs distincts par taille cible (16/20/24/32/40/48). Cela semble beaucoup, mais demande souvent moins d’effort que de passer des années à déboguer « pourquoi ça rend bizarre sur ce moniteur ».
Debugging : rendre le „pixel mush“ reproductible au lieu de le corriger au doigt mouillé
Les bugs High-DPI semblent souvent aléatoires. Avec quelques vérifications ils deviennent déterministes :
1) Consigner DPI et tailles ImageList à l’exécution
Loggez au démarrage et lors des changements de DPI : CurrentPPI du Form, Screen.PixelsPerInch (Attention : cela peut être le DPI système), ainsi que ImageList.Width/Height des listes concernées. Si, après un changement de moniteur, vous voyez encore 16 alors que vous attendiez 32, la cause est claire : le rebuild manque ou arrive trop tard.
2) Agrandir visuellement les icônes
Un test rapide consiste à régler temporairement les icônes de la barre d’outils sur 48 px. Une mauvaise mise à l’échelle saute alors immédiatement aux yeux. Des pipelines bien conçus restent nets à 48 px parce qu’elles rastérisent à partir d’une source adaptée.
3) Tester changement de thème et d’arrière-plan
Les halos en bordure sont souvent des problèmes d’alpha / premultiply. Testez en clair/sombre et sur des zones avec dégradé. Si le bord change selon l’arrière-plan, le traitement de la transparence est incorrect.
4) Remote Desktop / changement de moniteur comme script de test
Créez un court script de test pour la QS : démarrer l’app sur le moniteur A (100 %), déplacer la fenêtre sur le moniteur B (150 %), revenir, puis reconnecter le RDP. Si cela tient, beaucoup de problèmes clients sont déjà éliminés.
Migration dans des applications existantes : par étapes plutôt que Big Bang
Dans des Delphi-VCL applicatives ayant évolué, la logique des icônes est souvent répartie à de nombreux endroits : Menüs, Toolbars, ActionLists, TreeViews, Statusanzeigen. Une refonte en Big Bang comporte des risques. Une approche progressive a fait ses preuves :
- Inventaire : Quelles ImageLists existent ? Quels contrôles les utilisent ? Quelles tailles sont attendues ?
- Prioriser : Commencez par les zones les plus visibles (barre d’outils principale, navigation, menus contextuels).
- Source unique : Centraliser les icônes (ImageCollection ou chargeur dédié), plutôt que de charger des fichiers séparés par formulaire.
- Tester les changements de DPI : Dès le premier module migré, effectuer systématiquement des tests de changement de DPI.
Important : si tu fais fonctionner en parallèle l’ancienne et la nouvelle pipeline, documente des règles claires. Sinon se crée un paysage mixte dans lequel certains icônes sont nets et d’autres paraissent visiblement flous.
Performance et mémoire : mise à l’échelle à l’exécution sans effets secondaires
La mise à l’échelle coûte du CPU et de la mémoire. Dans un logiciel métier, cela passe rarement inaperçu au repos, mais le déplacement d’une fenêtre sur un autre moniteur ou le démarrage avec de nombreux formulaires peut entraîner des à-coups. Trois garde-fous pratiques :
- Limiter les tailles de cache : ne conservez pas indéfiniment chaque intermédiaire. Si tu n’as besoin que de 100 % et 150 %, mets en cache uniquement ces tailles.
- Construction paresseuse : rasteriser les icônes uniquement quand l’écran en a réellement besoin. Pour de grands menus, cela économise du temps de démarrage.
- Reconstruction par lot : lors d’un changement de DPI, ne déclenche pas la mise à jour de chaque contrôle individuellement. Une reconstruction centrale évite les mises à l’échelle redondantes.
Si tu travailles avec TVirtualImageList, une grande partie de ces concepts est déjà prise en charge, mais tu dois quand même veiller à ne pas empiler en plus ta propre mise à l’échelle.
Stratégies de repli : que faire si toutes les tailles d’icônes ne sont pas disponibles ?
Dans la réalité, tu n’as pas toujours tous les assets dans toutes les tailles. Il te faut alors une stratégie de repli claire pour éviter des résultats aléatoires :
- Préférer la réduction d’échelle : mieux vaut réduire de 64 px à 32 px que monter de 16 px à 32 px.
- Définir des paliers : fixe quelles tailles cibles tu supportes réellement (p. ex. 16/20/24/32/40/48) et associe proprement les DPI à ces paliers.
- Tester la transparence : pour les repliements, fais particulièrement attention au canal alpha — ce sont précisément ces cas qui génèrent des auréoles.
Une erreur typique consiste à prendre n’importe quelle taille suivante disponible. Cela fait varier la netteté perçue selon l’icône. Mieux vaut un plan de mappage strict et documenté.
Quand l’effort en vaut-il vraiment la peine ?
Il y a trois indicateurs clairs qu’une pipeline d’icônes High‑DPI soignée est justifiée :
- Tes utilisateurs utilisent des moniteurs mixtes (portable + écran externe) ou beaucoup de sessions RDP.
- L’application est durable et maintenue sur plusieurs années — la perception de l’UI fait partie de l’acceptation.
- Tu as de toute façon des étapes de modernisation à réaliser (élever le niveau de DPI‑Awareness, remplacer des controls, retravailler le layout de la barre d’outils).
Si l’application tourne uniquement sur un système kiosque fixe avec une résolution identique, on peut garder le sujet minimal : fournir une taille d’icône adaptée, régler correctement la DPI‑Awareness, et c’est tout.
Conclusion : le High‑DPI n’est pas un détail cosmétique, mais une décision de rendu
Les icônes floues dans la VCL sont rarement un bug isolé ; elles révèlent une chaîne imparfaite de sources, de mise à l’échelle et de caching. La méthode la plus robuste consiste à fournir des icônes en plusieurs résolutions et à les délivrer de façon cohérente via une pipeline centrale (p. ex. ImageCollection/VirtualImageList ou une couche d’icônes propre). La mise à l’échelle à l’exécution est pertinente quand tu as des sources dynamiques ou des symboles composés — mais uniquement avec une source maître, un cache basé sur la DPI et des règles de rebuild claires.
Si tu constates des symptômes précis (changement de DPI qui casse des icônes, auréoles au bord, tailles incorrectes après RDP), il vaut la peine d’isoler le problème et de l’aborder comme un petit composant d’architecture plutôt que d’empiler des workarounds par formulaire. Si tu as besoin d’aide pour le débogage ou pour une modernisation progressive, tu trouveras ici le point d’entrée approprié : Kontakt zur Net-Base Software GmbH.
Pour ce sujet, Timagelist High Dpi et Delphi Vcl Dpi-Awareness sont également importants. L’article situe ces aspects de manière compréhensible et montre ce qui compte dans la pratique quotidienne.
Étape suivante
Lorsque le sujet devient un projet réel, l'architecture, l'existant et l'exploitation doivent être examinés ensemble dès le départ.
Nous n'intervenons pas seulement sur des questions ponctuelles, mais aussi lorsque des fragments de code source, des problématiques liées aux systèmes legacy ou des concepts de portail doivent se transformer en un projet d'entreprise robuste.
- L'état des lieux, l'état cible et les risques techniques sont évalués conjointement.
- REST, l’accès aux données, les portails et le déploiement ne sont pas reportés à des phases ultérieures.
- Vous identifiez tôt quelle voie est viable économiquement et opérationnellement.