<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ko">
		<id>http://lhdangerous.godohosting.com/wiki/index.php?feed=atom&amp;namespace=0&amp;title=%ED%8A%B9%EC%88%98%3A%EC%83%88%EB%AC%B8%EC%84%9C</id>
		<title>도구의인간 메이커스 위키 - 새 문서 목록 [ko]</title>
		<link rel="self" type="application/atom+xml" href="http://lhdangerous.godohosting.com/wiki/index.php?feed=atom&amp;namespace=0&amp;title=%ED%8A%B9%EC%88%98%3A%EC%83%88%EB%AC%B8%EC%84%9C"/>
		<link rel="alternate" type="text/html" href="http://lhdangerous.godohosting.com/wiki/index.php/%ED%8A%B9%EC%88%98:%EC%83%88%EB%AC%B8%EC%84%9C"/>
		<updated>2026-04-27T02:57:12Z</updated>
		<subtitle>도구의인간 메이커스 위키</subtitle>
		<generator>MediaWiki 1.28.2</generator>

	<entry>
		<id>http://lhdangerous.godohosting.com/wiki/index.php/Python_http_requests_module</id>
		<title>Python http requests module</title>
		<link rel="alternate" type="text/html" href="http://lhdangerous.godohosting.com/wiki/index.php/Python_http_requests_module"/>
				<updated>2019-09-15T05:30:13Z</updated>
		
		<summary type="html">&lt;p&gt;Doguin: 새 문서: # HTTP request in Python : requests module python의 requests 모듈을 사용해  REST 프로토콜을 쉽게 다룰 수 있다. 너무 널리사용되는, 사실상의 파이선 내...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# HTTP request in Python : requests module&lt;br /&gt;
python의 requests 모듈을 사용해  REST 프로토콜을 쉽게 다룰 수 있다. 너무 널리사용되는, 사실상의 파이선 내장모듈이라고 볼 수 있다.&lt;br /&gt;
참고: https://realpython.com/api-integration-in-python/&lt;br /&gt;
공식문서: https://2.python-requests.org/en/master/  &lt;br /&gt;
&lt;br /&gt;
## 설치&lt;br /&gt;
```bash&lt;br /&gt;
$ pip install requests&lt;br /&gt;
```&lt;br /&gt;
* 아마도 대부분의 경우 기본으로 설치되어있음&lt;br /&gt;
&lt;br /&gt;
## 기본 사용법&lt;br /&gt;
### basic get&lt;br /&gt;
get(), post(), put() 메소드를 가지고 있고 서버의 응답이 이들 메소드의 리턴이 된다. 심플하다.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
import requests&lt;br /&gt;
&lt;br /&gt;
URL = ''https://todolist.example.com/tasks/''&lt;br /&gt;
resp = requests.get(URL)&lt;br /&gt;
if resp.status_code == 200: # OK&lt;br /&gt;
  for item in resp.json():&lt;br /&gt;
    print(item)&lt;br /&gt;
else :  # something wrong&lt;br /&gt;
  raise ApiError(resp.status_code)&lt;br /&gt;
```&lt;br /&gt;
* resp.json()의 리턴은 파이썬 오브젝트다 일반 딕셔너리나 리스트처럼 간편하게 다룰 수 있다.&lt;br /&gt;
* raw data를 그대로 보려면  'resp.text' 프로퍼티를 사용하면 된다.&lt;br /&gt;
&lt;br /&gt;
### parameter  전달&lt;br /&gt;
get() 메소드에 'params=' 아규먼트를 추가해 보낸다&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
params = {'key':'value'}&lt;br /&gt;
res = requests.get('http://www.tistoty.com', params=params)&lt;br /&gt;
print(res.url)&lt;br /&gt;
# http:./www.tistody.com/?key=value&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### header 전달&lt;br /&gt;
get(), post() 메소드에 'headers=' 아규먼트를 추가해 보낸다.&lt;br /&gt;
&lt;br /&gt;
### data 전달&lt;br /&gt;
post() 메소드에 'data=' 아규먼트를 추가해 보낸다.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
body = {&amp;quot;key1&amp;quot;: &amp;quot;value1&amp;quot;, &amp;quot;key2&amp;quot;: &amp;quot;value2&amp;quot; }&lt;br /&gt;
resp = requests.post(URL,&lt;br /&gt;
                     data=json.dumps(body),&lt;br /&gt;
                     headers={'Content-Type':'application/json'},&lt;br /&gt;
                     )&lt;br /&gt;
```&lt;br /&gt;
혹은 'data=' 대신에 'json='아규먼트를 사용하면 requests가 알아서 딕셔너리를 json으로 바꾸어준다. 아래 예는 위 코드와 동일하다.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
resp = requests.post(URL,json=body)&lt;br /&gt;
```&lt;/div&gt;</summary>
		<author><name>Doguin</name></author>	</entry>

	<entry>
		<id>http://lhdangerous.godohosting.com/wiki/index.php/GPS_module_neo-6m</id>
		<title>GPS module neo-6m</title>
		<link rel="alternate" type="text/html" href="http://lhdangerous.godohosting.com/wiki/index.php/GPS_module_neo-6m"/>
				<updated>2019-09-15T04:37:56Z</updated>
		
		<summary type="html">&lt;p&gt;Doguin: 새 문서: # GPS + raspberry pi  ## gps module Neo-6m gps 모듈을 사용한다. 대부분의 gps 모듈이 serial UART 통신을 사용한다. 참고자료가 많은 쪽이 좋으므로  시...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# GPS + raspberry pi&lt;br /&gt;
&lt;br /&gt;
## gps module&lt;br /&gt;
Neo-6m gps 모듈을 사용한다.&lt;br /&gt;
대부분의 gps 모듈이 serial UART 통신을 사용한다. 참고자료가 많은 쪽이 좋으므로  시리얼 통신방식 부품을 고른다.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://www.makerlab-electronics.com/my_uploads/2017/06/GPS-Module-01.jpg)&lt;br /&gt;
&lt;br /&gt;
	5Hz position update rate&lt;br /&gt;
	EEPROM to save configuration settings&lt;br /&gt;
	Rechargeable battery for Backup&lt;br /&gt;
	The cold start time of 38 s and Hot start time of 1 s&lt;br /&gt;
	Configurable from 4800 Baud to 115200 Baud rates. (default 9600)&lt;br /&gt;
	SuperSense ® Indoor GPS: -162 dBm tracking sensitivity&lt;br /&gt;
	Support SBAS (WAAS, EGNOS, MSAS, GAGAN)&lt;br /&gt;
	Separated 18X18mm GPS antenna&lt;br /&gt;
	Supply voltage: 3.3 V&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## 회로 구성&lt;br /&gt;
라즈베리의 8번째, 10번째 핀이  시리얼 통신용이다.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cdn.instructables.com/FP7/CQBO/ICJLZ1TL/FP7CQBOICJLZ1TL.LARGE.jpg?auto=webp&amp;amp;frame=1&amp;amp;width=664&amp;amp;fit=bounds)  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/49839d/Image%202019-08-30%20at%204.54.46%20PM.png)&lt;br /&gt;
&lt;br /&gt;
## 라즈베리파이 시리얼 포트 설정&lt;br /&gt;
참고: http://lhdangerous.godohosting.com/wiki/index.php/%EB%9D%BC%EC%A6%88%EB%B2%A0%EB%A6%AC%ED%8C%8C%EC%9D%B4_%EC%8B%9C%EB%A6%AC%EC%96%BC_%ED%86%B5%EC%8B%A0_%EC%84%A4%EC%A0%95_(setting_up_Raspberry_pi_serial_connection_via_GPIO) &lt;br /&gt;
&lt;br /&gt;
##  GPS FIX&lt;br /&gt;
* gps에서 사용되는 중요한 개념중에  FIX라는 것이 있다.&lt;br /&gt;
디바이스를 부팅하고나서도 위성으로부터 전파를 받아 디바이스의 위치를 계산할 수 았으려면 조금 시간이 걸리는데, 이렇게 충분한 데이터를 모아 자신의 위치를 계산할 수 있게되면 fix되었다라고 이야기한다. 더 구체적인 내용은 공부를 더 해보자.&lt;br /&gt;
&lt;br /&gt;
* neo-6m gps는 유난히  fix 하는데 시간이 오래 걸리는 듯 하다. 위성 신호가 잘 잡혀도 길게는 10분정도 걸리는 경우가 있다.  &lt;br /&gt;
&lt;br /&gt;
## NMEA 프로토콜&lt;br /&gt;
gps 통신 표준을 관리하는 곳은 재미있게도 NMEA, 'National Marine Electronics Association' 해양전자협회? 이다. 그래서 gps표준 프로토콜 이름도 'NMEA-0183' 이다.  &lt;br /&gt;
잘 정리된 한글자료: https://techlog.gurucat.net/239 [하얀쿠아의 이것저것 만들기 Blog]&lt;br /&gt;
nmea 표준 레퍼런스: https://www.sparkfun.com/datasheets/GPS/NMEA%20Reference%20Manual-Rev2.1-Dec07.pdf  &lt;br /&gt;
&lt;br /&gt;
NMEA 데이터 형태&lt;br /&gt;
 ``` $GPGGA,141113.999,3730.0308,N,12655.2369,E,1,06,1.7,98.9,M,,,,0000*3E&lt;br /&gt;
