오늘날의 디지털 시대에, 효율적인 이미지 처리 웹 응용 프로그램 및 APIs에 중요합니다. 이미지 관리의 핵심 측면 중 하나는 압축이며, 이는 품질에 상당한 위협없이 파일 크기를 줄이는 데 도움이됩니다.이 가이드는 Aspose.Imaging for .NET을 사용하여 역동적 인 이미지 압력 API를 구축함으로써 당신을 도와줍니다.
Aspose.Imaging은 .NET에서 이미지 작업을위한 강력한 라이브러리입니다.그것은 많은 형식을 지원하고 손실없는 (JPEG) 및 PNG) 작업 흐름을 포함하여 견고한 조작 기능을 제공합니다.우리는 효율적이고 확장 가능한 압축 서비스를 구축하기 위해 그것을 활용할 것입니다.
무엇을 만들 것인가
- 최종 포인트 :
POST /api/images/compress?format=jpeg&quality=75&maxWidth=1280&maxHeight=1280
- 최종 포인트 :
- 입력: 여러 부분 파일 (사진), 형식 / 품질 / 크기에 대한 선택적 쿼리 매개 변수
- 출력: 올바른 이미지와 함께 압축된 이미지 스트림
Content-Type
Caching 헤드셋 - 안전: 콘텐츠 유형 인증, 크기 제한 및 보관된 디코드/엔코드는
원칙
- 넷 8 (또는 .NET 6+)
- ASP.NET 코어 웹 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 결함은 일반적으로 첫 번째 버전을 위해 괜찮습니다; 당신이 추가 작은 P NG를 필요로하는 경우, 당신은 나중에 고급 튜닝을 추가 할 수 있습니다.
TryStripMetadata
그것은 최선의 접근 방식입니다; 메타 데이터 APIs는 출처 형식에 따라 다릅니다.
/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
첨부 파일 : 창조하기 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
: downscaling에 대한 제한stripMetadata
· 가짜true
작은 생산을 위해
5단계: API 테스트
모든 HTTP 클라이언트를 사용하여 multipart/form-data
단일 파일 필드 이름을 가진 요청 file
, 플러스 선택 쿼리 매개 변수. 확인:
- Response
Content-Type
경기 형식 - 반환된 파일 크기가 줄어든다.
- 예상대로 작업을 재개합니다.
디자인 선택 & 최고의 관행
- 포맷 명확한 설정: JPEG 사용
Quality
PNG는 예측 가능한 생산을 위해 손실이 없습니다. - 다운스케일 전에 암호화: 리시닝은 먼저 픽셀을 줄입니다 (대규모 우승), 그 다음 암코딩은 더 짧은 바이트.
- 수정 입력: 보관 콘텐츠 유형, 파일 크기, 쿼리 제한.
- ** 스트리밍**: 전체 파일을 메모리에 반복적으로 읽지 마십시오; 스트림을 짧고 검색 가능하게 유지하십시오.
- Caching: 당신이 결정적 인 입력에서 이름 / 콘텐츠를 추출하는 경우 변경되지 않은 반응을 표시; 그렇지 않으면 사용 사례에 캐시 헤드셋을 삽입합니다.
- Security: 콘텐츠 유형을 확인하고 의심스러운 지불을 거부합니다.
- ** 관찰 가능성**: 이전/다음 기록 크기 및 사용된 매개 변수; 이것은 기본 사항을 조정하는 데 도움이됩니다.
- Throttling: 공개적으로 노출되면, 속도 제한 또는 악용을 방지하기 위해 auth를 요구합니다.
일반 확장 (다음에 다운로드)
- WebP/AVIF 암호화는 더 작은 이미지를 위해 (새 옵션을 추가/
contentType
/ 파일 확장BuildOptions
). - PNG 튜닝 (필터링 / 압축 수준) 당신은 손실없는 자산을 필요로하는 경우.
- 프레세트 프로필* 예를 들어
thumbnail
,preview
,hires
알려진 매개 변수에 대한 지침.
- 프레세트 프로필* 예를 들어
- ETags 또는 콘텐츠 해싱은 캐시에서 동일한 응답을 제공합니다.
- Async 배치 끝점은 한 번에 여러 파일을 압축합니다.
Troubleshooting
- 큰 수입* : 증가
RequestSizeLimit
또는 흐름을 temp 저장합니다.
- 큰 수입* : 증가
- Wrong 색상: 안전한 색 공간은 기본으로 처리됩니다; 고급 사례는 명시적인 색형이 필요할 수 있습니다.
- ** 크기 감소 없음 (PNG)**: PNG는 손실이 없으며, 더 강력한 바이트 저축을 위해 JPEG로 다시 이동하거나 전환할 수 있습니다.
요약
당신은 지금 생산 준비가 된 역동적 인 이미지 압축 API를 사용하여 Aspose.Imaging. 컨트롤러는 업로드 및 매개 변수를 처리합니다; 서비스는 안전한, 형식 조명 압력 및 옵션 리시닝을 적용하고, 그 다음 캐시 헤드와 함께 적절하게 타입 된 응답을 다시 스트리밍합니다. 여기에서 더 많은 형식을 추가 할 수 있습니다, 프레세트, 그리고 당신의 웹 스택에 맞게 케시 전략.