##// END OF EJS Templates
enable retina display of Image objects...
MinRK -
Show More
@@ -20,6 +20,7 b' Authors:'
20 20 from __future__ import print_function
21 21
22 22 import os
23 import struct
23 24
24 25 from IPython.utils.py3compat import string_types
25 26
@@ -471,6 +472,32 b' class Javascript(DisplayObject):'
471 472 _PNG = b'\x89PNG\r\n\x1a\n'
472 473 _JPEG = b'\xff\xd8'
473 474
475 def _pngxy(data):
476 """read the (width, height) from a PNG header"""
477 ihdr = data.index(b'IHDR')
478 # next 8 bytes are width/height
479 w4h4 = data[ihdr+4:ihdr+12]
480 return struct.unpack('>ii', w4h4)
481
482 def _jpegxy(data):
483 """read the (width, height) from a JPEG header"""
484 # adapted from http://www.64lines.com/jpeg-width-height
485
486 idx = 4
487 while True:
488 block_size = struct.unpack('>H', data[idx:idx+2])[0]
489 idx = idx + block_size
490 if data[idx:idx+2] == b'\xFF\xC0':
491 # found Start of Frame
492 iSOF = idx
493 break
494 else:
495 # read another block
496 idx += 2
497
498 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
499 return w, h
500
474 501 class Image(DisplayObject):
475 502
476 503 _read_flags = 'rb'
@@ -478,7 +505,7 b' class Image(DisplayObject):'
478 505 _FMT_PNG = u'png'
479 506 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
480 507
481 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None):
508 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None, retina=False):
482 509 """Create a display an PNG/JPEG image given raw data.
483 510
484 511 When this object is returned by an expression or passed to the
@@ -512,6 +539,13 b' class Image(DisplayObject):'
512 539 Width to which to constrain the image in html
513 540 height : int
514 541 Height to which to constrain the image in html
542 retina : bool
543 Automatically set the width and height to half of the measured
544 width and height.
545 This only works for embedded images because it reads the width/height
546 from image data.
547 For non-embedded images, you can just set the desired display width
548 and height directly.
515 549
516 550 Examples
517 551 --------
@@ -561,12 +595,32 b' class Image(DisplayObject):'
561 595 raise ValueError("Cannot embed the '%s' image format" % (self.format))
562 596 self.width = width
563 597 self.height = height
598 self.retina = retina
564 599 super(Image, self).__init__(data=data, url=url, filename=filename)
600
601 if retina:
602 self._retina_shape()
603
604 def _retina_shape(self):
605 """load pixel-doubled width and height from image data"""
606 if not self.embed:
607 return
608 if self.format == 'png':
609 w, h = _pngxy(self.data)
610 elif self.format == 'jpeg':
611 w, h = _jpegxy(self.data)
612 else:
613 # retina only supports png
614 return
615 self.width = w // 2
616 self.height = h // 2
565 617
566 618 def reload(self):
567 619 """Reload the raw data from file or URL."""
568 620 if self.embed:
569 621 super(Image,self).reload()
622 if self.retina:
623 self._retina_shape()
570 624
571 625 def _repr_html_(self):
572 626 if not self.embed:
@@ -9,7 +9,7 b' Authors'
9 9 """
10 10
11 11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2009-2011 The IPython Development Team
12 # Copyright (C) 2009 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
@@ -19,10 +19,10 b' Authors'
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 import struct
23 22 import sys
24 23 from io import BytesIO
25 24
25 from IPython.core.display import _pngxy
26 26 from IPython.utils.decorators import flag_calls
27 27
28 28 # If user specifies a GUI, that dictates the backend, otherwise we read the
@@ -103,22 +103,16 b" def print_figure(fig, fmt='png'):"
103 103 dpi = rcParams['savefig.dpi']
104 104 if fmt == 'retina':
105 105 dpi = dpi * 2
106 fmt = 'png'
106 107 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
107 108 facecolor=fc, edgecolor=ec, dpi=dpi)
108 109 data = bytes_io.getvalue()
109 110 return data
110 111
111 def pngxy(data):
112 """read the width/height from a PNG header"""
113 ihdr = data.index(b'IHDR')
114 # next 8 bytes are width/height
115 w4h4 = data[ihdr+4:ihdr+12]
116 return struct.unpack('>ii', w4h4)
117
118 112 def retina_figure(fig):
119 113 """format a figure as a pixel-doubled (retina) PNG"""
120 114 pngdata = print_figure(fig, fmt='retina')
121 w, h = pngxy(pngdata)
115 w, h = _pngxy(pngdata)
122 116 metadata = dict(width=w//2, height=h//2)
123 117 return pngdata, metadata
124 118
General Comments 0
You need to be logged in to leave comments. Login now