From f20a0003ed33d1ffb1b694ee744f67d6eda567df Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 23 Jul 2024 15:35:07 -0500 Subject: [PATCH] fix: broken methods video.snap and canvas.download (#2126) * fix: broken methods video.snap and canvas.download * Allow canvas.draw to use actual image width/height. --- .../src/stdlib/pyscript/web/elements.py | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/pyscript.core/src/stdlib/pyscript/web/elements.py b/pyscript.core/src/stdlib/pyscript/web/elements.py index cdf2fc50..e6528531 100644 --- a/pyscript.core/src/stdlib/pyscript/web/elements.py +++ b/pyscript.core/src/stdlib/pyscript/web/elements.py @@ -614,12 +614,15 @@ class canvas(ContainerElement): Output: None """ - link = self.create("a") - link._dom_element.download = filename - link._dom_element.href = self._dom_element.toDataURL() - link._dom_element.click() + download_link = a(download=filename, href=self._dom_element.toDataURL()) - def draw(self, what, width, height): + # Adding the link to the DOM is recommended for browser compatibility to make + # sure that the click works. + self.append(download_link) + + download_link._dom_element.click() + + def draw(self, what, width=None, height=None): """Draw `what` on the current element Inputs: @@ -634,7 +637,12 @@ class canvas(ContainerElement): what = what._dom_element # https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage - self._dom_element.getContext("2d").drawImage(what, 0, 0, width, height) + ctx = self._dom_element.getContext("2d") + if width or height: + ctx.drawImage(what, 0, 0, width, height) + + else: + ctx.drawImage(what, 0, 0) class caption(ContainerElement): @@ -1404,6 +1412,8 @@ class video(ContainerElement): preload = DOMProperty("preload") src = DOMProperty("src") width = DOMProperty("width") + videoHeight = DOMProperty("videoHeight") + videoWidth = DOMProperty("videoWidth") def snap( self, @@ -1412,33 +1422,29 @@ class video(ContainerElement): height: int | None = None, ): """ - Captures a snapshot of a video. + Capture a snapshot (i.e. a single frame) of a video to a canvas. Inputs: - * to: element where to save the snapshot of the video frame to - * width: width of the image - * height: height of the image + * to: the canvas to save the video frame to (if None, one is created). + * width: width of the snapshot (defaults to the video width). + * height: height of the snapshot (defaults to the video height). Output: (Element) canvas element where the video frame snapshot was drawn into """ + width = width if width is not None else self.videoWidth + height = height if height is not None else self.videoHeight + if to is None: - to_canvas = self.create("canvas") - if width is None: - width = self._dom_element.width - if height is None: - height = self._dom_element.height - to_canvas._dom_element.width = width - to_canvas._dom_element.height = height + to = canvas(width=width, height=height) elif isinstance(to, Element): - if to._dom_element.tagName != "CANVAS": - raise TypeError("Element to snap to must a canvas.") - to_canvas = to + if to.tag != "canvas": + raise TypeError("Element to snap to must be a canvas.") elif getattr(to, "tagName", "") == "CANVAS": - to_canvas = canvas(to) + to = canvas(dom_element=to) # If 'to' is a string, then assume it is a query selector. elif isinstance(to, str): @@ -1447,13 +1453,13 @@ class video(ContainerElement): raise TypeError("No element with selector {to} to snap to.") if nodelist[0].tagName != "CANVAS": - raise TypeError("Element to snap to must a be canvas.") + raise TypeError("Element to snap to must be a canvas.") - to_canvas = canvas(nodelist[0]) + to = canvas(dom_element=nodelist[0]) - to_canvas.draw(self, width, height) + to.draw(self, width, height) - return canvas + return to class wbr(Element):