import openshot import os import re import time import pysrt import shutil from datetime import datetime from PIL import Image,ImageDraw,ImageFont import gspread import pandas as pd import csv from oauth2client.service_account import ServiceAccountCredentials def auth_gss_client(path, scopes): credentials = ServiceAccountCredentials.from_json_keyfile_name(path, scopes) return gspread.authorize(credentials) auth_json_path = 'noted-tesla-348011-74f70c9caeda.json' #由剛剛建立出的憑證,放置相同目錄以供引入 gss_scopes = ['https://spreadsheets.google.com/feeds'] #我們想要取用的範圍 gss_client = auth_gss_client(auth_json_path, gss_scopes) #呼叫我們的函式 #從剛剛建立的sheet,把網址中 https://docs.google.com/spreadsheets/d/〔key〕/edit 的 〔key〕的值代入 spreadsheet_key_path = '1LU5O8-oAotIFGPI9STPbElO0NHGA6eynuv9sYz81aOw' wks = gss_client.open_by_key(spreadsheet_key_path).sheet1 def srt_to_sheet(srt_file): subs = pysrt.open(srt_file) wks.clear() index = 0 for context in subs: index = context.index cell_list = wks.range('A1:C'+str(index)) number = 0 for context in subs: #print(context.start.minutes*60+context.start.seconds+ 0.001*context.start.milliseconds) index = context.index end = context.end start = context.start #print('A'+str(index)) cell_list[number].value = str(start) cell_list[number+1].value = str(end) cell_list[number+2].value = str(context.text) number = number+3 wks.update_cells(cell_list) def sheet_to_text(text_font): ck_anchor = cKey(0, 255, 0, 320) text_form = [] for context in wks.get_all_values(): #print(context.start.minutes*60+context.start.seconds+ 0.001*context.start.milliseconds) start = datetime.strptime(context[0], "%H:%M:%S,%f") end = datetime.strptime(context[1], "%H:%M:%S,%f") - datetime.strptime(context[0], "%H:%M:%S,%f") end_timeStamp=end.seconds+0.000001*end.microseconds start_timeStamp=start.minute*60+start.second+ 0.000001*start.microsecond text_form.append({'text':context[2],'start':start_timeStamp,'end':end_timeStamp,'size':36,'font':text_font}) #print({'text':context[2],'start':start_timeStamp,'end':end_timeStamp,'size':36,'font':text_font}) def cKey(r,g,b,fuzz): col=openshot.Color() col.red=openshot.Keyframe(r) col.green=openshot.Keyframe(g) col.blue=openshot.Keyframe(b) return openshot.ChromaKey(col, openshot.Keyframe(fuzz)) def video_writer_init(path): w = openshot.FFmpegWriter(path) w.SetAudioOptions(True, "aac", 44100, 2, openshot.LAYOUT_STEREO, 3000000) w.SetVideoOptions(True, "libx264", openshot.Fraction(30000, 1000), 1280, 720, openshot.Fraction(1, 1), False, False, 3000000) return w def video_photo_clip(video=None,layer=None, position=None, end=None ,scale_x=1,scale_y=1,location_x=0,location_y=0,ck=None,audio=True): clip = openshot.Clip(video) clip.Layer(layer) clip.Position(position) clip.End(end) clip.scale_x=openshot.Keyframe(scale_x) clip.scale_y=openshot.Keyframe(scale_y) clip.location_x=openshot.Keyframe(location_x) clip.location_y=openshot.Keyframe(location_y) if ck!=None: clip.AddEffect(ck) if audio==True: clip.has_audio=openshot.Keyframe(1) else: clip.has_audio=openshot.Keyframe(0) return clip def trim_punctuation(s): pat_block = u'[^\u4e00-\u9fff0-9a-zA-Z]+' pattern = u'([0-9]+{0}[0-9]+)|{0}'.format(pat_block) res = re.sub(pattern, lambda x: x.group(1) if x.group(1) else u" " ,s) return res #文字轉圖片 def txt2image(content, save_target,lang='zh',size=26,fon="font/DFT_B7.ttc"): unicode_text = trim_punctuation(content) font = '' if lang=='zh': font = ImageFont.truetype(font=fon, size=size) else : font = ImageFont.truetype(font="font/arial.ttf", size=size) W, H = (1280,500) canvas = Image.new('RGB', (W, H), "#00FF00") draw = ImageDraw.Draw(canvas) text= content if "\n" in text: w, h = draw.textsize(text.split("\n")[0],font = font) #draw.text(((W-w)/2,0), text[0:18],'black', font) text_border(draw,(W-w)/2,0,text.split("\n")[0],font,'black','white') w, h = draw.textsize(text.split("\n")[1],font = font) #draw.text(((W-w)/2,h+2), text[18:],'black', font) text_border(draw,(W-w)/2,h+2,text.split("\n")[1],font,'black','white') else: w, h = draw.textsize(content,font = font) #draw.text(((W-w)/2,0), text,'black', font) text_border(draw,(W-w)/2,0,text,font,'black','white') canvas.save(save_target, "PNG") def text_border(draw,x,y,text,font,shadowcolor,fillcolor): draw.text((x-1, y), text, font=font, fill=shadowcolor) draw.text((x+1, y), text, font=font, fill=shadowcolor) draw.text((x, y-1), text, font=font, fill=shadowcolor) draw.text((x, y+1), text, font=font, fill=shadowcolor) draw.text((x-1, y+1), text, font=font, fill=shadowcolor) draw.text((x+1, y-1), text, font=font, fill=shadowcolor) draw.text((x-1, y-1), text, font=font, fill=shadowcolor) draw.text((x+1, y+1), text, font=font, fill=shadowcolor) # thicker border draw.text((x-2, y-2), text, font=font, fill=shadowcolor) draw.text((x+2, y-2), text, font=font, fill=shadowcolor) draw.text((x-2, y+2), text, font=font, fill=shadowcolor) draw.text((x+2, y+2), text, font=font, fill=shadowcolor) # now draw the text over it draw.text((x, y), text, font=font, fill=fillcolor) def srt_to_csv(srt_file): subs = pysrt.open(srt_file) csv_file = srt_file.split('.')[0] + ".csv" with open(csv_file, 'w', newline='') as csvfile: # 建立 CSV 檔寫入器 writer = csv.writer(csvfile) for context in subs: writer.writerow([context.index, context.start,context.end, context.text]) return csv_file def csv_to_text(csv_file,text_font): text_form = [] with open(csv_file, newline='') as csvfile: # 讀取 CSV 檔案內容 rows = csv.reader(csvfile) # 以迴圈輸出每一列 for row in rows: start = datetime.strptime(row[1], "%H:%M:%S,%f") end = datetime.strptime(row[2], "%H:%M:%S,%f") - datetime.strptime(row[1], "%H:%M:%S,%f") end_timeStamp=end.seconds+0.000001*end.microseconds start_timeStamp=start.minute*60+start.second+ 0.000001*start.microsecond text_form.append({'text':row[3],'start':start_timeStamp,'end':end_timeStamp,'size':36,'font':text_font}) return text_form def text_to_short_vedio(mp4_file = "input/example/test3.mp4",sound_file = None ,vedio_time = 30,output_filename="output/demo.mp4",text_font = "font/DFT_B7.ttc",mode = "csv",correct = False): t = openshot.Timeline(1280, 720, openshot.Fraction(30000, 1000), 44100, 2, openshot.LAYOUT_STEREO) t.Open() # 去背參數 ck = cKey(0, 254, 0, 270) ck_anchor = cKey(0, 255, 0, 320) anchor = openshot.FFmpegReader(mp4_file) anchor.Open() anchor_clip = video_photo_clip(video=anchor,layer=2,scale_x=1,scale_y=1, location_x=0,location_y=0,position=0, end=vedio_time,audio=True) t.AddClip(anchor_clip) anchor.Close() number = 0 sound_srt_file = "" text_form = [] if sound_file==None: if mode!= "google": sound_file = mp4_file correct = False if ".csv" in sound_file : correct = True mode = "csv" #音檔自動產生srt(逐字稿) if not correct: # 未修正過的、需要產生SRT檔 cmd = "autosub -S zh-TW -D zh-TW " + sound_file os.system(cmd) sound_srt_file = sound_file.split('.')[0] + ".srt" if mode == "google" : srt_to_sheet(sound_srt_file) text_form = sheet_to_text(text_font) elif mode == "csv" : csv_file = srt_to_csv(sound_srt_file) text_form = csv_to_text(csv_file,text_font) else: if ".srt" in sound_file: sound_srt_file = sound_file if mode == "google" : srt_to_sheet(sound_srt_file) text_form = sheet_to_text(text_font) elif mode == "csv" : csv_file = srt_to_csv(sound_srt_file) text_form = csv_to_text(csv_file,text_font) else: if mode == "google" : text_form = sheet_to_text(text_font) elif mode == "csv" : csv_file = sound_file text_form = csv_to_text(csv_file,text_font) #產生字幕 try: number = 0 for text_tmp in text_form: file_name = "tmp/save_target_" + str(number) + ".png" txt2image(text_tmp['text'], file_name,lang='zh',size = text_tmp['size'],fon = text_tmp['font']) exec('text_anchor_{} = openshot.QtImageReader("tmp/save_target_{}.png")'.format(number,number)) exec('text_anchor_{}.Open()'.format(number)) exec('text_anchor_{}.Open()'.format(number)) exec('text_anchor_clip_{} = video_photo_clip(video=text_anchor_{},layer=4,scale_x=1,scale_y=1,\ location_x=0,location_y=0.67,position=text_tmp["start"], end=text_tmp["end"],ck=ck_anchor,audio=True)'.format(number,number)) exec('t.AddClip(text_anchor_clip_{})'.format(number)) exec('text_anchor_{}.Close()'.format(number)) number = number+1 except: print("無法開啟srt檔案(字幕產生失敗)") w = video_writer_init(output_filename) w.Open() frames = int(t.info.fps)*int(vedio_time) for n in range(frames): f=t.GetFrame(n) w.WriteFrame(f) t.Close() w.Close() #刪除暫存檔案 shutil.rmtree('tmp') os.mkdir('tmp') if __name__ == '__main__': #text_to_short_vedio(mp4_file = "input/example/導盲犬_投影片2.mp4", #sound_file ='input/example/導盲犬_投影片2.srt',vedio_time =110,text_font ="font/DFT_R7.ttc") file = srt_to_csv('input/example/導盲犬_投影片2.srt') text = csv_to_text(file,"font/DFT_R7.ttc") print(text)