핸드폰으로 사진을 세로로 찍어서 업로드 하면

웹화면에서 해당 이미지를 출력하면 가로로 누워서 보이는 현상이 있다.

 

이는 웹 브라우저가 이미지의 orientation 정보대로 보여주지 못하기 때문이다.

모바일 앱으로 보면 세로 이미지가 정상으로 출력된다.

 

 

위 사진은 이미지 정보중 Exif의 Orientation 값을 나타낸다.

1. 정상

2. 좌우반전

3. 180도 회전

4. 180도 회전 + 좌우반전

5. 270도 회전 + 좌우반전

6. 270도 회전

7. 90도 회전 + 좌우반전

8. 90도 회전

 

이를 해결하는 방법은

화면단에서 자바스크립트를 이용한 방법도 있으나 해당 이미지 파일을 이용하여 여러 문서파일도 만드는 작업이 있어

모바일 앱에서 이미지 업로드 시 자바에서 orientaion 정보를 이용하여 1값으로 회전하여 저장하는 방식으로 

문제를 해결했다.

 

다음은 자바 소스이다.

 

이미지 Exit 정보를 읽기 위해서는 라이브러리 metadata-extractor 이 필요하다.

pom.xml에 아래와 같이 디펜던시를 설정한다.

 

	<!-- image EXIF read -->
	<dependency>
		<groupId>com.drewnoakes</groupId>
		<artifactId>metadata-extractor</artifactId>
		<version>2.9.1</version>
	</dependency>

 

 

// 1. 원본 파일을 읽는다.
// 2. 원본 파일의 Orientation 정보를 읽는다.
// 3. 변경할 값들을 설정한다.
// 4. 회전하여 생성할 파일을 만든다.
// 5. 원본파일을 회전하여 파일을 저장한다.

// 1. 원본 파일을 읽는다.
File imageFile = new File("D:/o6.jpg");

// 2. 원본 파일의 Orientation 정보를 읽는다.
int orientation = 1; // 회전정보, 1. 0도, 3. 180도, 6. 270도, 8. 90도 회전한 정보
int width = 0; // 이미지의 가로폭
int height = 0; // 이미지의 세로높이
int tempWidth = 0; // 이미지 가로, 세로 교차를 위한 임의 변수

Metadata metadata; // 이미지 메타 데이터 객체
Directory directory; // 이미지의 Exif 데이터를 읽기 위한 객체
JpegDirectory jpegDirectory; // JPG 이미지 정보를 읽기 위한 객체

try {
	metadata = ImageMetadataReader.readMetadata(imageFile);
	directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
	jpegDirectory = metadata.getFirstDirectoryOfType(JpegDirectory.class);
	if(directory != null){
		orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION); // 회전정보
		width = jpegDirectory.getImageWidth(); // 가로
		height = jpegDirectory.getImageHeight(); // 세로
	}
	
	// 3. 변경할 값들을 설정한다.
    AffineTransform atf = new AffineTransform();
    switch (orientation) {
    case 1:
        break;
    case 2: // Flip X
    	atf.scale(-1.0, 1.0);
    	atf.translate(-width, 0);
        break;
    case 3: // PI rotation 
    	atf.translate(width, height);
    	atf.rotate(Math.PI);
        break;
    case 4: // Flip Y
    	atf.scale(1.0, -1.0);
    	atf.translate(0, -height);
        break;
    case 5: // - PI/2 and Flip X
    	atf.rotate(-Math.PI / 2);
    	atf.scale(-1.0, 1.0);
        break;
    case 6: // -PI/2 and -width
    	atf.translate(height, 0);
    	atf.rotate(Math.PI / 2);
        break;
    case 7: // PI/2 and Flip
    	atf.scale(-1.0, 1.0);
    	atf.translate(-height, 0);
    	atf.translate(0, width);
    	atf.rotate(  3 * Math.PI / 2);
        break;
    case 8: // PI / 2
    	atf.translate(0, width);
    	atf.rotate(  3 * Math.PI / 2);
        break;
    }
    
    switch (orientation) {
	case 5:
	case 6:
	case 7:
	case 8:
        tempWidth = width;
        width = height;
        height = tempWidth;
		break;
	}
    
	BufferedImage image = ImageIO.read(imageFile);
	final BufferedImage afterImage = new BufferedImage(width, height, image.getType());
	final AffineTransformOp rotateOp = new AffineTransformOp(atf, AffineTransformOp.TYPE_BILINEAR);
	final BufferedImage rotatedImage = rotateOp.filter(image, afterImage);
	Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpg");
    ImageWriter writer = iter.next();
    ImageWriteParam iwp = writer.getDefaultWriteParam();
    iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
    iwp.setCompressionQuality(1.0f);

    // 4. 회전하여 생성할 파일을 만든다.
    File outFile = new File("D:/o6_rotated.jpg");
    FileImageOutputStream fios = new FileImageOutputStream(outFile);
    
    // 5. 원본파일을 회전하여 파일을 저장한다.
    writer.setOutput(fios);
    writer.write(null, new IIOImage(rotatedImage ,null,null),iwp);
    fios.close();
    writer.dispose();
	
} catch (ImageProcessingException e) {
	e.printStackTrace();
} catch (MetadataException e) {
	e.printStackTrace();
} catch (IOException e) {
	e.printStackTrace();
}

 

참고로

css 를 이용하는 방법도 있으나

image-orientation: from-image;

이는 아직 파이어폭스에서만 지원하는 방식이다.

 

+ Recent posts