Skip to content

Commit

Permalink
Fixes transparency bug (not 100% tested). Also added imageio gif back…
Browse files Browse the repository at this point in the history
…end.
  • Loading branch information
Zulko committed Dec 14, 2014
1 parent 3fef00d commit b2bf715
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 92 deletions.
4 changes: 2 additions & 2 deletions moviepy/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def verbose_print(verbose, s):
def subprocess_call(cmd, verbose=True, errorprint=True):
""" Executes the given subprocess command."""

verbose_print(verbose, "\nMoviePy Running:\n>>> "+ " ".join(cmd))
verbose_print(verbose, "\n[MoviePy] Running:\n>>> "+ " ".join(cmd))

popen_params = {"stdout": DEVNULL,
"stderr": sp.PIPE,
Expand All @@ -44,7 +44,7 @@ def subprocess_call(cmd, verbose=True, errorprint=True):
proc.stderr.close()

if proc.returncode:
verbose_print(errorprint, "\nMoviePy: This command returned an error !")
verbose_print(errorprint, "\n[MoviePy] This command returned an error !")
raise IOError(err.decode('utf8'))
else:
verbose_print(verbose, "\n... command successful.\n")
Expand Down
31 changes: 18 additions & 13 deletions moviepy/video/VideoClip.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
from .io.ffmpeg_writer import ffmpeg_write_image, ffmpeg_write_video
from .io.ffmpeg_reader import ffmpeg_read_image
from .io.ffmpeg_tools import ffmpeg_merge_video_audio
from .io.gif_writers import write_gif, write_gif_with_tempfiles
from .io.gif_writers import (write_gif,
write_gif_with_tempfiles,
write_gif_with_image_io)
from .tools.drawing import blit
from ..Clip import Clip
from ..config import get_setting
Expand Down Expand Up @@ -447,8 +449,11 @@ def write_gif(self, filename, fps=None, program='ImageMagick',
>>> myClip.speedx(0.5).to_gif('myClip.gif')
"""
if program == 'imageio':
write_gif_with_image_io(self, filename, fps=fps, opt=opt, loop=loop,
verbose=verbose, colors=colors)

if tempfiles:
elif tempfiles:
write_gif_with_tempfiles(self, filename, fps=fps,
program=program, opt=opt, fuzz=fuzz,
verbose=verbose,
Expand Down Expand Up @@ -613,13 +618,13 @@ def on_color(self, size=None, color=(0, 0, 0), pos=None,
colorclip = ColorClip(size, color)

if col_opacity is not None:
colorclip = colorclip.set_opacity(col_opacity)

if self.duration is not None:
colorclip = colorclip.set_duration(self.duration)

result = CompositeVideoClip([colorclip, self.set_pos(pos)],
transparent=(col_opacity is not None))
colorclip = (ColorClip(size, color, duration=elf.duration)
.set_opacity(col_opacity))
result = CompositeVideoClip([colorclip, self.set_pos(pos)])
else:
result = CompositeVideoClip([self.set_pos(pos)],
size=size,
bg_color=color)

if (isinstance(self, ImageClip) and (not hasattr(pos, "__call__"))
and ((self.mask is None) or isinstance(self.mask, ImageClip))):
Expand Down Expand Up @@ -875,9 +880,9 @@ class ImageClip(VideoClip):


def __init__(self, img, ismask=False, transparent=True,
fromalpha=False):
fromalpha=False, duration=None):

VideoClip.__init__(self, ismask=ismask)
VideoClip.__init__(self, ismask=ismask, duration=duration)

if isinstance(img, str):
img = ffmpeg_read_image(img, with_mask=transparent)
Expand Down Expand Up @@ -993,11 +998,11 @@ class ColorClip(ImageClip):
"""


def __init__(self, size, col=(0, 0, 0), ismask=False):
def __init__(self, size, col=(0, 0, 0), ismask=False, duration=None):
w, h = size
shape = (h, w) if np.isscalar(col) else (h, w, len(col))
ImageClip.__init__(self, np.tile(col, w * h).reshape(shape),
ismask=ismask)
ismask=ismask, duration=duration)


class TextClip(ImageClip):
Expand Down
70 changes: 49 additions & 21 deletions moviepy/video/compositing/CompositeVideoClip.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,35 +29,48 @@ class CompositeVideoClip(VideoClip):
attribute set, then the duration of the composite video clip
is computed automatically
transparent
If False, the clips are overlaid on a surface
of the color `bg_color`. If True, the clips are overlaid on
a transparent surface, so that all pixels that are transparent
for all clips will be transparent in the composite clip. More
precisely, the mask of the composite clip is then the composite
of the masks of the different clips. Only use `transparent=True`
when you intend to use your composite clip as part of another
composite clip and you care about its transparency.
bg_color
Color for the unmasked and unfilled regions. Set to None for these
regions to be transparent (will be slower).
If all clips with a fps attribute have the same fps, it becomes the fps of
the result.
"""

def __init__(self, clips, size=None, bg_color=None, transparent=False,
def __init__(self, clips, size=None, bg_color=None, use_bgclip=False,
ismask=False):

if size is None:
size = clips[0].size

if bg_color is None:
bg_color = 0.0 if ismask else (0, 0, 0)

if use_bgclip and (clips[0].mask is None):
transparent = False
else:
transparent = (bg_color is None)

fps_list = list(set([c.fps for c in clips if hasattr(c,'fps')]))
if len(fps_list)==1:
self.fps= fps_list[0]

VideoClip.__init__(self)

self.size = size
self.ismask = ismask
self.clips = clips
self.transparent = transparent
self.bg_color = bg_color
self.bg = ColorClip(size, col=self.bg_color).get_frame(0)

if use_bgclip:
self.bg = clips[0]
self.clips = clips[1:]
else:
self.clips = clips
self.bg = ColorClip(size, col=self.bg_color)



# compute duration
ends = [c.end for c in self.clips]
Expand All @@ -70,19 +83,19 @@ def __init__(self, clips, size=None, bg_color=None, transparent=False,
if len(audioclips) > 0:
self.audio = CompositeAudioClip(audioclips)

# compute mask
# compute mask if necessary
if transparent:
maskclips = [c.mask.set_pos(c.pos) for c in self.clips
if c.mask is not None]
if maskclips != []:
self.mask = CompositeVideoClip(maskclips,self.size,
transparent=False, ismask=True)
self.mask = CompositeVideoClip(maskclips,self.size, ismask=True,
bg_color=0)

def make_frame(t):
""" The clips playing at time `t` are blitted over one
another. """

f = self.bg
f = self.bg.get_frame(t)
for c in self.playing_clips(t):
f = c.blit_on(f, t)
return f
Expand All @@ -97,11 +110,28 @@ def playing_clips(self, t=0):


def clips_array(array, rows_widths=None, cols_widths=None,
transparent = False, bg_color = None):
bg_color = None):

"""
rows_widths
widths of the different rows in pixels. If None, is set automatically.
cols_widths
widths of the different colums in pixels. If None, is set automatically.
cols_widths
bg_color
Fill color for the masked and unfilled regions. Set to None for these
regions to be transparent (will be slower).
"""

array = np.array(array)
sizes_array = np.array([[c.size for c in line] for line in array])

# find row width and col_widths automatically if not provided
if rows_widths is None:
rows_widths = sizes_array[:,:,1].max(axis=1)
if cols_widths is None:
Expand All @@ -117,14 +147,12 @@ def clips_array(array, rows_widths=None, cols_widths=None,
if (w < cw) or (h < rw):
clip = (CompositeVideoClip([clip.set_pos('center')],
size = (cw,rw),
transparent = transparent,
bg_color = bg_color).
set_duration(clip.duration))

array[i,j] = clip.set_pos((x,y))

return CompositeVideoClip(array.flatten(), size = (xx[-1],yy[-1]),
transparent=transparent,
bg_color = bg_color)


99 changes: 53 additions & 46 deletions moviepy/video/compositing/concatenate.py
Original file line number Diff line number Diff line change
@@ -1,73 +1,74 @@
import numpy as np

from moviepy.tools import deprecated_version_of
from moviepy.video.VideoClip import VideoClip
from moviepy.video.VideoClip import VideoClip, ColorClip
from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
from moviepy.audio.AudioClip import CompositeAudioClip

from moviepy.video.compositing.on_color import on_color

def concatenate_videoclips(clipslist, method="chain", transition=None, bg_color=(0, 0, 0),
transparent=False, ismask=False, padding = 0):
def concatenate_videoclips(clips, method="chain", transition=None,
bg_color=None, ismask=False, padding = 0):
""" Concatenates several video clips
Returns a video clip made by clip by concatenating several video clips.
(Concatenated means that they will be played one after another).
There are two methods: method="chain" will produce a clip that simply outputs
the frames of the succesive clips, without any correction if they are
not of the same size of anything.
With method="compose", if the clips do not have the same
resolution, the final resolution will be such that no clip has
to be resized.
As a consequence the final clip has the height of the highest
clip and the width of the widest clip of the list. All the
clips with smaller dimensions will appear centered. The border
will be transparent if mask=True, else it will be of the
color specified by ``bg_color``.
Returns a VideoClip instance if all clips have the same size and
there is no transition, else a composite clip.
There are two methods:
- method="chain": will produce a clip that simply outputs
the frames of the succesive clips, without any correction if they are
not of the same size of anything. If none of the clips have masks the
resulting clip has no mask, else the mask is a concatenation of masks
(using completely opaque for clips that don't have masks, obviously).
- method="compose", if the clips do not have the same
resolution, the final resolution will be such that no clip has
to be resized.
As a consequence the final clip has the height of the highest
clip and the width of the widest clip of the list. All the
clips with smaller dimensions will appear centered. The border
will be transparent if mask=True, else it will be of the
color specified by ``bg_color``.
If all clips with a fps attribute have the same fps, it becomes the fps of
the result.
Parameters
-----------
clipslist
clips
A list of video clips which must all have their ``duration``
attributes set.
method
"chain" or "compose": see above.
transition
A clip that will be played between each two clips of the list.
A clip that will be played between each two clips of the list.
bg_color
Color of the background, if any.
transparent
If True, the resulting clip's mask will be the concatenation of
the masks of the clips in the list. If the clips do not have the
same resolution, the border around the smaller clips will be
transparent.
Only for method='compose'. Color of the background.
Set to None for a transparent clip
padding
Duration during two consecutive clips. If negative, a clip will
play at the same time as the clip it follows. A non-null
padding automatically sets the method to `compose`.
Only for method='compose'. Duration during two consecutive clips.
Note that for negative padding, a clip will partly play at the same
time as the clip it follows (negative padding is cool for clips who fade
in on one another). A non-null padding automatically sets the method to
`compose`.
"""

if transition is not None:
l = [[v, transition] for v in clipslist[:-1]]
clipslist = reduce(lambda x, y: x + y, l) + [clipslist[-1]]
l = [[v, transition] for v in clips[:-1]]
clips = reduce(lambda x, y: x + y, l) + [clips[-1]]
transition = None


tt = np.cumsum([0] + [c.duration for c in clipslist])
tt = np.cumsum([0] + [c.duration for c in clips])

sizes = [v.size for v in clipslist]
sizes = [v.size for v in clips]


w = max([r[0] for r in sizes])
Expand All @@ -78,30 +79,36 @@ def concatenate_videoclips(clipslist, method="chain", transition=None, bg_color=
if method == "chain":
def make_frame(t):
i = max([i for i, e in enumerate(tt) if e <= t])
return clipslist[i].get_frame(t - tt[i])
return clips[i].get_frame(t - tt[i])

result = VideoClip(ismask = ismask, make_frame = make_frame)
if transparent:
clips_w_masks = [(c.add_mask() if c.mask is None else c) for c in clips]
masks = [c.mask for c in clips_w_masks]
result.mask = concatenate_videoclips(masks, method="chain", ismask=True)
if any([c.mask is not None for c in clips]):
masks = [c.mask if (c.mask is not None) else
ColorClip([1,1], col=1, ismask=True, duration=c.duration)
#ColorClip(c.size, col=1, ismask=True).set_duration(c.duration)
for c in clips]
result.mask = concatenate_videoclips(masks, method="chain", ismask=True)


elif method == "compose":
result = CompositeVideoClip( [c.set_start(t).set_pos('center')
for (c, t) in zip(clipslist, tt)],
size = (w, h), bg_color=bg_color, ismask=ismask,
transparent=transparent )
for (c, t) in zip(clips, tt)],
size = (w, h), bg_color=bg_color, ismask=ismask)

result.tt = tt
result.clipslist = clipslist
result.clips = clips
result.start_times = tt[:-1]
result.start, result.duration, result.end = 0, tt[-1] , tt[-1]

audio_t = [(c.audio,t) for c,t in zip(clipslist,tt) if c.audio is not None]
audio_t = [(c.audio,t) for c,t in zip(clips,tt) if c.audio is not None]
if len(audio_t)>0:
result.audio = CompositeAudioClip([a.set_start(t)
for a,t in audio_t])

fps_list = list(set([c.fps for c in clips if hasattr(c,'fps')]))
if len(fps_list)==1:
result.fps= fps_list[0]

return result


Expand Down
Loading

0 comments on commit b2bf715

Please sign in to comment.