user6945506 user6945506 - 1 month ago 20
Python Question

Python screen capture error

I am trying to modify the code given here for screen streaming. In the above tutorial it was for reading images from disk whereas I am trying to take screenshots. I receive this error.


assert isinstance(data, bytes), 'applications must write bytes'
AssertionError: applications must write bytes


What changes should I make for it to work?

This is what I've done so far -

<br>index.html<br>
<html>
<head>
<title>Video Streaming Demonstration</title>
</head>
<body>
<h1>Video Streaming Demonstration</h1>
<img src="{{ url_for('video_feed') }}">
</body>
</html>



app.py


#!/usr/bin/env python
from flask import Flask, render_template, Response
import time
# emulated camera
from camera import Camera

# Raspberry Pi camera module (requires picamera package)
# from camera_pi import Camera

app = Flask(__name__)


@app.route('/')
def index():
"""Video streaming home page."""
return render_template('index.html')


def gen(camera):
"""Video streaming generator function."""
while True:
time.sleep(0.1)
frame = camera.get_frame()
yield (frame)


@app.route('/video_feed')
def video_feed():
"""Video streaming route. Put this in the src attribute of an img tag."""
return Response(gen(Camera()),
mimetype='multipart/x-mixed-replace; boundary=frame')


if __name__ == '__main__':
app.run(host='0.0.0.0', debug=True, threaded=True)



camera.py


from time import time

from PIL import Image
from PIL import ImageGrab
import sys

if sys.platform == "win32":
grabber = Image.core.grabscreen

class Camera(object):

def __init__(self):
#self.frames = [open('shot0' + str(f) + '.png', 'rb').read() for f in range(1,61)]
self.frames = [ImageGrab.grab() for f in range(1,61)]

def get_frame(self):
return self.frames[int(time()) % 3]


Full error :
Link

xli xli
Answer

The response payload must be a sequence of bytes. In the example, the images returned are JPEGs as bytes objects.

However, the image returned by ImageGrab.grab() is some PIL image class instead of bytes. So, try saving the image as JPEG as bytes:

import io

Take screenshot only for every iteration in gen:

class Camera(object):
    def get_frame(self):
        frame = ImageGrab.grab()
        img_bytes = io.BytesIO()
        frame.save(img_bytes, format='JPEG')
        return img_bytes.getvalue()

gen function:

def gen(camera):
    while True:
        time.sleep(0.1)
        frame = camera.get_frame()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')