[태그:] perl

  • gps 태그 앨범 제작(5/4)

    구글 지도가 지원하는 clusterer를 사용하고 싶다. cpan으로 설치한 HTML:GoogleMap:V3 내부를 손봐야 했다. perl이 사용하는 perl module @INC(경로 비슷한?)를 찾았다.

    root@gen8# perl -V
    Summary of my perl5 (revision 5 version 30 subversion 1) configuration:
       
      Platform:
        osname=linux
    ...
      @INC:
        /usr/local/lib/perl5/site_perl/5.30.1/x86_64-linux-gnu
        /usr/local/lib/perl5/site_perl/5.30.1
        /usr/local/lib/perl5/vendor_perl/5.30.1/x86_64-linux-gnu
        /usr/local/lib/perl5/vendor_perl/5.30.1
        /usr/local/lib/perl5/5.30.1/x86_64-linux-gnu
        /usr/local/lib/perl5/5.30.1

    usr/local/lib 경로 아래 V3.pm을 찾아 지웠더니 에러를 받았다. 야호! perl을 잘 모르지만 내부를 조금 수정하면 내가 원하는 코드를 만들 수 있다. 여기에서 add marker 부분만 조금 수정했다. template을 사용하여 쉽게 수정했다.

    ...V3.pm 수정.
    ...
       my $template =<<"EndOfTemplate";
    function html_googlemaps_initialize() {
    
        [% # Github issue 22 %]
        [% IF center %]
    	myCenterLatLng = new google.maps.LatLng({lat: [% center.0 %], lng: [% center.1 %]});
        [% END %]
    
    
    	//2020.2.16 추가
    	var markers = [];
    
        // key map controls
        var map = new google.maps.Map(document.getElementById('[% id %]'), {
            mapTypeId: google.maps.MapTypeId.[% type %],
            [% IF center %]center: myCenterLatLng,[% END %]
            scrollwheel: false,
            zoom: [% zoom %],
            draggable: [% dragging ? 'true' : 'false' %]
        });
    
        [% FOREACH point IN points %]
    
        // marker
        myMarker[% loop.count %]LatLng = new google.maps.LatLng({lat: [% point.point.0 %], lng: [% point.point.1 %]});
        var marker[% loop.count %] = new google.maps.Marker({
            map: map,
            position: myMarker[% loop.count %]LatLng,
        });
    
        // marker infoWindow
        [% IF info_window AND point.html %]
        var contentString[% loop.count %] = '[% point.html %]';
        var infowindow[% loop.count %] = new google.maps.InfoWindow({
            content: contentString[% loop.count %]
        });
    
        marker[% loop.count %].addListener('click', function() {
            infowindow[% loop.count %].open(map, marker[% loop.count %]);
        });
    
    	//2020.2.16 추가
    	markers.push(marker[% loop.count %]);
    
        [% END %]
    
        [% END -%]
    
        [% FOREACH route IN poly_lines %]
    
        // polylines
        var route[% loop.count %]Coordinates = [
            [% FOREACH point IN route.points %]{lat: [% point.0 %], lng: [% point.1 %]}[% loop.last ? '' : ',' %]
            [% END %]
        ];
    
        var route[% loop.count %] = new google.maps.Polyline({
            path: route[% loop.count %]Coordinates,
            geodesic: true,
            strokeColor: '[% route.color %]',
            strokeOpacity: [% route.opacity %],
            strokeWeight: [% route.weight %]
        });
    
        route[% loop.count %].setMap(map);
        [% END %]
    	//20.2.16 추가
    	var markerCluster = new MarkerClusterer(map, markers);
    }
    google.maps.event.addDomListener(window, 'load', html_googlemaps_initialize);
    
    EndOfTemplate
    }
    ...생략
    sub onload_render {
        my ( $self ) = @_;
    
        # Add in all the defaults
        $self->{id}         ||= 'map';
        $self->{height}     ||= '400px';
        $self->{width}      ||= '600px';
        $self->{type}       ||= "NORMAL";
        $self->{zoom}       ||= 13;
        $self->{center}     ||= $self->_find_center;
        $self->{dragging}     = 1 unless defined $self->{dragging};
        $self->{info_window}  = 1 unless defined $self->{info_window};
    
        $self->{width}  .= 'px' if $self->{width} =~ m/^\d+$/;
        $self->{height} .= 'px' if $self->{height} =~ m/^\d+$/;
    
    	#	    my $header = '<script src="https://maps.googleapis.com/maps/api/js__KEY__"'
    	#        . ' async defer type="text/javascript"></script>'
    	#    ;
    	# 20.2.16 추가
    	#  필요에 따라 경로 수정
    
    	    my $header = '<script src="../map/marker/src/markerclusterer.js"></script>
    <script src="https://maps.googleapis.com/maps/api/js__KEY__"'
    	        . ' async defer type="text/javascript"></script>'
    	    ;
    
        my $key = $self->{api_key}
            ? "?key=@{[ $self->{api_key} ]}" : "";
    
        $header =~ s/__KEY__/$key/;
    
        my $map = sprintf(
            '<div id="%s" style="width: %s; height: %s%s"></div>',
            @{$self}{qw/ id width height / },
            exists($self->{'z_index'})
                ? '; z-index: ' . $self->{'z_index'} : ''
        );
    
        my $out;
        Template->new->process( \$self->_js_template,$self,\$out );
    
        $header .= "<script>$out</script>";
    
        return ( $header,$map );
    }
    ...생략

    대충 원하는대로 나온다.

  • gps 태그 앨범 제작(4/4)

    제길. perl 제작한 프로그램에 버그가 있다. mysql 접근 권한을 update를 주면 perl이 접속하면서 gps 정보를 초기화한다. perl 조회 계정을 하나 만들어 select 권한만 주었다.

    그리고 GPS에 N,S, E, W 네 방향이 있다. 완전 좌절..

    잘못한 update 칼럼을 찾아 다시 좌표를 넣어줘야 한다.

    #!/bin/bash
    
    #file 유무 확인
    if [ ! -f $1 ];then
    	echo "file is not there";
    	exit
    fi
    
    #N, S, E, W 방향 확인.
    
    GpsRefNS=$(exiv2 -pa $1 2> /dev/null | grep -ae "Exif\.GPSInfo\.GPSLatitudeRef.*Ascii" | sed 's/ \{1,\}/ /g'|cut -d' ' -f4-)
    GpsRefEW=$(exiv2 -pa $1 2> /dev/null | grep -ae "Exif\.GPSInfo\.GPSLongitudeRef.*Ascii" | sed 's/ \{1,\}/ /g'|cut -d' ' -f4-)
    
    if [ -z "$GpsRefNS" ]
    then
    	exit;
    fi;
    
    if [ -z "$GpsRefEW" ]
    then
    	exit;
    fi;
    
    GpsLat=$(exiv2 -pa $1 2> /dev/null | grep -ae "Exif\.GPSInfo\.GPSLatitude.*Rational" | sed 's/ \{1,\}/ /g' | cut -d' ' -f4-)
    GpsLong=$(exiv2 -pa $1 2> /dev/null | grep -ae "Exif\.GPSInfo\.GPSLongitude.*Rational" | sed 's/ \{1,\}/ /g'| cut -d' ' -f4-)
    
    #GpsLat마지막 숫자
    GpsLatSec=$(echo $GpsLat | cut -d' ' -f3 | tr -d "\"")
    GpsLatMin=$(echo $GpsLat | cut -d' ' -f2 | tr -d "\'")
    
    #초가 없는 경우 0을 입력.
    if [ -z "$GpsLatSec" ]
    	then
    		GpsLatSec=0;
    fi
    
    GpsLongSec=$(echo $GpsLong | cut -d' ' -f3 | tr -d "\"")
    GpsLongMin=$(echo $GpsLong | cut -d' ' -f2 | tr -d "\'")
    
    if [ -z "$GpsLongSec" ]
    	then
    		GpsLongSec=0;
    fi
    
    #GPS자표가 숫자인지 확인
    re='^[0-9]{1,3}$'
    #가끔 소수점도 있음..
    re='^[0-9]{1,3}(\.[0-9]{1,5}$|$)'
    
    if ! [[ $GpsLatSec =~ $re ]]
    then
    	exit 1;
    fi
    
    if ! [[ $GpsLatMin =~ $re ]]
    then
    	exit 1;
    fi
    
    GpsLatFloat=$(bc <<< "scale=4;($GpsLatSec/60+$GpsLatMin)/60")
    GpsLongFloat=$(bc <<< "scale=4;($GpsLongSec/60+$GpsLongMin)/60")
    
    
    #$Gps 인티저
    GpsLatInt=$(echo $GpsLat | cut -d' ' -f1 | tr -d "d-g");
    GpsLongInt=$(echo $GpsLong | cut -d' ' -f1 | tr -d "d-g");
    
    #$전체 숫자.
    GpsLatFull=$(bc <<< "scale=4;$GpsLatFloat+$GpsLatInt");
    GpsLongFull=$(bc <<< "scale=4;$GpsLongFloat+$GpsLongInt");
    
    #South, West면 반전
    if [ "$GpsRefNS" = "South" ]
    then
    	GpsLatFull=$(bc <<< "scale=4;$GpsLatFull*-1");
    fi
    
    if [ "$GpsRefEW" = "West" ]
    then
    	GpsLongFull=$(bc <<< "scale=4;$GpsLongFull*-1");
    fi
    
    echo $GpsLatFull,$GpsLongFull;

    이제 사진에 태그와 perl이 표시할 수 있는 내용을 입력해야 한다. perl에서 추가 모듈이 한글로 된 칼럼은 조회할 수 없다. 동일한 내용으로 영어로 만들었다. 이것도 개노가다.

    전에 만든 php를 활용하여 사진을 업데이트 했다.

  • gps 태그 앨범 제작(3/4)

    perl을 쓰기 위해 docker를 사용했다. commit대신 간단한 Dockerrun을 만들었다. commit으로 이미지를 만들면 다음에 다시 만들 수 없다한다.

    FROM perl:v5.30.1
    MAINTAINER ???
    RUN apt-get -y update
    #GooglaMaps::V3 설치
    RUN cpan HTML::GoogleMaps::V3
    #https 설정.
    RUN cpan install LMP::UserAgen Mozilla::CA
    RUN cpan install LWP::Protocol::https
    RUN cpan install Bundle::DBI
    RUN cpan install DBD::mysql

    host에 있는 mysql에 접속하기 위해 옵션을 docker에 run 옵션을 줬다.

    docker run -it --network=host -e LC_ALL=C.UTF-8 -v ????:/home/ perl:mysql_Map /bin/bash

    DBI:mysql로 연결할 때 띄어쓰면 에러를 볼 수 있다. 붙여써야 한다. 이걸 모르고 하루를 날렸다. 또 한글 출력에 문제가 있는데 binmode를 주석처리 했다.

    se utf8;
    use strict;
    use warnings;
    use DBI;
    use HTML::GoogleMaps::V3;
    #아래내용은 구글MAPs 에 사용.
    #binmode STDOUT, ":utf8";
    
    my $host ="127.0.0.1";
    my $user = "???";
    my $password = "?????";
    my $database = "?????";
    my $tablesname =  "????";
    
    #모두 붙여서 사용..
    #space 있으면 connect 에러
    my $dbh = DBI->connect("DBI:mysql:database=$database;host=$host", $user, $password, {RaiseError => 1});
    
    #한글 설정
    my $setkorean="SET NAMES utf8";
    $dbh->do($setkorean);
    #query 설정.
    #my $query = "select * from picture where 태그 like '%??%' limit 10";
    #테스트용 query
    my $query = "select * from picture where (태그 like '%??%' and gpsLatFloat != 0) limit 10";
    
    #query 실행
    #my $sth=$dbh->prepare($query);
    #$sth->execute();
    
    #while(my $ref = $sth->fetchrow_hashref()){
    #	print "Found: $ref->{'perl_tag'}";
    #}
    #print $sth->rows;
    
    my $map = HTML::GoogleMaps::V3->new(
        api_key => "???"
    );
    
    #query 실행
    my $sth=$dbh->prepare($query);
    $sth->execute();
    
    while(my $ref = $sth->fetchrow_hashref()){
    	print "Found: $ref->{'perl_tag'}";
    	$map->add_marker(
    		point => [$ref->{'gpsLongFloat'},$ref->{'gpsLatFloat'}],
    		html => qq{<a href=$ref->{perl_path}>$ref->{perl_tag}</a>},
    		);
    };#while loop
    
    $sth->finish();
    $dbh->disconnect();
    
    my ( $head, $map_div ) = $map->onload_render;
    
    print <<"END_HTML";
    <!doctype html>
    <html>
    <head>
    <meta charset="utf-8" />
    END_HTML
    
    print $head . "\n";
    
    print <<"END_HTML";
    </head>
    <body onload="html_googlemaps_initialize()">
    END_HTML
    
    print $map_div . "\n";
    
    print <<"END_HTML";
    </body>
    </html>
    END_HTML

    이제 marker infoWindows를 이쁘게 설정하면 된다. 아무래도 설명을 입력해야 할 듯 하다.

  • gps 태그 앨범 제작(2/4)

    몇 번 해보니 gps 좌표가 여러 형식이다. 삼성 카메라로 3개 형식을 얻을 수 있다.

    Exif.GPSInfo.GPSLatitude                     Rational    3  37deg 34' 0.982"
    Exif.GPSInfo.GPSLatitude                     Rational    3  37deg 34' 23"
    Exif.GPSInfo.GPSLatitude                     Rational    3  35.4328992deg

    모두 해당하는 경우를 하나 파일로 만들려 했으나, 틀을 깨어 3개 파일로 만들었다. 1번 파일이 2번 파일을 실행하고, 결과를 확인한다. 만족하지 못하면 3번 파일을 실행한다. 정규 표현식 검증은 여기에서 했다.

    #!/bin/bash
    
    #1번 스크립트
    #echo "hello"
    echo "$1로 파일 path를 입력"
    #업데이트할 파일 숫자 확인
    #echo $1
    iMaxNum=$(wc -l $1 | cut -d' '  -f1)
    #echo $iMaxNum
    
    cat $1 |\
    while read tmpFILE;
    do
    	tmpID=$(echo $tmpFILE | cut -d' ' -f1)
    	tmpPATH=$(echo $tmpFILE | cut -d' ' -f2)
    	#echo $tmpID, $tmpPATH;
    	gpsCoord=$(/home/now0930/script/사진에서정보추출/gpsTextToFloat.sh $tmpPATH)
    	#echo $gpsCoord;
    	#echo $tmpPATH
    	#echo "첫번째 실행"
    
    	if [ -z "$gpsCoord" ]
    	then
    		gpsCoord=$(/home/now0930/script/사진에서정보추출/gpsTextToFloatMore.sh $tmpPATH)
    		#echo "두번째 실행"
    		#echo $gpsCoord;
    
    	fi
    
    
    	#echo "여기확인"
    	#echo $tmpID, $gpsCoord;
    
    	gpsCoordLat=$(echo $gpsCoord | cut -d',' -f1)
    	gpsCoordLong=$(echo $gpsCoord | cut -d',' -f2)
    
    	#float 형식인지 확인하여 mysql update
    
    	#echo $tmpID
    	#echo $tmpID, $gpsCoordLat, $gpsCoordLong;
    
    
    	
    
    	if ! [ -z "$gpsCoordLat" ]
    	then
    		#데이터 베이스 업데이트
    		mysql << EOF
    
    		use myHome;
    		select id, 경로 from picture where id = $tmpID;
    		update picture set gpsLatFloat=$gpsCoordLat, gpsLongFloat=$gpsCoordLong where id=$tmpID;
    EOF
    
    	#echo $gpsCoordLat, $gpsCoordLong
    
    	fi
    done
    #!/bin/bash
    #2번 스크립트.
    #file 유무 확인
    if [ ! -f $1 ];then
    	echo "file is not there";
    	exit
    fi
    
    
    #Trap으로 metadata를 가지고 있는지 확인.
    #trap "exiv2 -pa  $1" EXIT
    #echo $1
    GpsLat=$(exiv2 -pa $1 2> /dev/null | grep -ae "Exif\.GPSInfo\.GPSLatitude.*Rational" | sed 's/ \{1,\}/ /g' | cut -d' ' -f4-)
    GpsLong=$(exiv2 -pa $1 2> /dev/null | grep -ae "Exif\.GPSInfo\.GPSLongitude.*Rational" | sed 's/ \{1,\}/ /g'| cut -d' ' -f4-)
    
    #echo $GpsLat;
    #echo $GpsLong;
    #printf "\n"
    
    #GpsLat마지막 숫자
    GpsLatSec=$(echo $GpsLat | cut -d' ' -f3 | tr -d "\"")
    GpsLatMin=$(echo $GpsLat | cut -d' ' -f2 | tr -d "\'")
    
    #초가 없는 경우 0을 입력.
    if [ -z "$GpsLatSec" ]
    	then
    		GpsLatSec=0;
    fi
    #echo $GpsLatSec;
    #echo $GpsLatMin;
    
    
    GpsLongSec=$(echo $GpsLong | cut -d' ' -f3 | tr -d "\"")
    GpsLongMin=$(echo $GpsLong | cut -d' ' -f2 | tr -d "\'")
    
    
    if [ -z "$GpsLongSec" ]
    	then
    		GpsLongSec=0;
    fi
    
    #echo $GpsLatSec;
    #echo $GpsLatMin;
    
    #echo $GpsLongSec;
    #echo $GpsLongMin;
    
    #GPS자표가 숫자인지 확인
    re='^[0-9]{1,3}$'
    #가끔 소수점도 있음..
    re='^[0-9]{1,3}(\.[0-9]{1,5}$|$)'
    
    #if [ -z "$GpsLat" ]
    #then
    #	echo "0,0"
    #	exit;
    #fi
    #echo $GpsLatSec, $GpsLongSec
    
    if ! [[ $GpsLatSec =~ $re ]]
    then
    	exit 1;
    fi
    
    if ! [[ $GpsLatMin =~ $re ]]
    then
    	exit 1;
    fi
    
    GpsLatFloat=$(bc <<< "scale=4;($GpsLatSec/60+$GpsLatMin)/60")
    GpsLongFloat=$(bc <<< "scale=4;($GpsLongSec/60+$GpsLongMin)/60")
    
    #echo $GpsLatFloat
    #echo $GpsLongFloat
    
    #$Gps 인티저
    GpsLatInt=$(echo $GpsLat | cut -d' ' -f1 | tr -d "d-g");
    GpsLongInt=$(echo $GpsLong | cut -d' ' -f1 | tr -d "d-g");
    
    #echo $GpsLatInt
    #echo $GpsLongInt
    
    #$전체 숫자.
    GpsLatFull=$(bc <<< "scale=4;$GpsLatFloat+$GpsLatInt");
    GpsLongFull=$(bc <<< "scale=4;$GpsLongFloat+$GpsLongInt");
    
    
    echo $GpsLatFull,$GpsLongFull;
    
    #!/bin/bash
    
    
    #Trap으로 metadata를 가지고 있는지 확인.
    #trap "exiv2 -pa  $1" EXIT
    
    #echo $GpsLat
    #echo $GpsLong
    #echo "구분자"
    #여기 확인..
    #GPS 형식 확인
    #xxx.xxxxdeg 형식일 경우 처리.
    renumberdeg='^[0-9]{1,}\.[0-9]{1,}deg'
    if [[ $GpsLat =~ $renumberdeg ]]
    then
    	#echo "여기 매치"
    	GpsLatFull=$(echo $GpsLat| cut -d'd' -f1)
    	#echo $GpsLatFull
    fi
    
    if [[ $GpsLong =~ $renumberdeg ]]
    then
    	GpsLongFull=$(echo $GpsLong | cut -d'd' -f1)
    	#echo $GpsLongFull
    fi
    echo $GpsLatFull,$GpsLongFull;
    

    이렇게 하면 gps 태그 달린 사진을 8개 남기고 입력할 수 있다. 나머지 8개는 포기한다.

  • gps 태그 앨범 제작(1/4)

    휴대폰으로 gps 태그를 포함하여 사진을 저장할 수 있다. 보통 사진을 너무 많이 찍는데 기억할만한 장소를 표시하고 싶다. 역시 구글링을 해보니 perl로 제작한 좋은 페이지를 찾았다.

    http://advent.perl.kr/2016/2016-12-06.html
    https://metacpan.org/pod/HTML::GoogleMaps::V3

    사진에 저장된 gps 태그를 보면 삼성 카메라 경우 각도+분+초로 되어있다. 이를 소수점으로 변환해야 한다. 공식은 (초/60 + 분)/60+각도다.

    하나 문제가 있는데 사진을 저장할 때 숫자로 저장하지 않아 뒤쪽 소수점을 다 날렸다. 사진 경로를 찾아 파일에 저장된 정확한 gps 위치를 기록해야 한다.

    가지고 있는 데이터베이스를 날릴 수 없어, id와 경로를 보고 위도, 경도를 업데이트 하기로 했다. 일단 위 식에 맞는 스크립트를 만들었다.

    #!/bin/bash
    
    #$1은 파일 경로. 데이터베이스에서 추출.
    #file 유무 확인
    if [ ! -f $1 ];then
    	echo "file is not there";
    	exit
    fi
    GpsLat=$(exiv2 -pa $1 2> /dev/null | grep -ae "Exif\.GPSInfo\.GPSLatitude.*Rational" | sed 's/ \{1,\}/ /g' | cut -d' ' -f4-)
    GpsLong=$(exiv2 -pa $1 2> /dev/null | grep -ae "Exif\.GPSInfo\.GPSLongitude.*Rational" | sed 's/ \{1,\}/ /g'| cut -d' ' -f4-)
    
    #echo $GpsLat;
    #echo $GpsLong;
    
    #GpsLat마지막 숫자
    GpsLatSec=$(echo $GpsLat | cut -d' ' -f3 | tr -d "\"")
    GpsLatMin=$(echo $GpsLat | cut -d' ' -f2 | tr -d "\'")
    
    GpsLongSec=$(echo $GpsLong | cut -d' ' -f3 | tr -d "\"")
    GpsLongMin=$(echo $GpsLong | cut -d' ' -f2 | tr -d "\'")
    
    #echo $GpsLatSec
    #echo $GpsLatMin
    
    GpsLatFloat=$(bc <<< "scale=4;($GpsLatSec/60+$GpsLatMin)/60")
    GpsLongFloat=$(bc <<< "scale=4;($GpsLongSec/60+$GpsLongMin)/60")
    
    #echo $GpsLatFloat
    #echo $GpsLongFloat
    
    #$Gps 인티저
    GpsLatInt=$(echo $GpsLat | cut -d' ' -f1 | tr -d "d-g");
    GpsLongInt=$(echo $GpsLong | cut -d' ' -f1 | tr -d "d-g");
    
    #echo $GpsLatInt
    #echo $GpsLongInt
    
    #전체 숫자.
    GpsLatFull=$(bc <<< "scale=4;$GpsLatFloat+$GpsLatInt");
    GpsLongFull=$(bc <<< "scale=4;$GpsLongFloat+$GpsLongInt");
    
    echo $GpsLatFull;
    echo $GpsLongFull;

    이제 데이터베이스를 내용을 파일로 출력하여 경로를 위 스크립트 인자로 넣어주면 된다.