使用 BottlePy 在 Python 代码中的每个循环迭代中自动重新加载 HTML 图像

Auto reload HTML image on each loop iteration in Python code using BottlePy

我正在使用 Raspberry Pi、超声波传感器和伺服电机构建一个 DIY 声纳,到目前为止,我已经设法让它在每次 180 度扫描时生成 picture/map,但是问题是我还想在本地网页上显示这张图片,并且我想让它在每次扫描时自动更新,而无需用户手动刷新页面(每次扫描的持续时间与前一次不同 - 那是一个问题)。我想到了使用 BottlePy 微型 Web 框架以及一些 jSON。这是代码:

Python:

import pigpio
import time
import RPi.GPIO as GPIO
import numpy as np
import cv2
import math
from PIL import Image as im

import bottle
from bottle import route, run, template, BaseTemplate, static_file

app = bottle.default_app()
BaseTemplate.defaults['get_url'] = app.get_url

@route('/')
def index():
    return template('index.html')


@route('/<filename:path>', name='static')
def serve_static(filename):
    return static_file(filename, root='static')

@route('/refresh')

def refresh():

...
    #matrix generation for map - newmapp
...

    data=im.fromarray(newmapp)
    data.save('/home/pi/Desktop/servo_web/static/map.png')
    
run(host='localhost', port=8080)

HTML/JS:

<!DOCTYPE html>
<html>
<head>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
        <title>HARTA</title>
</head>
<body>
    <img src="{{ get_url('static', filename='map.png') }}" />
    <script>
      $(document).ready(function(){
        setInterval(refreshFunction,300);
      });

      function refreshFunction(){
        $.getJSON('/refresh', function(){
        });
      }
    </script>
</body>
</html>

提前致谢!

从这个问题:Refresh image with a new one at the same url,你可以尝试添加一个 catchbreaker,本质上是强制浏览器重新加载图像而不是从缓存中获取它。

document.querySelector("img").src = `{{ get_url('static', filename='map.png?${new Date().getTime()}') }}`;

如果您将随机参数添加到 url - map.png?random_value(即带有时间和秒数的当前日期)- 然后浏览器会自动重新加载图像。

所以在JavaScript你可以做到

<img id="map" src="{{ get_url('static', filename='map.png') }}" />

$.get('/refresh', function(){            
     d = new Date();
     $("#map").attr("src", "{{ get_url('static', filename='map.png') }}?"+d.getTime());            
});  

最少的工作代码

import os
import time

import bottle
from bottle import route, run, template, BaseTemplate, static_file

import numpy as np
from PIL import Image

app = bottle.default_app()
BaseTemplate.defaults['get_url'] = app.get_url

@route('/')
def index():
    return template('''<!DOCTYPE html>
<html>
<head>
    <title>HARTA</title>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>
    <img id="map" src="{{ get_url('static', filename='map.png') }}" />
    <script>
      $(document).ready(function(){
        setInterval(refreshFunction, 1000);
      });

      function refreshFunction(){
        $.get('/refresh', function(){            
            d = new Date();
            $("#map").attr("src", "{{ get_url('static', filename='map.png') }}?"+d.getTime());            
            console.log($("#map").attr("src"));
        });
      }
    </script>
</body>
</html>''')

@route('/<filename:path>', name='static')
def serve_static(filename):
    return static_file(filename, root='static')

@route('/refresh')
def refresh():
    os.makedirs('static', exist_ok=True)
    newmapp = np.random.rand(100,100,3) * 255    
    data = Image.fromarray(newmapp.astype('uint8')).convert('RGBA')
    data.save('static/map.png')
    return "OK" 
    
run(host='localhost', port=8080)

“我想在每次扫描时都做到 auto-update,而无需用户手动刷新页面”

与其每次都刷新页面,更复杂但更有效的选择是使用 AJAX GET 请求在浏览器中动态呈现图像。使用 setInterval() 从客户端重复发送请求。您选择的时间间隔将决定您将向服务器发送多少请求,间隔越小 = 请求越多。这种模式称为轮询。

因为浏览器会尝试缓存图像而不是更新图像,所以在客户端添加缓存破坏 url 片段,并在服务器响应中添加 cache-control headers: https://whosebug.com/a/9943419/14082992

Bottle 可以使用图像的通配符路径忽略添加的 URL 片段:https://bottlepy.org/docs/dev/routing.html#wildcard-filters

使用 Bottle 的 response.set_header 设置缓存控制 headers: https://bottlepy.org/docs/dev/tutorial.html#the-response-object