xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/email/mime/image.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1# Copyright (C) 2001-2006 Python Software Foundation
2# Author: Barry Warsaw
3# Contact: [email protected]
4
5"""Class representing image/* type MIME documents."""
6
7__all__ = ['MIMEImage']
8
9from email import encoders
10from email.mime.nonmultipart import MIMENonMultipart
11
12
13class MIMEImage(MIMENonMultipart):
14    """Class for generating image/* type MIME documents."""
15
16    def __init__(self, _imagedata, _subtype=None,
17                 _encoder=encoders.encode_base64, *, policy=None, **_params):
18        """Create an image/* type MIME document.
19
20        _imagedata contains the bytes for the raw image data.  If the data
21        type can be detected (jpeg, png, gif, tiff, rgb, pbm, pgm, ppm,
22        rast, xbm, bmp, webp, and exr attempted), then the subtype will be
23        automatically included in the Content-Type header. Otherwise, you can
24        specify the specific image subtype via the _subtype parameter.
25
26        _encoder is a function which will perform the actual encoding for
27        transport of the image data.  It takes one argument, which is this
28        Image instance.  It should use get_payload() and set_payload() to
29        change the payload to the encoded form.  It should also add any
30        Content-Transfer-Encoding or other headers to the message as
31        necessary.  The default encoding is Base64.
32
33        Any additional keyword arguments are passed to the base class
34        constructor, which turns them into parameters on the Content-Type
35        header.
36        """
37        _subtype = _what(_imagedata) if _subtype is None else _subtype
38        if _subtype is None:
39            raise TypeError('Could not guess image MIME subtype')
40        MIMENonMultipart.__init__(self, 'image', _subtype, policy=policy,
41                                  **_params)
42        self.set_payload(_imagedata)
43        _encoder(self)
44
45
46_rules = []
47
48
49# Originally from the imghdr module.
50def _what(data):
51    for rule in _rules:
52        if res := rule(data):
53            return res
54    else:
55        return None
56
57
58def rule(rulefunc):
59    _rules.append(rulefunc)
60    return rulefunc
61
62
63@rule
64def _jpeg(h):
65    """JPEG data with JFIF or Exif markers; and raw JPEG"""
66    if h[6:10] in (b'JFIF', b'Exif'):
67        return 'jpeg'
68    elif h[:4] == b'\xff\xd8\xff\xdb':
69        return 'jpeg'
70
71
72@rule
73def _png(h):
74    if h.startswith(b'\211PNG\r\n\032\n'):
75        return 'png'
76
77
78@rule
79def _gif(h):
80    """GIF ('87 and '89 variants)"""
81    if h[:6] in (b'GIF87a', b'GIF89a'):
82        return 'gif'
83
84
85@rule
86def _tiff(h):
87    """TIFF (can be in Motorola or Intel byte order)"""
88    if h[:2] in (b'MM', b'II'):
89        return 'tiff'
90
91
92@rule
93def _rgb(h):
94    """SGI image library"""
95    if h.startswith(b'\001\332'):
96        return 'rgb'
97
98
99@rule
100def _pbm(h):
101    """PBM (portable bitmap)"""
102    if len(h) >= 3 and \
103            h[0] == ord(b'P') and h[1] in b'14' and h[2] in b' \t\n\r':
104        return 'pbm'
105
106
107@rule
108def _pgm(h):
109    """PGM (portable graymap)"""
110    if len(h) >= 3 and \
111            h[0] == ord(b'P') and h[1] in b'25' and h[2] in b' \t\n\r':
112        return 'pgm'
113
114
115@rule
116def _ppm(h):
117    """PPM (portable pixmap)"""
118    if len(h) >= 3 and \
119            h[0] == ord(b'P') and h[1] in b'36' and h[2] in b' \t\n\r':
120        return 'ppm'
121
122
123@rule
124def _rast(h):
125    """Sun raster file"""
126    if h.startswith(b'\x59\xA6\x6A\x95'):
127        return 'rast'
128
129
130@rule
131def _xbm(h):
132    """X bitmap (X10 or X11)"""
133    if h.startswith(b'#define '):
134        return 'xbm'
135
136
137@rule
138def _bmp(h):
139    if h.startswith(b'BM'):
140        return 'bmp'
141
142
143@rule
144def _webp(h):
145    if h.startswith(b'RIFF') and h[8:12] == b'WEBP':
146        return 'webp'
147
148
149@rule
150def _exr(h):
151    if h.startswith(b'\x76\x2f\x31\x01'):
152        return 'exr'
153