You are on page 1of 2

import import import import

argparse ctypes io os

import vapoursynth as vs from PIL import Image, ImageFont, ImageDraw, ImageColor # Configuration # Full path to the ffms2 library PATH_TO_FFMS2_DLL = r'C:\ffms2-2.19\x64\ffms2.dll' # Below affects the OSD TEXT_COLOR = ImageColor.getrgb('yellow') FONT_SIZE = 18 OSD = '''Frame Number: {0} of {1} Picture Type: {2}'''

def main(source, frames=[], additional_text=[]): """Take some screenshots using vapoursynth Arguments: frames -- list of frame numbers additional_text -- self explanatory """ core = vs.get_core() core.std.LoadPlugin(path=PATH_TO_FFMS2_DLL) if not os.path.exists(source + '.ffindex'): print('Indexing {0}'.format(os.path.realpath(source))) print('This may take some time.') clip = core.ffms2.Source(source=source) # REQUIRES LIBASS # would be a good alternative to using PIL to draw text # clip = core.assvapour.Subtitle(clip, 'ASSVAPOUR') clip = core.resize.Spline(clip=clip, format=vs.RGB24) print(clip) for frame_num in frames: if frame_num >= clip.num_frames: print('ERROR:', frame_num, 'is out of bounds. Skipping.\n') continue frame = clip.get_frame(frame_num) print('Processing frame', frame_num) R = frame.get_read_ptr(0) G = frame.get_read_ptr(1) B = frame.get_read_ptr(2) r_data = ctypes.string_at(R.value, frame.width*frame.height) g_data = ctypes.string_at(G.value, frame.width*frame.height) b_data = ctypes.string_at(B.value, frame.width*frame.height) # TODO: Make this suck less data = bytearray(frame.width * frame.height * 3) for i in range(frame.width * frame.height): data[i*3] = r_data[i] data[i*3+1] = g_data[i] data[i*3+2] = b_data[i]

data = io.BytesIO(data) data = data.getvalue() image = Image.frombytes('RGB', (frame.width, frame.height), data) font = ImageFont.truetype('verdana.ttf', FONT_SIZE) draw = ImageDraw.Draw(image) x_offset = 8 draw_text(draw, x_offset, 0, OSD.format(frame_num, clip.num_frames, frame.props._PictType.decode()), font, TEXT_COLOR, 'black') for line, text in enumerate(additional_text): draw_text(draw, x_offset, FONT_SIZE + FONT_SIZE*line + 3*line, text, font, TEXT_COLOR, 'black') output = os.path.basename(source) output = os.path.splitext(output)[0] + '-{0}'.format(frame_num) + '.png' image.save(output) def draw_text(draw, x, y, text, font, fill, border): # thin border draw.text((x-1, y), text, border, font) draw.text((x+1, y), text, border, font) draw.text((x, y-1), text, border, font) draw.text((x, y+1), text, border, font) # thicker border draw.text((x-1, y-1), text, border, font) draw.text((x+1, y-1), text, border, font) draw.text((x-1, y+1), text, border, font) draw.text((x+1, y+1), text, border, font) # inner text draw.text((x,y), text, fill, font) if __name__ == '__main__': DESCRIPTION = """Take screenshots using vapoursynth""" parser = argparse.ArgumentParser(description=DESCRIPTION) parser.add_argument('-i', '--input', dest='input', required=True, help='video file from which to take screenshots') parser.add_argument('-f', '--frames', dest='frames', required=True, default='', help='comma separated list of frame numbers') parser.add_argument('--text', dest='text', required=False, default="", help='Additional text to be written after the OSD, separate lines with \\n') args = parser.parse_args() source frames frames text = = args.input = args.frames.split(',') = [ int(frame) for frame in frames ] args.text.split('\\n')

main(source, frames, text)

You might also like