##// END OF EJS Templates
enable retina display of Image objects...
MinRK -
Show More
@@ -20,6 +20,7 b' Authors:'
20 from __future__ import print_function
20 from __future__ import print_function
21
21
22 import os
22 import os
23 import struct
23
24
24 from IPython.utils.py3compat import string_types
25 from IPython.utils.py3compat import string_types
25
26
@@ -471,6 +472,32 b' class Javascript(DisplayObject):'
471 _PNG = b'\x89PNG\r\n\x1a\n'
472 _PNG = b'\x89PNG\r\n\x1a\n'
472 _JPEG = b'\xff\xd8'
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 class Image(DisplayObject):
501 class Image(DisplayObject):
475
502
476 _read_flags = 'rb'
503 _read_flags = 'rb'
@@ -478,7 +505,7 b' class Image(DisplayObject):'
478 _FMT_PNG = u'png'
505 _FMT_PNG = u'png'
479 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
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 """Create a display an PNG/JPEG image given raw data.
509 """Create a display an PNG/JPEG image given raw data.
483
510
484 When this object is returned by an expression or passed to the
511 When this object is returned by an expression or passed to the
@@ -512,6 +539,13 b' class Image(DisplayObject):'
512 Width to which to constrain the image in html
539 Width to which to constrain the image in html
513 height : int
540 height : int
514 Height to which to constrain the image in html
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 Examples
550 Examples
517 --------
551 --------
@@ -561,12 +595,32 b' class Image(DisplayObject):'
561 raise ValueError("Cannot embed the '%s' image format" % (self.format))
595 raise ValueError("Cannot embed the '%s' image format" % (self.format))
562 self.width = width
596 self.width = width
563 self.height = height
597 self.height = height
598 self.retina = retina
564 super(Image, self).__init__(data=data, url=url, filename=filename)
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 def reload(self):
618 def reload(self):
567 """Reload the raw data from file or URL."""
619 """Reload the raw data from file or URL."""
568 if self.embed:
620 if self.embed:
569 super(Image,self).reload()
621 super(Image,self).reload()
622 if self.retina:
623 self._retina_shape()
570
624
571 def _repr_html_(self):
625 def _repr_html_(self):
572 if not self.embed:
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 # Distributed under the terms of the BSD License. The full license is in
14 # Distributed under the terms of the BSD License. The full license is in
15 # the file COPYING, distributed as part of this software.
15 # the file COPYING, distributed as part of this software.
@@ -19,10 +19,10 b' Authors'
19 # Imports
19 # Imports
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 import struct
23 import sys
22 import sys
24 from io import BytesIO
23 from io import BytesIO
25
24
25 from IPython.core.display import _pngxy
26 from IPython.utils.decorators import flag_calls
26 from IPython.utils.decorators import flag_calls
27
27
28 # If user specifies a GUI, that dictates the backend, otherwise we read the
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 dpi = rcParams['savefig.dpi']
103 dpi = rcParams['savefig.dpi']
104 if fmt == 'retina':
104 if fmt == 'retina':
105 dpi = dpi * 2
105 dpi = dpi * 2
106 fmt = 'png'
106 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
107 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
107 facecolor=fc, edgecolor=ec, dpi=dpi)
108 facecolor=fc, edgecolor=ec, dpi=dpi)
108 data = bytes_io.getvalue()
109 data = bytes_io.getvalue()
109 return data
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 def retina_figure(fig):
112 def retina_figure(fig):
119 """format a figure as a pixel-doubled (retina) PNG"""
113 """format a figure as a pixel-doubled (retina) PNG"""
120 pngdata = print_figure(fig, fmt='retina')
114 pngdata = print_figure(fig, fmt='retina')
121 w, h = pngxy(pngdata)
115 w, h = _pngxy(pngdata)
122 metadata = dict(width=w//2, height=h//2)
116 metadata = dict(width=w//2, height=h//2)
123 return pngdata, metadata
117 return pngdata, metadata
124
118
General Comments 0
You need to be logged in to leave comments. Login now