Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Make the various image functions a bit more robust via exceptions rather than returning None.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:fcec9a25cf05b3ae252860146ebf8db772453ded
User & Date: brandon 2018-11-08 23:09:20
Context
2018-11-08
23:16
Integrate support for GIF where appropriate (*not* in Blorb or TADS) check-in: 0e64a95c3b user: brandon tags: trunk
23:09
Make the various image functions a bit more robust via exceptions rather than returning None. check-in: fcec9a25cf user: brandon tags: trunk
22:48
Add function to determine GIF image dimensions check-in: 00fa7b52d2 user: brandon tags: trunk
Changes

Changes to treatyofbabel/babelerrors.py.

1
2
3
4
5
6
7
8
9
10
11
12
..
32
33
34
35
36
37
38












39
40
41
42
43
44
# -*- coding: utf-8 -*-
#
#       errors.py
#
#       Copyright © 2011, 2012, 2013, 2014 Brandon Invergo <brandon@invergo.net>
#
#       This file is part of Grotesque.
#
#       Grotesque is free software: you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation, either version 3 of the License, or
#       (at your option) any later version.
................................................................................
        return repr(self.value)


class BabelError(Exception):
    """Raised when an error occurs in determining information about a
    story file.













    """
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)




|







 







>
>
>
>
>
>
>
>
>
>
>
>






1
2
3
4
5
6
7
8
9
10
11
12
..
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
# -*- coding: utf-8 -*-
#
#       errors.py
#
#       Copyright © 2011, 2012, 2013, 2014, 2018 Brandon Invergo <brandon@invergo.net>
#
#       This file is part of Grotesque.
#
#       Grotesque is free software: you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation, either version 3 of the License, or
#       (at your option) any later version.
................................................................................
        return repr(self.value)


class BabelError(Exception):
    """Raised when an error occurs in determining information about a
    story file.

    """
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)


class BabelImgError(Exception):
    """Raised when an error occurs in determining information about an
    image file.

    """
    def __init__(self, value):
        self.value = value

    def __str__(self):
        return repr(self.value)

Changes to treatyofbabel/utils/_imgfuncs.py.

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
...
136
137
138
139
140
141
142
143
144
145
146
147
148
149

150
151



152

153
154



155






156
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with pyifbabel.  If not, see <http://www.gnu.org/licenses/>.


from _binaryfuncs import read_char, read_long, read_short



class CoverImage(object):
    def __init__(self, data=None, img_format=None, width=None,
                 height=None, description=None):
        self.data = data
        self.img_format = img_format
................................................................................
        self.width = width
        self.height = height
        self.description = description


def get_jpeg_dim(img):
    if read_char(img, 0) != 0xff or read_char(img, 1) != 0xD8:
        return (None, None)
    dp = 2
    ep = len(img)
    while True:
        if dp > ep:
            return (None, None)
        t1 = read_char(img, dp)
        dp += 1
        while t1 != 0xff:
            if dp > ep:
                return (None, None)
            t1 = read_char(img, dp)
            dp += 1
        t1 = read_char(img, dp)
        dp += 1
        while t1 == 0xff:
            if dp > ep:
                return (None, None)
            t1 = read_char(img, dp)
            dp += 1
        if t1 & 0xF0 == 0xC0 and not (t1 == 0xC4 or t1 == 0xC8 or t1 == 0xCC):
            dp += 3
            if dp > ep:
                return (None, None)
            h = read_char(img, dp) * 2**8
            dp += 1
            if dp > ep:
                return (None, None)
            h = h | read_char(img, dp)
            dp += 1
            if dp > ep:
                return (None, None)
            w = read_char(img, dp) * 2**8
            dp += 1
            if dp > ep:
                return (None, None)
            w = w | read_char(img, dp)
            return (w, h)
        elif t1 == 0xD8 or t1 == 0xD9:
            break
        else:
            if dp > ep:
                return (None, None)
            l = read_char(img, dp) * 2**8
            dp += 1
            if dp > ep:
                return (None, None)
            l = l | read_char(img, dp)
            l -= 2
            dp += l
            if dp > ep:
                return (None, None)
    return (None, None)


def get_png_dim(img):
    if (len(img) < 33 or
        not (ord(img[0]) == 137 and ord(img[1]) == 80 and
             ord(img[2]) == 78 and ord(img[3]) == 71 and
             ord(img[4]) == 13 and ord(img[5]) == 10 and
             ord(img[6]) == 26 and ord(img[7]) == 10) or
        not (img[12] == 'I' and img[13] == 'H' and
             img[14] == 'D' and img[15] == 'R')):
        return (None, None)
    w = read_long(img, 16)
    h = read_long(img, 20)
    return (w, h)


def get_gif_dim(img):
    # Look for the "GIF" magic number
    if ((read_char(img, 0, '<') != 0x47 or
         read_char(img, 1, '<') != 0x49 or
         read_char(img, 2, '<') != 0x46)):
        print("no GIF header")
        return (None, None)
    header_len = 6
    logscreen_len = 7
    packed_field = read_char(img, header_len+4, '<')
    print(packed_field)
    # The first bit of the packed field determines if there is a
    # Global Color Table
    global_color_tbl = packed_field & 0b10000000 == 0b10000000
    if global_color_tbl:
        # The last three bits determine the size of the GCT.
        # According to
        # http://giflib.sourceforge.net/whatsinagif/bits_and_bytes.html
