@@ -912,16 +912,28 @@ def isAvailable(cls):
912
912
return True
913
913
914
914
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 ):
916
917
self .embed_frames = embed_frames
917
918
self .default_mode = default_mode .lower ()
918
919
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
+
919
929
if self .default_mode not in ['loop' , 'once' , 'reflect' ]:
920
930
self .default_mode = 'loop'
921
931
import warnings
922
932
warnings .warn ("unrecognized default_mode: using 'loop'" )
923
933
924
934
self ._saved_frames = list ()
935
+ self ._total_bytes = 0
936
+ self ._hit_limit = False
925
937
super (HTMLWriter , self ).__init__ (fps , codec , bitrate ,
926
938
extra_args , metadata )
927
939
@@ -943,13 +955,27 @@ def setup(self, fig, outfile, dpi, frame_dir=None):
943
955
944
956
def grab_frame (self , ** savefig_kwargs ):
945
957
if self .embed_frames :
958
+ # Just stop processing if we hit the limit
959
+ if self ._hit_limit :
960
+ return
946
961
suffix = '.' + self .frame_format
947
962
f = InMemory ()
948
963
self .fig .savefig (f , format = self .frame_format ,
949
964
dpi = self .dpi , ** savefig_kwargs )
950
965
f .seek (0 )
951
966
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 )
953
979
else :
954
980
return super (HTMLWriter , self ).grab_frame (** savefig_kwargs )
955
981
@@ -1354,7 +1380,7 @@ def _end_redraw(self, evt):
1354
1380
self ._resize_id = self ._fig .canvas .mpl_connect ('resize_event' ,
1355
1381
self ._handle_resize )
1356
1382
1357
- def to_html5_video (self ):
1383
+ def to_html5_video (self , embed_limit = None ):
1358
1384
'''Returns animation as an HTML5 video tag.
1359
1385
1360
1386
This saves the animation as an h264 video, encoded in base64
@@ -1369,6 +1395,13 @@ def to_html5_video(self):
1369
1395
</video>'''
1370
1396
# Cache the rendering of the video as HTML
1371
1397
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
+
1372
1405
# First write the video to a tempfile. Set delete to False
1373
1406
# so we can re-open to read binary data.
1374
1407
with tempfile .NamedTemporaryFile (suffix = '.m4v' ,
@@ -1384,22 +1417,36 @@ def to_html5_video(self):
1384
1417
# Now open and base64 encode
1385
1418
with open (f .name , 'rb' ) as video :
1386
1419
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 )
1390
1432
1391
1433
# Now we can remove
1392
1434
os .remove (f .name )
1393
1435
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' ]
1396
1440
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.'
1403
1450
1404
1451
def to_jshtml (self , fps = None , embed_frames = True , default_mode = None ):
1405
1452
"""Generate HTML representation of the animation"""
0 commit comments