Net-Base Revista

18.08.2026

VCL High-DPI: Escalar ícones em tempo de execução e evitar pixelização em TImageList

High-DPI na VCL não é apenas uma caixa de seleção, mas uma cadeia de configuração de ImageList, eventos de alteração de DPI e renderização limpa. Este artigo prático mostra como você escala ícones em tempo de execução, evita artefatos e depura de forma reprodutível armadilhas típicas do TImageList.

18.08.2026

Do tema da revista à prática do projeto

Páginas de serviços e técnicas correspondentes ao artigo

Quem executa aplicações VCL em clientes modernos Windows cedo ou tarde encontra o mesmo sintoma: ícones parecem borrados em 125%/150%/200%, ficam serrilhados ou ganham uma borda cinza. É aí que o tema Ícones VCL High-DPI se torna prático: não porque High-DPI seja novo, mas porque os problemas normalmente só aparecem no dia a dia — em Terminalserver, na troca de dock de notebook ou sempre que cada monitor tem uma DPI diferente.

O cerne do problema quase nunca é “o PNG está corrompido”, mas a pipeline: de onde vem o ícone (recurso, ficheiro, SVG, fonte), em que resolução ele é fornecido, como ele entra na TImageList e quem escala quando e de que forma. Na VCL juntam‑se vários conceitos que é preciso distinguir: DPI-Awareness (se Windows escala a aplicação ou a própria aplicação se escala), Per-Monitor-DPI (cada monitor pode ter uma DPI diferente) e ImageList-Strategie (manter várias resoluções ou rasterizar em tempo de execução).

Este artigo não discute debates de design de UI, mas apresenta uma abordagem limpa e operacionalmente segura: escalar ícones em tempo de execução, porém de forma que não se transformem em massa de pixels, que os canais alfa permaneçam íntegros e que trocas de DPI funcionem sem cintilação ou tamanhos de imagem incorretos. Acrescentam‑se armadilhas, dicas de debug e uma avaliação honesta de quando o esforço adicional compensa.

Por que aparece borrão de pixels: entender a cadeia de escalonamento na VCL

Grafik zur Icon-Skalierung: Master-Icon wird in mehrere Zielgrf6dfen gerastert, doppelte Skalierung ffchrt zu Unsche4rfe
Uma única escala a partir de uma fonte master é controlável — passos de reamostragem duplos conduzem rapidamente a desfoque visível.

A causa mais frequente para ícones borrados é um down-/upscaling único feito no momento errado. Fluxo clássico em VCL legacy:

  • A aplicação fornece ícones apenas em 16×16 ou 24×24.
  • Windows ou a VCL escala para 20×20 / 32×32 / 48×48.
  • O escalador usa uma interpolação que é aceitável para fotografias, mas que em gráficos por pixel desfoca arestas.
  • Além disso, a transparência (alfa) é comprimida numa lógica de máscara ou convertida várias vezes.

Fica especialmente problemático quando várias escalas ocorrem em sequência: por exemplo, quando a ImageList já fornece um bitmap escalado e Windows — por ser DPI‑Unaware ou por conta da DPI do sistema — escala novamente por cima. Resultado: desfoque duplo.

Um segundo ponto, subestimado em muitos projetos, é o momento da escala. Com Per-Monitor-DPI (PMv2, isto é, Per-Monitor-DPI-Awareness v2) a DPI efetiva pode mudar quando uma janela muda de monitor ou quando um cliente Remote‑Desktop ajusta a DPI dinamicamente. Se então uma TImageList ou um cache não for reconstruído corretamente, de repente vê‑se ícones em tamanho errado ou com um raster incorreto.

TImageList unter High-DPI: typische Fallen in echten Anwendungen

A TImageList foi historicamente projetada para pequenas bitmaps, com dimensões fixas, índices e uma lógica de armazenamento relativamente rígida. Em ambientes High‑DPI isso gera armadilhas práticas:

1) Width/Height fixos

Muitos formulários VCL definem ImageList.Width/Height em tempo de design e deixam assim. Com 150% Windows quer, por exemplo, trocar de 16×16 para 24×24. Se a lista permanecer em 16×16, as imagens ou são cortadas ou são escaladas em outro local — ambos indesejáveis.

2) PNG-Alpha e lógica de máscaras