................................................................................
    if gce_block:
        gce_len = 8
    else:
        gce_len = 0
    # Image Descriptior block
    img_descr_offset = gce_offset + gce_len
    if read_char(img, img_descr_offset, '<') != 0x2C:
        return (None, None)
    w = read_short(img, img_descr_offset+5, '<')
    h = read_short(img, img_descr_offset+7, '<')
    return (w, h)


def deduce_img_format(img):

    (w, h) = get_jpeg_dim(img)
    if w is not None and h is not None:



        return "jpeg"

    (w, h) = get_png_dim(img)
    if w is not None and h is not None:



        return "png"






    return None







>







 







|




|




|






|





|



|



|



|






|



|




|
|



|
|
|
|
|
|
|
<







|
|
|
<
<



<







 







|






>
|
<
>
>
>

>
|
<
>
>
>

>
>
>
>
>
>

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
...
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
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with pyifbabel.  If not, see <http://www.gnu.org/licenses/>.


from _binaryfuncs import read_char, read_long, read_short
from treatyofbabel.babelerrors import BabelImgError


class CoverImage(object):
    def __init__(self, data=None, img_format=None, width=None,
                 height=None, description=None):
        self.data = data
        self.img_format = img_format
................................................................................
        self.width = width
        self.height = height
        self.description = description


def get_jpeg_dim(img):
    if read_char(img, 0) != 0xff or read_char(img, 1) != 0xD8:
        raise BabelImgError("Data does not contain a JPEG image")
    dp = 2
    ep = len(img)
    while True:
        if dp > ep:
            raise BabelImgError("Invalid JPEG image")
        t1 = read_char(img, dp)
        dp += 1
        while t1 != 0xff:
            if dp > ep:
                raise BabelImgError("Invalid JPEG image")
            t1 = read_char(img, dp)
            dp += 1
        t1 = read_char(img, dp)
        dp += 1
        while t1 == 0xff:
            if dp > ep:
                raise BabelImgError("Invalid JPEG image")
            t1 = read_char(img, dp)
            dp += 1
        if t1 & 0xF0 == 0xC0 and not (t1 == 0xC4 or t1 == 0xC8 or t1 == 0xCC):
            dp += 3
            if dp > ep:
                raise BabelImgError("Invalid JPEG image")
            h = read_char(img, dp) * 2**8
            dp += 1
            if dp > ep:
                raise BabelImgError("Invalid JPEG image")
            h = h | read_char(img, dp)
            dp += 1
            if dp > ep:
                raise BabelImgError("Invalid JPEG image")
            w = read_char(img, dp) * 2**8
            dp += 1
            if dp > ep:
                raise BabelImgError("Invalid JPEG image")
            w = w | read_char(img, dp)
            return (w, h)
        elif t1 == 0xD8 or t1 == 0xD9:
            break
        else:
            if dp > ep:
                raise BabelImgError("Invalid JPEG image")
            l = read_char(img, dp) * 2**8
            dp += 1
            if dp > ep:
                raise BabelImgError("Invalid JPEG image")
            l = l | read_char(img, dp)
            l -= 2
            dp += l
            if dp > ep:
                raise BabelImgError("Invalid JPEG image")
    raise BabelImgError("Invalid JPEG image")


def get_png_dim(img):
    if (len(img) < 33):
        raise BabelImgError("Data does not contain a PNG image")
    header1 = [read_char(img, x) for x in range(8)]
    header2 = [read_char(img, 12+x) for x in range(4)]
    if ((header1 != [137, 80, 78, 71, 13, 10, 26, 10] or
         header2 != [ord(c) for c in ['I', 'H', 'D', 'R']])):
        raise BabelImgError("Data does not contain a PNG image")

    w = read_long(img, 16)
    h = read_long(img, 20)
    return (w, h)


def get_gif_dim(img):
    # Look for the "GIF" magic number
    header = [read_char(img, x) for x in range(3)]
    if header != [ord(c) for c in ['G', 'I', 'F']]:
        raise BabelImgError("Data does not contain a GIF image")


    header_len = 6
    logscreen_len = 7
    packed_field = read_char(img, header_len+4, '<')

    # The first bit of the packed field determines if there is a
    # Global Color Table
    global_color_tbl = packed_field & 0b10000000 == 0b10000000
    if global_color_tbl:
        # The last three bits determine the size of the GCT.
        # According to
        # http://giflib.sourceforge.net/whatsinagif/bits_and_bytes.html
................................................................................
    if gce_block:
        gce_len = 8
    else:
        gce_len = 0
    # Image Descriptior block
    img_descr_offset = gce_offset + gce_len
    if read_char(img, img_descr_offset, '<') != 0x2C:
        raise BabelImgError("Invalid GIF image")
    w = read_short(img, img_descr_offset+5, '<')
    h = read_short(img, img_descr_offset+7, '<')
    return (w, h)


def deduce_img_format(img):
    try:
        get_jpeg_dim(img)

    except BabelImgError:
        pass
    else:
        return "jpeg"
    try:
        get_png_dim(img)

    except BabelImgError:
        pass
    else:
        return "png"
    try:
        get_gif_dim(img)
    except BabelImgError:
        pass
    else:
        return "gif"
    return None