Computer >> 컴퓨터 >  >> 프로그래밍 >> C#

C#에서 이미지를 압축해 저장하는 방법 – Bitmap과 GDI+ 활용 가이드


C# 이미지 처리의 기본: Bitmap과 GDI+

비트맵(Bitmap)은 그래픽 이미지를 구성하는 픽셀 데이터와 그 속성 정보를 함께 담고 있는 객체입니다. 비트맵을 파일로 저장할 때는 여러 표준 형식을 사용할 수 있으며, .NET의 GDI+는 BMP, GIF, EXIF, JPG(JPEG), PNG, TIFF 형식을 기본적으로 지원합니다.

Bitmap 클래스가 제공하는 다양한 생성자를 활용하면 파일, 스트림 등 여러 소스로부터 이미지 객체를 만들 수 있고, Save 메서드를 통해 이미지를 스트림이나 파일 시스템에 손쉽게 저장할 수 있습니다.

이미지를 압축해서 지정한 경로에 저장하기

아래 예제의 CompressAndSaveImageAsync 메서드는 입력받은 Bitmap 이미지를 JPEG 형식으로 압축한 뒤 지정된 경로에 저장합니다. 저장 시 Encoder.Quality 매개변수를 사용해 JPEG 품질(기본값 50)을 조절할 수 있습니다.

생성되는 새 이미지 파일 이름은 현재 사용자 ID현재 날짜·시간을 조합해 자동으로 만들어지므로 파일명 중복 문제를 피할 수 있습니다.

코드 예제

private async Task<string> CompressAndSaveImageAsync(Bitmap inputImage, int quality = 50)
{
    string imageSavedPath = string.Empty;
    try
    {
        // JPEG 인코더 가져오기
        var jpgEncoder = await GetEncoderAsync(ImageFormat.Jpeg);

        // 품질(quality) 인코더 매개변수 설정
        var imageEncoder = Encoder.Quality;
        var imageEncoderParameters = new EncoderParameters(1);
        var imageEncoderParameter = new EncoderParameter(imageEncoder, quality);
        imageEncoderParameters.Param[0] = imageEncoderParameter;

        // 사용자 ID와 현재 시각을 조합해 고유한 파일명 생성
        var userId = Regex.Replace(WindowsIdentity.GetCurrent().Name, @"[^0-9a-zA-Z]+", "_");
        var currentDateTime = Regex.Replace(DateTimeOffset.Now.ToString().Split('+')[0].Trim(), @"[^0-9a-zA-Z]+", "_");
        var imageName = $"{userId}_{currentDateTime}.jpg";

        // 저장 경로 지정 후 이미지 저장
        imageSavedPath = @"C:\Users\K\Desktop\Questions\Images";
        inputImage.Save(imageSavedPath, jpgEncoder, imageEncoderParameters);
        inputImage.Dispose();
    }
    catch (Exception ex)
    {
        throw;
    }
    return imageSavedPath;
}

private async Task<ImageCodecInfo> GetEncoderAsync(ImageFormat format)
{
    ImageCodecInfo imageCodecInfo = null;
    try
    {
        // 시스템에서 사용 가능한 이미지 인코더 목록 조회
        var codecs = ImageCodecInfo.GetImageEncoders();
        foreach (var codec in codecs)
        {
            if (codec.FormatID == format.Guid)
            {
                imageCodecInfo = codec;
            }
        }
    }
    catch (Exception ex)
    {
        throw;
    }
    return imageCodecInfo;
}

핵심 포인트 정리

  • JPEG 품질 조절: Encoder.QualityEncoderParameter를 사용하면 품질을 0~100 사이 값으로 자유롭게 설정할 수 있습니다. 값이 작을수록 용량은 줄어들지만 화질이 저하됩니다.
  • 인코더 검색: ImageCodecInfo.GetImageEncoders()로 시스템에 설치된 인코더 목록을 조회한 뒤, FormatID가 대상 형식(ImageFormat.Jpeg)의 GUID와 일치하는 인코더를 찾아 사용합니다.
  • 중복 방지 파일명: 사용자 ID와 타임스탬프를 정규식으로 정제해 조합하면 파일명 충돌 없이 이미지를 체계적으로 관리할 수 있습니다.
  • 리소스 해제: 저장이 끝난 Bitmap은 Dispose()로 반드시 해제해 메모리 누수를 방지해야 합니다.

실제 프로젝트에서는 Path.Combine(imageSavedPath, imageName)처럼 경로와 파일명을 결합해 전체 저장 경로를 구성하는 것이 안전합니다. 또한 이 예제는 WindowsIdentity처럼 Windows 전용 API를 사용하므로, 크로스 플랫폼 환경이라면 다른 방식으로 사용자 식별 값을 얻어야 한다는 점도 참고하세요.