3 pygments.formatters.img |
3 pygments.formatters.img |
4 ~~~~~~~~~~~~~~~~~~~~~~~ |
4 ~~~~~~~~~~~~~~~~~~~~~~~ |
5 |
5 |
6 Formatter for Pixmap output. |
6 Formatter for Pixmap output. |
7 |
7 |
8 :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS. |
8 :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. |
9 :license: BSD, see LICENSE for details. |
9 :license: BSD, see LICENSE for details. |
10 """ |
10 """ |
11 |
11 |
12 import os |
12 import os |
13 import sys |
13 import sys |
14 |
14 |
15 from pygments.formatter import Formatter |
15 from pygments.formatter import Formatter |
16 from pygments.util import get_bool_opt, get_int_opt, get_list_opt, \ |
16 from pygments.util import get_bool_opt, get_int_opt, get_list_opt, \ |
17 get_choice_opt, xrange |
17 get_choice_opt |
18 |
18 |
19 import subprocess |
19 import subprocess |
20 |
20 |
21 # Import this carefully |
21 # Import this carefully |
22 try: |
22 try: |
44 'BOLD': ['Bold'], |
44 'BOLD': ['Bold'], |
45 'BOLDITALIC': ['Bold Oblique', 'Bold Italic'], |
45 'BOLDITALIC': ['Bold Oblique', 'Bold Italic'], |
46 } |
46 } |
47 |
47 |
48 # A sane default for modern systems |
48 # A sane default for modern systems |
49 DEFAULT_FONT_NAME_NIX = 'Bitstream Vera Sans Mono' |
49 DEFAULT_FONT_NAME_NIX = 'DejaVu Sans Mono' |
50 DEFAULT_FONT_NAME_WIN = 'Courier New' |
50 DEFAULT_FONT_NAME_WIN = 'Courier New' |
51 DEFAULT_FONT_NAME_MAC = 'Courier New' |
51 DEFAULT_FONT_NAME_MAC = 'Menlo' |
52 |
52 |
53 |
53 |
54 class PilNotAvailable(ImportError): |
54 class PilNotAvailable(ImportError): |
55 """When Python imaging library is not available""" |
55 """When Python imaging library is not available""" |
56 |
56 |
57 |
57 |
58 class FontNotFound(Exception): |
58 class FontNotFound(Exception): |
59 """When there are no usable fonts specified""" |
59 """When there are no usable fonts specified""" |
60 |
60 |
61 |
61 |
62 class FontManager(object): |
62 class FontManager: |
63 """ |
63 """ |
64 Manages a set of fonts: normal, italic, bold, etc... |
64 Manages a set of fonts: normal, italic, bold, etc... |
65 """ |
65 """ |
66 |
66 |
67 def __init__(self, font_name, font_size=14): |
67 def __init__(self, font_name, font_size=14): |
123 def _create_mac(self): |
123 def _create_mac(self): |
124 font_map = {} |
124 font_map = {} |
125 for font_dir in (os.path.join(os.getenv("HOME"), 'Library/Fonts/'), |
125 for font_dir in (os.path.join(os.getenv("HOME"), 'Library/Fonts/'), |
126 '/Library/Fonts/', '/System/Library/Fonts/'): |
126 '/Library/Fonts/', '/System/Library/Fonts/'): |
127 font_map.update( |
127 font_map.update( |
128 ((os.path.splitext(f)[0].lower(), os.path.join(font_dir, f)) |
128 (os.path.splitext(f)[0].lower(), os.path.join(font_dir, f)) |
129 for f in os.listdir(font_dir) if f.lower().endswith('ttf'))) |
129 for f in os.listdir(font_dir) if f.lower().endswith('ttf')) |
130 |
130 |
131 for name in STYLES['NORMAL']: |
131 for name in STYLES['NORMAL']: |
132 path = self._get_mac_font_path(font_map, self.font_name, name) |
132 path = self._get_mac_font_path(font_map, self.font_name, name) |
133 if path is not None: |
133 if path is not None: |
134 self.fonts['NORMAL'] = ImageFont.truetype(path, self.font_size) |
134 self.fonts['NORMAL'] = ImageFont.truetype(path, self.font_size) |
162 raise FontNotFound('Font %s (%s) not found in registry' % |
162 raise FontNotFound('Font %s (%s) not found in registry' % |
163 (basename, styles[0])) |
163 (basename, styles[0])) |
164 return None |
164 return None |
165 |
165 |
166 def _create_win(self): |
166 def _create_win(self): |
167 try: |
167 lookuperror = None |
168 key = _winreg.OpenKey( |
168 keynames = [ (_winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows NT\CurrentVersion\Fonts'), |
169 _winreg.HKEY_LOCAL_MACHINE, |
169 (_winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Fonts'), |
170 r'Software\Microsoft\Windows NT\CurrentVersion\Fonts') |
170 (_winreg.HKEY_LOCAL_MACHINE, r'Software\Microsoft\Windows NT\CurrentVersion\Fonts'), |
171 except EnvironmentError: |
171 (_winreg.HKEY_LOCAL_MACHINE, r'Software\Microsoft\Windows\CurrentVersion\Fonts') ] |
|
172 for keyname in keynames: |
172 try: |
173 try: |
173 key = _winreg.OpenKey( |
174 key = _winreg.OpenKey(*keyname) |
174 _winreg.HKEY_LOCAL_MACHINE, |
175 try: |
175 r'Software\Microsoft\Windows\CurrentVersion\Fonts') |
176 path = self._lookup_win(key, self.font_name, STYLES['NORMAL'], True) |
|
177 self.fonts['NORMAL'] = ImageFont.truetype(path, self.font_size) |
|
178 for style in ('ITALIC', 'BOLD', 'BOLDITALIC'): |
|
179 path = self._lookup_win(key, self.font_name, STYLES[style]) |
|
180 if path: |
|
181 self.fonts[style] = ImageFont.truetype(path, self.font_size) |
|
182 else: |
|
183 if style == 'BOLDITALIC': |
|
184 self.fonts[style] = self.fonts['BOLD'] |
|
185 else: |
|
186 self.fonts[style] = self.fonts['NORMAL'] |
|
187 return |
|
188 except FontNotFound as err: |
|
189 lookuperror = err |
|
190 finally: |
|
191 _winreg.CloseKey(key) |
176 except EnvironmentError: |
192 except EnvironmentError: |
177 raise FontNotFound('Can\'t open Windows font registry key') |
193 pass |
178 try: |
194 else: |
179 path = self._lookup_win(key, self.font_name, STYLES['NORMAL'], True) |
195 # If we get here, we checked all registry keys and had no luck |
180 self.fonts['NORMAL'] = ImageFont.truetype(path, self.font_size) |
196 # We can be in one of two situations now: |
181 for style in ('ITALIC', 'BOLD', 'BOLDITALIC'): |
197 # * All key lookups failed. In this case lookuperror is None and we |
182 path = self._lookup_win(key, self.font_name, STYLES[style]) |
198 # will raise a generic error |
183 if path: |
199 # * At least one lookup failed with a FontNotFound error. In this |
184 self.fonts[style] = ImageFont.truetype(path, self.font_size) |
200 # case, we will raise that as a more specific error |
185 else: |
201 if lookuperror: |
186 if style == 'BOLDITALIC': |
202 raise lookuperror |
187 self.fonts[style] = self.fonts['BOLD'] |
203 raise FontNotFound('Can\'t open Windows font registry key') |
188 else: |
|
189 self.fonts[style] = self.fonts['NORMAL'] |
|
190 finally: |
|
191 _winreg.CloseKey(key) |
|
192 |
204 |
193 def get_char_size(self): |
205 def get_char_size(self): |
194 """ |
206 """ |
195 Get the character size. |
207 Get the character size. |
196 """ |
208 """ |
235 `font_name` |
247 `font_name` |
236 The font name to be used as the base font from which others, such as |
248 The font name to be used as the base font from which others, such as |
237 bold and italic fonts will be generated. This really should be a |
249 bold and italic fonts will be generated. This really should be a |
238 monospace font to look sane. |
250 monospace font to look sane. |
239 |
251 |
240 Default: "Bitstream Vera Sans Mono" on Windows, Courier New on \\*nix |
252 Default: "Courier New" on Windows, "Menlo" on Mac OS, and |
|
253 "DejaVu Sans Mono" on \\*nix |
241 |
254 |
242 `font_size` |
255 `font_size` |
243 The font size in points to be used. |
256 The font size in points to be used. |
244 |
257 |
245 Default: 14 |
258 Default: 14 |
501 """ |
514 """ |
502 Create drawables for the line numbers. |
515 Create drawables for the line numbers. |
503 """ |
516 """ |
504 if not self.line_numbers: |
517 if not self.line_numbers: |
505 return |
518 return |
506 for p in xrange(self.maxlineno): |
519 for p in range(self.maxlineno): |
507 n = p + self.line_number_start |
520 n = p + self.line_number_start |
508 if (n % self.line_number_step) == 0: |
521 if (n % self.line_number_step) == 0: |
509 self._draw_linenumber(p, n) |
522 self._draw_linenumber(p, n) |
510 |
523 |
511 def _paint_line_number_bg(self, im): |
524 def _paint_line_number_bg(self, im): |
519 draw = ImageDraw.Draw(im) |
532 draw = ImageDraw.Draw(im) |
520 recth = im.size[-1] |
533 recth = im.size[-1] |
521 rectw = self.image_pad + self.line_number_width - self.line_number_pad |
534 rectw = self.image_pad + self.line_number_width - self.line_number_pad |
522 draw.rectangle([(0, 0), (rectw, recth)], |
535 draw.rectangle([(0, 0), (rectw, recth)], |
523 fill=self.line_number_bg) |
536 fill=self.line_number_bg) |
524 draw.line([(rectw, 0), (rectw, recth)], fill=self.line_number_fg) |
537 if self.line_number_separator: |
|
538 draw.line([(rectw, 0), (rectw, recth)], fill=self.line_number_fg) |
525 del draw |
539 del draw |
526 |
540 |
527 def format(self, tokensource, outfile): |
541 def format(self, tokensource, outfile): |
528 """ |
542 """ |
529 Format ``tokensource``, an iterable of ``(tokentype, tokenstring)`` |
543 Format ``tokensource``, an iterable of ``(tokentype, tokenstring)`` |