Dependendo da versão Delphi e dos controles VCL, chega‑se rapidamente a um modo misto: PNGs com alpha são mantidos internamente por vezes como bitmap 32‑bit, por vezes como máscara+cor. Assim que se fazem múltiplas conversões (PNG → Bitmap → ImageList → Draw), surgem halos acinzentados ou bordas duras. O efeito é frequentemente sensível ao fundo: numa toolbar escura parece pior do que num painel claro.

3) Mudanças de DPI em tempo de execução: caches, handles, OwnerDraw

Alguns controles cacheiam a representação das imagens ou assumem handles de ImageList numa etapa em que a DPI ainda não está finalizada. Especialmente em toolbars, TreeViews/ListViews e cenários OwnerDraw, após alterações de DPI vê‑se esporadicamente tamanhos de imagem incorretos ou ícones vazios, até ocorrer um repaint ou um RecreateWnd.

4) Terminalserver e Remote-Desktop como teste de realidade

Quando a aplicação é usada via RDP, alterações de DPI e reconnects de sessão não são exóticos. É exatamente aí que uma estratégia de ImageList pouco robusta se revela problemática: o utilizador vê ícones borrados ou barras de ferramentas mal escaladas após o reconnect, embora localmente tudo estivesse correto.

Abordagem limpa: fornecer várias resoluções em vez de upscaling bruto

A decisão mais importante é conceitual: pretende escalar ícones em tempo de execução a partir de uma única imagem base (p. ex. 16×16 → 32×32), ou fornece várias resoluções nativas e escolhe a adequada conforme a DPI?

Na prática, quase sempre vence a abordagem de várias resoluções. Pode‑se recorrer ao upscaling quando a fonte é vetorial (SVG, icon‑font) ou quando são necessários apenas fatores moderados. Assim que se amplia muito a partir de uma imagem raster pequena, perde‑se a qualidade das arestas, e isso é imediatamente visível em ecrãs modernos.

No universo VCL, para este enfoque hoje são relevantes dois blocos:

  • TImageCollection: contentor para imagens em várias dimensões/variantes.
  • TVirtualImageList: gera a partir disso, em tempo de execução, uma ImageList na dimensão actualmente necessária e reage a alterações de DPI.

Isto não resolve todos os problemas, mas desloca‑os para o lugar certo: você define as fontes de imagem de forma limpa, e a escala/seleção acontece de forma consistente.

Escalar ícones High‑DPI na VCL em tempo de execução: quando faz sentido (e quando não)

Existem motivos legítimos para escalar ícones em tempo de execução:

  • Carrega ícones dinamicamente (p. ex. a partir de uma pasta de plugins, pacotes de branding específicos do cliente, pacotes de configuração).
  • Quer uma pipeline unificada para várias fontes (ICO, PNG, SVG) e não pretende vincular todas as variantes em tempo de build.
  • Gera ícones programaticamente (badges de estado, overlays, símbolos compostos).

Não faz sentido escalamento em tempo de execução quando você, na prática, só tem ícones clássicos de barra de ferramentas a partir de um conjunto fixo. Nesse caso, o caminho de menor manutenção é: entregar várias resoluções corretamente e deixar a VCL escolher.

Se você fizer escalamento em tempo de execução, faça-o com regras claras:

  • Nunca escalar novamente a partir de um bitmap já escalado. Sempre partir de uma fonte master (idealmente vetorial ou em alta resolução).
  • Cache por tamanho alvo e DPI, caso contrário você reescalará em cada paint — isso consome CPU e pode provocar gagueira.
  • Preservar alpha: minimizar conversões, usar 32-bit RGBA, não achatar o fundo em bitmap.

Arquitetura pragmática: pipeline de ícones como componente independente

Em aplicações maiores vale a pena não dispersar o assunto por toda parte, mas construir uma pequena pipeline. Não precisa ser um framework — antes um domínio de responsabilidade claro:

  • Fonte de ícones: De onde vêm os master-assets (recursos, ficheiros, base de dados, API)?
  • Rasterizador/Scaler: Como se gera a partir do master a tamanho alvo (interpolação, eventual render de SVG)?
  • Cache: Chave (Icon-ID, pixels alvo, DPI, theme) e ciclo de vida (invalidar em troca de DPI, troca de theme, troca de pacote).
  • Adaptador para consumer: Como o resultado chega às estruturas VCL (TImageList/TVirtualImageList, OwnerDraw, PaintBox)?

