diff --git a/README.md b/README.md index 13b42b54..5be335f4 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ python extract_scene.py -p example_scenes.py SquareToCircle `-p` gives a preview of an animation, `-w` will write it to a file, and `-s` will show/save the final image in the animation. -You will probably want to change the MOVIE_DIR constant to be whatever direction you want video files to output to. +You will probably want to change the ANIMATIONS_DIR constant to be whatever direction you want video files to output to. Look through the old_projects folder to see the code for previous 3b1b videos. diff --git a/camera.py b/camera.py index 4b30258d..19b299f2 100644 --- a/camera.py +++ b/camera.py @@ -49,7 +49,7 @@ class Camera(object): def init_background(self): if self.background_image is not None: - path = get_full_image_path(self.background_image) + path = get_full_raster_image_path(self.background_image) image = Image.open(path).convert(self.image_mode) height, width = self.pixel_shape #TODO, how to gracefully handle backgrounds diff --git a/constants.py b/constants.py index 257cd97d..31673f08 100644 --- a/constants.py +++ b/constants.py @@ -61,19 +61,23 @@ RIGHT_SIDE = SPACE_WIDTH*RIGHT # Change this to point to where you want # animation files to output -MOVIE_DIR = os.path.join(os.path.expanduser('~'), "Dropbox (3Blue1Brown)/3Blue1Brown Team Folder/animations") -STAGED_SCENES_DIR = os.path.join(MOVIE_DIR, "staged_scenes") +MEDIA_DIR = os.path.join(os.path.expanduser('~'), "Dropbox (3Blue1Brown)/3Blue1Brown Team Folder") + +ANIMATIONS_DIR = os.path.join(MEDIA_DIR, "animations") +RASTER_IMAGE_DIR = os.path.join(MEDIA_DIR, "designs", "raster_images") +SVG_IMAGE_DIR = os.path.join(MEDIA_DIR, "designs", "svg_images") +#TODO, staged scenes should really go into a subdirectory of a given scenes directory +STAGED_SCENES_DIR = os.path.join(ANIMATIONS_DIR, "staged_scenes") ### THIS_DIR = os.path.dirname(os.path.realpath(__file__)) FILE_DIR = os.path.join(THIS_DIR, "files") -IMAGE_DIR = os.path.join(FILE_DIR, "images") -GIF_DIR = os.path.join(FILE_DIR, "gifs") TEX_DIR = os.path.join(FILE_DIR, "Tex") -TEX_IMAGE_DIR = os.path.join(IMAGE_DIR, "Tex") +TEX_IMAGE_DIR = TEX_DIR #TODO, What is this doing? +#These two may be depricated now. MOBJECT_DIR = os.path.join(FILE_DIR, "mobjects") IMAGE_MOBJECT_DIR = os.path.join(MOBJECT_DIR, "image") -for folder in [FILE_DIR, IMAGE_DIR, GIF_DIR, MOVIE_DIR, TEX_DIR, +for folder in [FILE_DIR, RASTER_IMAGE_DIR, SVG_IMAGE_DIR, ANIMATIONS_DIR, TEX_DIR, TEX_IMAGE_DIR, MOBJECT_DIR, IMAGE_MOBJECT_DIR, STAGED_SCENES_DIR]: if not os.path.exists(folder): @@ -84,8 +88,6 @@ TEMPLATE_TEX_FILE = os.path.join(THIS_DIR, "template.tex") TEMPLATE_TEXT_FILE = os.path.join(THIS_DIR, "text_template.tex") -LOGO_PATH = os.path.join(IMAGE_DIR, "logo.png") - FFMPEG_BIN = "ffmpeg" diff --git a/extract_scene.py b/extract_scene.py index 75945e85..537884f7 100644 --- a/extract_scene.py +++ b/extract_scene.py @@ -190,7 +190,7 @@ def main(): ) config["output_directory"] = os.path.join( - MOVIE_DIR, + ANIMATIONS_DIR, config["file"].replace(".py", "") ) diff --git a/files/images/Bubbles_speech.svg b/files/images/Bubbles_speech.svg deleted file mode 100644 index 173ebf35..00000000 --- a/files/images/Bubbles_speech.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/files/images/Bubbles_thought.svg b/files/images/Bubbles_thought.svg deleted file mode 100644 index c77ebca4..00000000 --- a/files/images/Bubbles_thought.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - diff --git a/files/images/PiCreature/PiCreatures_plain.svg b/files/images/PiCreature/PiCreatures_plain.svg deleted file mode 100644 index 552043d6..00000000 --- a/files/images/PiCreature/PiCreatures_plain.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - diff --git a/helpers.py b/helpers.py index 2dd96c8c..2683bd6c 100644 --- a/helpers.py +++ b/helpers.py @@ -410,13 +410,13 @@ def cammel_case_initials(name): ################################################ -def get_full_image_path(image_file_name): +def get_full_raster_image_path(image_file_name): possible_paths = [ image_file_name, - os.path.join(IMAGE_DIR, image_file_name), - os.path.join(IMAGE_DIR, image_file_name + ".jpg"), - os.path.join(IMAGE_DIR, image_file_name + ".png"), - os.path.join(IMAGE_DIR, image_file_name + ".gif"), + os.path.join(RASTER_IMAGE_DIR, image_file_name), + os.path.join(RASTER_IMAGE_DIR, image_file_name + ".jpg"), + os.path.join(RASTER_IMAGE_DIR, image_file_name + ".png"), + os.path.join(RASTER_IMAGE_DIR, image_file_name + ".gif"), ] for path in possible_paths: if os.path.exists(path): diff --git a/mobject/image_mobject.py b/mobject/image_mobject.py index 0a602c0b..e4a74382 100644 --- a/mobject/image_mobject.py +++ b/mobject/image_mobject.py @@ -23,7 +23,7 @@ class ImageMobject(Mobject): def __init__(self, filename_or_array, **kwargs): digest_config(self, kwargs) if isinstance(filename_or_array, str): - path = get_full_image_path(filename_or_array) + path = get_full_raster_image_path(filename_or_array) image = Image.open(path).convert(self.image_mode) self.pixel_array = np.array(image) else: diff --git a/mobject/mobject.py b/mobject/mobject.py index ec1ff7c3..d79c5482 100644 --- a/mobject/mobject.py +++ b/mobject/mobject.py @@ -96,7 +96,7 @@ class Mobject(object): def save_image(self, name = None): self.get_image().save( - os.path.join(MOVIE_DIR, (name or str(self)) + ".png") + os.path.join(ANIMATIONS_DIR, (name or str(self)) + ".png") ) def copy(self): diff --git a/mobject/svg_mobject.py b/mobject/svg_mobject.py index ede49a77..0c90ffef 100644 --- a/mobject/svg_mobject.py +++ b/mobject/svg_mobject.py @@ -37,8 +37,8 @@ class SVGMobject(VMobject): raise Exception("Must specify file for SVGMobject") possible_paths = [ self.file_name, - os.path.join(IMAGE_DIR, self.file_name), - os.path.join(IMAGE_DIR, self.file_name + ".svg"), + os.path.join(SVG_IMAGE_DIR, self.file_name), + os.path.join(SVG_IMAGE_DIR, self.file_name + ".svg"), ] for path in possible_paths: if os.path.exists(path): diff --git a/nn/part1.py b/nn/part1.py index 12540128..2efa5d80 100644 --- a/nn/part1.py +++ b/nn/part1.py @@ -1532,7 +1532,7 @@ class BreakUpMacroPatterns(IntroduceEachLayer): prefixes = self.prefixes vects = [ np.array(Image.open( - get_full_image_path("handwritten_" + p), + get_full_raster_image_path("handwritten_" + p), ))[:,:,0].flatten()/255.0 for p in prefixes ] @@ -1921,7 +1921,7 @@ class SecondLayerIsLittleEdgeLayer(IntroduceEachLayer): def setup_activations_and_nines(self): layers = self.network_mob.layers nine_im, loop_im, line_im = images = [ - Image.open(get_full_image_path("handwritten_%s"%s)) + Image.open(get_full_raster_image_path("handwritten_%s"%s)) for s in "nine", "upper_loop", "right_line" ] nine_array, loop_array, line_array = [ diff --git a/old_projects/counting_in_binary.py b/old_projects/counting_in_binary.py index 7428e146..1a6acfb7 100644 --- a/old_projects/counting_in_binary.py +++ b/old_projects/counting_in_binary.py @@ -14,7 +14,7 @@ from scene import Scene, SceneFromVideo from script_wrapper import command_line_create_scene MOVIE_PREFIX = "counting_in_binary/" -BASE_HAND_FILE = os.path.join(MOVIE_DIR, MOVIE_PREFIX, "Base.mp4") +BASE_HAND_FILE = os.path.join(ANIMATIONS_DIR, MOVIE_PREFIX, "Base.mp4") FORCED_FRAME_DURATION = 0.02 TIME_RANGE = (0, 42) INITIAL_PADDING = 27 @@ -88,7 +88,7 @@ class Hand(ImageMobject): def __init__(self, num, small = False, **kwargs): Mobject2D.__init__(self, **kwargs) path = os.path.join( - MOVIE_DIR, MOVIE_PREFIX, "images", "Hand%d.png"%num + ANIMATIONS_DIR, MOVIE_PREFIX, "images", "Hand%d.png"%num ) invert = False if not self.read_in_cached_attrs(path, invert): @@ -164,7 +164,7 @@ class SaveEachNumber(OverHand): OverHand.construct(self) for count in COUNT_TO_FRAME_NUM: path = os.path.join( - MOVIE_DIR, MOVIE_PREFIX, "images", + ANIMATIONS_DIR, MOVIE_PREFIX, "images", "Hand%d.png"%count ) Image.fromarray(self.frames[COUNT_TO_FRAME_NUM[count]]).save(path) diff --git a/old_projects/playground_counting_in_binary.py b/old_projects/playground_counting_in_binary.py index 2ba8f831..ed7cd705 100644 --- a/old_projects/playground_counting_in_binary.py +++ b/old_projects/playground_counting_in_binary.py @@ -55,7 +55,7 @@ class Hand(ImageMobject): def __init__(self, num, **kwargs): Mobject2D.__init__(self, **kwargs) path = os.path.join( - MOVIE_DIR, MOVIE_PREFIX, "images", "Hand%d.png"%num + ANIMATIONS_DIR, MOVIE_PREFIX, "images", "Hand%d.png"%num ) invert = False if self.read_in_cached_attrs(path, invert): @@ -81,14 +81,14 @@ class EdgeDetection(SceneFromVideo): return "-".join([filename.split(".")[0], str(t1), str(t2)]) def construct(self, filename, t1, t2): - path = os.path.join(MOVIE_DIR, filename) + path = os.path.join(ANIMATIONS_DIR, filename) SceneFromVideo.construct(self, path) self.apply_gaussian_blur() self.apply_edge_detection(t1, t2) class BufferedCounting(SceneFromVideo): def construct(self): - path = os.path.join(MOVIE_DIR, "CountingInBinary.m4v") + path = os.path.join(ANIMATIONS_DIR, "CountingInBinary.m4v") time_range = (3, 42) SceneFromVideo.construct(self, path, time_range = time_range) self.buffer_pixels(spreads = (3, 2)) @@ -128,7 +128,7 @@ class ClearLeftSide(SceneFromVideo): return scenename def construct(self, scenename): - path = os.path.join(MOVIE_DIR, MOVIE_PREFIX, scenename + ".mp4") + path = os.path.join(ANIMATIONS_DIR, MOVIE_PREFIX, scenename + ".mp4") SceneFromVideo.construct(self, path) self.highlight_region_over_time_range( Region(lambda x, y : x < -1, shape = self.shape) @@ -146,7 +146,7 @@ class DraggedPixels(SceneFromVideo): return args[0] def construct(self, video): - path = os.path.join(MOVIE_DIR, MOVIE_PREFIX, video+".mp4") + path = os.path.join(ANIMATIONS_DIR, MOVIE_PREFIX, video+".mp4") SceneFromVideo.construct(self, path) self.drag_pixels() @@ -163,11 +163,11 @@ class DraggedPixels(SceneFromVideo): class SaveEachNumber(SceneFromVideo): def construct(self): - path = os.path.join(MOVIE_DIR, MOVIE_PREFIX, "ClearLeftSideBufferedCounting.mp4") + path = os.path.join(ANIMATIONS_DIR, MOVIE_PREFIX, "ClearLeftSideBufferedCounting.mp4") SceneFromVideo.construct(self, path) for count in COUNT_TO_FRAME_NUM: path = os.path.join( - MOVIE_DIR, MOVIE_PREFIX, "images", + ANIMATIONS_DIR, MOVIE_PREFIX, "images", "Hand%d.png"%count ) Image.fromarray(self.frames[COUNT_TO_FRAME_NUM[count]]).save(path) @@ -182,7 +182,7 @@ class ShowCounting(SceneFromVideo): return filename def construct(self, filename): - path = os.path.join(MOVIE_DIR, MOVIE_PREFIX, filename + ".mp4") + path = os.path.join(ANIMATIONS_DIR, MOVIE_PREFIX, filename + ".mp4") SceneFromVideo.construct(self, path) total_time = len(self.frames)*self.frame_duration for count in range(32): @@ -207,7 +207,7 @@ class ShowFrameNum(SceneFromVideo): return filename def construct(self, filename): - path = os.path.join(MOVIE_DIR, MOVIE_PREFIX, filename+".mp4") + path = os.path.join(ANIMATIONS_DIR, MOVIE_PREFIX, filename+".mp4") SceneFromVideo.construct(self, path) for frame, count in zip(self.frames, it.count()): print(count + "of" + len(self.frames)) diff --git a/scene/scene.py b/scene/scene.py index 621328f2..d1500e11 100644 --- a/scene/scene.py +++ b/scene/scene.py @@ -32,7 +32,7 @@ class Scene(object): "save_frames" : False, "save_pngs" : False, "pngs_mode" : "RGBA", - "output_directory" : MOVIE_DIR, + "output_directory" : ANIMATIONS_DIR, "name" : None, "always_continually_update" : False, "random_seed" : 0, diff --git a/stage_animations.py b/stage_animations.py deleted file mode 100644 index 6f129239..00000000 --- a/stage_animations.py +++ /dev/null @@ -1,50 +0,0 @@ -import sys -import inspect -import os -import shutil -import itertools as it -from extract_scene import is_scene, get_module -from constants import MOVIE_DIR, STAGED_SCENES_DIR - - -def get_sorted_scene_names(module_name): - module = get_module(module_name) - line_to_scene = {} - for name, scene_class in inspect.getmembers(module, is_scene): - lines, line_no = inspect.getsourcelines(scene_class) - line_to_scene[line_no] = name - return [ - line_to_scene[line_no] - for line_no in sorted(line_to_scene.keys()) - ] - - - -def stage_animaions(module_name): - scene_names = get_sorted_scene_names(module_name) - movie_dir = os.path.join( - MOVIE_DIR, module_name.replace(".py", "") - ) - files = os.listdir(movie_dir) - sorted_files = [] - for scene in scene_names: - for clip in filter(lambda f : f.startswith(scene), files): - sorted_files.append( - os.path.join(movie_dir, clip) - ) - for f in os.listdir(STAGED_SCENES_DIR): - os.remove(os.path.join(STAGED_SCENES_DIR, f)) - for f, count in zip(sorted_files, it.count()): - symlink_name = os.path.join( - STAGED_SCENES_DIR, - "Scene_%03d"%count + f.split(os.sep)[-1] - ) - os.symlink(f, symlink_name) - - - -if __name__ == "__main__": - if len(sys.argv) < 2: - raise Exception("No module given.") - module_name = sys.argv[1] - stage_animaions(module_name) \ No newline at end of file diff --git a/stage_scenes.py b/stage_scenes.py index 6f129239..e79d341c 100644 --- a/stage_scenes.py +++ b/stage_scenes.py @@ -4,7 +4,7 @@ import os import shutil import itertools as it from extract_scene import is_scene, get_module -from constants import MOVIE_DIR, STAGED_SCENES_DIR +from constants import ANIMATIONS_DIR, STAGED_SCENES_DIR def get_sorted_scene_names(module_name): @@ -22,15 +22,15 @@ def get_sorted_scene_names(module_name): def stage_animaions(module_name): scene_names = get_sorted_scene_names(module_name) - movie_dir = os.path.join( - MOVIE_DIR, module_name.replace(".py", "") + animation_dir = os.path.join( + ANIMATIONS_DIR, module_name.replace(".py", "") ) - files = os.listdir(movie_dir) + files = os.listdir(animation_dir) sorted_files = [] for scene in scene_names: for clip in filter(lambda f : f.startswith(scene), files): sorted_files.append( - os.path.join(movie_dir, clip) + os.path.join(animation_dir, clip) ) for f in os.listdir(STAGED_SCENES_DIR): os.remove(os.path.join(STAGED_SCENES_DIR, f)) diff --git a/topics/characters.py b/topics/characters.py index 432c30e5..fef18cb8 100644 --- a/topics/characters.py +++ b/topics/characters.py @@ -13,7 +13,7 @@ from animation.simple_animations import Write, ShowCreation, AnimationGroup from scene import Scene -PI_CREATURE_DIR = os.path.join(IMAGE_DIR, "PiCreature") +PI_CREATURE_DIR = os.path.join(MEDIA_DIR, "designs", "PiCreature") PI_CREATURE_SCALE_FACTOR = 0.5 LEFT_EYE_INDEX = 0 @@ -51,7 +51,7 @@ class PiCreature(SVGMobject): except: warnings.warn("No PiCreature design with mode %s"%mode) svg_file = os.path.join( - PI_CREATURE_DIR, + FILE_DIR, "PiCreatures_plain.svg" ) SVGMobject.__init__(self, file_name = svg_file, **kwargs) diff --git a/topics/objects.py b/topics/objects.py index b445d861..769ea8ff 100644 --- a/topics/objects.py +++ b/topics/objects.py @@ -388,7 +388,11 @@ class Bubble(SVGMobject): digest_config(self, kwargs, locals()) if self.file_name is None: raise Exception("Must invoke Bubble subclass") - SVGMobject.__init__(self, **kwargs) + try: + SVGMobject.__init__(self, **kwargs) + except IOError as err: + self.file_name = os.path.join(FILE_DIR, self.file_name) + SVGMobject.__init__(self, **kwargs) self.center() self.stretch_to_fit_height(self.height) self.stretch_to_fit_width(self.width) @@ -515,4 +519,22 @@ class Broadcast(LaggedStart): self, ApplyMethod, circles, lambda c : (c.restore,), **kwargs - ) \ No newline at end of file + + ) + + + + + + + + + + + + + + + + +