eQuantic.UIeQuantic.UI
Docs
Playground
GitHub
DocsEcosystem
Image Component
Edit this page
3 min read
🌐 This page in: English · Português
The Image component is a high-performance alternative to the standard HTML <img> tag, heavily inspired by Next.js. It helps optimize images for speed and search engine ranking.
Features
Lazy Loading: Images are only loaded when they enter the viewport by default.
CLS Prevention: Automatically sets width and height to prevent layout shifts.
Layout Modes: Supports standard fixed sizing or a Fill mode for responsive containers.
Blur-up Placeholders: Support for low-resolution placeholders while the full image loads.
LCP Optimization: Use the Priority flag for critical above-the-fold images.
Server-Side Optimization: Auto resize, format conversion (WebP/AVIF), and quality control via eQuantic.UI.Images.
Basic Usage
1
2
3
4
5
6
7
new Image
{
Src = "/path/to/image.jpg",
Alt = "Description",
Width = 800,
Height = 600
}
Layout Modes
Fixed (Default)
Requires Width and Height. The image maintains these dimensions.
Fill
The image will fill its parent container. The parent MUST have relative positioning.
1
2
3
4
5
6
7
8
new Container
{
ClassName = "relative h-64",
Children =
{
new Image { Src = "/hero.webp", Fill = true }
}
}
Placeholders
Use Blur placeholders for a smoother loading experience.
1
2
3
4
5
6
7
8
new Image
{
Src = "/large.jpg",
Width = 800,
Height = 600,
Placeholder = ImagePlaceholder.Blur,
BlurDataURL = "data:image/webp;base64,..."
}
Server-Side Optimization
The eQuantic.UI.Images package enables Next.js-style server-side image optimization. When enabled, local images are automatically resized, converted to WebP, and served via an optimized endpoint.
How It Works
1
2
3
4
5
6
7
8
9
10
Image Component (Optimize = true)
▼ Generates srcset URLs
/_equantic/image?url=/images/hero.jpg&w=640&q=80
▼ Image Optimization Endpoint
├── Validates parameters (width in allowed sizes, quality 1-100)
├── Checks filesystem cache (obj/eQuantic/image-cache/)
├── On miss: resize → format convert → cache → serve
└── Content negotiation: Accept header → WebP or JPEG fallback
Setup
1. Install the package
1
<PackageReference Include="eQuantic.UI.Images" />
2. Register services
1
2
3
4
5
6
7
8
9
10
11
// Program.cs
builder.Services.AddUI(options =>
{
options.UseImageOptimization(opts =>
{
opts.DefaultQuality = 80; // 1-100, default: 75
opts.Formats = ["image/webp"]; // Preferred output formats
opts.CacheTtlSeconds = 14400; // Cache TTL (default: 4 hours)
opts.MaxSourceSize = 10 * 1024 * 1024; // Max source size (default: 10MB)
});
});
3. Map the endpoint
1
2
app.UseStaticFiles();
app.MapUI(); // Automatically maps /_equantic/image endpoint via UIOptions
Optimization Modes
Fixed-Size Images (1x/2x Density Descriptors)
When Width is set and Fill is false, the component generates 1x and 2x density descriptors for retina displays:
1
2
3
4
5
6
7
new Image
{
Src = "/images/hero.jpg",
Alt = "Hero",
Width = 800,
Height = 600
}
Generated HTML:
1
2
3
4
5
6
7
8
9
10
11
<img
src="/_equantic/image?url=%2Fimages%2Fhero.jpg&w=828&q=80"
srcset="
/_equantic/image?url=%2Fimages%2Fhero.jpg&w=828&q=80 1x,
/_equantic/image?url=%2Fimages%2Fhero.jpg&w=1920&q=80 2x
"
width="800"
height="600"
loading="lazy"
decoding="async"
/>
Responsive Images (Width Descriptors)
When using Fill mode or without Width, the component generates a full srcset with all configured sizes:
1
2
3
4
5
6
new Image
{
Src = "/images/hero.jpg",
Alt = "Full-width hero",
Fill = true
}
Generated HTML:
1
2
3
4
5
6
7
8
9
10
<img
src="/_equantic/image?url=%2Fimages%2Fhero.jpg&w=3840&q=80"
srcset="/_equantic/image?url=%2Fimages%2Fhero.jpg&w=32&q=80 32w,
/_equantic/image?url=%2Fimages%2Fhero.jpg&w=48&q=80 48w,
... (all configured sizes) ...
/_equantic/image?url=%2Fimages%2Fhero.jpg&w=3840&q=80 3840w"
sizes="100vw"
loading="lazy"
decoding="async"
/>
Custom Quality
Override the global quality setting per image:
1
2
3
4
5
6
7
8
new Image
{
Src = "/images/background.jpg",
Alt = "Background",
Width = 1200,
Height = 800,
Quality = 50 // Lower quality for background images
}
Opt-In / Opt-Out
Optimization is controlled at two levels:
Global (UseImageOptimization())
Per-Image (Optimize)
Result
Enabled
null (default)
Optimized
Enabled
true
Optimized
Enabled
false
Not optimized
Not called
null (default)
Not optimized
Not called
true
Optimized\*
\*Requires the endpoint to be mapped; otherwise, URLs will be generated but won't resolve.
1
2
3
4
5
6
7
// Explicit opt-out (e.g., SVGs don't need optimization)
new Image
{
Src = "/images/logo.svg",
Alt = "Logo",
Optimize = false
}
Security
Only local images (paths starting with /) are optimized. External URLs are never proxied.
Path traversal attacks (..) are blocked.
Width must be in the configured allowed sizes (DeviceSizes + ImageSizes).
Quality must be 1-100.
Source file size is limited by MaxSourceSize (default 10MB).
Content Negotiation
The endpoint reads the browser's Accept header and serves the best supported format:
1.
Checks configured Formats (e.g., ["image/avif", "image/webp"])
2.
Returns the first format the browser supports
3.
Falls back to JPEG if no match
Caching
Filesystem cache: Optimized images are cached in obj/eQuantic/image-cache/ (configurable)
Cache key: SHA256 of (url, width, quality, format)
TTL: Configurable via CacheTtlSeconds (default: 4 hours)
Thread-safe: Concurrent requests for the same image are deduplicated
Response headers: Cache-Control: public, max-age={ttl}, Vary: Accept
Blur Placeholder Generator
The BlurPlaceholderGenerator service creates tiny 8px-wide JPEG placeholders as base64 data URLs:
1
2
3
4
5
6
// Inject from DI
var generator = app.Services.GetRequiredService<BlurPlaceholderGenerator>();
// Generate from file
var dataUrl = await generator.GenerateFromFileAsync("wwwroot/images/hero.jpg");
// Returns: "data:image/jpeg;base64,/9j/4AAQ..."
Configuration Options
Property
Type
Default
Description
DeviceSizes
int[]
[640, 750, 828, 1080, 1200, 1920, 2048, 3840]
Allowed widths for viewport-sized images.
ImageSizes
int[]
[32, 48, 64, 96, 128, 256, 384]
Allowed widths for smaller images.
Formats
string[]
["image/webp"]
Preferred output formats (ordered by priority).
DefaultQuality
int
75
Default quality (1-100).
CacheTtlSeconds
int
14400
Cache TTL in seconds (4 hours).
CacheDirectory
string
"obj/eQuantic/image-cache"
Filesystem cache directory.
MaxSourceSize
long
10485760
Max source image size in bytes (10MB).
Properties
Property
Type
Default
Description
Src
string
-
Image source URL.
Alt
string
-
Alternative text for accessibility.
Width
int?
-
Width in pixels.
Height
int?
-
Height in pixels.
Fill
bool
false
If true, fills the parent container.
Loading
ImageLoading
Lazy
Lazy or Eager.
Priority
bool
false
High priority for preloading (LCP).
Placeholder
ImagePlaceholder
None
Blur or Empty.
BlurDataURL
string?
-
Small Data URL for blurred background.
ObjectFit
string?
"cover"
CSS object-fit property (for Fill).
Optimize
bool?
null
Override global optimization setting.
Quality
int
0
Image quality (1-100). 0 = use global default.
SrcSet
string?
-
Manual srcset (ignored when optimized).
Sizes
string?
-
Manual sizes attribute.
Architecture
The eQuantic.UI.Images package follows the self-contained package pattern:
1
2
3
4
5
6
7
8
9
eQuantic.UI.Core
└── ImageOptimizationState (static bridge)
↑ read by ↑ written by
eQuantic.UI.Components eQuantic.UI.Images
└── Image component ├── ImageOptimizer (SixLabors.ImageSharp)
├── ImageCache (filesystem + SemaphoreSlim)
├── ImageOptimizationMiddleware
├── BlurPlaceholderGenerator
└── ImageExtensions (DI + endpoint)
This avoids circular dependencies: Core defines the state, Components reads it, Images writes it.