File size: 6,498 Bytes
d82cf6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
"""Collection of image encoders and decoders.

Modules must subclass ImageDecoder and ImageEncoder for each method of
decoding/encoding they support.

Modules must also implement the two functions::

    def get_decoders():
        # Return a list of ImageDecoder instances or []
        return []

    def get_encoders():
        # Return a list of ImageEncoder instances or []
        return []

"""

import os.path

from pyglet.util import CodecRegistry, Decoder, Encoder, DecodeException, EncodeException
from pyglet import compat_platform


class _ImageCodecRegistry(CodecRegistry):
    """Subclass of CodecRegistry that adds support for animation methods."""

    def __init__(self):
        self._decoder_animation_extensions = {}
        super().__init__()

    def add_decoders(self, module):
        """Override the default method to also add animation decoders.
        """
        super().add_decoders(module)
        for decoder in module.get_decoders():
            for extension in decoder.get_animation_file_extensions():
                if extension not in self._decoder_animation_extensions:
                    self._decoder_animation_extensions[extension] = []
                self._decoder_animation_extensions[extension].append(decoder)

    def get_animation_decoders(self, filename=None):
        """Get a list of animation decoders. If a `filename` is provided, only
           decoders supporting that extension will be returned. An empty list
           will be return if no encoders for that extension are available.
        """
        if filename:
            extension = os.path.splitext(filename)[1].lower()
            return self._decoder_animation_extensions.get(extension, [])
        return self._decoders

    def decode_animation(self, filename, file, **kwargs):
        first_exception = None

        for decoder in self.get_animation_decoders(filename):
            try:
                return decoder.decode_animation(filename, file, **kwargs)
            except DecodeException as e:
                if not first_exception:
                    first_exception = e
                if file:
                    file.seek(0)

        for decoder in self.get_animation_decoders():   # Try ALL codecs
            try:
                return decoder.decode_animation(filename, file, **kwargs)
            except DecodeException:
                if file:
                    file.seek(0)

        if not first_exception:
            raise DecodeException(f"No decoders available for this file type: {filename}")
        raise first_exception


registry = _ImageCodecRegistry()
add_decoders = registry.add_decoders
add_encoders = registry.add_encoders
get_animation_decoders = registry.get_animation_decoders
get_decoders = registry.get_decoders
get_encoders = registry.get_encoders


class ImageDecodeException(DecodeException):
    pass


class ImageEncodeException(EncodeException):
    pass


class ImageDecoder(Decoder):

    def get_animation_file_extensions(self):
        """Return a list of accepted file extensions, e.g. ['.gif', '.flc']
        Lower-case only.
        """
        return []

    def decode(self, filename, file):
        """Decode the given file object and return an instance of `Image`.
        Throws ImageDecodeException if there is an error.  filename
        can be a file type hint.
        """
        raise NotImplementedError()

    def decode_animation(self, filename, file):
        """Decode the given file object and return an instance of :py:class:`~pyglet.image.Animation`.
        Throws ImageDecodeException if there is an error.  filename
        can be a file type hint.
        """
        raise ImageDecodeException('This decoder cannot decode animations.')

    def __repr__(self):
        return "{0}{1}".format(self.__class__.__name__,
                               self.get_animation_file_extensions() +
                               self.get_file_extensions())


class ImageEncoder(Encoder):

    def encode(self, image, filename, file):
        """Encode the given image to the given file.  filename
        provides a hint to the file format desired.
        """
        raise NotImplementedError()

    def __repr__(self):
        return "{0}{1}".format(self.__class__.__name__, self.get_file_extensions())


def add_default_codecs():
    # Add the codecs we know about.  These should be listed in order of
    # preference.  This is called automatically by pyglet.image.

    # Compressed texture in DDS format
    try:
        from pyglet.image.codecs import dds
        registry.add_encoders(dds)
        registry.add_decoders(dds)
    except ImportError:
        pass

    # Mac OS X default: Quartz
    if compat_platform == 'darwin':
        try:
            from pyglet.image.codecs import quartz
            registry.add_encoders(quartz)
            registry.add_decoders(quartz)
        except ImportError:
            pass

    # Windows 7 default: Windows Imaging Component
    if compat_platform in ('win32', 'cygwin'):
        from pyglet.libs.win32.constants import WINDOWS_7_OR_GREATER
        if WINDOWS_7_OR_GREATER:  # Supports Vista and above.
            try:
                from pyglet.image.codecs import wic
                registry.add_encoders(wic)
                registry.add_decoders(wic)
            except ImportError:
                pass

    # Windows XP default: GDI+
    if compat_platform in ('win32', 'cygwin'):
        try:
            from pyglet.image.codecs import gdiplus
            registry.add_encoders(gdiplus)
            registry.add_decoders(gdiplus)
        except ImportError:
            pass

    # Linux default: GdkPixbuf 2.0
    if compat_platform.startswith('linux'):
        try:
            from pyglet.image.codecs import gdkpixbuf2
            registry.add_encoders(gdkpixbuf2)
            registry.add_decoders(gdkpixbuf2)
        except ImportError:
            pass

    # Fallback: PIL
    try:
        from pyglet.image.codecs import pil
        registry.add_encoders(pil)
        registry.add_decoders(pil)
    except ImportError:
        pass

    # Fallback: PNG loader (slow)
    try:
        from pyglet.image.codecs import png
        registry.add_encoders(png)
        registry.add_decoders(png)
    except ImportError:
        pass

    # Fallback: BMP loader (slow)
    try:
        from pyglet.image.codecs import bmp
        registry.add_encoders(bmp)
        registry.add_decoders(bmp)
    except ImportError:
        pass