У данашњој дигиталној ери, ефикасна обрада је од суштинског значаја за веб апликације и АПИ. Један од кључних аспеката управљања сликом је компресија, која помаже у смањењу величине датотеке без значајне компромиса на квалитет. Овај водич вас пролази кроз изградњу динамичке АПИ компакције слике користећи Асписе.Имање за .НЕТ. На крају ћете имати функционалну АСП.НЕт Цоре Веб АПС који прихвата слику и враћа компримовани излаз према параметрима претраге (формат, квалитета, ресинг и још много тога).

Aspose.Imaging je moćna knjižnica za rad sa slikama u .NET. podržava mnoge formate i pruža snažne funkcije manipulacije, uključujući gubitak (JPEG) i bez gubitaka (PNG) tokove rada.

Шта ћете изградити

    • Крајња тачка * : POST /api/images/compress?format=jpeg&quality=75&maxWidth=1280&maxHeight=1280
  • Увод: Мултипартни датотека (слика), опционални параметри за претрагу за формат / квалитет / величину
  • Излазе: компресирани поток слике са правилним Content-Type Кацхинг главе
  • Сигурност: валидација типа садржаја, ограничења величине и чувани декод / енкод

Принципи

  • NET 8 (или .NET 6+)
  • Пројекат ASP.NET Core Web API
  • НУГЕТ : Aspose.Imaging
  • Опционално: иницијализација лиценце у апликацији за стартап (ако користите лиценцирани објекат)

Структура пројекта (минимално)

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

Потпуни пример (Сервис + Контролер)

Замените именоване просторе места са именом простора вашег пројекта.

/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) контролише губитак компресије.
  • ПНГ дефолти су обично фине за прву верзију; ако вам је потребан додатни мали ПНГ, можете додати напредни тунинг касније.
  • TryStripMetadata је најбољи напор приступ; метадане АПИ варирају по изворном формату.

/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 (ИД регистрација + опционална лиценца)

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

Корак по корак водич

Корак 1: Поставите пројекат

Креирајте АСП.НЕТ Цоре Веб АПИ пројекат. Aspose.Imaging Подешавање пакета. креирајте Models, Services, и Controllers Списак као што је приказано горе.

Корак 2: Конфигурисати Аппосе.Имагинг (опционална лиценца)

Ако имате лиценцу, покрените је на стартапу (види Program.csОво избегава евалуацију водених знакова и обезбеђује пуну функционалност.

Корак 3: Увођење услуге компресије

У том ImageCompressionService:

  • Преузмите слике преко Image.Load(Stream)
  • Опционално уклањају метадане
  • Опционално рецизира са сачуваним односом аспекта
  • Uštede na JPEG ili PNG sa opcijama koje odgovaraju formatu

Корак 4: Изградите АПИ контролер

ImageController изложбе POST /api/images/compress узимање датотеке и претраге параметара:

  • format: jpeg или png (у подразумевању jpeg)
  • quality1 – 100 (само ЈПЕГ; дефолт 80)
  • maxWidth/maxHeightОграничења за спуштање
  • stripMetadata• Дефолт true Za manju proizvodnju

Корак 5: Тестирање АПИ-а

Користите било који ХТТП клијент да бисте послали multipart/form-data Захтев са једним пољем датотеке именом file, плус опционални параметри за претрагу. проверите:

  • Response Content-Type Формат утакмице
  • Величина враћеног датотеке се смањује
  • Повратак рада као што је очекивано

Дизајн избора и најбоље праксе

  • Формат-овере подешавања: ЈПЕГ користи QualityPNG ostaje bez gubitaka za predvidljiv proizvod.
  • Downscale pre kodiranja: Resizing prvo smanjuje piksele (najveće veličine dobija), a zatim kodiranje kratke bajte dalje.
  • Sanitize inputs: tip sadržaja za čuvanje, veličina datoteke, granice upitnika.
  • Стреинг: Избегавајте читање целог датотеке у меморију поновљено; држите токове краткотрајним и траженим.
  • Цацхинг: Маркирају одговоре као непроменљиве ако добијете име / садржај из детерминистичких уноса; у супротном тунирајте кеш наслове на ваш случај коришћења.
  • Сигурност: Проверите тип садржаја и одбаците сумњиве плаћања. размотрите скенирање за погрешне слике.
  • Observabilnost: Log veličine pre/posle i parametri korišteni; to vam pomaže da tune predviđanja.
  • Троттинг: Ако је јавно изложена, лимит стопе или захтева аутх да би се спречило злоупотреба.

Уобичајене проширења (наставити касније)

  • WebP/AVIF кодирачи за још мање слике (додајте нове опције/contentTypeПроширење датотеке у BuildOptions).
  • ПНГ тунинг (ниво филтрирања/компресије) ако вам је потребан екстра мали имовина без губитка.
  • ** Преузмите профиле** као thumbnail, preview, hires Истраживање познатих параметара.
  • Етаг или хашинг садржаја да служи идентичне одговоре из кеше.
  • Async batch endpoint za komprimiranje više datoteka u jednom trenutku.

Troubleshooting

  • Велики унос: повећање RequestSizeLimit или пребацивање у складиштење.
  • Борне боје: Обезбеђени боји се обрађују по подразумевању; напредни случајеви могу захтевати експлицитну врсту боја.
  • Нема смањења величине (ПНГ): ПНГ је без губитака; омогућава повраћање или прелазак на ЈПЕГ за јаче штедње бита.

Резюме

Сада имате припремљену за производњу динамичку АПИ за компресију слике користећи Аспасе.Имагинг. Контролер управља преузимањима и параметрима; услуга се примењује безбедно, формат-оверивање и опционално рецидирање, а затим враћа правилно типиран одговор са кеш насловима. Овде можете додати више формата, пресета и кешинг стратегија да одговара вашем веб стаку.

More in this category