Vantagem: você pode depurar bugs de DPI reproduzíveis num único lugar em vez de procurar „onde é que se escala de novo“ em 40 Forms.

Tratar corretamente troca de DPI: eventos, rebuild, repaint

Notebook mit zwei Monitoren unterschiedlicher DPI, Fensterwechsel zeigt unterschiedliche Icon-Grf6dfen in einer Desktop-App
Per-Monitor-DPI ist der Realit etstest: 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 blödes 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 interpolação mais arredondamento, lassen sich viele Effekte erklären:

  • Arredondamento de DPI: 125% não é um dobrador limpo. De 16 px vira 20 px (16 * 1,25). De 24 px vira 30 px. São números irregulares que dificultam as bordas dos pixels.
  • Filtro de reamostragem: Bilinear/Bicubic torna as bordas mais suaves. Isso é aceitável para fotos, frequentemente não para ícones.
  • Efeitos de subpixel: Windows pode, dependendo do caminho de renderização, usar ou não antialiasing por subpixel. Em ícones você quer arestas controladas e, de preferência, nenhuma etapa de filtragem múltipla.

Se você tem ícones raster, é prática comum em muitas equipes fornecer PNGs separados por tamanho-alvo (16/20/24/32/40/48). Parece muito, mas frequentemente dá menos trabalho do que passar anos debugando por que isso na tela X parece estranho.

Depuração: tornar o borrão de pixels reproduzível em vez de consertar por achismo

Arbeitsplatz mit Debug-Notizen ffcr Icon-Skalierung und Hintergrundtests zur Alpha-Kante
Boas rotinas de depuração de DPI testam tamanhos, fundos e pontos de rebuild — não apenas a primeira captura de tela.

Bugs de High-DPI costumam parecer aleatórios. Com alguns checks eles ficam determinísticos:

1) Logar DPI e ImageList-Größen em tempo de execução

Registre no log na inicialização e na mudança de DPI: CurrentPPI do Form, Screen.PixelsPerInch (atenção: isto pode ser o DPI do sistema), bem como ImageList.Width/Height das listas afetadas. Se, após trocar de monitor, você ainda vir 16 embora espere 32, a causa está clara: falta o rebuild ou ele ocorre tarde demais.

2) Aumentar os ícones visivelmente

Um teste rápido é configurar temporariamente os ícones da toolbar para 48 px. Escalação ruim salta imediatamente aos olhos. Pipelines bem implementadas permanecem nítidas mesmo a 48 px, porque rasterizam a partir de uma fonte adequada.

3) Testar mudança de tema e de fundo

Halos na borda são frequentemente problemas de alpha/premultiply. Teste em claro/escuro e em superfícies com gradiente. Se a borda muda conforme o fundo, o tratamento da transparência está incorreto.

4) Remote Desktop / troca de monitor como script de teste

Crie um script curto para QA: iniciar a app no Monitor A (100%), mover a janela para o Monitor B (150%), retornar, então reconectar RDP. Se isso se comportar de forma estável, muitos problemas de cliente já estarão eliminados.

Migração em aplicações existentes: por fases em vez de Big Bang

Em aplicações Delphi-VCL desenvolvidas ao longo do tempo, a lógica de ícones costuma estar espalhada por muitos lugares: Menüs, Toolbars, ActionLists, TreeViews, exibições de status. Uma reestruturação Big-Bang traz risco. Mostrou-se eficaz um procedimento por etapas:

  • Inventário: Quais ImageLists existem? Quais Controls as usam? Quais tamanhos são esperados?
  • Priorizar: Primeiro as áreas mais proeminentes (toolbar principal, navegação, menus de contexto).
  • Fonte única: Centralizar ícones (ImageCollection ou um loader próprio), em vez de carregar ficheiros individuais por Form.
  • Testes de mudança de DPI: A partir do primeiro módulo migrado, executar testes de mudança de DPI de forma consistente.

Importante: Se você opera em paralelo com pipelines antiga e nova, documente regras claras. Caso contrário surge uma paisagem mista em que alguns ícones estão nítidos e outros aparentam estar visivelmente desfocados.

Performance und Speicher: Laufzeit-Skalierung ohne Nebenwirkungen