&lt;br /&gt;
$GPGSA,A,3,02,07,01,20,04,13,,,,,,,3.7,1.7,3.2*31&lt;br /&gt;
&lt;br /&gt;
$GPRMC,141113.999,A,3730.0308,N,12655.2369,E,19.77,195.23,101200,,*3C&lt;br /&gt;
&lt;br /&gt;
$GPGGA,141114.999,3730.0264,N,12655.2351,E,1,07,1.2,98.8,M,,,,0000*3C&lt;br /&gt;
&lt;br /&gt;
$GPGSA,A,3,02,07,01,20,24,04,13,,,,,,2.3,1.2,1.9*3E&lt;br /&gt;
&lt;br /&gt;
$GPRMC,141114.999,A,3730.0264,N,12655.2351,E,15.51,202.12,101200,,*3C&lt;br /&gt;
&lt;br /&gt;
$GPGGA,141115.999,3730.0231,N,12655.2345,E,1,07,1.2,98.7,M,,,,0000*37&lt;br /&gt;
&lt;br /&gt;
$GPGSA,A,3,02,07,01,20,24,04,13,,,,,,2.3,1.2,1.9*3E&lt;br /&gt;
&lt;br /&gt;
$GPGSV,2,1,07,07,84,025,47,04,51,289,48,20,40,048,47,02,32,203,46*74&lt;br /&gt;
&lt;br /&gt;
$GPGSV,2,2,07,01,23,101,47,13,20,131,32,24,19,268,40*49&lt;br /&gt;
&lt;br /&gt;
$GPRMC,141115.999,A,3730.0231,N,12655.2345,E,12.14,194.75,101200,,*33&lt;br /&gt;
&lt;br /&gt;
$GPGGA,141116.999,3730.0210,N,12655.2330,E,1,07,1.2,98.5,M,,,,0000*37&lt;br /&gt;
&lt;br /&gt;
$GPGSA,A,3,02,07,01,20,24,04,13,,,,,,2.3,1.2,1.9*3E&lt;br /&gt;
&lt;br /&gt;
$GPRMC,141116.999,A,3730.0210,N,12655.2330,E,8.01,194.65,101200,,*0F&lt;br /&gt;
&lt;br /&gt;
$GPGGA,141117.998,3730.0199,N,12655.2320,E,1,06,1.3,98.2,M,,,,0000*33&lt;br /&gt;
&lt;br /&gt;
$GPGSA,A,3,02,07,01,20,24,04,,,,,,,2.4,1.3,2.0*30&lt;br /&gt;
```&lt;br /&gt;
* $ : 각 문장의 시작&lt;br /&gt;
* \n (CR/LF) : 각 문장의 끝&lt;br /&gt;
* sentence id : $다음에 오는 다섯 글자로,디바이스 종류를 밝히는두자(예를들어 GP) 와 이어지는 데이터 종류를 밝히는 3글자(예를들어 GGA)로 구성됨.&lt;br /&gt;
* 데이터: 콤마로 구분된 데이터들은  앞의 sentence id에 따라 해석하게 된다.&lt;br /&gt;
가장 기본적인 몇가지만 읽는 방법을 알아보자&lt;br /&gt;
### GPGGA&lt;br /&gt;
GPGGA는 'Global Positioning System Fix Data'를 의미한다.  아래의 GPGGA 예제 sentence를 살펴보자.&lt;br /&gt;
&lt;br /&gt;
 GPGGA는 총 17개의 field를 가진다.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/de0df9/Image%202019-09-04%20at%203.10.19%20PM.png)&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/69bb04/Image%202019-09-04%20at%203.10.36%20PM.png)&lt;br /&gt;
&lt;br /&gt;
### GPRMC&lt;br /&gt;
GPRMC는 'Recommended Minimum Specific GNSS Data'로 정의되어있다.&lt;br /&gt;
NMEA에는 GPS에서 필수적인 PVT(Position, Velocity, Time) 데이터의 고유한 버전이 있다.&lt;br /&gt;
그것을 RMC라고 부른다. 'RMC'에서 RM이 Recommended Minimum의 약자이고, C는 GNSS를 의미한다. RMA, RMB도 있으며 각각 LORAN-C와 Navigation을 의미한다. 상식으로 알아두자.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/fc6b5f/Image%202019-09-04%20at%203.11.51%20PM.png)&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/f09f14/Image%202019-09-04%20at%203.12.04%20PM.png)&lt;br /&gt;
&lt;br /&gt;
### GPGSV&lt;br /&gt;
GSV는 'GNSS Satellite in View' 를 의미한다. 각각 위성의 상태에 대해 나와있는 문장이다.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/50a166/Image%202019-09-04%20at%203.13.52%20PM.png)&lt;br /&gt;
&lt;br /&gt;
### checksum&lt;br /&gt;
NMEA checksum 계산방법 및 예제코드&lt;br /&gt;
지금까지 예제로 보여준 NMEA sentence들을 살펴보면 알겠지만, checksum은 * 뒤에 16진수 두자리로 표시한다.&lt;br /&gt;
&lt;br /&gt;
checksum의 계산은 $, * 의 사이에 있는 각 문자를 exclusive-or (XOR) 연산한 값을 표시한다.&lt;br /&gt;
&lt;br /&gt;
어떤 NMEA sentence가 주어지면, * 뒤에 있는 16진수 두자리의 checksum과 직접 XOR연산한 값이 일치하는지를 검사해야 한다. 일치하지 않는다면, 그 sentence는 통신상의 문제 등의 이유로, 결함이 있는 것으로 간주해야 하며, 사용하면 안된다.&lt;br /&gt;
예를 들어보자.&lt;br /&gt;
&lt;br /&gt;
&amp;gt;$GPRMC,155123.000,A,4043.8432,N,07359.7653,W,0.15,83.25,200407,,\*28&lt;br /&gt;
&lt;br /&gt;
이와 같은 NMEA sentence가 주어졌을때, checksum계산을 위한 XOR연산은 아래 각 문자들에 대해서 수행하면 된다.&lt;br /&gt;
&lt;br /&gt;
&amp;gt;GPRMC,155123.000,A,4043.8432,N,07359.7653,W,0.15,83.25,200407,,&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## python 에서  NMEA 데이터 사용 예제&lt;br /&gt;
### manually&lt;br /&gt;
참고: http://ozzmaker.com/using-python-with-a-gps-receiver-on-a-raspberry-pi/&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
import serial&lt;br /&gt;
&lt;br /&gt;
port = &amp;quot;/dev/serial0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def parseGPS(data):&lt;br /&gt;
#    print &amp;quot;raw:&amp;quot;, data #prints raw data&lt;br /&gt;
    if data[0:6] == &amp;quot;$GPRMC&amp;quot;:&lt;br /&gt;
        sdata = data.split(&amp;quot;,&amp;quot;)&lt;br /&gt;
        if sdata[2] == 'V':&lt;br /&gt;
            print &amp;quot;no satellite data available&amp;quot;&lt;br /&gt;
            return&lt;br /&gt;
        print &amp;quot;---Parsing GPRMC---&amp;quot;,&lt;br /&gt;
        time = sdata[1][0:2] + &amp;quot;:&amp;quot; + sdata[1][2:4] + &amp;quot;:&amp;quot; + sdata[1][4:6]&lt;br /&gt;
        lat = decode(sdata[3]) #latitude&lt;br /&gt;
        dirLat = sdata[4]      #latitude direction N/S&lt;br /&gt;
        lon = decode(sdata[5]) #longitute&lt;br /&gt;
        dirLon = sdata[6]      #longitude direction E/W&lt;br /&gt;
        speed = sdata[7]       #Speed in knots&lt;br /&gt;
        trCourse = sdata[8]    #True course&lt;br /&gt;
        date = sdata[9][0:2] + &amp;quot;/&amp;quot; + sdata[9][2:4] + &amp;quot;/&amp;quot; + sdata[9][4:6]#date&lt;br /&gt;
&lt;br /&gt;
        print &amp;quot;time : %s, latitude : %s(%s), longitude : %s(%s), speed : %s, True Course : %s, Date : %s&amp;quot; %  (time,lat,dirLat,lon,dirLon,speed,trCourse,date)&lt;br /&gt;
&lt;br /&gt;
def decode(coord):&lt;br /&gt;
    #Converts DDDMM.MMMMM &amp;gt; DD deg MM.MMMMM min&lt;br /&gt;
    x = coord.split(&amp;quot;.&amp;quot;)&lt;br /&gt;
    head = x[0]&lt;br /&gt;
    tail = x[1]&lt;br /&gt;
    deg = head[0:-2]&lt;br /&gt;
    min = head[-2:]&lt;br /&gt;
    return deg + &amp;quot; deg &amp;quot; + min + &amp;quot;.&amp;quot; + tail + &amp;quot; min&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
print &amp;quot;Receiving GPS data&amp;quot;&lt;br /&gt;
ser = serial.Serial(port, baudrate = 9600, timeout = 0.5)&lt;br /&gt;
while True:&lt;br /&gt;
   data = ser.readline()&lt;br /&gt;
   parseGPS(data)&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
### pynmea2 library 사용&lt;br /&gt;
NMEA 데이터 파싱을 도와주는 pynmea2 라이브러리를 사용할 수 있다.&lt;br /&gt;
* 라이브러리 설치&lt;br /&gt;
```bash&lt;br /&gt;
$ pip install pynmea2&lt;br /&gt;
```&lt;br /&gt;
* 예제&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
import serial&lt;br /&gt;
import pynmea2&lt;br /&gt;
&lt;br /&gt;
port = &amp;quot;/dev/serial0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
def parseGPS(str):&lt;br /&gt;
    if str.find('GGA') &amp;gt; 0:&lt;br /&gt;
        msg = pynmea2.parse(str)&lt;br /&gt;
        print &amp;quot;Timestamp: %s -- Lat: %s %s -- Lon: %s %s -- Altitude: %s %s -- Satellites: %s&amp;quot; % (msg.timestamp,msg.lat,msg.lat_dir,msg.lon,msg.lon_dir,msg.altitude,msg.altitude_units,msg.num_sats)&lt;br /&gt;
&lt;br /&gt;
serialPort = serial.Serial(port, baudrate = 9600, timeout = 0.5)&lt;br /&gt;
while True:&lt;br /&gt;
    str = serialPort.readline()&lt;br /&gt;
    parseGPS(str)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## GPSD&lt;br /&gt;
gpsd 는 GPS daemon의 약자로, 백그라운드에서 동작하면서  gps 사용을 도와주는 프로그램이다. 시리얼포트에서 들어오는 로데이터를 바로 사용할 수도 있지만, gpsd과, 이와 연계된 라이브러리를 사용하면 더 쉽게  gps가 제공하는 정보를 활용할 수 있다.&lt;br /&gt;
Adafruit 참고자료: https://learn.adafruit.com/adafruit-ultimate-gps-hat-for-raspberry-pi/use-gpsd&lt;br /&gt;
gpsd 공식문서:https://gpsd.gitlab.io/gpsd/index.html&lt;br /&gt;
&lt;br /&gt;
### gpsd 와 파이썬 라이브러리 설치&lt;br /&gt;
```bash&lt;br /&gt;
$ sudo apt-get update&lt;br /&gt;
$ sudo apt-get install gpsd gpsd-clients python-gps&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 라즈비안의 디폴트 서비스 제거&lt;br /&gt;
라즈비안에서는 라즈베리파이에 USB를 통해 외부 gps장치를 연결이 감지되면 gpsd가 실행되도록하는 systemd 서비스가 기본 켜져있다. 이 부분이 간섭일으키므로  disable 시킨다.&lt;br /&gt;
```bash&lt;br /&gt;
$ sudo systemctl stop gpsd.socket&lt;br /&gt;
$ sudo systemctl disable gpsd.socket&lt;br /&gt;
```&lt;br /&gt;
#### 부팅시 gpsd 자동으로 시작하기&lt;br /&gt;
* [ ] systemd를 죽이는 대신에 usb가 아닌 serial0에 연결된 gps 가 부팅과 동시에 실행되도록 하려면, /etc/default/gpsd 를 수정토록 한다.&lt;br /&gt;
```bash&lt;br /&gt;
$ sudo nano /etc/default/gpsd&lt;br /&gt;
```&lt;br /&gt;
 from:&lt;br /&gt;
 &amp;gt;DEVICES=&amp;quot;&amp;quot;  &lt;br /&gt;
