I dagens digitale tidsalder er effektiv billedbehandling afgørende for webapplikationer og APIs. En af de vigtigste aspekter af billedsstyring er kompression, som hjælper med at reducere filstørrelser uden signifikant kompromittering af kvaliteten. Denne guide går dig gennem opbygning af en dynamisk image-kompression API ved hjælp af Aspose.Imaging for .NET. Til sidst vil du have en funktionel ASP.NET Core Web API, der accepterer billeder og returnerer komprimeret udgang efter efterspørgsel parametre (format, kvalitet, resing, og mere).
Aspose.Imaging er en kraftfuld bibliotek til at arbejde med billeder i .NET. Det understøtter mange formater og giver robuste manipulationsfunktioner, herunder tab (JPEG) og tabsløse (PNG) arbejdsprocesser.
Hvad du vil bygge
- ”Endpoint” er:
POST /api/images/compress?format=jpeg&quality=75&maxWidth=1280&maxHeight=1280
- Inputs: Multipart fil (billede), valgfrie spørgeskemaer for format/kvalitet/resize
- Outputs: Komprimeret billedstrøm med korrekt
Content-Type
og caching headers - Sikkerhed: Validering af indholdstype, størrelsesgrænser og gemt dekode/encode
Forudsætninger
- • NET 8 (eller .NET 6+)
- ASP.NET Core Web API projekt
- Det er nu:
Aspose.Imaging
- Optionelt: licens initialisering i app startups (hvis du bruger en licensieret bygning)
Projektstrukturen (minimalt)
/Controllers
ImageController.cs
/Services
ImageCompressionService.cs
/Models
CompressionRequest.cs
Program.cs
appsettings.json
Et komplet eksempel (Service + Controller)
Udskift pladserens navnepladser med dit projekt.
/Models/CompressionRequest.cs
namespace ImageApi.Models;
public sealed class CompressionRequest
{
// "jpeg" or "png"
public string Format { get; init; } = "jpeg";
// 1..100 (applies to JPEG only; PNG is lossless)
public int? Quality { get; init; } = 80;
// Optional resize bounds; image is resized preserving aspect ratio if either is provided.
public int? MaxWidth { get; init; }
public int? MaxHeight { get; init; }
// If true, strip metadata (EXIF, IPTC) where applicable to reduce size further.
public bool StripMetadata { get; init; } = true;
// Guardrails
public void Validate()
{
var fmt = Format?.ToLowerInvariant();
if (fmt is not "jpeg" and not "png")
throw new ArgumentException("Unsupported format. Use 'jpeg' or 'png'.");
if (Quality is { } q && (q < 1 || q > 100))
throw new ArgumentException("Quality must be between 1 and 100.");
if (MaxWidth is { } w && w <= 0) throw new ArgumentException("MaxWidth must be positive.");
if (MaxHeight is { } h && h <= 0) throw new ArgumentException("MaxHeight must be positive.");
}
}
/Services/ImageCompressionService.cs
using Aspose.Imaging;
using Aspose.Imaging.ImageOptions;
using ImageApi.Models;
namespace ImageApi.Services;
public interface IImageCompressionService
{
Task<(MemoryStream output, string contentType, string fileExt)> CompressAsync(
Stream input, CompressionRequest req, CancellationToken ct = default);
}
public sealed class ImageCompressionService : IImageCompressionService
{
private readonly ILogger<ImageCompressionService> _logger;
public ImageCompressionService(ILogger<ImageCompressionService> logger)
{
_logger = logger;
}
public async Task<(MemoryStream output, string contentType, string fileExt)> CompressAsync(
Stream input, CompressionRequest req, CancellationToken ct = default)
{
req.Validate();
// Defensive copy to a seekable stream
var inbound = new MemoryStream();
await input.CopyToAsync(inbound, ct).ConfigureAwait(false);
inbound.Position = 0;
// Load image via Aspose.Imaging
using var image = Image.Load(inbound);
// Optional: strip metadata (where applicable)
if (req.StripMetadata)
{
TryStripMetadata(image);
}
// Optional resize (preserve aspect ratio)
if (req.MaxWidth.HasValue || req.MaxHeight.HasValue)
{
ResizeInPlace(image, req.MaxWidth, req.MaxHeight);
}
// Choose encoder and options
string fmt = req.Format.ToLowerInvariant();
var (options, contentType, ext) = BuildOptions(fmt, req.Quality);
// Save to output
var output = new MemoryStream();
image.Save(output, options);
output.Position = 0;
_logger.LogInformation("Compressed image to {Bytes} bytes as {Ext}", output.Length, ext);
return (output, contentType, ext);
}
private static void ResizeInPlace(Image image, int? maxW, int? maxH)
{
var w = image.Width;
var h = image.Height;
double scaleW = maxW.HasValue ? (double)maxW.Value / w : 1.0;
double scaleH = maxH.HasValue ? (double)maxH.Value / h : 1.0;
double scale = Math.Min(scaleW, scaleH);
if (scale < 1.0)
{
int newW = Math.Max(1, (int)Math.Round(w * scale));
int newH = Math.Max(1, (int)Math.Round(h * scale));
image.Resize(newW, newH);
}
}
private static (ImageOptionsBase options, string contentType, string ext) BuildOptions(string fmt, int? quality)
{
switch (fmt)
{
case "jpeg":
{
var q = quality ?? 80;
var jpeg = new JpegOptions { Quality = q };
return (jpeg, "image/jpeg", "jpg");
}
case "png":
{
// PNG is lossless; using defaults ensures broad compatibility.
// Many PNG tunables exist, but defaults are safe and effective.
var png = new PngOptions();
return (png, "image/png", "png");
}
default:
throw new ArgumentOutOfRangeException(nameof(fmt), "Unsupported format.");
}
}
private static void TryStripMetadata(Image image)
{
try
{
// Not every format exposes EXIF/IPTC the same way; a best-effort clear:
if (image is RasterImage raster)
{
raster.RemoveAllFonts();
raster.SetPropertyItems(Array.Empty<PropertyItem>());
}
}
catch
{
// Non-fatal; ignore if format doesn't support these operations
}
}
}
Notes
JpegOptions.Quality
(1-100) kontrollerer tab kompression.- PNG-defekter er typisk fine for en første version; hvis du har brug for ekstra små pNG’er, kan du tilføje avanceret tuning senere.
TryStripMetadata
er en best-effort tilgang; metadata APIs varierer afhængigt af kildeformat.
/Controllers/ImageController.cs
using ImageApi.Models;
using ImageApi.Services;
using Microsoft.AspNetCore.Mvc;
namespace ImageApi.Controllers;
[ApiController]
[Route("api/images")]
public sealed class ImageController : ControllerBase
{
private static readonly HashSet<string> AllowedContentTypes = new(StringComparer.OrdinalIgnoreCase)
{
"image/jpeg", "image/png", "image/gif", "image/webp", "image/bmp", "image/tiff"
};
private readonly IImageCompressionService _svc;
private readonly ILogger<ImageController> _logger;
public ImageController(IImageCompressionService svc, ILogger<ImageController> logger)
{
_svc = svc;
_logger = logger;
}
// POST /api/images/compress?format=jpeg&quality=75&maxWidth=1280&maxHeight=1280
[HttpPost("compress")]
[RequestSizeLimit(25_000_000)] // 25 MB cap; adjust to your needs
public async Task<IActionResult> Compress(
[FromQuery] string? format,
[FromQuery] int? quality,
[FromQuery] int? maxWidth,
[FromQuery] int? maxHeight,
[FromQuery] bool stripMetadata = true,
IFormFile? file = null,
CancellationToken ct = default)
{
if (file is null || file.Length == 0)
return BadRequest("No file uploaded.");
if (!AllowedContentTypes.Contains(file.ContentType))
return BadRequest("Unsupported content type. Upload a common raster image (JPEG, PNG, GIF, WebP, BMP, TIFF).");
var req = new CompressionRequest
{
Format = string.IsNullOrWhiteSpace(format) ? "jpeg" : format!,
Quality = quality,
MaxWidth = maxWidth,
MaxHeight = maxHeight,
StripMetadata = stripMetadata
};
await using var input = file.OpenReadStream();
var (output, contentType, ext) = await _svc.CompressAsync(input, req, ct);
// Strong caching for immutable responses (tune for your app/CDN)
Response.Headers.CacheControl = "public,max-age=31536000,immutable";
return File(output, contentType, fileDownloadName: BuildDownloadName(file.FileName, ext));
}
private static string BuildDownloadName(string originalName, string newExt)
{
var baseName = Path.GetFileNameWithoutExtension(originalName);
return $"{baseName}-compressed.{newExt}";
}
}
Program.cs
(DI registrering + valgfri licens)
using Aspose.Imaging;
using ImageApi.Services;
var builder = WebApplication.CreateBuilder(args);
// Optional: initialize Aspose license from a file or stream if you have one
// var license = new Aspose.Imaging.License();
// license.SetLicense("Aspose.Total.lic");
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<IImageCompressionService, ImageCompressionService>();
var app = builder.Build();
app.UseRouting();
app.UseAuthorization();
app.MapControllers();
// Enable for local testing
app.UseSwagger();
app.UseSwaggerUI();
app.Run();
Step-by-Step Guide
Første skridt: Sæt projektet op
Skab et ASP.NET Core Web API projekt. Aspose.Imaging
NuGet pakke. skab den Models
, Services
, og Controllers
arkiver som vist ovenfor.
Trin 2: Konfigurer Aspose.Imaging (valglig licens)
Hvis du har en licens, skal du initialisere den ved start (se Program.cs
Dette undgår evaluering af vandmærker og sikrer fuld funktionalitet.
Trin 3: Implementering af kompressionstjenesten
Den ImageCompressionService
:
- Oplader billeder via
Image.Load(Stream)
- Optionelt striber metadata
- Optionelt residerer med aspektforhold bevaret
- Sparer til JPEG eller PNG med formatmæssige muligheder
Trin 4: Opbyg API-kontroller
ImageController
Udstillinger POST /api/images/compress
Tag en fil og spørge parametre:
format
:jpeg
ellerpng
(default afjpeg
)quality
1–100 (kun JPEG; standard 80)maxWidth
/maxHeight
Grænser for nedskillelsestripMetadata
af defaulttrue
For mindre udbytte
Trin 5: Testning af branden
Brug ethvert HTTP-klient til at sende en multipart/form-data
Forespørgsel med et enkelt filfelt, der hedder file
, plus valgfrie spørgeskemaer. Kontrollér:
- Response
Content-Type
Kampe i format - Returnerede filer reduceres
- Gennemførelse af arbejde som forventet
Designvalg og bedste praksis
- Format-varselindstillinger: JPEG bruger
Quality
PNG forbliver tabløs for forudsigelig produktion. - Downscale før kodning: Resizing reducerer piksler først (største størrelser vinder), derefter koder skridt byte yderligere.
- Sanitize inputs: Guard indholdstype, filstørrelse, forespørgselsegrænser.
- Streaming: Undgå at læse hele filen ind i hukommelsen gentagne gange; holde strømme kortlivede og søgbare.
- Caching: Markér svar som uændret, hvis du afgiver navn/indhold fra deterministiske indtægter; ellers tune cache-hovedere til din brug.
- Sikkerhed: Validerer indholdstypen og afviser mistænkelige betalinger. overveje at scanne for malformede billeder.
- Observabilitet: Log størrelser før/efter og parametre, der bruges; dette hjælper dig med at tune forekomster.
- Throttling: Hvis udsat offentligt, rentegrænse eller kræve auth for at forhindre misbrug.
Gennemsigtige udvidelser (drop-in senere)
- WebP/AVIF koder til endnu mindre billeder (tilføj nye muligheder/
contentType
Filforlængelse iBuildOptions
). - PNG tuning (filtering/kompression niveau) hvis du har brug for ekstra små, tabløse aktiver.
- ** Preset profiler** som
thumbnail
,preview
,hires
Mapping til kendte parametre. - ETags eller indhold hashing til at tjene identiske svar fra cache.
- Async batch endpoint til at komprimere flere filer på én gang.
Troubleshooting
- ** Store indtægter**: Øget
RequestSizeLimit
eller strøm til temp opbevaring. - Range farver: Sikker farvespace behandles af standard; avancerede tilfælde kan kræve en udtrykkelig farve type.
- Ingen størrelsesreduktion (PNG): PNG er tabløst; tillader resize eller skifte til JPEG for stærkere bytebesparelser.
Samlinger
Du har nu en produktionsberettiget dynamisk image kompression API ved hjælp af Aspose.Imaging. Controller håndterer opladninger og parametre; tjenesten anvender sikker, format-bevidst komprimering og valgfri resing, så strømmer tilbage en korrekt typet respons med cache heads. Fra her kan du tilføje flere formater, forudset, og caching strategier til at matche din web stack.
More in this category
- Optimering af animerede GIF'er i .NET ved hjælp af Aspose.Imaging
- Optimerer Multi-Page TIFF'er for arkiver i .NET med Aspose
- Cropping produktbilleder til e-handelsplatforme ved hjælp af Aspose.Imaging for .NET
- Data-drevne animationer i .NET med Aspose.Imaging
- HEIC til JPEG/PNG Conversion med Aspose.Imaging for .NET