이미지 파일에서 좌표를 추출해 주소명 받아오기

hongo·2023년 7월 2일
2
post-custom-banner

이미지 메타데이터 추출

metadata-extractor 라이브러리를 사용하면 쉽게 이미지에서 메타데이터를 추출해올 수 있다.

해당 라이브러리를 사용하기 위해 gradle에 의존성을 추가한다.

dependencies {
    implementation 'com.drewnoakes:metadata-extractor:2.16.0'
	...
}

의존성을 추가한 후 ImageMetadataReader를 사용하면 편하게 메타데이터를 가져올 수 있다.

String imageLocation = "이미지 파일 위치";
File image = new File(imageLocation);
Metadata metadata = ImageMetadataReader.readMetadata(image);

메타데이터는 이미지의 Height, Width, Date/Time등 여러 정보가 들어있고 이를 각 Directory에 담아두고 있다.

그 중 GpsDirectory에는 이미지의 위도, 경도 정보가 존재한다.

(근데 이미지 파일을 열어보면 지도가 같이 떠서... Exif~ Directory에 주소 정보가 이미 있을 것 같긴한데, 좌표값을 input으로 다른 api를 사용해보기 위해 우선 좌표 정보를 뽑아 해보기로했다...)

public void printCoordinate() {
    GpsDirectory gpsDirectory = metadata.getFirstDirectoryOfType(GpsDirectory.class);
    if(hasGpsInformation(gpsDirectory)) {
        double longitude = gpsDirectory.getGeoLocation().getLongitude();
        double latitude = gpsDirectory.getGeoLocation().getLatitude();
        System.out.println("위도 : " + latitude + ", 경도 : " + longitude);
    }
}

private boolean hasGpsInformation(GpsDirectory gpsDirectory) {
    return gpsDirectory.containsTag(GpsDirectory.TAG_LATITUDE) && gpsDirectory.containsTag(GpsDirectory.TAG_LONGITUDE);
}

// 출력 결과
// 위도 : 37.505522222222226, 경도 : 127.05077777777778

KakaoApi를 사용해 좌표로 주소명 가져오기

이제 좌표를 얻었으니 주소값을 가져와보자. Kakao가 제공하는 Api를 사용해보자

Api를 사용하기위해선 애플리케이션의 REST API키가 필요하다. kakao 애플리케이션 관리 페이지에서 내 애플리케이션을 추가한 후 생성한 애플리케이션의 REST API 키를 보관해둔다.

kakao local API를 보면 https://dapi.kakao.com/v2/local/geo/coord2address.${FORMAT} url로 좌표 정보를 넘겨주면 주소 정보를 받아올 수 있다고 한다. 필요한 헤더와 쿼리 파라미터를 참조해 요청을 보내보자.

public String getAddressByCoordinate(double longitude, double latitude) throws Exception {
    return parseAddressFromJsonData(getAddressJSONDataByCoordinate(longitude, latitude));
}

// 위치 정보를 jsonString으로 받아온다
private String getAddressJSONDataByCoordinate(double longitude, double latitude) throws Exception {
    String jsonString = "";
    String buf;
    
    // 쿼리 파라미터 설정
    String apiUrl = "https://dapi.kakao.com/v2/local/geo/coord2address?x="+longitude+"&y="+latitude;
    URL url = new URL(apiUrl);
    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
    
    // 헤더 정보 설정
    String apikey = "내 애플리케이션의 REST API 키";
    String auth = "KakaoAK "+apikey;
    connection.setRequestProperty("Authorization", auth);

    BufferedReader br = new BufferedReader(new InputStreamReader(
        connection.getInputStream(), "UTF-8"));
    while ((buf = br.readLine()) != null) {
        jsonString += buf;
    }
    return jsonString;
}

// JsonString에서 주소명을 파싱한다
private String parseAddressFromJsonData(String jsonData) {
    JSONObject jsonObject = (JSONObject) JSONValue.parse(jsonData);
    JSONArray documents = (JSONArray) jsonObject.get("documents");
    JSONObject roadAddress = (JSONObject) ((JSONObject) documents.get(0)).get("road_address");
    return (String) roadAddress.get("address_name");
}

요청을 보내면 위치 정보를 response로 받아올 수 있다.

나는 주소명을 알고 싶으므로, 받은 json data에서 document -> road_address 에 있는 address_name을 가져온다. (json-simple라이브러리의 JSONObject, JSONArray를 사용했다.)

(더 효율적으로 json data에서 가져오는 방법이 있을 것 같지만 일단은 이렇게...ㅎㅎ 나중에 수정하겠습니다 진짜루)

전체코드

public class Image {
	private final File image;
    private final Metadata metadata;

    public ImageMetadata(String imageLocation) throws ImageProcessingException, IOException {
        this.image = new File(imageLocation);
        this.metadata = ImageMetadataReader.readMetadata(image);
    }

    public String getAddress() throws Exception {
        GpsDirectory gpsDirectory = metadata.getFirstDirectoryOfType(GpsDirectory.class);
        if(hasGpsInformation(gpsDirectory)) {
            double longitude = gpsDirectory.getGeoLocation().getLongitude();
            double latitude = gpsDirectory.getGeoLocation().getLatitude();
            return getAddressByCoordinate(longitude, latitude);
        }
        return null;
    }

    private boolean hasGpsInformation(GpsDirectory gpsDirectory) {
        return gpsDirectory.containsTag(GpsDirectory.TAG_LATITUDE) && gpsDirectory.containsTag(GpsDirectory.TAG_LONGITUDE);
    }

    private String getAddressByCoordinate(double longitude, double latitude) throws Exception {
        return parseAddressFromJsonData(getAddressJSONDataByCoordinate(longitude, latitude));
    }

    // 위치 정보를 jsonString으로 받아온다
    private String getAddressJSONDataByCoordinate(double longitude, double latitude) throws Exception {
        String jsonString = "";
        String buf;

        // 쿼리 파라미터 설정
        String apiUrl = "https://dapi.kakao.com/v2/local/geo/coord2address?x="+longitude+"&y="+latitude;
        URL url = new URL(apiUrl);
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

        // 헤더 정보 설정
        String apikey = "내 애플리케이션의 REST API 키";
        String auth = "KakaoAK "+apikey;
        connection.setRequestProperty("Authorization", auth);

        BufferedReader br = new BufferedReader(new InputStreamReader(
                connection.getInputStream(), "UTF-8"));
        while ((buf = br.readLine()) != null) {
            jsonString += buf;
        }
        return jsonString;
    }

    // JsonString에서 주소명을 파싱한다
    private String parseAddressFromJsonData(String jsonData) {
        JSONObject jsonObject = (JSONObject) JSONValue.parse(jsonData);
        JSONArray documents = (JSONArray) jsonObject.get("documents");
        JSONObject roadAddress = (JSONObject) ((JSONObject) documents.get(0)).get("road_address");
        return (String) roadAddress.get("address_name");
    }
}
post-custom-banner

0개의 댓글