Map Python objects to PDF syntax.
(obj)
| 296 | |
| 297 | |
| 298 | def pdfRepr(obj): |
| 299 | """Map Python objects to PDF syntax.""" |
| 300 | |
| 301 | # Some objects defined later have their own pdfRepr method. |
| 302 | if hasattr(obj, 'pdfRepr'): |
| 303 | return obj.pdfRepr() |
| 304 | |
| 305 | # Floats. PDF does not have exponential notation (1.0e-10) so we |
| 306 | # need to use %f with some precision. Perhaps the precision |
| 307 | # should adapt to the magnitude of the number? |
| 308 | elif isinstance(obj, (float, np.floating)): |
| 309 | if not np.isfinite(obj): |
| 310 | raise ValueError("Can only output finite numbers in PDF") |
| 311 | r = b"%.10f" % obj |
| 312 | return r.rstrip(b'0').rstrip(b'.') |
| 313 | |
| 314 | # Booleans. Needs to be tested before integers since |
| 315 | # isinstance(True, int) is true. |
| 316 | elif isinstance(obj, bool): |
| 317 | return [b'false', b'true'][obj] |
| 318 | |
| 319 | # Integers are written as such. |
| 320 | elif isinstance(obj, (int, np.integer)): |
| 321 | return b"%d" % obj |
| 322 | |
| 323 | # Non-ASCII Unicode strings are encoded in UTF-16BE with byte-order mark. |
| 324 | elif isinstance(obj, str): |
| 325 | return pdfRepr(obj.encode('ascii') if obj.isascii() |
| 326 | else codecs.BOM_UTF16_BE + obj.encode('UTF-16BE')) |
| 327 | |
| 328 | # Strings are written in parentheses, with backslashes and parens |
| 329 | # escaped. Actually balanced parens are allowed, but it is |
| 330 | # simpler to escape them all. TODO: cut long strings into lines; |
| 331 | # I believe there is some maximum line length in PDF. |
| 332 | # Despite the extra decode/encode, translate is faster than regex. |
| 333 | elif isinstance(obj, bytes): |
| 334 | return ( |
| 335 | b'(' + |
| 336 | obj.decode('latin-1').translate(_str_escapes).encode('latin-1') |
| 337 | + b')') |
| 338 | |
| 339 | # Dictionaries. The keys must be PDF names, so if we find strings |
| 340 | # there, we make Name objects from them. The values may be |
| 341 | # anything, so the caller must ensure that PDF names are |
| 342 | # represented as Name objects. |
| 343 | elif isinstance(obj, dict): |
| 344 | return _fill([ |
| 345 | b"<<", |
| 346 | *[Name(k).pdfRepr() + b" " + pdfRepr(v) for k, v in obj.items()], |
| 347 | b">>", |
| 348 | ]) |
| 349 | |
| 350 | # Lists. |
| 351 | elif isinstance(obj, (list, tuple)): |
| 352 | return _fill([b"[", *[pdfRepr(val) for val in obj], b"]"]) |
| 353 | |
| 354 | # The null keyword. |
| 355 | elif obj is None: |
no test coverage detected
searching dependent graphs…