TIL 45 - 웹앱 파일 업로드 시 이미지 회전 현상

Leo·2023년 2월 16일
0

SpringBoot

목록 보기
3/4

문제 발생

  • 웹앱에서 파일 업로드 기능을 실제 앱환경 카메라를 이용해 촬영후 업로드시 사진이 뒤집히는 현상

원인

  • 이미지 파일이 클 경우 resize를 하는데 이 과정에서 이미지 파일 방향이 바뀜

해결 방법

  • 이미지 파일의 metadata에 사진의 방향값을 가지고 있는데 resize 전에 원본의 방향 값을 추출해내 미리 정상 방향으로 회전시켜놓음
  • metadata 추출 시 필요한 라이브러리를 dependency에 추가해줘야함
gradle
implementation 'com.drewnoakes:metadata-extractor:2.18.0'

maven 
<dependency>
    <groupId>com.drewnoakes</groupId>
    <artifactId>metadata-extractor</artifactId>
    <version>2.18.0</version>
</dependency>

작업 계획

  1. 원본 이미지 파일을 InputSteam 클래스로 변환 후 metadata 추출
  2. 추출한 meta데이터에서 방향 값(orientation) 추출
  3. 원본의 orientation 값에 따라 방향을 설정해줌
  4. 이미지 resize 후 S3에 업로드

 private MultipartFile resizeImageFile(String fileName, String fileExt, MultipartFile file, int targetWidth) {
        try {

            // file에서 메타데이터 추출
            Metadata metadata = getMetadata(file.getInputStream());
            // 메타데이터에서 방향값 추출
            int orientation = getOrientation(metadata);

            // MultipartFile -> BufferedImage Convert
            BufferedImage image = ImageIO.read(file.getInputStream());

            // 이미지 파일 방향이 1이 아닌 경우 파일 회전
            if (orientation != 1) {
                image = rotateImage(image, orientation);
            }

            // newWidth : newHeight = originWidth : originHeight
            int originWidth = image.getWidth();

            // origin 이미지가 resizing될 사이즈보다 작을 경우 resizing 작업 안 함
            if (originWidth < targetWidth)
                return file;

            BufferedImage bufferedImage = Scalr.resize(image, targetWidth);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, fileExt, baos);
            baos.flush();

            return new MockMultipartFile(fileName, file.getOriginalFilename(),
                file.getContentType(), baos.toByteArray());
        } catch (IOException e) {
            throw new AmazonS3Exception("Cannot resize image file");
        } catch (MetadataException e) {
            throw new RuntimeException(e);
        }
    }
resizeImageFile(이미지 리사이즈 전체 코드)
   
  public Metadata getMetadata(InputStream inputStream) {
        Metadata metadata;

        try {
            metadata = ImageMetadataReader.readMetadata(inputStream);
        } catch (ImageProcessingException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return metadata;
    }
getMetadata(메타데이터 가져오기)

metadata 추출하는 방법은 file, inputStream을 이용하는 방법 2가지가 있음 여기서는 inpustStream을 이용함(관련 문서)


    public Integer getOrientation(Metadata metadata) throws MetadataException {
        int orientation = 1;

        Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);

        // directory는 있는데 그 안에 orientation값이 없을 수 있어 두개 다 체크
        if(directory != null && directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION))  {
            orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
        }

        return orientation;
    }
getOrientation(방향값 가져오기)
    public BufferedImage rotateImage (BufferedImage bufferedImage, int orientation) {

        BufferedImage rotatedImage;

        if(orientation == 6 ) {
            rotatedImage = Scalr.rotate(bufferedImage, Scalr.Rotation.CW_90);
        } else if (orientation == 3) {
            rotatedImage = Scalr.rotate(bufferedImage, Scalr.Rotation.CW_180);
        } else if(orientation == 8) {
            rotatedImage = Scalr.rotate(bufferedImage, Scalr.Rotation.CW_270);
        } else {
            rotatedImage = bufferedImage;
        }

        return rotatedImage;
    }
rotateImage(방향값을 기준으로 이미지를 돌려줌)
orientation 값에 따른 실제 방향

참고 사이트

profile
느리지만 확실하게

0개의 댓글