diff options
-rw-r--r-- | example/demo.rst | 12 | ||||
-rw-r--r-- | presentty/image.py | 44 | ||||
-rw-r--r-- | presentty/rst.py | 4 |
3 files changed, 57 insertions, 3 deletions
diff --git a/example/demo.rst b/example/demo.rst index c105e7d..e202bc2 100644 --- a/example/demo.rst +++ b/example/demo.rst | |||
@@ -154,3 +154,15 @@ Images | |||
154 | .. image:: gg.jpg | 154 | .. image:: gg.jpg |
155 | 155 | ||
156 | "Golden Gate Bridge" by Kevin Cole (CC-BY: https://flic.kr/p/7L2Rdu) | 156 | "Golden Gate Bridge" by Kevin Cole (CC-BY: https://flic.kr/p/7L2Rdu) |
157 | |||
158 | Scaling Images | ||
159 | ============== | ||
160 | .. container:: handout | ||
161 | |||
162 | You can also give the image directive a scale parameter to scale the image. | ||
163 | the image will be centered within the slide. | ||
164 | |||
165 | .. image:: gg.jpg | ||
166 | :scale: 75 | ||
167 | |||
168 | "Golden Gate Bridge" by Kevin Cole (CC-BY: https://flic.kr/p/7L2Rdu) | ||
diff --git a/presentty/image.py b/presentty/image.py index 9aabee8..d82face 100644 --- a/presentty/image.py +++ b/presentty/image.py | |||
@@ -32,13 +32,17 @@ def nearest_color(x): | |||
32 | return 'f' | 32 | return 'f' |
33 | 33 | ||
34 | class ANSIImage(urwid.Widget): | 34 | class ANSIImage(urwid.Widget): |
35 | def __init__(self, uri, hinter=None): | 35 | def __init__(self, uri, hinter=None, scale=1, background=None): |
36 | super(ANSIImage, self).__init__() | 36 | super(ANSIImage, self).__init__() |
37 | self.uri = uri | 37 | self.uri = uri |
38 | image = self._loadImage() | 38 | image = self._loadImage() |
39 | self.htmlparser = HTMLParser.HTMLParser() | 39 | self.htmlparser = HTMLParser.HTMLParser() |
40 | self.ratio = float(image.size[0])/float(image.size[1]) | 40 | self.ratio = float(image.size[0])/float(image.size[1]) |
41 | self.hinter = hinter | 41 | self.hinter = hinter |
42 | if scale > 1: | ||
43 | scale = 1 | ||
44 | self.scale = scale | ||
45 | self.background = background or 'black' | ||
42 | 46 | ||
43 | def _loadImage(self): | 47 | def _loadImage(self): |
44 | image = PIL.Image.open(self.uri) | 48 | image = PIL.Image.open(self.uri) |
@@ -81,7 +85,18 @@ class ANSIImage(urwid.Widget): | |||
81 | def render(self, size, focus=False): | 85 | def render(self, size, focus=False): |
82 | spanre = self.SPAN_RE | 86 | spanre = self.SPAN_RE |
83 | htmlparser = self.htmlparser | 87 | htmlparser = self.htmlparser |
84 | width, height = self.pack(size, focus) | 88 | |
89 | # Calculate image size and any bounding box | ||
90 | total_width, total_height = self.pack(size, focus) | ||
91 | width, height = self.pack([s * self.scale for s in size], focus) | ||
92 | width = int(width) | ||
93 | height = int(height) | ||
94 | top_pad = (total_height - height) // 2 | ||
95 | bottom_pad = total_height - height - top_pad | ||
96 | left_pad = (total_width - width) // 2 | ||
97 | right_pad = total_width - width - left_pad | ||
98 | padding_attr = urwid.AttrSpec(self.background, self.background) | ||
99 | |||
85 | jp2a = subprocess.Popen(['jp2a', '--colors', '--fill', | 100 | jp2a = subprocess.Popen(['jp2a', '--colors', '--fill', |
86 | '--width=%s' % width, | 101 | '--width=%s' % width, |
87 | '--height=%s' % height, | 102 | '--height=%s' % height, |
@@ -104,10 +119,23 @@ class ANSIImage(urwid.Widget): | |||
104 | current_fg = None | 119 | current_fg = None |
105 | current_bg = None | 120 | current_bg = None |
106 | current_props = None | 121 | current_props = None |
122 | |||
123 | # Top pad | ||
124 | for padding in range(0, top_pad): | ||
125 | line_list.append(' ' * total_width) | ||
126 | attr_list.append([(padding_attr, 1)] * total_width) | ||
127 | |||
107 | for line in data.split('<br/>'): | 128 | for line in data.split('<br/>'): |
108 | if not line: | 129 | if not line: |
109 | continue | 130 | continue |
131 | |||
132 | # Left pad | ||
133 | line_text += ' ' * left_pad | ||
134 | for fake_attr in range(0, left_pad): | ||
135 | line_attrs.append((padding_attr, 1)) | ||
136 | |||
110 | for span in line.split('</span>'): | 137 | for span in line.split('</span>'): |
138 | |||
111 | if not span: | 139 | if not span: |
112 | continue | 140 | continue |
113 | m = spanre.match(span) | 141 | m = spanre.match(span) |
@@ -141,10 +169,22 @@ class ANSIImage(urwid.Widget): | |||
141 | current_attr = [None, 0] | 169 | current_attr = [None, 0] |
142 | current_fg = None | 170 | current_fg = None |
143 | current_bg = None | 171 | current_bg = None |
172 | |||
173 | # Right pad | ||
174 | line_text += ' ' * right_pad | ||
175 | for fake_attr in range(0, right_pad): | ||
176 | line_attrs.append((padding_attr, 1)) | ||
177 | |||
144 | line_list.append(line_text) | 178 | line_list.append(line_text) |
145 | line_text = '' | 179 | line_text = '' |
146 | attr_list.append(line_attrs) | 180 | attr_list.append(line_attrs) |
147 | line_attrs = [] | 181 | line_attrs = [] |
182 | |||
183 | # Bottom pad | ||
184 | for padding in range(0, bottom_pad): | ||
185 | line_list.append(' ' * total_width) | ||
186 | attr_list.append([(padding_attr, 1)] * total_width) | ||
187 | |||
148 | canvas = urwid.TextCanvas(line_list, attr_list) | 188 | canvas = urwid.TextCanvas(line_list, attr_list) |
149 | return canvas | 189 | return canvas |
150 | 190 | ||
diff --git a/presentty/rst.py b/presentty/rst.py index 8368a6a..3c55f1e 100644 --- a/presentty/rst.py +++ b/presentty/rst.py | |||
@@ -306,8 +306,10 @@ class UrwidTranslator(docutils.nodes.GenericNodeVisitor): | |||
306 | if not PIL: | 306 | if not PIL: |
307 | return | 307 | return |
308 | uri = node['uri'] | 308 | uri = node['uri'] |
309 | scale = float(node.get('scale', 100))/100.0 | ||
309 | fn = os.path.join(self.basedir, uri) | 310 | fn = os.path.join(self.basedir, uri) |
310 | w = image.ANSIImage(fn, self.hinter) | 311 | w = image.ANSIImage(fn, self.hinter, scale=scale, |
312 | background=self.palette['_default'].background) | ||
311 | self._append(node, w, 'pack') | 313 | self._append(node, w, 'pack') |
312 | 314 | ||
313 | def visit_ansi(self, node): | 315 | def visit_ansi(self, node): |