From fbe77f942216ae397dbe85c80e6d2460ef32244f Mon Sep 17 00:00:00 2001 From: Quantum Date: Sat, 3 Oct 2020 00:35:41 -0400 Subject: [PATCH] Add .cur writer --- win2xcur/cursor.py | 6 ++++++ win2xcur/parser/cur.py | 3 ++- win2xcur/writer/windows.py | 26 ++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 win2xcur/writer/windows.py diff --git a/win2xcur/cursor.py b/win2xcur/cursor.py index 903e8f0..f864459 100644 --- a/win2xcur/cursor.py +++ b/win2xcur/cursor.py @@ -4,6 +4,9 @@ from wand.sequence import SingleImage class CursorImage: + image: SingleImage + hotspot: Tuple[int, int] + def __init__(self, image: SingleImage, hotspot: Tuple[int, int]) -> None: self.image = image self.hotspot = hotspot @@ -13,6 +16,9 @@ class CursorImage: class CursorFrame: + images: List[CursorImage] + delay: int + def __init__(self, images: List[CursorImage], delay: int = 0) -> None: self.images = images self.delay = delay diff --git a/win2xcur/parser/cur.py b/win2xcur/parser/cur.py index 0f7035e..5ae4ed9 100644 --- a/win2xcur/parser/cur.py +++ b/win2xcur/parser/cur.py @@ -9,6 +9,7 @@ from win2xcur.parser.base import BaseParser class CURParser(BaseParser): MAGIC = b'\0\0\02\0' + ICO_TYPE_CUR = 2 ICON_DIR = struct.Struct(' List[Tuple[int, int]]: reserved, ico_type, image_count = self.ICON_DIR.unpack(self.blob[:self.ICON_DIR.size]) assert reserved == 0 - assert ico_type == 2 + assert ico_type == self.ICO_TYPE_CUR assert image_count == len(self._image.sequence) offset = self.ICON_DIR.size diff --git a/win2xcur/writer/windows.py b/win2xcur/writer/windows.py new file mode 100644 index 0000000..25da088 --- /dev/null +++ b/win2xcur/writer/windows.py @@ -0,0 +1,26 @@ +from itertools import chain +from typing import List + +from win2xcur.cursor import CursorFrame +from win2xcur.parser import CURParser + + +def to_cur(frame: CursorFrame) -> bytes: + header = CURParser.ICON_DIR.pack(0, CURParser.ICO_TYPE_CUR, len(frame)) + directory: List[bytes] = [] + image_data: List[bytes] = [] + offset = CURParser.ICON_DIR.size + len(frame) * CURParser.ICON_DIR_ENTRY.size + + for image in frame: + clone = image.image.clone() + if clone.width > 256 or clone.height > 256: + raise ValueError(f'Image too big for CUR format: {clone.width}x{clone.height}') + blob = clone.make_blob('png') + image_data.append(blob) + x_offset, y_offset = image.hotspot + directory.append(CURParser.ICON_DIR_ENTRY.pack( + clone.height & 0xFF, clone.height & 0xFF, 0, 0, x_offset, y_offset, len(blob), offset + )) + offset += len(blob) + + return b''.join(chain([header], directory, image_data))