MySQL - 이미지 INSERT/SELECT

2020. 8. 19. 15:48개발노트

Python, MySQL을 사용했습니다.

  • Python 라이브러리
import pymysql
from PIL import Image
import base64
from io import BytesIO
import time

테이블 생성

sql = """CREATE TABLE image_upload_test(
        id INT AUTO_INCREMENT PRIMARY KEY,
        image_data BLOB,
        date VARCHAR(50),
        time VARCHAR(50)
    )"""

인코딩한 문자열을 INSERT 할 예정이기 때문에 BLOB자료형으로 이미지가 들어갈 컬럼을 만들어줬습니다.


이미지 인코딩과 INSERT

with open("testimage.jpg", "rb") as image_file:
	binary_image = image_file.read()
# Base64로 인코딩
binary_image = base64.b64encode(binary_image)
# UTF-8로 디코딩 
binary_image = binary_image.decode('UTF-8')
sql = "INSERT INTO image_upload_test (image, date, time) VALUES(%s,%s,%s)"

curs.execute(sql, (binary_image, date, time))
_conn.commit()
_conn.close()

with as 문을 사용하면 이미지 파일을 읽고 인코딩 작업을 마친 후 자동으로 파일을 종료시킵니다.

base64 인코딩하면 아래와 같은 형태의 데이터로 변환됩니다.

b'SAWGAWGIVJPAS12WAQGbG8gV29ybGQh'

base64 인코딩 후 bytes타입을 가지기 때문에 문자열을 얻기 위해 'UTF-8'으로 디코딩합니다.

디코딩하지 않고 MySql의 BLOB타입 컬럼에 INSERT 했을 경우 SELECT 해서 데이터를 불러왔을 때

b"b'SAWGAWGIVJPAS12WAQGbG8gV29ybGQh'" 같은 형태를 가지는 문제가 있었습니다.

이미지 SELECT 후 디코딩

이미지가 제대로 디코딩되었는지 확인하기 위해서 PIL라이브러리의 image함수를 사용합니다.

sql = "SELECT * FROM ORDER BY id DESC limit 1"
    curs.execute(sql)
    images = curs.fetchone()
    
    if images:
        get_image = Image.open(BytesIO(image['image_data']))
        get_image = image['image']
        get_image.show()

이미지가 제대로 불러와졌는지 PIL show메서드로 테스트합니다.

 

웹 페이지에 이미지 출력

Flask와 jinja2로 테스트 했습니다.

sql = "SELECT * FROM ORDER BY id DESC limit 1"
    curs.execute(sql)
    images = curs.fetchone()
    
    if images:
        get_image = image['image']
        get_image = get_image.decode("UTF-8") 

SELECT 하면 get_image 변수는 아래와 같은 형태의 데이터를 가지기 때문에 

b'SAWGAWGIVJPAS12WAQGbG8gV29ybGQh'

'UTF-8'으로 한번 더 디코딩합니다.

SAWGAWGIVJPAS12WAQGbG8gV29ybGQh

페이지를 render 할 때 get_image변수를 담아 함께 render 합니다.

return render_template('home.html', get_image = get_image)

html템플릿에서 jinja문과 함께 아래와 같이 사용하면 이미지를 출력할 수 있습니다.

<img src="data:image/jpg;charset=utf-8;base64,{{get_image}}">

data:image/<이미지 형식>;charset=<문자셋>;<인코딩방식>,{{ 이미지 데이터 }}


알려진 문제점
인라인 이미지 (HTML에 포함된 base64로 인코딩 된 이미지)는 병목 현상으로 유선으로 33 % 더 많은 데이터를 전송하고 직렬로 수행합니다 (웹 브라우저는 인라인 이미지를 기다려야 페이지 다운로드를 완료할 수 있습니다)
"NoSQL 사용을 권장"