Nykypäivän digitaalisessa iässä tehokas kuvankäsittely on välttämätöntä web-sovelluksille ja API:ille. Yksi tärkeimmistä näkökohdista kuvakäsittelyn on kompressi, joka auttaa vähentämään tiedostojen koon ilman huomattavaa vaarantaa laatua. Tämä opas ohjaa sinua rakentamalla dynaaminen kuva-kompressio API käyttämällä Aspose.Imaging for .NET. Lopulta sinulla on toimiva ASP.NET Core Web API, jolla hyväksyt kuvat ja palautetaan kompressoitu tuotto kyselyn parametrien (muoto, laatu, uudelleenkuvaaminen ja enemmän).

Aspose.Imaging on tehokas kirjasto kuvien kanssa .NET. Se tukee monia muotoja ja tarjoaa vahvoja manipulointiominaisuuksia, mukaan lukien tappio (JPEG) ja tappamaton (PNG) työnkulut.

Mitä rakennat

  • Lopullinen kohde *: POST /api/images/compress?format=jpeg&quality=75&maxWidth=1280&maxHeight=1280
  • Inputs: Monikokoinen tiedosto (kuva), valinnaiset kyselyparametrit muotoon / laatuun / koon
  • Outputs: Kompressiivinen kuvan virta oikealla Content-Type ja caching päälliköt
  • Turvallisuus: Sisällöntyyppinen validointi, koon rajoitukset ja säilytetty dekode/encode

edellytykset

  • • .NET 8 (tai .Net 6+)
  • ASP.NET Core Web API -hanke
  • Ja nyt: Aspose.Imaging
  • Vaihtoehtoinen: lisenssin aloittaminen sovelluksen käynnistämisessä (jos käytät lisensoitua rakennetta)

Projektin rakenne (minimi)

/Controllers
  ImageController.cs
/Services
  ImageCompressionService.cs
/Models
  CompressionRequest.cs
Program.cs
appsettings.json

Täydellinen esimerkki (Service + Controller)

Vaihda paikanhaltijan nimipaikat projektisi nimipisteellä.

/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) hallitsee tappion kompressiota.
  • PNG-vaatimukset ovat tyypillisesti hienoja ensimmäiselle versiolle; jos tarvitset ylimääräisiä pieniä pNG:itä, voit lisätä kehittyneitä tunteita myöhemmin.
  • TryStripMetadata on parhaiten tehokas lähestymistapa; metadata APIs vaihtelevat lähdeformaatin mukaan.

/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 (Rekisteröinti + valinnainen lisenssi)

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();

Vaiheittainen opas

Vaihe 1: Suunnittele projekti

Luo ASP.NET Core Web API -hanke. Aspose.Imaging Laajennettu paketti. luo Models, Services, ja Controllers Käsikirjoja kuten edellä on kuvattu.

Vaihe 2: Aseta Aspose.Imaging (vaihtoehtoinen lisenssi)

Jos sinulla on lisenssi, aloita se startupissa (katso Program.csTämä estää arvioinnin vesimerkkejä ja varmistaa täydellisen toiminnallisuuden.

Vaihe 3: Kompressiopalvelun toteuttaminen

Se on ImageCompressionService:

  • Lataa kuvia kautta Image.Load(Stream)
  • Vaihtoehtoisesti metatiedot
  • Vaihtoehtoisesti kierrätys aspekti suhteessa säilytetty
  • Säästää JPEG: lle tai PNG:lle muotoon sopivilla vaihtoehdoilla

Vaihe 4: Rakenna API-ohjain

ImageController Näyttelyt POST /api/images/compress Tiedosto ja kysely parametrit:

  • format: jpeg tai png ( oletusarvoinen jpeg)
  • quality1–100 (vain JPEG; oletusarvo 80)
  • maxWidth/maxHeight• rajat laskeutumiseen
  • stripMetadata• Defaultti true Vähemmän tuotantoa

Vaihe 5: Testaa API

Käytä HTTP-klienttia lähettääksesi multipart/form-data pyyntö yhdellä tiedoston kentällä nimeltään file, plus valinnaiset kyselyparametrit. Tarkista:

  • Response Content-Type Otteluformaatti
  • Palautetun tiedoston koko pienenee
  • Työt toistetaan odotettua

Suunnitteluvaihtoehdot ja parhaat käytännöt

  • Format-varmuuden asetukset: JPEG käyttää QualityPNG on ennustettavissa oleva tuotto.
  • Downscale ennen koodausta: Resizing vähentää pikselejä ensin (suurin koko voittaa), sitten koodat lyhennät bytejä edelleen.
  • Sanitisaatiot: Säilytä sisältö tyyppi, tiedoston koko, kyselyn rajat.
  • Streaming: Vältä koko tiedoston lukemista muistiin toistuvasti; pidä virrat lyhytaikaisia ja etsimättömiä.
  • Caching: Markkaa vastaukset muuttumattomana, jos tuodaan nimen/sisällön deterministisista tuloksista; muutoin tunnistaa cache-päälliköt käytöstäsi.
  • Turvallisuus: Valitse sisällön tyyppi ja hylkää epäilyttäviä maksuja.
  • ** Huomaamattomuus**: Rekisteröinti ennen/ jälkeen ja käytetyt parametrit; tämä auttaa sinua tunnistamaan oletukset.
  • Trotling: Jos julkisesti esitetään, korko-raja tai vaatii auth estääkseen väärinkäytön.

Yleiset laajennukset (drop-in myöhemmin)

  • WebP/AVIF koodit vielä pienemmille kuville (lisätä uusia vaihtoehtoja/contentType/ tiedoston laajennus BuildOptions).
  • PNG tuning (suodatus/kompressiotaso) jos tarvitset vähäisiä menetettömiä varoja.
  • Lisää profiileja kuten thumbnail, preview, hires Tietyt parametrit tunnetaan tiedossa.
  • ETags tai sisällön hashing palvelemaan samankaltaisia vastauksia cache.
  • Async batch endpoint kompressoi useita tiedostoja kerralla.

Troubleshooting

    • Suuri tulos*: Lisääntyminen RequestSizeLimit tai virtaa temp tallennukseen.
  • Punainen väri: Varmista värivaihe on käsitelty oletusarvoilla; kehittyneet tapaukset saattavat vaatia nimenomaista värityyppiä.
  • ** Ei koon vähennystä (PNG)**: PNG on häviämätön; mahdollistaa uudelleenmuodostuksen tai siirtymisen JPEG:een vahvempien bytin säästöjen vuoksi.

Yhteenveto

Nyt sinulla on tuotantoa valmiina dynaaminen kuvan kompressi API käyttämällä Aspose.Imaging. ohjaimen käsittelee latauksia ja parametreja; palvelu soveltaa turvallista, muoto-varmuus kompressio ja valinnainen uudelleenkäyttö, sitten virtaa takaisin asianmukaisesti kirjoitettu vastaus cache-päälliköt. Täältä voit lisätä enemmän muodoja, esityksiä ja caching strategioita sopii web stack.

More in this category