From a46bfd791630f5b681191a97d67136723cefac8f Mon Sep 17 00:00:00 2001 From: Quantum Date: Sat, 26 Sep 2020 19:37:48 -0400 Subject: [PATCH] Add support for shadows --- win2xcur/main.py | 18 ++++++++++++++++++ win2xcur/shadow.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 win2xcur/shadow.py diff --git a/win2xcur/main.py b/win2xcur/main.py index 23174e1..7c3cd69 100644 --- a/win2xcur/main.py +++ b/win2xcur/main.py @@ -3,6 +3,7 @@ import os import sys import traceback +from win2xcur import shadow from win2xcur.parser import open_blob from win2xcur.writer.x11 import check_xcursorgen, to_x11 @@ -13,6 +14,20 @@ def main() -> None: help='Windows cursor files to convert (*.cur, *.ani)') parser.add_argument('-o', '--output', '--output-dir', default=os.curdir, help='Directory to store converted cursor files.') + parser.add_argument('-s', '--shadow', action='store_true', + help="Whether to emulate Windows's shadow effect") + parser.add_argument('-O', '--shadow-opacity', type=int, default=50, + help='Opacity of the shadow (0 to 255)') + parser.add_argument('-r', '--shadow-radius', type=float, default=0.1, + help='Radius of shadow blur effect (as fraction of width)') + parser.add_argument('-S', '--shadow-sigma', type=float, default=0.1, + help='Sigma of shadow blur effect (as fraction of width)') + parser.add_argument('-x', '--shadow-x', type=float, default=0.05, + help='x-offset of shadow (as fraction of width)') + parser.add_argument('-y', '--shadow-y', type=float, default=0.05, + help='x-offset of shadow (as fraction of height)') + parser.add_argument('-c', '--shadow-color', default='#000000', + help='color of the shadow') args = parser.parse_args() @@ -27,6 +42,9 @@ def main() -> None: print('Error occurred while processing %s:' % (name,), file=sys.stderr) traceback.print_exc() else: + if args.shadow: + shadow.apply_to_frames(cursor.frames, color=args.shadow_color, radius=args.shadow_radius, + sigma=args.shadow_sigma, xoffset=args.shadow_x, yoffset=args.shadow_y) result = to_x11(cursor.frames) output = os.path.join(args.output, os.path.splitext(os.path.basename(name))[0]) with open(output, 'wb') as f: diff --git a/win2xcur/shadow.py b/win2xcur/shadow.py new file mode 100644 index 0000000..6d32340 --- /dev/null +++ b/win2xcur/shadow.py @@ -0,0 +1,28 @@ +from typing import List + +from wand.image import BaseImage, Image + +from win2xcur.cursor import CursorFrame + + +def apply_to_image(image: BaseImage, *, color: str, radius: float, sigma: float, xoffset: float, + yoffset: float) -> Image: + opacity = Image(width=image.width, height=image.height, pseudo='xc:white') + opacity.composite(image.channel_images['opacity'], left=round(xoffset * image.width), + top=round(yoffset * image.height)) + opacity.gaussian_blur(radius * image.width, sigma * image.width) + opacity.negate() + opacity.modulate(50) + + shadow = Image(width=image.width, height=image.height, pseudo='xc:' + color) + shadow.composite(opacity, operator='copy_opacity') + + result = image.clone() + result.composite(shadow, operator='difference') + return result + + +def apply_to_frames(frames: List[CursorFrame], **kwargs): + for frame in frames: + for cursor in frame: + cursor.image = apply_to_image(cursor.image, **kwargs)