eQuantic.UIeQuantic.UI
Docs
Playground
GitHub
DocsEcossistema
Image
Editar esta página
6 min de leitura
Um bitmap num slot de tamanho explícito. O tamanho é argumento do construtor e não sugestão, porque o layout nunca consegue inferir extensão de uma fonte que ele não decodificou, e um slot que espera a rede é uma página que se reorganiza na frente do leitor.
1
Image("/images/hero.jpg", 640, 360, label: "O time no offsite de 2026")
Escrito com a factory, como o resto do vocabulário. A mesma chamada realiza na web e no Photon, e nada nela nomeia um alvo.
O slot
Parâmetro
Tipo
Significado
source
string
Onde está a arte. Um caminho que o alvo consiga buscar.
width
float
A largura do slot, em pixels independentes de densidade.
height
float
A altura do slot.
fit
ImageFit
Como a arte preenche o slot. Cover por padrão.
label
string
O que um leitor de tela fala. Vazio significa decorativa, que é a regra do HTML e vale nos dois alvos.
Mais três se definem como propriedades, porque são a exceção e não a forma:
Propriedade
Tipo
Significado
DarkSource
string?
A arte do modo ESCURO, quando uma imagem só não serve aos dois.
CornerRadius
CornerRadii
Raio por canto; a arte é recortada nele.
Fit
ImageFit
Também definível aqui, para uma árvore construída sem a factory.
1
2
3
4
5
6
new Image("/brand/wordmark.svg", 180, 40)
{
DarkSource = "/brand/wordmark-white.svg",
CornerRadius = new CornerRadii(8),
Label = "", // decorativa: o nome ao lado já diz
}
Fit
ImageFit
O que faz
Cover
Preenche recortando pelo centro. O padrão, e o que uma fotografia quer.
Contain
Cabe inteira dentro do slot, com barras. A fonte toda fica visível.
Stretch
Preenche distorcendo. Reservado para arte que aguenta.
Arte escura é um PAR, não um desvio
Um wordmark desenhado em tinta para superfícies claras e em branco para escuras não cabe num arquivo só. Para cores isso se resolve com um par de ColorToken; para arte não, então o par mora no nó e o realizador resolve do mesmo jeito: sem desvio no código do app e sem ninguém perguntar o modo na hora de pintar.
Na web as duas fontes são entregues e o CSS mostra uma, seguindo a preferência do sistema e o modo forçado pelo próprio app, que o controlador de tema carimba como data-theme.
O que cada alvo desenha
Web: um <img> com a largura e a altura do slot, object-fit vindo do Fit, border-radius vindo do CornerRadius, src do Source e alt do Label.
Photon: o engine desenha uma caixa de placeholder SurfaceSubtle sob o mesmo raio até a carga de textura chegar: o padrão de degradação documentado, dito aqui para a forma da página ser a mesma nos dois alvos mesmo enquanto os pixels não são.
Cercas do v1, iguais nos dois: nine-slice, os estados de carregamento e de erro, e o crossfade de decodificação entram junto com os sistemas de asset e de animação, em vez de chegarem neste nó.
Otimização de imagem no servidor
O eQuantic.UI.Images acrescenta um endpoint: um serviço autônomo que redimensiona, recodifica e guarda imagens em cache sob demanda.
Leia isto primeiro, porque a forma do recurso não é a que parece. O endpoint não está ligado ao nó Image. Nada no vocabulário pede uma variante redimensionada a ele, e o nó não tem propriedade de qualidade, de srcset nem de opt-in, e esta página dizia o contrário, e descrevia um elemento só-web que precedeu o vocabulário. O que existe é o serviço; apontar alguma coisa para ele é jogada de quem chama, hoje.
Ligando
1
2
3
4
5
6
7
8
9
10
11
12
13
builder.Services.AddUI(options =>
{
options.UseImageOptimization(opts =>
{
opts.DefaultQuality = 80; // 1-100, padrão 75
opts.Formats = ["image/webp"]; // formatos de saída preferidos
opts.CacheTtlSeconds = 14400; // padrão 4 horas
opts.MaxSourceSize = 10 * 1024 * 1024; // padrão 10 MB
});
});
app.UseStaticFiles();
app.MapUI(); // mapeia /_equantic/image
O contrato
1
GET /_equantic/image?url=<caminho>&w=<largura>&q=<qualidade>
Parâmetro
Regra
url
Obrigatório. Precisa começar com / e não pode conter .., então não sai da raiz de conteúdo.
w
Obrigatório. Precisa ser um dos AllowedWidths, senão a resposta é 400 nomeando os valores aceitos.
q
Opcional, 1–100. Cai para o DefaultQuality.
O formato da resposta é negociado a partir do cabeçalho Accept contra os Formats, com um fallback que o browser sempre consegue ler. Um miss redimensiona, converte e grava o resultado em CacheDirectory; um hit serve os bytes do cache com Cache-Control: public, max-age=<CacheTtlSeconds>. Uma fonte maior que MaxSourceSize é recusada em vez de decodificada, venha de onde vier: o otimizador e o gerador de placeholder param de ler no limite, então um stream aberto por quem chama segue o mesmo limite de um arquivo em wwwroot.
O que ele lê, e o que volta
Uma fonte é lida quando os seus bytes são um JPEG, PNG, GIF, WebP ou BMP, diga o nome o que disser. Um .tiff é recusado antes de ser aberto, e um arquivo que o otimizador não consegue ler, ou cujo cabeçalho pede mais de 16.383 × 16.383 pixels, recebe 400 sem nenhum pixel decodificado. O otimizador roda sobre o SkiaSharp, e os nativos dele para Linux, macOS e Windows vêm com o pacote, então não há nada para instalar nem chave de licença para configurar.
•
Orientação. A orientação que a câmera gravou é aplicada aos pixels, então w é a largura como exibida, e ImageOptimizer.GetDimensionsAsync responde o tamanho como exibido.
•
Animação. Um GIF ou WebP animado é servido como está, com o próprio content type, como o otimizador do Next.js serve: nenhum encoder aqui escreve quadros.
•
A resposta. Ela vem num dos formatos que um encoder daqui escreve, então Formats aceita image/webp, image/png e image/jpeg, e qualquer outro, image/avif inclusive, para o app na inicialização. Os pixels são sRGB e não levam perfil de cor, o que o browser lê como sRGB.
Opções
Opção
Padrão
Significado
DefaultQuality
75
Qualidade quando a requisição não diz.
DeviceSizes
640, 750, 828, 1080, 1200, 1920, 2048, 3840
Larguras para imagens de largura total.
ImageSizes
32, 48, 64, 96, 128, 256, 384
Larguras para imagens menores que a viewport.
AllowedWidths
derivado
DeviceSizes e ImageSizes, sem repetição e ordenados. É a lista da validação.
Formats
image/webp
Formatos de saída, melhor primeiro: image/webp, image/png, image/jpeg.
CacheTtlSeconds
14400
O que a resposta diz ao browser.
CacheDirectory
obj/eQuantic/image-cache
Onde os resultados codificados ficam.
MaxSourceSize
10 MB
Acima disso a fonte é recusada, lida pelo endpoint ou entregue por quem chama.
Placeholders desfocados
O BlurPlaceholderGenerator transforma um stream ou um arquivo numa data URL base64 minúscula. Obtido dos serviços que o UseImageOptimization registra, ou injetado, ele não lê nenhuma fonte além do MaxSourceSize do app:
1
2
var placeholders = app.Services.GetRequiredService<BlurPlaceholderGenerator>();
var placeholder = await placeholders.GenerateFromFileAsync("wwwroot/images/hero.jpg");
É um utilitário autônomo pelo mesmo motivo que o endpoint é: o vocabulário não tem propriedade de placeholder para receber o resultado.
Veja também
•
Componentes: o resto do vocabulário
•
Design System: tokens, incluindo o par de ColorToken que o DarkSource espelha
•
Estilo: o HtmlElement e a saída de emergência só-web