1

I'm trying to take a screenshot and send it to another computer using python. I've tried to do it in many different ways. Unfortunately, I didn't find a way to do it. I would appreciate your help!

server:

from PIL import Image
from PIL import ImageGrab
import socket


server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 1111))
server_socket.listen(1)
print('Waiting For Connection...')
(client_socket, client_address) = server_socket.accept()
print('Connected to: ', client_address[0])


img = ImageGrab.grab(bbox=(10, 10, 500, 500))
photo_to_send= img.tobytes()
size = len(photo_to_send)
client_socket.send(bytes(str(size), 'utf-8'))

while size >= 0:
    msg = photo_to_send[:4096]
    client_socket.send(bytes(str(msg), 'utf-8'))
    photo_to_send= photo_to_send[4096:]

client:

import socket
from PIL import Image


my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_socket.connect(('127.0.0.1', 1111))
print("Connected to the server")

size = int(my_socket.recv(1024).decode('utf-8'))

the_photo = ""
the_photo = the_photo.encode('utf-8')

while size > 0:
    data = my_socket.recv(4096)
    size -= len(data)
    the_photo += data


img_to_save = Image.frombytes("RGB", (490,490), the_photo)
img_to_save .save("screenshot.png")

which_part
  • 792
  • 3
  • 11
  • 26
tomer
  • 21
  • 4
  • What kind of transport would you like to use? What are your problems with that? – Ulrich Eckhardt Nov 25 '19 at 19:13
  • my problem is that the client does not get all the bytes or that he gets to many bytes. As a reasult the client gets an extremly blurry picture. Thank you for your help! – tomer Nov 25 '19 at 19:41

4 Answers4

1

You can use pickle to serialize your Image objects. Pickle just converts an python object into bytes. pickle.dumps just encodes it to bytes and pickle.loads decodes it back.

Hope this helps!

Community
  • 1
  • 1
Wouterr
  • 516
  • 7
  • 16
1

The problem is that you are sending the textual value of the length immediately before the data itself. For example, if the image data started with AAABBB, you would be sending

1234AAABBB...

But if the image was bigger, you might send something like

56789AAABBB...

The client has no way of telling where the length ends and the data starts! To fix this, you need to send a fixed size length parameter. If you still want to a textual length, you could use zfill:

client_socket.send(str(size).zfill(16).encode())
...
size = int(my_socket.recv(16).decode())

(where 16 is chosen to be long enough to fit any possible image size)


This is not terribly efficient; real protocols usually use binary encoding:

client_socket.send(struct.pack('>I', size))
...
size, = struct.unpack('>I', my_socket.recv(4))

But this may be more complex than you need for your application.

nneonneo
  • 171,345
  • 36
  • 312
  • 383
  • Thank you very much for your help! Unfortunately this didn't solve my problem. My problem is that the bytes the server sends and the bytes the client gets are a little bit different. – tomer Nov 26 '19 at 16:00
0

The problem was that I encoded the photo twice. Thanks for your help! I really appreciate it!

Here is the solution:

server:

from PIL import ImageGrab
import socket


server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 1112))
server_socket.listen(1)
print('Waiting For Connection...')
(client_socket, client_address) = server_socket.accept()
print('Connected to: ', client_address[0])


img = ImageGrab.grab(bbox=(10, 10, 500, 500))
photo_to_send = img.tobytes()

size = len(photo_to_send)
print(size)
print(photo_to_send)
client_socket.send(bytes(str(size), 'utf-8'))

client_socket.send(photo_to_send)

client:

import socket
from PIL import Image

my_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
my_socket.connect(('127.0.0.1', 1112))
print("Connected to the server")

size = int(my_socket.recv(10).decode('utf-8'))
print(size)

the_photo = my_socket.recv(size)

print(the_photo)
img_to_save = Image.frombytes("RGB", (490, 490), the_photo)
img_to_save.save("screenshot.png")

tomer
  • 21
  • 4
0

struct and pickle makes everything easy for you.

server.py

imageBytes = pickle.dumps(image)
sock.sendall(struct.pack("L", len(imageBytes)) + imageBytes)

client.py

data = b""
payload_size = struct.calcsize("L")
while True:
    data += sock.recv(payload_size)
    packedImageSize = data[:payload_size]
    imageSize = struct.unpack("L", packedImageSize)[0]
    data = data[payload_size:]
    while len(data) < imageSize:
        data += sock.recv(65000)
    frameData = data[:imageSize]
    data = data[imageSize:]
    frame = pickle.loads(frameData)
Anirudh
  • 3
  • 3