import io from typing import Optional, Union from .. import json, optional_features from ..logging import log from .javascript import run_javascript try: from PIL import Image as PIL_Image optional_features.register('pillow') except ImportError: pass async def read() -> Optional[str]: """Read text from the clipboard. Note: This function only works in secure contexts (HTTPS or localhost). """ result = await run_javascript(''' if (navigator.clipboard) { return navigator.clipboard.readText() } else { console.error('Clipboard API is only available in secure contexts (HTTPS or localhost).') } ''') if result is None: log.warning('Clipboard API is only available in secure contexts (HTTPS or localhost).') return result def write(text: str) -> None: """Write text to the clipboard. Note: This function only works in secure contexts (HTTPS or localhost). :param text: text to write """ run_javascript(f''' if (navigator.clipboard) {{ navigator.clipboard.writeText({json.dumps(text)}) }} else {{ console.error('Clipboard API is only available in secure contexts (HTTPS or localhost).') }} ''') async def read_image() -> Union['PIL_Image.Image', None]: """Read PIL images from the clipboard. Note: This function only works in secure contexts (HTTPS or localhost) and requires Pillow to be installed. *Added in version 2.10.0* """ if not optional_features.has('pillow'): log.warning('Pillow is not installed, so we cannot read images from the clipboard.') return None content = await run_javascript(''' if (navigator.clipboard) { const items = await navigator.clipboard.read(); for (const item of items) { if (item.types.length > 0 && /^image/.test(item.types[0])) { return await item.getType(item.types[0]); } } } else { console.error('Clipboard API is only available in secure contexts (HTTPS or localhost).'); } ''', timeout=5) if not content: return None buffer = io.BytesIO(content) return PIL_Image.open(buffer)