@@ -912,16 +912,28 @@ def isAvailable(cls):
912912 return True
913913
914914 def __init__ (self , fps = 30 , codec = None , bitrate = None , extra_args = None ,
915- metadata = None , embed_frames = False , default_mode = 'loop' ):
915+ metadata = None , embed_frames = False , default_mode = 'loop' ,
916+ embed_limit = None ):
916917 self .embed_frames = embed_frames
917918 self .default_mode = default_mode .lower ()
918919
920+ # Save embed limit, which is given in MB
921+ if embed_limit is None :
922+ self ._bytes_limit = rcParams ['animation.embed_limit' ]
923+ else :
924+ self ._bytes_limit = embed_limit
925+
926+ # Convert from MB to bytes
927+ self ._bytes_limit *= 1024 * 1024
928+
919929 if self .default_mode not in ['loop' , 'once' , 'reflect' ]:
920930 self .default_mode = 'loop'
921931 import warnings
922932 warnings .warn ("unrecognized default_mode: using 'loop'" )
923933
924934 self ._saved_frames = list ()
935+ self ._total_bytes = 0
936+ self ._hit_limit = False
925937 super (HTMLWriter , self ).__init__ (fps , codec , bitrate ,
926938 extra_args , metadata )
927939
@@ -943,13 +955,27 @@ def setup(self, fig, outfile, dpi, frame_dir=None):
943955
944956 def grab_frame (self , ** savefig_kwargs ):
945957 if self .embed_frames :
958+ # Just stop processing if we hit the limit
959+ if self ._hit_limit :
960+ return
946961 suffix = '.' + self .frame_format
947962 f = InMemory ()
948963 self .fig .savefig (f , format = self .frame_format ,
949964 dpi = self .dpi , ** savefig_kwargs )
950965 f .seek (0 )
951966 imgdata64 = encodebytes (f .read ()).decode ('ascii' )
952- self ._saved_frames .append (imgdata64 )
967+ self ._total_bytes += len (imgdata64 )
968+ if self ._total_bytes >= self ._bytes_limit :
969+ warnings .warn ("Animation size has reached {0._total_bytes} "
970+ "bytes, exceeding the limit of "
971+ "{0._bytes_limit}. If you're sure you want "
972+ "a larger animation embedded, set the "
973+ "animation.embed_limit rc parameter to a "
974+ "larger value (in MB). This and further frames"
975+ " will be dropped." .format (self ))
976+ self ._hit_limit = True
977+ else :
978+ self ._saved_frames .append (imgdata64 )
953979 else :
954980 return super (HTMLWriter , self ).grab_frame (** savefig_kwargs )
955981
@@ -1354,7 +1380,7 @@ def _end_redraw(self, evt):
13541380 self ._resize_id = self ._fig .canvas .mpl_connect ('resize_event' ,
13551381 self ._handle_resize )
13561382
1357- def to_html5_video (self ):
1383+ def to_html5_video (self , embed_limit = None ):
13581384 '''Returns animation as an HTML5 video tag.
13591385
13601386 This saves the animation as an h264 video, encoded in base64
@@ -1369,6 +1395,13 @@ def to_html5_video(self):
13691395</video>'''
13701396 # Cache the rendering of the video as HTML
13711397 if not hasattr (self , '_base64_video' ):
1398+ # Save embed limit, which is given in MB
1399+ if embed_limit is None :
1400+ embed_limit = rcParams ['animation.embed_limit' ]
1401+
1402+ # Convert from MB to bytes
1403+ embed_limit *= 1024 * 1024
1404+
13721405 # First write the video to a tempfile. Set delete to False
13731406 # so we can re-open to read binary data.
13741407 with tempfile .NamedTemporaryFile (suffix = '.m4v' ,
@@ -1384,22 +1417,36 @@ def to_html5_video(self):
13841417 # Now open and base64 encode
13851418 with open (f .name , 'rb' ) as video :
13861419 vid64 = encodebytes (video .read ())
1387- self ._base64_video = vid64 .decode ('ascii' )
1388- self ._video_size = 'width="{0}" height="{1}"' .format (
1389- * writer .frame_size )
1420+ vid_len = len (vid64 )
1421+ if vid_len >= embed_limit :
1422+ warnings .warn ("Animation movie is {} bytes, exceeding "
1423+ "the limit of {}. If you're sure you want a "
1424+ "large animation embedded, set the "
1425+ "animation.embed_limit rc parameter to a "
1426+ "larger value (in MB)." .format (vid_len ,
1427+ embed_limit ))
1428+ else :
1429+ self ._base64_video = vid64 .decode ('ascii' )
1430+ self ._video_size = 'width="{}" height="{}"' .format (
1431+ * writer .frame_size )
13901432
13911433 # Now we can remove
13921434 os .remove (f .name )
13931435
1394- # Default HTML5 options are to autoplay and to display video controls
1395- options = ['controls' , 'autoplay' ]
1436+ # If we exceeded the size, this attribute won't exist
1437+ if hasattr (self , '_base64_video' ):
1438+ # Default HTML5 options are to autoplay and display video controls
1439+ options = ['controls' , 'autoplay' ]
13961440
1397- # If we're set to repeat, make it loop
1398- if self .repeat :
1399- options .append ('loop' )
1400- return VIDEO_TAG .format (video = self ._base64_video ,
1401- size = self ._video_size ,
1402- options = ' ' .join (options ))
1441+ # If we're set to repeat, make it loop
1442+ if hasattr (self , 'repeat' ) and self .repeat :
1443+ options .append ('loop' )
1444+
1445+ return VIDEO_TAG .format (video = self ._base64_video ,
1446+ size = self ._video_size ,
1447+ options = ' ' .join (options ))
1448+ else :
1449+ return 'Video too large to embed.'
14031450
14041451 def to_jshtml (self , fps = None , embed_frames = True , default_mode = None ):
14051452 """Generate HTML representation of the animation"""
0 commit comments