在今天的数字时代,有效的图像处理对于网页应用和API至关重要。 图形管理的一个关键方面是压缩,这有助于减少文件大小而不会对质量造成重大损害. 此指南将通过使用 Aspose.Imaging 为 .NET 构建一个充满活力的图标压縮 API 您最终将拥有一个功能性的 ASP.NET Core Web API,它会根据查询参数(格式、质量、重复等)接受图表并返回压制输出。

Aspose.Imaging 是一個強大的圖書館,可用於 .NET 中的圖像,它支持許多格式,並提供堅固的操作功能,包括損失(JPEG)和無损(PNG)工作流。

你要建造的

  • “终点”: POST /api/images/compress?format=jpeg&quality=75&maxWidth=1280&maxHeight=1280
  • ** 输入**:多部分文件(图像),可选的查询参数格式/质量/重量
  • ** 输出**:压缩图像流与正确 Content-Type 和Caching Headers
  • 安全:内容类型验证、尺寸限制和保存的代码/编码

原則

  • .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)控制损失压缩。
  • PNG 默认情况通常适用于第一版;如果您需要额外小型PNG,您可以稍后添加先进的调节。
  • TryStripMetadata 这是一个最努力的方法;代数据API因源格式而异。

/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注册 + 可选许可证)

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:设置项目

创建一个 ASP.NET Core Web API 项目。 Aspose.Imaging NuGet 包. 创建 Models, Services, 和 Controllers 如上所示的文件。

步骤2:设置 Aspose.Imaging(可选许可)

如果您有许可证,请在初创公司启动(参见) Program.cs这避免了评估水标,并确保了完整的功能。

步骤3:实施压缩服务

是的 ImageCompressionService:

  • 通过下载图像 Image.Load(Stream)
  • 可选切割甲状腺数据
  • 可选复制与视角比例保留
  • 存储到 JPEG 或 PNG 与格式合适的选项

步骤4:建立API控制器

ImageController 展示 POST /api/images/compress 接收文件和查询参数:

  • format: jpegpng (默认) jpeg)
  • quality: 1 至 100 (仅 JPEG;默认 80)
  • maxWidth/文本翻译为/maxHeight标签:下滑的边界
  • stripMetadata• 假设 true 以较小的产量

步骤5:测试火灾

使用任何 HTTP 客户端发送一个 multipart/form-data 请求一个单个文件字段名为 file, plus 可选查询参数. 检查:

  • Response Content-Type 比赛格式
  • 返回文件大小减少
  • 按照预期的重建工作

设计选择与最佳实践

  • ** 格式警告设置**:使用 JPEG Quality; PNG 保持为可预测的产量无损。
  • 下载之前编码:重新编辑首先会减少像素(大尺寸获胜),然后加密缩写比特进一步。
  • 清洁输入:保存内容类型、文件大小、查询界限。
  • :避免重复阅读整个文件到记忆中;保持流短寿和可搜索。
  • Caching:如果您从定义输入中提取名称/内容,则标记不变的答案;否则将缓存标题插入您的使用案例。
  • 安全性:验证内容类型并拒绝可疑的付费。
  • 可观察性:记录前/后大小和使用的参数;这有助于调整默认情况。
  • ** 折磨**:如果公开曝光,利率限制或要求 auth 防止滥用。

常见扩展(下载后)

  • WebP/AVIF编码器为更小的图像(添加新选项/contentType文件扩展在 BuildOptions).
  • PNG tuning(过滤/压缩级别)如果您需要额外小型无损资产。
  • 预定个人资料thumbnail, preview, hires 地图到已知的参数。
  • ** 标签** 或内容黑客服务相同的回复从缓存。
  • Async batch 终点,以同时压缩多个文件。

Troubleshooting

  • 大输入:增加 RequestSizeLimit 或流到 temp 存储。
  • Wrong 色彩:保证颜色空间以默认方式处理;先进的案例可能需要明确的颜型。
  • ** 没有尺寸减少(PNG)**: PNG 是无损的;允许重定向或转换到 JPEG 以获得更强大的比特节约。

总结

您现在有一个生产准备的动态图像压缩 API 使用 Aspose.Imaging. 控制器处理上传和参数; 该服务适用于安全的,格式清晰的压縮和可选的重复,然后返回一个正确打字的答案与缓存标题。 从这里,您可以添加更多的格形式,预设置,和查询策略,以适应您的网页板。

More in this category