Is there any way to save a dirty canvas?

后端 未结 3 982
夕颜
夕颜 2021-01-21 06:57

I am making screenshots of videos with HTML5 canvas, the video is hosted elsewhere, everything works except toDataURL() because the canvas is dirty. So, I am wondering, is ther

相关标签:
3条回答
  • 2021-01-21 07:05

    The short answer is "No."

    The longer answer might be yes.

    Maybe your server can download the video and host it, then play it from your same domain?

    If you control the server that is hosting the video you could enable cors.

    (Or you could combine the two and have the video uploaded to a cors-enabled site that is not your own.)

    Otherwise, you're out of luck.

    0 讨论(0)
  • 2021-01-21 07:09

    What about, I haven't tried it yet, if you redraw the original canvas on another canvas which you then save to an image. (and use css or position the canvases over each other to "hide" the second canvas).

    Will the second canvas be dirty?

    (thinking about a technique like thisone)

    0 讨论(0)
  • 2021-01-21 07:20

    I tried the copying of the canvas but this just returned the same dirty canvas error.

    In the end to get this work I implemented a small service that would extract remote sources (videos) and make them look as though they were local i.e. by reading the source server side and writing out to my HTML/JS page. Once this was done it all worked fine.

    I used Python / Flask to do this, here is the snippet. Not perfect in regards to handle partial content requests but should get someone going.

    To use it I access my videos using: /remote?url=

    from datetime import timedelta
    from flask import make_response, request, current_app, Flask, url_for, render_template, Response
    from functools import update_wrapper
    import requests
    import logging
    import json
    from werkzeug.datastructures import Headers
    import httplib
    import os
    import subprocess
    import base64
    httplib.HTTPConnection.debuglevel = 1
    
    app = Flask(__name__)
    
    
    logging.basicConfig() 
    logging.getLogger().setLevel(logging.DEBUG)
    requests_log = logging.getLogger("requests.packages.urllib3")
    requests_log.setLevel(logging.DEBUG)
    requests_log.propagate = True
    
    def crossdomain(origin=None, methods=None, headers=None,
                    max_age=21600, attach_to_all=True,
                    automatic_options=True):
        if methods is not None:
            methods = ', '.join(sorted(x.upper() for x in methods))
        if headers is not None and not isinstance(headers, basestring):
            headers = ', '.join(x.upper() for x in headers)
        if not isinstance(origin, basestring):
            origin = ', '.join(origin)
        if isinstance(max_age, timedelta):
            max_age = max_age.total_seconds()
    
        def get_methods():
            if methods is not None:
                return methods
    
            options_resp = current_app.make_default_options_response()
            return options_resp.headers['allow']
    
        def decorator(f):
            def wrapped_function(*args, **kwargs):
                if automatic_options and request.method == 'OPTIONS':
                    resp = current_app.make_default_options_response()
                else:
                    resp = make_response(f(*args, **kwargs))
                if not attach_to_all and request.method != 'OPTIONS':
                    return resp
    
                h = resp.headers
    
                h['Access-Control-Allow-Origin'] = origin
                h['Access-Control-Allow-Methods'] = get_methods()
                h['Access-Control-Max-Age'] = str(max_age)
                if headers is not None:
                    h['Access-Control-Allow-Headers'] = headers
                return resp
    
            f.provide_automatic_options = False
            return update_wrapper(wrapped_function, f)
        return decorator
    
    def stream_remote(url, headers=None):
        logging.debug(headers) 
        range = headers["Range"]
        logging.debug(range)
        r = requests.get(url, stream=True, headers={"range":range})
        logging.debug(r.headers)
        for block in r.iter_content(1024):
            if not block:
                break
            yield block
    
    
    @app.route('/remote/')
    def get_remote():
        # Gets a remote file to make it look like it is local for CORS purposes
        url = request.args.get("url", None)
        resp_headers = Headers()
        resp_headers.add('Accept-Ranges','bytes')
    
        if url is None:
            return "Error. No URL provided"
        else:
            headers = request.headers
            logging.debug(headers)
            return Response(stream_remote(url, headers),mimetype='video/mp4',headers=resp_headers)
    
    if __name__ == '__main__':
        app.debug = True
        app.run(host="127.0.0.1", port=9001)
    
    0 讨论(0)
提交回复
热议问题