Skip to content

Commit

Permalink
helper: Use pyscreenshot for cross-platform QR capture
Browse files Browse the repository at this point in the history
pyscreenshot supports capturing screenshots via numerous backends
and can automatically select the best one depending on platform.
This enables capturing of the QR code on wayland-based desktops
while maintaining support for Windows.
  • Loading branch information
evan-a-a committed Apr 19, 2023
1 parent 5f407bb commit 7360348
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 135 deletions.
47 changes: 3 additions & 44 deletions helper/helper/qr.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,66 +12,25 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import mss
import zxingcpp
import base64
import io
import os
import sys
import subprocess # nosec
import tempfile
from mss.exception import ScreenShotError
import pyscreenshot as ImageGrab
from PIL import Image
import numpy.core.multiarray # noqa


def _capture_screen():
try:
with mss.mss() as sct:
monitor = sct.monitors[0] # 0 is the special "all monitors" value.
sct_img = sct.grab(monitor) # mss format
return Image.frombytes("RGB", sct_img.size, sct_img.bgra, "raw", "BGRX")
except ScreenShotError:
# One common error is that mss doesn't work with Wayland
if sys.platform.startswith("linux"):
# Try calling screenshot tools, with original library path
env = dict(os.environ)
lp = env.get("LD_LIBRARY_PATH_ORIG")
if lp is not None:
env["LD_LIBRARY_PATH"] = lp
else:
env.pop("LD_LIBRARY_PATH", None)
fd, fname = tempfile.mkstemp(suffix=".png")

try:
# Try using gnome-screenshot
rc = subprocess.call( # nosec
["gnome-screenshot", "-f", fname], env=env
)
if rc == 0:
return Image.open(fname)
except FileNotFoundError:
# Try using spectacle (KDE)
try:
rc = subprocess.call( # nosec
["spectacle", "-b", "-n", "-o", fname], env=env
)
if rc == 0:
return Image.open(fname)
except FileNotFoundError:
pass # Fall through to ValueError
finally:
os.unlink(fname)
raise ValueError("Unable to capture screenshot")

import numpy.core.multiarray # noqa

def scan_qr(image_data=None):
if image_data:
msg = base64.b64decode(image_data)
buf = io.BytesIO(msg)
img = Image.open(buf)
else:
img = _capture_screen()
img = ImageGrab.grab()

result = zxingcpp.read_barcode(img)
if result and result.valid:
Expand Down
138 changes: 50 additions & 88 deletions helper/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions helper/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "authenticator-helper"
version = "0.1.0"
version = "0.2.0"
description = "Yubico Authenticator Helper"
authors = ["Dain Nilsson <[email protected]>"]
packages = [
Expand All @@ -11,9 +11,8 @@ packages = [
[tool.poetry.dependencies]
python = "^3.8"
yubikey-manager = "5.1.0"
mss = "^8.0.3"
zxing-cpp = "^2.0.0"
Pillow = "^9.5.0"
pyscreenshot = "^3.1"

[tool.poetry.dev-dependencies]
pyinstaller = {version = "^5.10.1", python = "<3.12"}
Expand Down

0 comments on commit 7360348

Please sign in to comment.