&lt;br /&gt;
 to:&lt;br /&gt;
 &amp;gt;DEVICES=&amp;quot;/dev/serial0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 그리고  systemd  서비스는 다시 켜준다.&lt;br /&gt;
 ```bash&lt;br /&gt;
 $ sudo systemctl enable gpsd.socket&lt;br /&gt;
 $ sudo systemctl start gpsdsocket&lt;br /&gt;
 ```&lt;br /&gt;
&lt;br /&gt;
### gpsd 실행&lt;br /&gt;
```bash&lt;br /&gt;
$ sudo gpsd /dev/serial0 -F /var/run/gpsd.sock&lt;br /&gt;
```&lt;br /&gt;
끌 때는&lt;br /&gt;
``` bash&lt;br /&gt;
$ sudo killall gpsd&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### test: cgps&lt;br /&gt;
gpsd가 제공하는 데이터를 실시간으로 확인할 수 있다.&lt;br /&gt;
```bash&lt;br /&gt;
$ cgps&lt;br /&gt;
```&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/dc6e40/Image%202019-09-04%20at%2012.36.37%20PM.png)&lt;br /&gt;
&lt;br /&gt;
### gpsd 가 제공하는 데이터 구조&lt;br /&gt;
gpsd의 데이터는 json 형식으로,  'class' attribute 에 따라 해석한다.&lt;br /&gt;
gpsd 프로토콜 공식문서: https://gpsd.gitlab.io/gpsd/gpsd_json.html&lt;br /&gt;
&lt;br /&gt;
####  gpsd + python 예제&lt;br /&gt;
* gpsd로부터  TPV (time, position, velocity) 기본정보 가져오기&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
#! /usr/bin/python&lt;br /&gt;
&lt;br /&gt;
from gps import *&lt;br /&gt;
import time&lt;br /&gt;
&lt;br /&gt;
gpsd = gps(mode=WATCH_ENABLE|WATCH_NEWSTYLE)&lt;br /&gt;
print 'latitude\tlongitude\ttime utc\t\t\taltitude\tepv\tept\tspeed\tclimb' # '\t' = TAB to try and output the data in columns.&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    while True:&lt;br /&gt;
        report = gpsd.next() #&lt;br /&gt;
        if report['class'] == 'TPV':&lt;br /&gt;
&lt;br /&gt;
            print  getattr(report,'lat',0.0),&amp;quot;\t&amp;quot;,&lt;br /&gt;
            print  getattr(report,'lon',0.0),&amp;quot;\t&amp;quot;,&lt;br /&gt;
            print getattr(report,'time',''),&amp;quot;\t&amp;quot;,&lt;br /&gt;
            print  getattr(report,'alt','nan'),&amp;quot;\t\t&amp;quot;,&lt;br /&gt;
            print  getattr(report,'epv','nan'),&amp;quot;\t&amp;quot;,&lt;br /&gt;
            print  getattr(report,'ept','nan'),&amp;quot;\t&amp;quot;,&lt;br /&gt;
            print  getattr(report,'speed','nan'),&amp;quot;\t&amp;quot;,&lt;br /&gt;
            print getattr(report,'climb','nan'),&amp;quot;\t&amp;quot;&lt;br /&gt;
&lt;br /&gt;
        time.sleep(1)&lt;br /&gt;
&lt;br /&gt;
except (KeyboardInterrupt, SystemExit): #when you press ctrl+c&lt;br /&gt;
    print &amp;quot;Done.\nExiting.&amp;quot;&lt;br /&gt;
```&lt;br /&gt;
* 인공위성 정보 가져오기&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
#! /usr/bin/python&lt;br /&gt;
&lt;br /&gt;
from gps import *&lt;br /&gt;
import time&lt;br /&gt;
import os&lt;br /&gt;
&lt;br /&gt;
gpsd = gps(mode=WATCH_ENABLE|WATCH_NEWSTYLE)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while True:&lt;br /&gt;
&lt;br /&gt;
        report = gpsd.next() #&lt;br /&gt;
        if report['class'] == 'SKY':&lt;br /&gt;
            os.system('clear')&lt;br /&gt;
            print ' Satellites (total of', len(gpsd.satellites) , ' in view)'&lt;br /&gt;
            for i in gpsd.satellites:&lt;br /&gt;
                print 't', i&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
            print '\n\n'&lt;br /&gt;
            print 'PRN = PRN ID of the satellite. 1-63 are GNSS satellites, 64-96 are GLONASS satellites, 100-164 are SBAS satellites'&lt;br /&gt;
            print 'E = Elevation in degrees'&lt;br /&gt;
            print 'As = Azimuth, degrees from true north'&lt;br /&gt;
            print 'ss = Signal stength in dB'&lt;br /&gt;
            print 'used = Used in current solution?'&lt;br /&gt;
