Skip to content

AWS S3 이미지 파일 Deflater 활용하여 압축을 통해서 JPG 기준 이미지 16.01% 크기 감소

김무건 edited this page Sep 11, 2023 · 8 revisions

image

블로그 정리

https://velog.io/@geon_km/S3-%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%8C%8C%EC%9D%BC-%EC%95%95%EC%B6%95Compressed%EC%9D%84-%ED%86%B5%ED%95%B4-%EC%B5%9C%EC%A0%81%ED%99%94

sequenceDiagram
    participant 사용자 as 사용자 
    participant Client as 클라이언트
    participant Server as 서버
    participant S3 as AWS S3
    
    사용자->>Client: 회원 이미지 업로드 클릭
    Client->>Server: 이미지 업로드 요청
    Server->>Server: 이미지 압축
    Server->>S3: 압축된 이미지 업로드
    S3-->>Server: 업로드 성공 메시지
    Server->>S3: 압축된 이미지 다운로드 요청
    S3-->>Server: 압축된 이미지 다운로드
    Server->>Server: 이미지 디코딩
    Server-->>Client: 이미지 전달
    Client-->>사용자: 이미지 성공 처리
Loading
    public static byte[] compressImage(byte[] data) {
        Deflater deflater = new Deflater();
        deflater.setLevel(Deflater.BEST_COMPRESSION);
        deflater.setInput(data);
        deflater.finish();

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
        byte[] tmp = new byte[4 * 1024];
        while (!deflater.finished()) {
            int size = deflater.deflate(tmp);
            outputStream.write(tmp, 0, size);
        }
        try {
            outputStream.close();
        } catch (Exception ignored) {
        }
        return outputStream.toByteArray();
    }


    public static byte[] decompressImage(byte[] data) {
        Inflater inflater = new Inflater();
        inflater.setInput(data);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
        byte[] tmp = new byte[4 * 1024];
        try {
            while (!inflater.finished()) {
                int count = inflater.inflate(tmp);
                outputStream.write(tmp, 0, count);
            }
            outputStream.close();
        } catch (Exception ignored) {
        }
        return outputStream.toByteArray();
    }

    public String uploadCompressedImage(MultipartFile file) {
        if (file == null || file.isEmpty())
            return "";

        byte[] originalImageBytes;
        try {
            originalImageBytes = file.getBytes();
        } catch (IOException e) {
            log.error("Error reading multipartFile", e);
            return "";
        }

        byte[] compressedImageBytes = ImageUtils.compressImage(originalImageBytes);

        String originalFilename = file.getOriginalFilename();
        String fileName = UUID.randomUUID() + ".compressed";

        log.info("uploadCompressedImage fileName: {}", fileName);
        s3Client.putObject(new PutObjectRequest(bucketName, fileName, new ByteArrayInputStream(compressedImageBytes), null));

        return fileName;
    }

[문제점 및 이슈]

  1. 개발을 하면서 다른 서비스를 살펴보면 (ex. 이커머스, 쇼핑몰) 많은 사진을 처리를 한다. 이때 현업에서는 어떻게 이미지 및 파일을 처리하는지 궁금증을 가지게 되었음
  2. AWS S3는 높은 확장성을 가지고 있으나 파일의 크기와 이용에 따라 비용을 발생을 함.
  3. 최근 AWS 학습 및 서비스를 배포하면서 서버 비용이 발생하여 AWS 비용을 낮추기 위해 다양한 방식을 생각

[원인 분석]

  1. 기존의 파일 업로드는 Local의 파일의 속성 및 사이즈가 동일하게 업로드
  2. 압축, 압축을 푸는 과정에서 오버헤드가 발생할 수 있다고 생각함
  3. 이미지 확장자 JPG, GIF, GIF에 따라서 압축 효율이 차이가 발생

[해결 방안]

  1. 자바의 Deflater를 이용하여 이미지를 Compress를 하여 사이즈를 줄여 업로드
  2. 압축을 하여 파일의 무결성을 보장하기 위해 무손실 압출을 통해 데이터의 무결성 보장
  3. 압축 오버헤드를 고려하여 회원의 @OneToOne 부분에만 처리함.
Clone this wiki locally