TileMill을 사용하다가 SHP 파일을 인코딩과 관련된 문제점에 봉착하였다. 우선 UTF-8로 인코딩 되지 않은 EUC-KR로 인코딩된 문자는 깨져서 보이는 것이었다. 그래서 QGIS에서 SHP파일을 읽어 UTF-8로 다시 인코딩하여 Export한 후 TileMill에서 사용할 수 있게 Google Mercator로 투영된 prj 파일과 함께 zip파일로 묶어 TileMill에서 읽어보았다.

"행정지명"이라는 값을 가진 "구분" 필드를 조건을 걸어 주어 랜더링 하려고 했으나 아래와 같은 에러를 마주치게 되었다. 예를 들어 h004_point 레이어 같은 경우에는 명칭, 구분, 형태 등의 필드를 포함하고 있는데 이러한 필드에 조건(ex: h004_point [명칭= 'null'])을 걸어 TileMill에서 랜더링 하려고 할 때, 이것이 적용되지 않는 것이었다. field부분만 한글로 되면 Invalid code에러를 발생시키는 것이었다. 조건에 따른 데이터 값은 한글로 되어 있어도 잘 동작하였다(ex: h004_point[gubun='행정지명']).

[field="데이터 "]와 같은 식으로 조건이 들어가야 하는데 field가 한글일 경우 에러를 일으키는 것이었다.

원래 Mapnik에서는 encoding 요소가 없으면 기본으로 UTF-8 인코딩을 사용하지만, encoding 요소를 지정 해서 다른 인코딩도 적용시킬 수 있다. 하지만 TileMill은 encoding 요소를 지정할 방법이 없는 것 같았다. (https://github.com/mapbox/tilemill/issues/557, https://github.com/mapbox/tilemill/issues/547)

 

결국 내가 이 문제를 해결하는 방법은 TileMill에서 고쳐주는 것을 기다리는 것과 혹은 내가 TileMill을 고치는 것, 마지막으로 SHP파일을 고치는 것이다.

기다리기는 시간이 없고, TileMill은 Node.js로 되어 있어서 고치기는 쉽지 않고 시간도 많이 걸릴 것 같아 그냥 SHP파일의 Field명을 한글에서 영어로 고치기로 했다(절대 옳은 방법이 아니니 따라 하지 마세요!).우선 내가 사용할 조건이 있는 Field명을 뽑아 보기로 했다.

명칭, 구분, 도로번호, 종류, 기타, 용도, 구조, 층수, 형태 …

name, class, road_no, road_category, category, etc, usage, structure, floor, form …

어차피 이런 속성 데이터는 dbf파일에 저장되어 있기 때문에 dbf파일의 인코딩과 Field명을 고쳐주면 된다. 그리고 이러한 삽질을 한 GIS사이트가 있었는데 러시아 사이트였다. http://gis-lab.info/qa/dbf-encode.html 사이트에서 크릴릭 알파벳과 씨름하다 dbfpy(http://dbfpy.sourceforge.net/)와 이를 토대로 러시아 개발자가 만든 http://gis-lab.info/programs/python/dbf-encode.zip 프로그램을 다운받았다.

dbf-encode.py -f euc-kr -t utf-8 input.dbf output.dbf와 같은 형식으로 사용하면 된다. 하지만 또 문제점에 봉착하였다. Field가 인코딩이 변하지 않는 것이었다. 결국 field 설정 부분을 발로 짜 보았다(막 짠 것이니 아시는 분은 도움의 댓 글을 부탁 드립니다). 아래 코드를 사용하려면 한글로 된 필드 명에 대한 배열을 미리 사전 형태로 가지고 있어야 합니다. 필드 이름 자체를 한글로 utf-8인코딩 하려고 했으나 실패 하였습니다. QGIS에서도 UTF-8로 export해도 깨지는 글자가 있었습니다.

 

ngi = {'관리기관':'authority', '관리번호':'authority_no', '구분':'class', '구조':'structure', '기타':'etc', '높이':'height', '도로구분':'road_category', '도로번호':'road_no', '도로폭':'road_width', '도엽명':'map_name', '도엽코드':'map_code', '등고수치':'contour', '등급':'grade', '면적':'area', '명칭':'name', '번호':'no', '보도':'sidewalk', '분리대유무':'separator', '상태':'status', '상하구분':'updown', '상하단구분':'updown2', '설치연도':'year', '수령':'su-ryung', '수용량':'capacity', '수종':'su-jong', '수치':'value', '시점':'time', '연장':'length', '용도':'usage', '일방통행':'oneway', '자전거도로':'bicycle_road', '재질':'quality', '종류':'category', '종점':'terminal', '좌표':'coord', '주기':'period', '주생산광물':'main_mineral', '주성분':'ingredient', '직경':'diameter', '차로수':'road_count', '층수':'floor', '통과하중':'pass_load', '포장재질':'packing_material', '폭':'width', '표고':'altitude', '하천명':'river_name', '하천번호':'river_no', '행선지':'destination', '형태':'form', 'UFID':'UFID'}

 

# copy dbf header from inFile to outFile

for f in inFile.header.fields:

outFile.addField( f )

 

for f in outFile.header.fields:

key = unicode( f.name, options.inEncoding).encode(options.outEncoding)

field_name = ngi.get(key)

f.name = field_name

Posted by 강부자아들
,