&lt;br /&gt;
        time.sleep(1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
except (KeyboardInterrupt, SystemExit): #when you press ctrl+c&lt;br /&gt;
    print &amp;quot;Done.\nExiting.&amp;quot;&lt;br /&gt;
```&lt;/div&gt;</summary>
		<author><name>Doguin</name></author>	</entry>

	<entry>
		<id>http://lhdangerous.godohosting.com/wiki/index.php/Google_API_python_client_%EC%82%AC%EC%9A%A9%EB%B2%95-simple</id>
		<title>Google API python client 사용법-simple</title>
		<link rel="alternate" type="text/html" href="http://lhdangerous.godohosting.com/wiki/index.php/Google_API_python_client_%EC%82%AC%EC%9A%A9%EB%B2%95-simple"/>
				<updated>2019-09-14T06:39:47Z</updated>
		
		<summary type="html">&lt;p&gt;Doguin: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Python Google&lt;br /&gt;
 API 사용하기&lt;br /&gt;
라즈베리파이에서 gmail등의 구글 서비스를 확인하고 조작 할 수 있는 python 코드 사용법. 구글의 표준  api를 사용한다. 이하에서는 Gmail과 Google calendar 를 예로 사용한다.&lt;br /&gt;
참고: https://developers.google.com/gmail/api/quickstart/python&lt;br /&gt;
&lt;br /&gt;
## Google OAuth2.0 을 통한 인증&lt;br /&gt;
참고:&lt;br /&gt;
* 구글 공식 개념설명: https://developers.google.com/identity/protocols/OAuth2&lt;br /&gt;
* 구글 샘플: https://developers.google.com/gmail/api/quickstart/python&lt;br /&gt;
* 라이브러리 도큐먼트: https://google-auth-oauthlib.readthedocs.io/en/latest/reference/google_auth_oauthlib.flow.html&lt;br /&gt;
&lt;br /&gt;
gmail 데이터를 사용하는 웹 서비스나 어플리케이션, 혹은 기기를 만든다고 하면, 신뢰와 관련한 2가지 문제가 발생한다.&lt;br /&gt;
1. 이 사용자가 정말 본인인가?&lt;br /&gt;
2. 이 어플이 어디까지 민감한 정보를 다루도록 허용할 것인가?&lt;br /&gt;
&lt;br /&gt;
1번 문제를 authentication의 문제라고하고, 두번째의 문제를 authorization의 문제라고 한다.&lt;br /&gt;
개인개발자가 해결하기에는 어려운 두가지 문제를 구글이라는 능력자에게 위탁해버리는 해결책이  OAuth2.0 이라는 프로토콜이다.&lt;br /&gt;
&lt;br /&gt;
간단히 요약하자면, 구글의 인증을 받은 프로젝트(구글인증서버에 대해 클라이언트)는 클라이언트 인증정보(Oauth2.0 client ID, Pass 등) 을 발급받아 가지고 있다가  Gmail 데이터가 필요한 순간에 사용자가 직접 어플에 구글 아이디를 입력하는 대신 구글의 로그인 창(consent screen)을 띄워주고, 구글측에서 사용자가 확인되면 사용자에게 '이러이러한 앱에서 너의  gmail 데이터에 접근하도록 허락할래?'라고 물어본 후, 허락들 받으면 어플에 gmil api에 리퀘스트를 보낼때 꼭 필요한 Access Token을 발급해주는 절차이다.&lt;br /&gt;
&lt;br /&gt;
  ![||600](https://cl.ly/333ddb/Screen%20Recording%202019-08-07%20at%2012.55%20PM-Animated%20Image%20(Small).gif)&lt;br /&gt;
&lt;br /&gt;
Oauth2.0의 개념에 대한 설명은 다양한 자료에서 다루고 있으므로 참고하도록 하고, 여기서는 Raspberry pi 상에서  Gmail 정보를 가져오은 python 스크립트를 구현하기 위한 실제적인 내용들만 확인하자.&lt;br /&gt;
&lt;br /&gt;
### 1. google cloud platform 가입&lt;br /&gt;
gmail api 는 구글 클라우드 플랫폼이라는 서비스의 일부이다. 먼저 구글 계정을 만들어 google cloud platform에 가입하고 프로젝트를 새로 생성한다.&lt;br /&gt;
http://www.google.com/cloud&lt;br /&gt;
기존의  gmail 계정을 사용해도 되며, 무료로 가입해도 대부분의 기본 기능을 마음껏 사용할 수 있다.(신용카드 등록을 해도 결제가 되지는 않는다. 신용카드 등록하지 않고 창을 닫아도 작동되는 듯 하다.)&lt;br /&gt;
&lt;br /&gt;
### 2. 새 프로젝트 생성&lt;br /&gt;
구글 클라우드 플랫폼 콘솔화면에서 새로운 프로젝트를 생성한다.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/ab0ad7/Image%202019-08-05%20at%205.45.31%20PM.png)&lt;br /&gt;
Gmail-test라고 이름지었다.&lt;br /&gt;
&lt;br /&gt;
### 3. Gmail API 켜기&lt;br /&gt;
API 및 서비스 &amp;gt; 대시보드 ( https://console.developers.google.com/apis )에서 Gamil api를 Enabled 시켜준다.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/a8753e/Image%202019-08-05%20at%205.49.35%20PM.png)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/3e7ee6/Image%202019-08-05%20at%205.59.36%20PM.png)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/24249b/Image%202019-08-05%20at%206.04.18%20PM.png)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/2017ec/Image%202019-08-02%20at%206.40.18%20PM.png)&lt;br /&gt;
&lt;br /&gt;
### 4. 인증정보 (OAuth Client ID, PASS) 생성&lt;br /&gt;
&amp;quot;이 프로그램은 너의 구글 계정에서 이러이러한 개인정보를 가져다가 쓸거야. 허용할래?&amp;quot; 라고 물어보는 화면을 consent screen이라고 한다. 메뉴 &amp;gt; APIs &amp;amp; Services &amp;gt; 사용자 인증정보 에서 인증 정보를 만든다. 3가지 방식 중 고를 수 있도록 되어있는데, 어떤 방식을 골라야 할지 잘 모른다면 마지막의 '사용자 인증정보 선택 도움말'을 활용한다. 우리는 OAuth 클라이언트 ID를 선택.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/9cd427/Image%202019-08-05%20at%206.23.17%20PM.png)&lt;br /&gt;
동의 화면 (구글 로그인창) 구성&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/1c08c7/Image%202019-08-05%20at%206.28.06%20PM.png)&lt;br /&gt;
프로젝트 이름, 로고, 문의사항 보낼 수 있는 지원 이메일 등등 넣을 수 있다.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/9f43dd/Image%202019-08-05%20at%206.32.38%20PM.png)&lt;br /&gt;
만들고 있는 프로젝트 유형에 따라 애플리케이션 유형을 선택한다.&lt;br /&gt;
우리는 raspberry pi 의 cli 환경에서 사용할 예정이므로 구글에서 제공하는 동의화면을 바로 디바이스에 띄울 수가 없고, 제3의 디바이스를 통해 접근토록 해야한다.&lt;br /&gt;
이런경우 반드시 **'기타'** 를 선택한다.&lt;br /&gt;
'OAuth 클라이언트 이름'은 프로젝트명과는 별개로, 나는 gmail_test라고 지었다.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/4b1766/Image%202019-08-05%20at%206.35.38%20PM.png)&lt;br /&gt;
인증정보 생성 완료!&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/4e7818/Image%202019-08-05%20at%206.36.31%20PM.png)&lt;br /&gt;
&lt;br /&gt;
인증정보 (credentials)를 다운로드 해 두면 번거롭게 한자씩 타이핑해 넣지 않아도 되므로 편하다.&lt;br /&gt;
&amp;lt;br&amp;gt;![||600](https://cl.ly/6972be/Image%202019-08-05%20at%206.37.49%20PM.png)&lt;br /&gt;
다운받은  .json 파일은 실행시킬 파이선 코드와 같은 위치에 넣어둔다.&lt;br /&gt;
&lt;br /&gt;
### 2. Google Client Library 를 설치한다.&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
$pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib&lt;br /&gt;
```&lt;br /&gt;
* [x] 라즈베리에서 설치하려니  sudo 권한이 필요한데, 확인 필요하다.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
### 3. Gmail api 공식 샘플 코드를 실행시켜 잘 작동하는지 확인&lt;br /&gt;
참고: https://developers.google.com/gmail/api/quickstart/python&lt;br /&gt;
* 27행의 'credentials.json' 은 앞서 받아둔 클라이언트 인증 정보파일로 파일명 바꾼다.&lt;br /&gt;
&lt;br /&gt;
* 우리는 라즈베리파이의 콘솔환경에서 실행시키고 있으므로, consent screen을 디바이스에 바로 띄울 수 없다. 제3의 디바이스에서 브라우저를 열고 consent screen 을 찾아가서 확인 코드를 받고 콘솔 창에 입력하는 방식으로 해야하는데, 이를 위해서는 28행의 'flow.run_local_server(port=0)' 은 'flow.run_console()'로 교체되어야 한다.  &lt;br /&gt;
참고: https://google-auth-oauthlib.readthedocs.io/en/latest/reference/google_auth_oauthlib.flow.html&lt;br /&gt;
&lt;br /&gt;
* 예제는 gmail에서 데이터를 읽어오는 것까지만 권한 요청한다. 만일 프로젝트에서 필요로하는 권한의 범위가 달라진다면 행8의  SCOPES = [...]를 수정, 혹은 추가 해야 한다.   &lt;br /&gt;
참고: https://developers.google.com/gmail/api/auth/scopes&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
# gmail-test.py&lt;br /&gt;
# raspberry pi 콘솔용.  gmail label 목록을 불러온다.&lt;br /&gt;
&lt;br /&gt;
import pickle&lt;br /&gt;
import os.path&lt;br /&gt;
from googleapiclient.discovery import build&lt;br /&gt;
from google_auth_oauthlib.flow import InstalledAppFlow&lt;br /&gt;
from google.auth.transport.requests import Request&lt;br /&gt;
&lt;br /&gt;
# If modifying these scopes, delete the file token.pickle.&lt;br /&gt;
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Shows basic usage of the Gmail API.&lt;br /&gt;
    Lists the user's Gmail labels.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    creds = None&lt;br /&gt;
    # The file token.pickle stores the user's access and refresh tokens, and is&lt;br /&gt;
    # created automatically when the authorization flow completes for the first&lt;br /&gt;
    # time.&lt;br /&gt;
    if os.path.exists('token.pickle'):&lt;br /&gt;
        with open('token.pickle', 'rb') as token:&lt;br /&gt;
            creds = pickle.load(token)&lt;br /&gt;
    # If there are no (valid) credentials available, let the user log in.&lt;br /&gt;
    if not creds or not creds.valid:&lt;br /&gt;
        if creds and creds.expired and creds.refresh_token:&lt;br /&gt;
            creds.refresh(Request())&lt;br /&gt;
        else:&lt;br /&gt;
            flow = InstalledAppFlow.from_client_secrets_file(&lt;br /&gt;
                'client_secret_497460368822-l2vljgso619t68g4nnfbej5i9kel4767.apps.googleusercontent.com.json', SCOPES)&lt;br /&gt;
            creds = flow.run_console()&lt;br /&gt;
            print(creds)&lt;br /&gt;
        # Save the credentials for the next run&lt;br /&gt;
        with open('token.pickle', 'wb') as token:&lt;br /&gt;
            pickle.dump(creds, token)&lt;br /&gt;
&lt;br /&gt;
    service = build('gmail', 'v1', credentials=creds)&lt;br /&gt;
&lt;br /&gt;
    # Call the Gmail API&lt;br /&gt;
    results = service.users().labels().list(userId='me').execute()&lt;br /&gt;
    labels = results.get('labels', [])&lt;br /&gt;
&lt;br /&gt;
    if not labels:&lt;br /&gt;
        print('No labels found.')&lt;br /&gt;
    else:&lt;br /&gt;
        print('Labels:')&lt;br /&gt;
        for label in labels:&lt;br /&gt;
            print(label['name'])&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;![||600]( https://cl.ly/8829db/Screen%20Recording%202019-08-07%20at%2003.23%20PM-Animated%20Image%20(Large).gif )&lt;br /&gt;
&lt;br /&gt;
## Google api python library 사용법&lt;br /&gt;
구글 공식 문서: https://github.com/googleapis/google-api-python-client/blob/master/docs/start.md#building-and-calling-a-service  &lt;br /&gt;
google python 라이브러리가 지원하는 모든 google api 리스트와 사용법 reference: https://github.com/googleapis/google-api-python-client/blob/c977304a1af233058f572787538edafc2ef122e6/docs/dyn/index.md&lt;br /&gt;
&lt;br /&gt;
구글의 모든 서비스 api는 비슷한 구조를 가지고 있다. gmail도 마찬가지.&lt;br /&gt;
### 1. 구글 서비스 객체 만들기&lt;br /&gt;
* apiclient.discovery.build()사용해 서비스 객체 만든다.  &lt;br /&gt;
* 어떤 서비스 api를 사용할 것인지,  api버전은 어느 것 사용하는지, [link](https://github.com/googleapis/google-api-python-client/blob/c977304a1af233058f572787538edafc2ef122e6/docs/dyn/index.md) 중에서 선택한다.  &lt;br /&gt;
* 앞서 획득한 access token도 이때 전달한다.&lt;br /&gt;
```python&lt;br /&gt;
from apiclient.discovery import build&lt;br /&gt;
service = build('api_name', 'api_version', credencials='아까얻은 AcessToken')&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 2. collection&lt;br /&gt;
구글 서비스의 모든 데이터는 계층적인 집합을 이루고 있는데, 이 한 단위의 계층을 collection이라고 부른다.&lt;br /&gt;
gmail 같으면 user 콜렉션 아래에는 여러개의 message 콜렉션이 있고, 그 아래에는.... 하는 식이다.&lt;br /&gt;
이들 콜렉션에 아래와 같이 접근할 수 있다.&lt;br /&gt;
```python&lt;br /&gt;
collection = service.users().messages()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
### 3. request and response&lt;br /&gt;
어떤 특정한 collection에 대해 구글에 요청할 수 있는 명령어는 콜렉션마다 다 다르다. [이곳](https://developers.google.com/gmail/api/v1/reference/) 에서 검색 할 수 있다.&lt;br /&gt;
gmail의 message 콜렉션이 list()명령을 가지고 있다면,&lt;br /&gt;
```python&lt;br /&gt;
request = service.users().messages().list(userId='me')&lt;br /&gt;
```&lt;br /&gt;
실제 request를 구글 api 서버에 보내고 응답을 받아오는 건  execute() 함수를 사용.&lt;br /&gt;
```python&lt;br /&gt;
response = request.execute()&lt;br /&gt;
# or&lt;br /&gt;
response = servie.users().mesages().list(userId='me').execute()&lt;br /&gt;
```&lt;br /&gt;
* 구글로부터의 답장은 원래는  JSON형식으로 온다. 그렇지만 우리가 사용하는 python api가 자동으로 사용하기 쉽게  python 데이터 타입(dict)로 바꾸어주기 때문에 get()함수로 원하는 항목을 쉽게 뽑아 쓸 수 있다.&lt;br /&gt;
&lt;br /&gt;
## 구글 캘린더 예제&lt;br /&gt;
구글 캘린더 api소개자료의 가장 기본 예제.  &lt;br /&gt;
참고: https://developers.google.com/calendar/quickstart/python&lt;br /&gt;
```python&lt;br /&gt;
# quickstart.py&lt;br /&gt;
# 사용자의 기본캘린더 (primary)에서&lt;br /&gt;
# 지금이후(timeMin=now)로 시작하는&lt;br /&gt;
# 10개의 이벤트(maxResult-10)를 가져와 표시하기&lt;br /&gt;
&lt;br /&gt;
from __future__ import print_function&lt;br /&gt;
import datetime&lt;br /&gt;
import pickle&lt;br /&gt;
import os.path&lt;br /&gt;
from googleapiclient.discovery import build&lt;br /&gt;
from google_auth_oauthlib.flow import InstalledAppFlow&lt;br /&gt;
from google.auth.transport.requests import Request&lt;br /&gt;
&lt;br /&gt;
# If modifying these scopes, delete the file token.pickle.&lt;br /&gt;
SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;Shows basic usage of the Google Calendar API.&lt;br /&gt;
    Prints the start and name of the next 10 events on the user's calendar.&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    creds = None&lt;br /&gt;
    # The file token.pickle stores the user's access and refresh tokens, and is&lt;br /&gt;
    # created automatically when the authorization flow completes for the first&lt;br /&gt;
    # time.&lt;br /&gt;
    if os.path.exists('token.pickle'):&lt;br /&gt;
        with open('token.pickle', 'rb') as token:&lt;br /&gt;
            creds = pickle.load(token)&lt;br /&gt;
    # If there are no (valid) credentials available, let the user log in.&lt;br /&gt;
    if not creds or not creds.valid:&lt;br /&gt;
        if creds and creds.expired and creds.refresh_token:&lt;br /&gt;
            creds.refresh(Request())&lt;br /&gt;
        else:&lt;br /&gt;
            flow = InstalledAppFlow.from_client_secrets_file(&lt;br /&gt;
                'credentials.json', SCOPES)&lt;br /&gt;
            creds = flow.run_local_server(port=0)&lt;br /&gt;
        # Save the credentials for the next run&lt;br /&gt;
        with open('token.pickle', 'wb') as token:&lt;br /&gt;
            pickle.dump(creds, token)&lt;br /&gt;
&lt;br /&gt;
    service = build('calendar', 'v3', credentials=creds)&lt;br /&gt;
&lt;br /&gt;
    # Call the Calendar API&lt;br /&gt;
    now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time&lt;br /&gt;
    print('Getting the upcoming 10 events')&lt;br /&gt;
    events_result = service.events().list(calendarId='primary', timeMin=now,&lt;br /&gt;
                                        maxResults=10, singleEvents=True,&lt;br /&gt;
                                        orderBy='startTime').execute()&lt;br /&gt;
    events = events_result.get('items', [])&lt;br /&gt;
&lt;br /&gt;
    if not events:&lt;br /&gt;
        print('No upcoming events found.')&lt;br /&gt;
    for event in events:&lt;br /&gt;
        start = event['start'].get('dateTime', event['start'].get('date'))&lt;br /&gt;
        print(start, event['summary'])&lt;br /&gt;
&lt;br /&gt;
if __name__ == '__main__':&lt;br /&gt;
    main()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
## json module  for python&lt;br /&gt;
참고: https://www.w3schools.com/python/python_json.asp  &lt;br /&gt;
&lt;br /&gt;
Json 데이터를 다루어야 하는 경우, 파이썬에 기본 포함 되어있는 json모듈을 사용하면 JSON 파일/string을 파이썬  dictionary 나  list 로 만들어 사용할 수 있어 편리하다. 더우기 indent=  아규먼트를 사용하면 print() 로 표시할 때 줄 맞추어 주므로 보기에도 편하다.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
import json&lt;br /&gt;
...&lt;br /&gt;
print json.dumps(response, sort_keys=True, indent=4)&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
For example, if the printed JSON is the following:&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;count&amp;quot;: 2,&lt;br /&gt;
    &amp;quot;items&amp;quot;: [&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;cents&amp;quot;: 5,&lt;br /&gt;
            &amp;quot;name&amp;quot;: &amp;quot;#586 1923-26 5-cent blue Theodore Roosevelt MLH perf 10&amp;quot;&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
            &amp;quot;cents&amp;quot;: 5,&lt;br /&gt;
            &amp;quot;name&amp;quot;: &amp;quot;#628 1926 5-cent Ericsson Memorial MLH&amp;quot;&lt;br /&gt;
        }&lt;br /&gt;
    ]&lt;br /&gt;
}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
# You can access the data like this:&lt;br /&gt;
print 'Num 5 cent stamps: %d' % response['count']&lt;br /&gt;
print 'First stamp name: %s' % response['items'][0]['name']&lt;br /&gt;
```&lt;br /&gt;
|method|용도 |&lt;br /&gt;
|-|-|&lt;br /&gt;
|json.load(json) / json.load**s**(json_string)|JSON 파일을 python dictionary 로 바꾸어 읽어들임 / json 문자열을 파이썬 데이타로 변환 |&lt;br /&gt;
|json.dump(puthon_object) / json.dump**s**(python_object)|python 데이터를 JSON으로 바꾸어 파일로 저장/ python 데이터를 json 형식 문자열로 변환.  &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;   parameter: sort_keys=(True/False), &amp;lt;br&amp;gt; parameter: indent= 들여쓰기칸수|&lt;/div&gt;</summary>
		<author><name>Doguin</name></author>	</entry>

	<entry>
		<id>http://lhdangerous.godohosting.com/wiki/index.php/Python_datetime_%EB%AA%A8%EB%93%88_quick_reference</id>
		<title>Python datetime 모듈 quick reference</title>
		<link rel="alternate" type="text/html" href="http://lhdangerous.godohosting.com/wiki/index.php/Python_datetime_%EB%AA%A8%EB%93%88_quick_reference"/>
				<updated>2019-09-11T10:21:49Z</updated>
		
		<summary type="html">&lt;p&gt;Doguin: 새 문서: # datetime 모듈 quick reference 공식문서 참고: https://docs.python.org/ko/3/library/datetime.html 쉬운 한글자료: https://python.bakyeono.net/chapter-11-3.html 일상생...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# datetime 모듈 quick reference&lt;br /&gt;
공식문서 참고: https://docs.python.org/ko/3/library/datetime.html&lt;br /&gt;
쉬운 한글자료: https://python.bakyeono.net/chapter-11-3.html&lt;br /&gt;
일상생활에서 사용하는 날짜와 시간을 다루기 위한 파이썬 기본 모듈.&lt;br /&gt;
날짜를 나타내는  datetime.date class, 시각을 나타내는 datetime.time class, 둘 모두를 나타내는 datetime.datetime class 를 가지고 있다.&lt;br /&gt;
&lt;br /&gt;
당연하게도  OS에서 현재  timezone과 시간이 올바르게 셋팅되어있어야한다.&lt;br /&gt;
라즈베리파이에서는  raspi-config 프로그램으로 타임존을 셋팅해주면 된다.&lt;br /&gt;
&lt;br /&gt;
OS 기반의 시간을 다루는 time 모듈도 있으니 참고.&lt;br /&gt;
&lt;br /&gt;
## datetime.date class&lt;br /&gt;
* 특정날짜 객체 생성: datetime.date(1978,8,6)&lt;br /&gt;
* 오늘날짜 객체 생성: datetime.date.today()&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
# datetime.date-test.py&lt;br /&gt;
from datetime import date&lt;br /&gt;
&lt;br /&gt;
print(date(1978,8,6))&lt;br /&gt;
print(date.today())&lt;br /&gt;
&lt;br /&gt;
# 1978-08-06&lt;br /&gt;
# 2019-08-14&lt;br /&gt;
```&lt;br /&gt;
|datetime.date class 속성 또는 메서드	|값 또는 기능|&lt;br /&gt;
|-|-|&lt;br /&gt;
year|	년&lt;br /&gt;
month	|월&lt;br /&gt;
day|	일&lt;br /&gt;
weekday()	|요일 (월요일=0, 일요일=6)&lt;br /&gt;
isoformat()	|ISO 표준 문자열 표현&amp;lt;br&amp;gt;“년-월-일”(예: 1986-03-06)과 같은 형식&lt;br /&gt;
strftime(format)	| 형식을 지정하여 표현 (자료 참고)&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
# datetime.date-test.py&lt;br /&gt;
from datetime import date&lt;br /&gt;
&lt;br /&gt;
myBirthDay = date(1978,8,6)&lt;br /&gt;
today = date.today()&lt;br /&gt;
print(myBirthDay)&lt;br /&gt;
print(today)&lt;br /&gt;
&lt;br /&gt;
# 1978-08-06&lt;br /&gt;
# 2019-08-14&lt;br /&gt;
&lt;br /&gt;
print('나는 %d년 %d월 %d일에 태어남' %(myBirthDay.year, myBirthDay.month,myBirthDay.day))&lt;br /&gt;
# 나는 1978년 8월 6일에 태어남&lt;br /&gt;
&lt;br /&gt;
day = '월화수목금토일'[today.weekday()]&lt;br /&gt;
print('오늘은 %s요일이에요' %day)&lt;br /&gt;
# 오늘은 수요일이에요&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## datetime.time class&lt;br /&gt;
밀리세컨드까지 특정해 표현가능.&lt;br /&gt;
* 특정 시각 객체 생성: datetime.time(13,30,0,100000) # 13시30분0초.100000&lt;br /&gt;
|datetime.time class 속성 또는 메서드|	값 또는 기능|&lt;br /&gt;
|-|-|&lt;br /&gt;
hour	|시&lt;br /&gt;
minute|	분&lt;br /&gt;
second	|초&lt;br /&gt;
microsecond	|마이크로초&lt;br /&gt;
isoformat()	I|SO 표준 문자열 표현&lt;br /&gt;
strftime(format)	|임의 형식으로 문자열 표현&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
# python interpreter&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; from datetime import time&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; at = time(15, 30, 45)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; at.hour, at.minute, at.second  # 시, 분, 초&lt;br /&gt;
(15, 30, 45)&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; at.microsecond                 # 마이크로초&lt;br /&gt;
0&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; at.isoformat()                 # ISO 표준 문자열 표현&lt;br /&gt;
'15:30:45'&lt;br /&gt;
```&lt;br /&gt;
### isoformat 문자열을 다시  datetime객체로&lt;br /&gt;
* datetime.fromisoformat(string)&lt;br /&gt;
&lt;br /&gt;
## datetime.datetime class&lt;br /&gt;
datetime.date 와 datetime.time 을 합쳐놓은 class. 양쪽의 속성과 메소드를 모두 사용할 수 있다.&lt;br /&gt;
* 특정 일시 객체 생성: datetime(년, 월, 일, 시, 분, 초, 마이크로초)&lt;br /&gt;
* 현재 일시 객체 생성: datetime.now()&lt;br /&gt;
* 날짜와 시각 결합: datetime.combine(날짜, 시각)&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
# python interpreter&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; from datetime import datetime&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; datetime(2017, 11, 14)&lt;br /&gt;
datetime.datetime(2017, 11, 14, 0, 0)&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; datetime(2017, 11, 14, 8, 30)&lt;br /&gt;
datetime.datetime(2017, 11, 14, 8, 30)&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; datetime(2017, 11, 14, 8, 30, 50, 200000)&lt;br /&gt;
datetime.datetime(2017, 11, 14, 8, 30, 50, 200000)&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; datetime.now()  # 현재 일시&lt;br /&gt;
datetime.datetime(2017, 11, 14, 19, 4, 7, 950704)&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; datetime.combine(date.today(), time(15))  # 오늘 3시&lt;br /&gt;
datetime.datetime(2017, 11, 14, 15, 0)&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; now = datetime.now()&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; now.year, now.month, now.day, '월화수목금토일'[now.weekday()]&lt;br /&gt;
(2017, 11, 14, '화')&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; now.hour, now.minute, now.second, now.microsecond&lt;br /&gt;
(19, 8, 52, 283277)&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; now.date(), now.time()&lt;br /&gt;
(datetime.date(2017, 11, 14), datetime.time(19, 8, 52, 283277))&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; now.isoformat()&lt;br /&gt;
'2017-11-14T19:08:52.283277'&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## datetime.timedelta class&lt;br /&gt;
두시간 사이의 차를 나타내는 timedelta class를 사용가능하다.&lt;br /&gt;
예를 들어,&lt;br /&gt;
date2 = date1 + timedelta&lt;br /&gt;
timedelta = date1 - date2&lt;br /&gt;
와 같은 연산이 가능하다.&lt;br /&gt;
자세한 내용은 참고자료 검토.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
# python interpreter&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; from datetime import datetime, timedelta&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; now = datetime.now()                 # 현재 일시&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; after_1000h = timedelta(hours=1000)  # 1천 시간&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; now + after_1000h                    # 지금부터 1천 시간 후&lt;br /&gt;
datetime.datetime(2017, 12, 26, 11, 42, 32, 103816)&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; birthday = date(1986, 3, 6)          # 생년월일&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; today = date.toady()                 # 오늘&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; today - birthday                     # 태어난 뒤 오늘까지의 기간&lt;br /&gt;
datetime.timedelta(11576)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 세계시계 datetime.tzinfo class&lt;br /&gt;
* time 이나 datetime 오브젝트의 멤버변수인 tzinfo가 None이 아닌 값(tzinfo나 그 서브클래스인 timezone 오브젝트)을 갖는 경우 세계시계로 작동하게 된다. (공식 문서에서 aware 라고 표현됨.)&lt;br /&gt;
* 생성자에  `tzinfo=` 아규먼트를 넣어줌으로써 세계시계작동시킨다.&lt;br /&gt;
* 써머타임 등 고려해 직접 tzinfo의 서브클래스를 작성 토록되어있지만(tzinfo는 추상클래스다) utc+9:00(서울 ) 등등 대부분의 간단한 경우를 나타내기 위해 이미 만들어져있는 timezone class를 사용할 수 있다.  &lt;br /&gt;
참고: https://spoqa.github.io/2019/02/15/python-timezone.html&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; from datetime import datetime,  timedelta, tzinfo, timezone&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; datetime.utcnow()&lt;br /&gt;
datetime.datetime(2019, 8, 14, 21, 12, 22, 857347) # 영국 그리니치의 현재시간을 표시하고있기는 하지만 tzinfo=None으로, 세계시간 aware 하지는 않다.&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; datetime.now(timezone.utc)&lt;br /&gt;
datetime.datetime(2019, 8, 14, 21, 14, 17, 112890, tzinfo=datetime.timezone.utc) # 세계시간 aware한 세계표준시&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; seoulnow = datetime.now(timezone(timedelta(hours=9))) # utc+9:00 (서울표준시)&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; seoulnow&lt;br /&gt;
datetime.datetime(2019, 8, 15, 6, 18, 34, 177299, tzinfo=datetime.timezone(datetime.timedelta(0, 32400)))&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; seoulnow.utcoffset()&lt;br /&gt;
datetime.timedelta(0, 32400) # 세계표준시와 시차&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; seoulnow.tzname()&lt;br /&gt;
'UTC+09:00' # 타임존 이름보기&lt;br /&gt;
&lt;br /&gt;
&amp;gt;&amp;gt;&amp;gt; seoulnow.astimezone(timezone(timedelta(hours=-4))) # 같은 시간을 뉴욕표준시(utc-4:00)로 표현하면?  &lt;br /&gt;
datetime.datetime(2019, 8, 14, 17, 18, 34, 177299, tzinfo=datetime.timezone(datetime.timedelta(-1, 72000)))&lt;br /&gt;
```&lt;/div&gt;</summary>
		<author><name>Doguin</name></author>	</entry>

	<entry>
		<id>http://lhdangerous.godohosting.com/wiki/index.php/PIL_(python_image_library)_/_pillow_quick_reference</id>
		<title>PIL (python image library) / pillow quick reference</title>
		<link rel="alternate" type="text/html" href="http://lhdangerous.godohosting.com/wiki/index.php/PIL_(python_image_library)_/_pillow_quick_reference"/>
				<updated>2019-09-11T10:01:50Z</updated>
		
		<summary type="html">&lt;p&gt;Doguin: 새 문서: # PIL (python Imaging library) Quick reference python 에서 비트맵 이미지를 그리고 편집하고 등등 여러가지 할 수 있는 오픈소스 이미지 프로세싱 라...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# PIL (python Imaging library) Quick reference&lt;br /&gt;
python 에서 비트맵 이미지를 그리고 편집하고 등등 여러가지 할 수 있는 오픈소스 이미지 프로세싱 라이브러리. 간편해서 매우널리 쓰인다.&lt;br /&gt;
&lt;br /&gt;
## PIL 설치&lt;br /&gt;
* 오리지날 PIL 은 개발중단 되었고,  pillow  프로젝트가 뒤를 잇고 있다. 대부분의 사용방법이 동일하다.&lt;br /&gt;
* 더 다양한 기능을 활용하기 위해 아래 외부 라이브러리를 먼저 설치해도 좋다.&lt;br /&gt;
(아래는 라즈베리파이에서  apt-get을 사용해 설치했으나 macos 에서는 homebrew사용해 설치 할 수 잇다.)&lt;br /&gt;
참고: https://pillow.readthedocs.io/en/stable/installation.html#external-libraries&lt;br /&gt;
&lt;br /&gt;
```bash&lt;br /&gt;
$ sudo apt-get install libjpeg-dev -y&lt;br /&gt;
$ sudo apt-get install zlib1g-dev -y&lt;br /&gt;
$ sudo apt-get install libfreetype6-dev -y&lt;br /&gt;
$ sudo apt-get install liblcms1-dev -y&lt;br /&gt;
$ sudo apt-get install libopenjp2-7 -y&lt;br /&gt;
$ sudo apt-get install libtiff5 -y&lt;br /&gt;
&lt;br /&gt;
$ sudo pip3 install pillow&lt;br /&gt;
```&lt;br /&gt;
## Image class&lt;br /&gt;
PIL 의 가장 기본이 되는 클래스. 비트맵 이미지 데이터를 갖는다.&lt;br /&gt;
* Image.open() 을 사용해 비트맵 이미지를 불러들여 Image 오브젝트 만들 수 있다.&lt;br /&gt;
&lt;br /&gt;
 ```python&lt;br /&gt;
form PIL import Image&lt;br /&gt;
im = Image.open(&amp;quot;hopper.ppm&amp;quot;)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
* 혹은 Image.new(mode, size, color=0) 를 통해 수동으로 이미지 오브젝트를 만들 수도 있다.&lt;br /&gt;
&lt;br /&gt;
|parameter|설명|&lt;br /&gt;
|-|-|&lt;br /&gt;
|mode| 1 (1-bit pixels, black and white, stored with one pixel per byte),&lt;br /&gt;
 ||L (8-bit pixels, black and white),&lt;br /&gt;
 ||P (8-bit pixels, mapped to any other mode using a color palette)&lt;br /&gt;
||RGB (3x8-bit pixels, true color)&lt;br /&gt;
||RGBA (4x8-bit pixels, true color with transparency mask)&lt;br /&gt;
||CMYK (4x8-bit pixels, color separation)&lt;br /&gt;
||YCbCr (3x8-bit pixels, color video format)&lt;br /&gt;
||Note that this refers to the JPEG, and not the ITU-R BT.2020, standard&lt;br /&gt;
||HSV (3x8-bit pixels, Hue, Saturation, Value color space)&lt;br /&gt;
||I (32-bit signed integer pixels)&lt;br /&gt;
||F (32-bit floating point pixels)|&lt;br /&gt;
|size| 2-tuple (width, height)|&lt;br /&gt;
|color|  배경색. RGB 모드인 경우 3-tuple|&lt;br /&gt;
&lt;br /&gt;
* array 로부터 이미지를 만들 수도 있는데, Numpy 사용하는 경우 유용하다.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
from PIL import Image&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
im = Image.open('hopper.jpg')&lt;br /&gt;
a = np.asarray(im)&lt;br /&gt;
&lt;br /&gt;
im = Image.fromarray(a)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
* image.show()를 사용해 이미지를 미리보기 할 수 있다.&lt;br /&gt;
os의 미리보기 유틸리티를 활용한다. macos에서 는 quicklook으로 이미지를 보여준다.&lt;br /&gt;
&lt;br /&gt;
 ```python&lt;br /&gt;
im.show()&lt;br /&gt;
```&lt;br /&gt;
* image.save(filename) 으로 파일로 저장할 수 있다.&lt;br /&gt;
파일명에 따라 파일포맷을 자동으로 결정한다.&lt;br /&gt;
&lt;br /&gt;
 ```python&lt;br /&gt;
import os, sys&lt;br /&gt;
from PIL import Image&lt;br /&gt;
&lt;br /&gt;
 f,e = os,path.splitext(filename) # 파일명과 확장자로 나눔&lt;br /&gt;
outfile = f + &amp;quot;.jpg&amp;quot;&lt;br /&gt;
if filename != outfile:&lt;br /&gt;
  try:&lt;br /&gt;
    Image.open(filename).save(outfile) # .jpg로 save하면 자동으로 jpg 포맷으로 변환&lt;br /&gt;
  except:&lt;br /&gt;
    print(&amp;quot;cannot convert&amp;quot;, filename)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
* crop(), transpose(), paste() 할 수 있다.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
box = (100,100,400,400)&lt;br /&gt;
region = im.crop(box)&lt;br /&gt;
&lt;br /&gt;
region = region.transpose(Image.ROTATE_180)&lt;br /&gt;
im.paste(region, box)&lt;br /&gt;
```&lt;br /&gt;
|Parameters| 기능|&lt;br /&gt;
|-|-|&lt;br /&gt;
|PIL.Image.FLIP_LEFT_RIGHT|좌우반전|&lt;br /&gt;
|PIL.Image.FLIP_TOP_BOTTOM|상하반전|&lt;br /&gt;
| PIL.Image.ROTATE_90|90도 회전|&lt;br /&gt;
| PIL.Image.ROTATE_180|180도 회전 |&lt;br /&gt;
|PIL.Image.ROTATE_270|-90도 회전 |&lt;br /&gt;
| PIL.Image.TRANSPOSE||&lt;br /&gt;
|PIL.Image.TRANSVERSE|-|&lt;br /&gt;
&lt;br /&gt;
## ImageDraw class&lt;br /&gt;
* Image  object 위에 간단한  2d drawing .&lt;br /&gt;
1. 빈 image를 만든다.&lt;br /&gt;
2. ImageDraw.Draw(image)로 drawing context를 득한다.&lt;br /&gt;
3. 여러가지 그림도 그리고 글씨도(!) 쓴다.&lt;br /&gt;
4. image.show()로 디스플레이한다.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
from PIL import Image, ImageDraw, ImageFont&lt;br /&gt;
# get an image&lt;br /&gt;
base = Image.open('Pillow/Tests/images/hopper.png').convert('RGBA')&lt;br /&gt;
&lt;br /&gt;
# make a blank image for the text, initialized to transparent text color&lt;br /&gt;
txt = Image.new('RGBA', base.size, (255,255,255,0))&lt;br /&gt;
&lt;br /&gt;
# get a font&lt;br /&gt;
fnt = ImageFont.truetype('Pillow/Tests/fonts/FreeMono.ttf', 40)&lt;br /&gt;
# get a drawing context&lt;br /&gt;
d = ImageDraw.Draw(txt)&lt;br /&gt;
&lt;br /&gt;
# draw text, half opacity&lt;br /&gt;
d.text((10,10), &amp;quot;Hello&amp;quot;, font=fnt, fill=(255,255,255,128))&lt;br /&gt;
# draw text, full opacity&lt;br /&gt;
d.text((10,60), &amp;quot;World&amp;quot;, font=fnt, fill=(255,255,255,255))&lt;br /&gt;
&lt;br /&gt;
out = Image.alpha_composite(base, txt)&lt;br /&gt;
&lt;br /&gt;
out.show()&lt;br /&gt;
```&lt;br /&gt;
* ImageDraw.Draw(im, mode=None)&lt;br /&gt;
  im - 그림그릴 이미지 오브젝트&lt;br /&gt;
  mode - 흑백모드 '1',  grayscale모드 'L' , RGB, RGBA ...&lt;br /&gt;
&lt;br /&gt;
* ImageDraw.ImageDraw.point(xy, fill=None)&lt;br /&gt;
  xy - 점들의 좌표. 2-tuples like [(x, y), (x, y), ...] or numeric values like [x, y, x, y, ...]&lt;br /&gt;
  fill - 점 색&lt;br /&gt;
&lt;br /&gt;
* ImageDraw.ImageDraw.rectangle(xy, fill=None, outline=None, width=0)&lt;br /&gt;
  xy - 두 대각 꼭지점. [(x0, y0), (x1, y1)] or [x0, y0, x1, y1]&lt;br /&gt;
  outline - 선 색&lt;br /&gt;
  fill - 채움 색&lt;br /&gt;
  width - 라인 두께&lt;br /&gt;
&lt;br /&gt;
* ImageDraw.ImageDraw.line(xy, fill=None, width=0, joint=None)&lt;br /&gt;
  xy - 선분을 이루는 점의 연속. [(x, y), (x, y), ...] or [x, y, x, y, ...]&lt;br /&gt;
  fill - 채움 색&lt;br /&gt;
  width - 라인 두께 (pixel)&lt;br /&gt;
  joint - None or &amp;quot;curve&amp;quot; 모서리 둥글리기&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
from PIL import Image, ImageDraw&lt;br /&gt;
&lt;br /&gt;
im = Image.open(&amp;quot;hopper.jpg&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
draw = ImageDraw.Draw(im)&lt;br /&gt;
draw.line((0, 0) + im.size, fill=128)&lt;br /&gt;
draw.line((0, im.size[1], im.size[0], 0), fill=128)&lt;br /&gt;
&lt;br /&gt;
# write to stdout&lt;br /&gt;
im.save(sys.stdout, &amp;quot;PNG&amp;quot;)&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
* ImageDraw.ImageDraw.arc(xy, start, end, fill=None, width=0)&lt;br /&gt;
  xy - 아크 외접 사각형. [(x0, y0), (x1, y1)] or [x0, y0, x1, y1]&lt;br /&gt;
  start - 출발각(degree), 3시방향이 0˚부터 시작해서 시계방향으로 증가.&lt;br /&gt;
  end - 도착각&lt;br /&gt;
  fill - 도형의 색&lt;br /&gt;
  width - 라인 두께 (pixel)&lt;br /&gt;
&lt;br /&gt;
* ImageDraw.ImageDraw.ellipse(xy, fill=None, outline=None, width=0)&lt;br /&gt;
  xy - 타원 외접 사각형. [(x0, y0), (x1, y1)] or [x0, y0, x1, y1]&lt;br /&gt;
  outline - 선 색&lt;br /&gt;
  fill - 채움 색&lt;br /&gt;
  width - 라인 두께(pixel)&lt;br /&gt;
&lt;br /&gt;
## ImageText class -  text 표시하기&lt;br /&gt;
폰트를 로딩한 후, ImageDraw.text() 를 사용해 텍스트를 표시할 수 있다.&lt;br /&gt;
&lt;br /&gt;
*  ImageFont.truetype(font=None, size=10, index=0, encoding='', layout_engine=None)&lt;br /&gt;
font - truetype font  파일.&lt;br /&gt;
size - 폰트 크기. piont 단위&lt;br /&gt;
index - light, bold  등 fontface  선택. 디폴트는 index=0&lt;br /&gt;
encoding - 'unic'(unicode. default), 'symb'(Microsoft Symbol), 'ADOB'(Adobe Standard), 'ADBE'(Adobe Export), 'armn'(Apple Roman)&lt;br /&gt;
&lt;br /&gt;
  ```python&lt;br /&gt;
  from PIL import Image, ImageDraw, ImageFont&lt;br /&gt;
&lt;br /&gt;
  im = Image.new('RGB', (128,64),0)&lt;br /&gt;
  draw = ImageDraw.Draw(im)&lt;br /&gt;
&lt;br /&gt;
  font = ImageFont.truetype(&amp;quot;Arial.ttf&amp;quot;,15)&lt;br /&gt;
&lt;br /&gt;
  draw.text((10,10), &amp;quot;hello world\n I'm a boy \n You are a girl&amp;quot;, font=font)&lt;br /&gt;
  im.show()&lt;br /&gt;
&lt;br /&gt;
  ```&lt;br /&gt;
&lt;br /&gt;
* ImageDraw.ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=0, align=&amp;quot;left&amp;quot;, direction=None, features=None, language=None)&lt;br /&gt;
텍스트를 표시한다.&lt;br /&gt;
xy - 텍스트 위치. 텍스트 상자의 좌상단위치임.&lt;br /&gt;
text - 표시할 텍스트.&lt;br /&gt;
fill - 텍스트 컬러&lt;br /&gt;
font - ImageFont instance&lt;br /&gt;
spacing - 줄 간격,(pixel)&lt;br /&gt;
align - &amp;quot;left&amp;quot;, &amp;quot;center&amp;quot; or &amp;quot;right&amp;quot;&lt;br /&gt;
direction - 'rtl'(right to left) or 'ltr' or 'ttb'(top to bottom). libraqm 라이브러리 필요함.&lt;br /&gt;
features - opentype의 다양한 기능&lt;br /&gt;
language - https://www.w3.org/International/articles/language-tags/&lt;br /&gt;
&lt;br /&gt;
* ImageDraw.ImageDraw.textsize(text, font=None, spacing=4, direction=None, features=None, language=None)&lt;br /&gt;
 표시될 text의 크기를 (가로, 세로)(pixel) 로 리턴한다.&lt;br /&gt;
text - 표시할 텍스트&lt;br /&gt;
font - ImageFont instance&lt;br /&gt;
spacing - 행 간격&lt;br /&gt;
&lt;br /&gt;
### 한글표시&lt;br /&gt;
* 한글폰트가 잘 표시되지 않는다는 리포트가 많이 있었으나 테스트 결과 별다른 조작 없이 잘 된다.&lt;br /&gt;
python2에서 유니코드 지원이 원활치 않아 있었던 문제로 생각된다. python3에서는 잘 된다.&lt;br /&gt;
* 폰트파일의 위치는 중요하다. 기본적으로 cwd(currunt working directory - 디폴트는 실행중인 스크립트와 같은 위치) 에서 폰트를 찾고, 못찾으면 os에 설치된 폰트 파일을 찾아서 사용한다.(똑똑한데?) 그럼에도 내가 한참 헤맨 이유는 atom editor의 script  package가 편집중인 스크립트의 위치가 아닌 프로젝트의 위치를  cwd 로 하도록 설정되어있었기 때문... script package 설정변경으로 간단히 해결됨.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
from PIL import Image, ImageDraw, ImageFont&lt;br /&gt;
&lt;br /&gt;
im = Image.new('RGB', (128,64),0)&lt;br /&gt;
draw = ImageDraw.Draw(im)&lt;br /&gt;
&lt;br /&gt;
font = ImageFont.truetype(&amp;quot;malgun.ttf&amp;quot;,15,0)&lt;br /&gt;
&lt;br /&gt;
draw.text(&lt;br /&gt;
(10,10),&lt;br /&gt;
'''세종대왕&lt;br /&gt;
만만세''',&lt;br /&gt;
font=font)&lt;br /&gt;
&lt;br /&gt;
im.show()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
![||600](https://cl.ly/5d93f4/Image%202019-07-30%20at%2010.13.53%20PM.png)&lt;br /&gt;
&lt;br /&gt;
## Image sequences (GIF animation)&lt;br /&gt;
* Image.open(&amp;quot;....gif&amp;quot;) 로 여러 프레임이 있는 이미지를 열었다면, image.seek() 과 image.tell()로 특정 프레임을 로드하고 볼 수 있다.  파일 끝에서는  EOFError 발생한다.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
from PIL import Image&lt;br /&gt;
im = Image.open(&amp;quot;source.gif&amp;quot;)&lt;br /&gt;
im.seek(1)&lt;br /&gt;
&lt;br /&gt;
try:&lt;br /&gt;
    while 1:&lt;br /&gt;
        im.seek(im.tell()+1)&lt;br /&gt;
        im.show()&lt;br /&gt;
except EOFError:&lt;br /&gt;
    pass&lt;br /&gt;
```&lt;br /&gt;
* ImageSequence.Iterator 를 사용하면 좀 더 편하게 프레임을 조작 할 수 있다.&lt;br /&gt;
&lt;br /&gt;
```python&lt;br /&gt;
from PIL import Image&lt;br /&gt;
from PIL import ImageSequence&lt;br /&gt;
&lt;br /&gt;
im = Image.open(&amp;quot;source.gif&amp;quot;)&lt;br /&gt;
for frame in ImageSequence.Iterator(im):&lt;br /&gt;
    frame.show()&lt;br /&gt;
```&lt;br /&gt;
&lt;br /&gt;
## 두개의 image 합치기&lt;br /&gt;
* Image.paste(im, box= None, mask= None)  &lt;br /&gt;
함수를 사용해서 원래의 이미지 위해 다른 이미지를 덧씌울 수 있다.&lt;br /&gt;
 * im : 덧씌울 Image  object&lt;br /&gt;
 * box: 2-tuple or 4-tuple 로, 덧씌울 이미지의 위치&lt;br /&gt;
 * mask: 원한다면  mask적용할 수도 있다('1'mode 이미지, 혹은  RGBA 모드 이미지가 사용되면  A channel). 255 값을 갖는 점은 이미지가 덧씌워지고, 0값을 갖는 점은 원래의 이미지가 그대로 사용된다.&lt;/div&gt;</summary>
		<author><name>Doguin</name></author>	</entry>

	</feed>