在今天的数字时代,有效的图像处理对于网页应用和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
:jpeg
或png
(默认)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. 控制器处理上传和参数; 该服务适用于安全的,格式清晰的压縮和可选的重复,然后返回一个正确打字的答案与缓存标题。 从这里,您可以添加更多的格形式,预设置,和查询策略,以适应您的网页板。