[Python3] Bluetooth로 이미지 전송받았을 때, Bytes를 Image파일로 만들기(저장하기)

2021. 11. 19. 03:09Dev/Python

파이썬3에서 확인 by Raspberry pi

 

Bluetooth로 이미지 전송받기

Bluetooth를 통해 이미지를 전송받았을 때는 이미지가 Bytes타입으로 넘어온다.

UART를 통해 전송되는데, UART는 한번에 전송 가능한 데이터의 비트 수가 한정되어 있기 때문에 서버쪽에서 Bluetooth recv로 전송받을수 있는 바이트 수를 아무리 늘려도 한번에 받지 못하고 계속해서 데이터가 넘어오게 된다.

따라서 전송 받을 이미지의 크기를 받고, 해당 크기를 바탕으로 byte를 계속해서 받아온 후에 이미지로 만들어야 한다.

그런데 recv를 호출하게 되면 데이터를 받을 때까지 대기하게 되므로 아래와 같은 코드는 작동하지 않는다.

while True :
	//한번에 10000바이트의 데이터를 받지만, UART 전송은 나눠서 오기 때문에 의미가 없다. 실제로 크기를 찍어보면 10바이트 이내로 계속해서 데이터가 넘어오는 것을 확인 가능함
    data = socket.recv(10000)
    
    //이 코드는 작동하지 않는다. 왜냐하면 recv를 통해 데이터가 들어올 때 까지 계속해서 대기하고 있기 때문
    if not data :
    	break;

 

method를 이용해 이미지 버퍼 만들기

따라서 method를 아래와 같이 만들어서 계속해서 데이터를 받아오면 된다.

//parameter : socket = bluetooth socket, length = 받아올 이미지의 바이트의 크기
def getBytesStream(socket, length):
	//버퍼를 선언해서 데이터가 올 때까지 계속해서 버퍼에 저장
    buf = b''
    try:
        step = length
        while True:
            data = socket.recv(step)
            buf += data
            //이미지의 크기만큼 받아오고, 전부 이미지의 크기만큼 받아오면 break
            if len(buf) == length:
                break
            elif len(buf) < length:
                step = length - len(buf)

    except Exception as e:
        print(e)

    return buf[:length]

 

Bluetooth로 이미지의 크기 받아오기

그렇다면 이미지마다 사이즈가 다른데 이미지의 크기는 어떻게 받아올 수 있을까?

이미지를 받아오기 전, 먼저 사이즈를 받아오면 된다. 그 이후 위의 코드에서 받아온 buf를  stream으로 선언하여 이미지로 저장하면 됨

while True:
	//이미지의 크기를 받아온다
    length = int.from_bytes(socket.recv(3), 'big')
    //이미지의 크기를 정상적으로 받아오면 이미지 byte 스트림을 만든다.
    if length:
        data = getBytesStream(socket, length)
        stream = io.BytesIO(data)
        //파일명 선언
        fileName = '-'.join(now().split(' ')) + '.jpeg'
        print(fileName)
        //스트림을 PIL.Image로 open하고 save하면 해당 경로에 저장됨
        img = Image.open(stream)
        img.save(fileName)