win2xcur/win2xcur/parser/cur.py

43 lines
1.4 KiB
Python
Raw Normal View History

2020-09-26 18:14:55 -04:00
import struct
2020-09-27 00:53:23 -04:00
from typing import List, Tuple
2020-09-26 18:14:55 -04:00
from wand.image import Image
from win2xcur.cursor import CursorFrame, CursorImage
2020-09-27 00:53:23 -04:00
from win2xcur.parser.base import BaseParser
2020-09-26 18:14:55 -04:00
2020-09-27 00:53:23 -04:00
class CURParser(BaseParser):
2020-09-26 18:14:55 -04:00
MAGIC = b'\0\0\02\0'
ICO_TYPE_CUR = 2
2020-09-26 18:14:55 -04:00
ICON_DIR = struct.Struct('<HHH')
ICON_DIR_ENTRY = struct.Struct('<BBBBHHII')
@classmethod
2020-09-27 00:53:23 -04:00
def can_parse(cls, blob: bytes) -> bool:
2020-09-26 18:14:55 -04:00
return blob[:len(cls.MAGIC)] == cls.MAGIC
2020-09-27 00:53:23 -04:00
def __init__(self, blob: bytes) -> None:
super().__init__(blob)
2020-09-26 18:14:55 -04:00
self._image = Image(blob=blob, format='cur')
self._hotspots = self._parse_header()
self.frames = [CursorFrame([
CursorImage(image, hotspot, image.width) for image, hotspot in zip(self._image.sequence, self._hotspots)
2020-09-26 18:14:55 -04:00
])]
2020-09-27 00:53:23 -04:00
def _parse_header(self) -> List[Tuple[int, int]]:
2020-09-26 18:14:55 -04:00
reserved, ico_type, image_count = self.ICON_DIR.unpack(self.blob[:self.ICON_DIR.size])
assert reserved == 0
assert ico_type == self.ICO_TYPE_CUR
2020-09-26 18:14:55 -04:00
assert image_count == len(self._image.sequence)
offset = self.ICON_DIR.size
hotspots = []
for i in range(image_count):
width, height, palette, reserved, hx, hy, size, file_offset = self.ICON_DIR_ENTRY.unpack(
self.blob[offset:offset + self.ICON_DIR_ENTRY.size])
hotspots.append((hx, hy))
offset += self.ICON_DIR_ENTRY.size
2020-09-26 20:42:03 -04:00
return hotspots