Escalonamento custa CPU e memória. Em uma software empresarial isso raramente salta aos olhos em ociosidade, mas ao arrastar a janela para um monitor novo ou ao iniciar com muitos Forms pode ocorrer gagueira. Três diretrizes práticas:

  • Cache-Größen begrenzen: Não mantenha cada estágio intermediário indefinidamente. Se você precisa apenas de 100% e 150%, faça cache apenas desses.
  • Lazy Build: Rasterize os ícones apenas quando a tela realmente os precisar. Em menus grandes isso reduz o tempo de inicialização.
  • Batch-Rebuild: Ao trocar o DPI, não dispare cada Control individualmente. Um rebuild central evita escalonamento redundante.

Se você trabalha com TVirtualImageList, muito disso já está contemplado como conceito, mas você deve mesmo assim tomar cuidado para não construir por cima uma escalagem própria adicional.

Fallback-Strategien: Was tun, wenn nicht alle Icon-Größen vorliegen?

Na realidade você nem sempre terá todos os assets em todas as tamanhos. Então precisa de uma estratégia de fallback clara para evitar resultados aleatórios:

  • Prefer Downscale: Melhor reduzir de 64 px para 32 px do que ampliar de 16 px para 32 px.
  • Definiere Stufen: Defina quais tamanhos-alvo você realmente suporta (p.ex. 16/20/24/32/40/48) e mapeie o DPI de forma consistente para eles.
  • Transparenz testen: Nos fallbacks, preste atenção especial ao canal alpha — é exatamente aí que surgem halos.

Um erro típico é pegar qualquer próxima resolução disponível. Isso faz a nitidez percebida variar conforme o ícone. Melhor é um plano de mapeamento rígido e documentado.

Wann lohnt sich der Aufwand wirklich?

Existem três indicadores claros de que vale a pena uma pipeline de ícones High-DPI bem feita:

  • Seus usuários trabalham com monitores mistos (laptop + externo) ou muito por RDP.
  • A aplicação é de longa duração e será mantida por anos — a percepção da UI faz parte da aceitação.
  • Você já tem passos de modernização planejados (elevar DPI-Awareness, trocar Controls, revisar o layout da toolbar).

Se a aplicação, por outro lado, roda apenas em um sistema kiosk fixo com resolução idêntica, é possível manter o tema ao mínimo: fornecer um tamanho de ícone apropriado, definir a DPI-Awareness corretamente e pronto.

Fazit: High-DPI ist kein kosmetisches Detail, sondern eine Rendering-Entscheidung

Ícones desfocados na VCL raramente são um erro isolado; são um indicativo de uma cadeia suja entre fontes, escalonamento e caching. A abordagem mais robusta é fornecer ícones em várias resoluções e entregá-los de forma consistente através de uma pipeline central (p.ex. ImageCollection/VirtualImageList ou uma camada própria de ícones). Escalonamento em tempo de execução faz sentido quando você tem fontes dinâmicas ou símbolos compostos, mas somente com uma fonte master, cache baseado em DPI e regras claras de rebuild.

Se você tem sintomas concretos (troca de DPI que danifica ícones, halos nas bordas, tamanhos incorretos após RDP), vale a pena isolar o problema de forma dirigida e tratá‑lo como um pequeno componente de arquitetura, em vez de empilhar soluções alternativas por formulário. Se precisar de suporte no debugging ou em uma modernização progressiva, você encontra aqui o ponto de entrada adequado: Contato para Net-Base Software GmbH.

Para este tema são também importantes Timagelist High Dpi e Delphi Vcl Dpi-Awareness. O artigo contextualiza esses aspectos de forma clara e mostra no que importa na prática diária.

Conversar sobre projeto ou iniciativa de modernização com Net-Base.

Próximo passo

Quando o tema se tornar um projeto real, arquitetura, ambiente existente e operação devem ser considerados em conjunto desde o início.

Não apenas apoiamos questões pontuais, mas também quando fragmentos de código-fonte, temas legados ou ideias de portais precisam evoluir para um projeto empresarial robusto.

  • Estado atual, estado-alvo e riscos técnicos são avaliados em conjunto.
  • REST, o acesso a dados, os portais e o Rollout não são adiados para fases posteriores.
  • Você identifica cedo qual caminho é viável econômica e operacionalmente.

Partilhar publicação

Compartilhar esta publicação diretamente

LinkedIn, X, XING, Facebook, WhatsApp e E‑Mail estão disponíveis imediatamente. Para o Instagram, preparamos diretamente o link e o texto curto.

E-mail

O Instagram abre numa nova aba. O link e o texto curto são copiados previamente para a área de transferência.