Showing
8 changed files
with
151 additions
and
91 deletions
| ... | @@ -126,8 +126,8 @@ class AdminMakeVideoController extends AdminController | ... | @@ -126,8 +126,8 @@ class AdminMakeVideoController extends AdminController |
| 126 | ->title('一言诗词库') | 126 | ->title('一言诗词库') |
| 127 | ->from(PoemTable2::make()) | 127 | ->from(PoemTable2::make()) |
| 128 | ->model(OnePoem2::class,'id','title'); | 128 | ->model(OnePoem2::class,'id','title'); |
| 129 | - $form->textarea('feel','有感'); | 129 | + $form->textarea('feel','有感')->default('读此一言,仿佛身临其境!'); |
| 130 | - $form->text('weather','天气'); | 130 | + $form->text('weather','天气')->default('多云'); |
| 131 | $form->text('huangli','黄历')->default('宜'); | 131 | $form->text('huangli','黄历')->default('宜'); |
| 132 | 132 | ||
| 133 | $form->radio('thumbnail','封面') | 133 | $form->radio('thumbnail','封面') | ... | ... |
| ... | @@ -120,32 +120,27 @@ class VideoTempController extends AdminController | ... | @@ -120,32 +120,27 @@ class VideoTempController extends AdminController |
| 120 | 'date' => '日期组件', | 120 | 'date' => '日期组件', |
| 121 | 'feel' => '临境有感组件', | 121 | 'feel' => '临境有感组件', |
| 122 | ]); | 122 | ]); |
| 123 | - $form->select('position','组件位置')->options(VideoTemp::POSITION_OPTIONS); | 123 | + $form->select('position','组件位置')->options(VideoTemp::POSITION_OPTIONS)->addElementClass('position'); |
| 124 | + | ||
| 125 | + $form->selectTable('font_file','字体') | ||
| 126 | + ->title('字体选择') | ||
| 127 | + ->from(FontTable::make()) | ||
| 128 | + ->model(Font::class,'file','name'); | ||
| 129 | + $form->number('font_size', '字号')->default(24)->min(12); | ||
| 130 | + $form->color('text_color', '字体颜色')->default('#f5f5f5')->addElementClass('text_color'); | ||
| 124 | 131 | ||
| 125 | $form->radio('draw', '文字效果') | 132 | $form->radio('draw', '文字效果') |
| 126 | ->options(['fade'=>'淡入淡出', 'fix'=>'固定显示'])->default('fade') | 133 | ->options(['fade'=>'淡入淡出', 'fix'=>'固定显示'])->default('fade') |
| 127 | ->when('fade',function (Form\NestedForm $form){ | 134 | ->when('fade',function (Form\NestedForm $form){ |
| 128 | $form->number('fade_time', 'fade时间')->default(1500); | 135 | $form->number('fade_time', 'fade时间')->default(1500); |
| 129 | - $form->selectTable('font_file','字体') | ||
| 130 | - ->title('字体选择') | ||
| 131 | - ->from(FontTable::make()) | ||
| 132 | - ->model(Font::class,'file','name'); | ||
| 133 | - $form->number('font_size', '字号')->default(12)->min(12); | ||
| 134 | - $form->color('text_color', '字体颜色')->default('#f5f5f5')->addElementClass('text_color'); | ||
| 135 | }) | 136 | }) |
| 136 | ->when('fix',function (Form\NestedForm $form){ | 137 | ->when('fix',function (Form\NestedForm $form){ |
| 137 | - $form->number('text_bg_box', '背景厚度')->default(0) | ||
| 138 | - ->addElementClass('text_bg_box')->help('设置背景块边缘厚度(用于在背景块边缘用背景色填充一圈),默认为0'); | ||
| 139 | $form->color('text_bg_color', '背景色')->default('#5c6bc6')->addElementClass('text_bg_color'); | 138 | $form->color('text_bg_color', '背景色')->default('#5c6bc6')->addElementClass('text_bg_color'); |
| 140 | - $form->selectTable('font_file','字体') | ||
| 141 | - ->title('字体选择') | ||
| 142 | - ->from(FontTable::make()) | ||
| 143 | - ->model(Font::class,'file','name'); | ||
| 144 | - $form->number('font_size', '字号')->default(12)->min(12); | ||
| 145 | - $form->color('text_color', '字体颜色')->default('#f5f5f5')->addElementClass('text_color'); | ||
| 146 | $form->number('opacity', '透明度')->min(0)->max(100) | 139 | $form->number('opacity', '透明度')->min(0)->max(100) |
| 147 | ->addElementClass('opacity')->default(100) | 140 | ->addElementClass('opacity')->default(100) |
| 148 | ->help('范围为0-100,100表示不透明,0表示完全透明'); | 141 | ->help('范围为0-100,100表示不透明,0表示完全透明'); |
| 142 | + $form->number('text_bg_box', '背景厚度')->default(0) | ||
| 143 | + ->addElementClass('text_bg_box')->help('设置背景块边缘厚度(用于在背景块边缘用背景色填充一圈),默认为0'); | ||
| 149 | }); | 144 | }); |
| 150 | }); | 145 | }); |
| 151 | 146 | ... | ... |
| ... | @@ -24,7 +24,7 @@ class TemplateTable extends LazyRenderable | ... | @@ -24,7 +24,7 @@ class TemplateTable extends LazyRenderable |
| 24 | $grid->column('','组件信息') | 24 | $grid->column('','组件信息') |
| 25 | ->display('展开') | 25 | ->display('展开') |
| 26 | ->expand(function (){ | 26 | ->expand(function (){ |
| 27 | - $th = ['id','模板id','名称','位置','字号']; | 27 | + $th = ['id','模板id','名称','位置','字号','文字颜色','文字效果','fade时间','背景色','透明度','背景厚度']; |
| 28 | return Table::make($th, $this->componentsTable->toArray())->withBorder(); | 28 | return Table::make($th, $this->componentsTable->toArray())->withBorder(); |
| 29 | }); | 29 | }); |
| 30 | 30 | ... | ... |
| ... | @@ -63,11 +63,11 @@ class AdminMakeImmerse implements ShouldQueue | ... | @@ -63,11 +63,11 @@ class AdminMakeImmerse implements ShouldQueue |
| 63 | 63 | ||
| 64 | // 判断双轨 没有则制作空轨 | 64 | // 判断双轨 没有则制作空轨 |
| 65 | $is_bgm = $this->adminMakeVideo->temp->bg_music == 1; //是否手动上传背景音 | 65 | $is_bgm = $this->adminMakeVideo->temp->bg_music == 1; //是否手动上传背景音 |
| 66 | + $bgm = $this->getAbsolutePath($this->adminMakeVideo->temp->bgm_url); | ||
| 66 | if ($this->media_info['format']['nb_streams'] >= 2) { /** 音频视频轨都有 */ | 67 | if ($this->media_info['format']['nb_streams'] >= 2) { /** 音频视频轨都有 */ |
| 67 | if ($is_bgm) { | 68 | if ($is_bgm) { |
| 68 | // 有背景音 融合 | 69 | // 有背景音 融合 |
| 69 | $audio = $this->getAbsolutePath($this->getTempPath('.mp3','audio')); | 70 | $audio = $this->getAbsolutePath($this->getTempPath('.mp3','audio')); |
| 70 | - $bgm = $this->getAbsolutePath($this->adminMakeVideo->temp->bgm_url); | ||
| 71 | $cmd = $this->ffmpeg . | 71 | $cmd = $this->ffmpeg . |
| 72 | ' -y -i ' . escapeshellarg($file) . | 72 | ' -y -i ' . escapeshellarg($file) . |
| 73 | ' -y -i ' . escapeshellarg($bgm) . | 73 | ' -y -i ' . escapeshellarg($bgm) . |
| ... | @@ -93,7 +93,6 @@ class AdminMakeImmerse implements ShouldQueue | ... | @@ -93,7 +93,6 @@ class AdminMakeImmerse implements ShouldQueue |
| 93 | if ($is_bgm) { | 93 | if ($is_bgm) { |
| 94 | // 有背景音 融合 | 94 | // 有背景音 融合 |
| 95 | $audio_empty = $audio; | 95 | $audio_empty = $audio; |
| 96 | - $bgm = $this->getAbsolutePath($this->adminMakeVideo->temp->bgm_url); | ||
| 97 | $audio = $this->getAbsolutePath($this->getTempPath('.mp3','audio')); | 96 | $audio = $this->getAbsolutePath($this->getTempPath('.mp3','audio')); |
| 98 | $cmd = $this->ffmpeg . | 97 | $cmd = $this->ffmpeg . |
| 99 | ' -y -i ' . escapeshellarg($audio_empty) . | 98 | ' -y -i ' . escapeshellarg($audio_empty) . |
| ... | @@ -150,7 +149,8 @@ class AdminMakeImmerse implements ShouldQueue | ... | @@ -150,7 +149,8 @@ class AdminMakeImmerse implements ShouldQueue |
| 150 | if (!$this->execCmd($cmd)) return ; | 149 | if (!$this->execCmd($cmd)) return ; |
| 151 | 150 | ||
| 152 | // 分析视频 入库 | 151 | // 分析视频 入库 |
| 153 | - $video_info = $this->mediainfo($this->getAbsolutePath($output)); | 152 | + $video_info = $this->mediaInfo($this->getAbsolutePath($output)); |
| 153 | + | ||
| 154 | Immerse::query()->create([ | 154 | Immerse::query()->create([ |
| 155 | 'user_id' => 1, | 155 | 'user_id' => 1, |
| 156 | 'title' => '', | 156 | 'title' => '', |
| ... | @@ -184,8 +184,6 @@ class AdminMakeImmerse implements ShouldQueue | ... | @@ -184,8 +184,6 @@ class AdminMakeImmerse implements ShouldQueue |
| 184 | 184 | ||
| 185 | public function mediaInfo($file) | 185 | public function mediaInfo($file) |
| 186 | { | 186 | { |
| 187 | - if ($this->media_info) return $this->media_info; | ||
| 188 | - | ||
| 189 | $cmd = $this->ffprobe . ' -v quiet -print_format json -show_format -show_streams ' . escapeshellarg($file); | 187 | $cmd = $this->ffprobe . ' -v quiet -print_format json -show_format -show_streams ' . escapeshellarg($file); |
| 190 | $output = $this->execCmd($cmd); | 188 | $output = $this->execCmd($cmd); |
| 191 | $data = json_decode($output, true); | 189 | $data = json_decode($output, true); |
| ... | @@ -199,6 +197,7 @@ class AdminMakeImmerse implements ShouldQueue | ... | @@ -199,6 +197,7 @@ class AdminMakeImmerse implements ShouldQueue |
| 199 | 197 | ||
| 200 | public function execCmd($cmd) | 198 | public function execCmd($cmd) |
| 201 | { | 199 | { |
| 200 | + echo $cmd . "\n". "\n"; | ||
| 202 | return shell_exec("{$cmd} 2>&1"); | 201 | return shell_exec("{$cmd} 2>&1"); |
| 203 | } | 202 | } |
| 204 | 203 | ... | ... |
| ... | @@ -27,6 +27,8 @@ class UserMakeImmerse implements ShouldQueue | ... | @@ -27,6 +27,8 @@ class UserMakeImmerse implements ShouldQueue |
| 27 | 27 | ||
| 28 | protected $ffprobe; | 28 | protected $ffprobe; |
| 29 | 29 | ||
| 30 | + protected $media_info; | ||
| 31 | + | ||
| 30 | protected $output_width; | 32 | protected $output_width; |
| 31 | 33 | ||
| 32 | protected $output_height; | 34 | protected $output_height; |
| ... | @@ -66,9 +68,9 @@ class UserMakeImmerse implements ShouldQueue | ... | @@ -66,9 +68,9 @@ class UserMakeImmerse implements ShouldQueue |
| 66 | if ($this->immerse->type == 1){ | 68 | if ($this->immerse->type == 1){ |
| 67 | // 1. 分析用户上传音频 | 69 | // 1. 分析用户上传音频 |
| 68 | $upload_file = Storage::disk('public')->path($this->immerse->upload_file); | 70 | $upload_file = Storage::disk('public')->path($this->immerse->upload_file); |
| 69 | - $mediainfo = $this->mediainfo($upload_file); | 71 | + $this->media_info = $this->mediainfo($upload_file); |
| 70 | // 记录媒体信息时长 | 72 | // 记录媒体信息时长 |
| 71 | - $duration = $mediainfo['format']['duration'] ?: 0; | 73 | + $duration = $this->media_info['format']['duration'] ?: 0; |
| 72 | 74 | ||
| 73 | // $font = Storage::disk('public')->path('ffmpeg/arialuni.ttf'); | 75 | // $font = Storage::disk('public')->path('ffmpeg/arialuni.ttf'); |
| 74 | 76 | ||
| ... | @@ -118,7 +120,7 @@ class UserMakeImmerse implements ShouldQueue | ... | @@ -118,7 +120,7 @@ class UserMakeImmerse implements ShouldQueue |
| 118 | $origin_mediainfo = $this->mediainfo($origin_video_path); | 120 | $origin_mediainfo = $this->mediainfo($origin_video_path); |
| 119 | 121 | ||
| 120 | //用户录音超长,截取用户录音 | 122 | //用户录音超长,截取用户录音 |
| 121 | - if ($mediainfo['format']['duration'] > $origin_mediainfo['format']['duration']) { | 123 | + if ($this->media_info['format']['duration'] > $origin_mediainfo['format']['duration']) { |
| 122 | if ($this->immerse->bgm == '' || $this->immerse->bgm == null) { | 124 | if ($this->immerse->bgm == '' || $this->immerse->bgm == null) { |
| 123 | $audio = Storage::disk('public')->path($this->getTempPath('.mp3','audio')); | 125 | $audio = Storage::disk('public')->path($this->getTempPath('.mp3','audio')); |
| 124 | $cmd = $this->ffmpeg . ' -y ' . | 126 | $cmd = $this->ffmpeg . ' -y ' . |
| ... | @@ -173,7 +175,7 @@ class UserMakeImmerse implements ShouldQueue | ... | @@ -173,7 +175,7 @@ class UserMakeImmerse implements ShouldQueue |
| 173 | }else{ | 175 | }else{ |
| 174 | // 1. 分析用户上传视频 | 176 | // 1. 分析用户上传视频 |
| 175 | $upload_file = Storage::disk('public')->path($this->immerse->upload_file); | 177 | $upload_file = Storage::disk('public')->path($this->immerse->upload_file); |
| 176 | - $mediainfo = $this->mediainfo($upload_file); | 178 | + $this->media_info = $this->mediainfo($upload_file); |
| 177 | 179 | ||
| 178 | // 记录媒体信息时长 | 180 | // 记录媒体信息时长 |
| 179 | // $duration = $mediainfo['format']['duration'] ?: 0; | 181 | // $duration = $mediainfo['format']['duration'] ?: 0; |
| ... | @@ -208,7 +210,7 @@ class UserMakeImmerse implements ShouldQueue | ... | @@ -208,7 +210,7 @@ class UserMakeImmerse implements ShouldQueue |
| 208 | $watermark = Storage::disk('public')->path('images/LOGO_eng.png'); | 210 | $watermark = Storage::disk('public')->path('images/LOGO_eng.png'); |
| 209 | 211 | ||
| 210 | // 截取中间帧作为视频封面 | 212 | // 截取中间帧作为视频封面 |
| 211 | - $frame = ceil($mediainfo['streams'][0]['nb_frames'] / 2); | 213 | + $frame = ceil($this->media_info['streams'][0]['nb_frames'] / 2); |
| 212 | $thumbnail = Storage::disk('public')->path($this->getTempPath('.jpg','thumbnail')); | 214 | $thumbnail = Storage::disk('public')->path($this->getTempPath('.jpg','thumbnail')); |
| 213 | $cmd = $this->ffmpeg . ' -y ' . | 215 | $cmd = $this->ffmpeg . ' -y ' . |
| 214 | ' -i ' . escapeshellarg($upload_file) . | 216 | ' -i ' . escapeshellarg($upload_file) . |
| ... | @@ -490,83 +492,99 @@ class UserMakeImmerse implements ShouldQueue | ... | @@ -490,83 +492,99 @@ class UserMakeImmerse implements ShouldQueue |
| 490 | $components = $this->immerse->temp()->first()->components()->get(); | 492 | $components = $this->immerse->temp()->first()->components()->get(); |
| 491 | 493 | ||
| 492 | $drawtext = ''; | 494 | $drawtext = ''; |
| 493 | - | ||
| 494 | foreach ($components as $component) { | 495 | foreach ($components as $component) { |
| 495 | $text_color = $component->text_color ?? 'white'; | 496 | $text_color = $component->text_color ?? 'white'; |
| 496 | $text_bg_color = $component->text_bg_color ?? '0xd0cdcc'; | 497 | $text_bg_color = $component->text_bg_color ?? '0xd0cdcc'; |
| 497 | $opacity = $component->opacity ? $component->opacity / 100 : 0.5; | 498 | $opacity = $component->opacity ? $component->opacity / 100 : 0.5; |
| 498 | - $font_file = Storage::disk('public')->path($component->font_file ?? 'ffmpeg/arialuni.ttf'); | 499 | + $font_file = Storage::disk('public')->path($component->font_file); |
| 499 | $text_bg_box = $component->text_bg_box ?? 0; | 500 | $text_bg_box = $component->text_bg_box ?? 0; |
| 500 | - $fix_bounds = $component->fix_bounds == 1; | ||
| 501 | 501 | ||
| 502 | - switch ($component->name){ | ||
| 503 | - case 'every_poem': | ||
| 504 | - case 'one_poem': | ||
| 505 | - $content = $this->immerse->poem->content; | ||
| 506 | - $text_file = Storage::disk('public')->path($this->getTempPath('.txt','text')); | ||
| 507 | - file_put_contents($text_file, $content); | ||
| 508 | 502 | ||
| 509 | - $text_color = $component->text_color ?? 'white'; | 503 | + // 文字淡入淡出模式 |
| 510 | - $text_bg_color = $component->text_bg_color ?? '0xd0cdcc'; | 504 | + if ($component->draw == 'fade'){ |
| 511 | - $opacity = $component->opacity ? $component->opacity / 100 : '0.5'; | 505 | + $contents = []; // |
| 506 | + switch ($component->name){ | ||
| 507 | + case 'one_poem': | ||
| 508 | + foreach ($this->immerse->poem2->verses as $item) { | ||
| 509 | + if ($item->stanza != '') $contents[] = $item->stanza; | ||
| 510 | + } | ||
| 511 | + break; | ||
| 512 | + case 'one_poem_with_annotate': | ||
| 513 | + foreach ($this->immerse->poem2->verses as $item) { | ||
| 514 | + if ($item->stanza != '') $contents[] = $item->stanza; | ||
| 515 | + if ($item->annotate != '') $contents[] = $item->annotate; | ||
| 516 | + } | ||
| 517 | + break; | ||
| 518 | + case 'weather': | ||
| 519 | + $contents[] = $this->immerse->weather; | ||
| 520 | + break; | ||
| 521 | + case 'date': | ||
| 522 | + $contents[] = Carbon::now()->format('Y年m月d日H时'); | ||
| 523 | + break; | ||
| 524 | + case 'feel': | ||
| 525 | + $contents[] = $this->immerse->feel ?: '读此一言,仿佛身临其境。'; | ||
| 526 | + break; | ||
| 527 | + } | ||
| 512 | 528 | ||
| 513 | - $drawtext .= 'drawtext="'. | 529 | + $FID = $FOD = floatval($component->fade_time / 1000); |
| 514 | - 'fontfile=' . escapeshellarg($font_file) . ':' . | 530 | + $round = round($this->media_info['format']['duration'] / count($contents),1); |
| 515 | - 'textfile=' . escapeshellarg($text_file) . ':' . | 531 | + if ($round < 1) $round = 1; |
| 516 | - 'fontsize=' . $this->calcFontSize($component->font_size) . ':' . | 532 | + $sub_text = ''; |
| 517 | - 'fontcolor=' . $text_color . '@' . $opacity . ':' . | 533 | + foreach ($contents as $key => $content){ |
| 518 | - 'x=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][0]) . ':' . | 534 | + $DS = $key * $round; |
| 519 | - 'y=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][1]) . ':' . | 535 | + $DE = $DS + $round; |
| 520 | - 'fix_bounds='. $fix_bounds . ':' . | ||
| 521 | - 'box=1:boxborderw='. $text_bg_box . ':' . | ||
| 522 | - 'boxcolor=' . $text_bg_color . '@' . $opacity . '", '; | ||
| 523 | - break; | ||
| 524 | - case 'weather': | ||
| 525 | - $content = $this->immerse->weather; | ||
| 526 | $text_file = Storage::disk('public')->path($this->getTempPath('.txt','text')); | 536 | $text_file = Storage::disk('public')->path($this->getTempPath('.txt','text')); |
| 527 | file_put_contents($text_file, $content); | 537 | file_put_contents($text_file, $content); |
| 528 | - $drawtext .= 'drawtext="'. | 538 | + $sub_text .= 'drawtext="'. |
| 529 | 'fontfile=' . escapeshellarg($font_file) . ':' . | 539 | 'fontfile=' . escapeshellarg($font_file) . ':' . |
| 530 | 'textfile=' . escapeshellarg($text_file) . ':' . | 540 | 'textfile=' . escapeshellarg($text_file) . ':' . |
| 531 | 'fontsize=' . $this->calcFontSize($component->font_size) . ':' . | 541 | 'fontsize=' . $this->calcFontSize($component->font_size) . ':' . |
| 532 | - 'fontcolor=' . $text_color . '@' . $opacity . ':' . | 542 | + 'fontcolor_expr=' . escapeshellarg($text_color . '%{eif\\\\: clip(255*(1*between(t\\, ' . $DS . ' + ' . $FID . '\\, ' . $DE . ' - ' . $FOD . ') + ((t - ' . $DS . ')/' . $FID . ')*between(t\\, ' . $DS . '\\, ' . $DS . ' + ' . $FID . ') + (-(t - ' . $DE . ')/' . $FOD . ')*between(t\\, ' . $DE . ' - ' . $FOD . '\\, ' . $DE . '))\\, 0\\, 255) \\\\: x\\\\: 2 }') . ':' . |
| 533 | 'x=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][0]) . ':' . | 543 | 'x=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][0]) . ':' . |
| 534 | 'y=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][1]) . ':' . | 544 | 'y=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][1]) . ':' . |
| 535 | - 'fix_bounds='. $fix_bounds . ':' . | 545 | + '", '; |
| 536 | - 'box=1:boxborderw='. $text_bg_box . ':' . | 546 | + } |
| 537 | - 'boxcolor=' . $text_bg_color . '@' . $opacity . '", '; | ||
| 538 | 547 | ||
| 539 | - break; | 548 | + $drawtext .= $sub_text; |
| 540 | - case 'date': | 549 | + } |
| 541 | - $content = Carbon::now()->format('Y年m月d日H时'); | 550 | + |
| 542 | - $text_file = Storage::disk('public')->path($this->getTempPath('.txt','text')); | 551 | + // 文字固定模式 |
| 543 | - file_put_contents($text_file, $content); | 552 | + if ($component->draw == 'fix'){ |
| 544 | - $drawtext .= 'drawtext="'. | 553 | + $contents = []; // |
| 545 | - 'fontfile=' . escapeshellarg($font_file) . ':' . | 554 | + switch ($component->name){ |
| 546 | - 'textfile=' . escapeshellarg($text_file) . ':' . | 555 | + case 'one_poem_with_annotate': |
| 547 | - 'fontsize=' . $this->calcFontSize($component->font_size) . ':' . | 556 | + case 'one_poem': |
| 548 | - 'fontcolor=' . $text_color . '@' . $opacity . ':' . | 557 | + $stanzas = ''; |
| 549 | - 'x=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][0]) . ':' . | 558 | + foreach ($this->immerse->poem2->verses as $item) { |
| 550 | - 'y=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][1]) . ':' . | 559 | + if ($item->stanza != '') $stanzas = $item->stanza . "\n"; |
| 551 | - 'fix_bounds='. $fix_bounds . ':' . | 560 | + } |
| 552 | - 'box=1:boxborderw='. $text_bg_box . ':' . | 561 | + $contents[] = $stanzas; |
| 553 | - 'boxcolor=' . $text_bg_color . '@' . $opacity . '", '; | 562 | + break; |
| 554 | - break; | 563 | + case 'weather': |
| 555 | - case 'feel': | 564 | + $contents[] = $this->immerse->weather; |
| 556 | - $content = $this->immerse->content; | 565 | + break; |
| 566 | + case 'date': | ||
| 567 | + $contents[] = Carbon::now()->format('Y年m月d日H时'); | ||
| 568 | + break; | ||
| 569 | + case 'feel': | ||
| 570 | + $contents[] = $this->immerse->feel ?: '读此一言,仿佛身临其境。'; | ||
| 571 | + break; | ||
| 572 | + } | ||
| 573 | + $sub_text = ''; | ||
| 574 | + foreach ($contents as $key => $content){ | ||
| 557 | $text_file = Storage::disk('public')->path($this->getTempPath('.txt','text')); | 575 | $text_file = Storage::disk('public')->path($this->getTempPath('.txt','text')); |
| 558 | file_put_contents($text_file, $content); | 576 | file_put_contents($text_file, $content); |
| 559 | - $drawtext .= 'drawtext="'. | 577 | + $sub_text .= 'drawtext="'. |
| 560 | 'fontfile=' . escapeshellarg($font_file) . ':' . | 578 | 'fontfile=' . escapeshellarg($font_file) . ':' . |
| 561 | 'textfile=' . escapeshellarg($text_file) . ':' . | 579 | 'textfile=' . escapeshellarg($text_file) . ':' . |
| 562 | 'fontsize=' . $this->calcFontSize($component->font_size) . ':' . | 580 | 'fontsize=' . $this->calcFontSize($component->font_size) . ':' . |
| 563 | 'fontcolor=' . $text_color . '@' . $opacity . ':' . | 581 | 'fontcolor=' . $text_color . '@' . $opacity . ':' . |
| 564 | 'x=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][0]) . ':' . | 582 | 'x=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][0]) . ':' . |
| 565 | 'y=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][1]) . ':' . | 583 | 'y=' . escapeshellarg(VideoTemp::POSITION_FFMPEG[$component->position][1]) . ':' . |
| 566 | - 'fix_bounds='. $fix_bounds . ':' . | ||
| 567 | 'box=1:boxborderw='. $text_bg_box . ':' . | 584 | 'box=1:boxborderw='. $text_bg_box . ':' . |
| 568 | 'boxcolor=' . $text_bg_color . '@' . $opacity . '", '; | 585 | 'boxcolor=' . $text_bg_color . '@' . $opacity . '", '; |
| 569 | - break; | 586 | + } |
| 587 | + $drawtext .= $sub_text; | ||
| 570 | } | 588 | } |
| 571 | } | 589 | } |
| 572 | 590 | ... | ... |
| ... | @@ -58,6 +58,11 @@ class Immerse extends Model | ... | @@ -58,6 +58,11 @@ class Immerse extends Model |
| 58 | return $this->hasOne(OnePoem::class,'id','poem_id'); | 58 | return $this->hasOne(OnePoem::class,'id','poem_id'); |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | + public function poem2() | ||
| 62 | + { | ||
| 63 | + return $this->hasOne(OnePoem2::class,'id','poem_id'); | ||
| 64 | + } | ||
| 65 | + | ||
| 61 | public function temp() | 66 | public function temp() |
| 62 | { | 67 | { |
| 63 | return $this->hasOne(VideoTemp::class,'id','temp_id'); | 68 | return $this->hasOne(VideoTemp::class,'id','temp_id'); | ... | ... |
| ... | @@ -34,7 +34,8 @@ class VideoTemp extends Model | ... | @@ -34,7 +34,8 @@ class VideoTemp extends Model |
| 34 | public function componentsTable() | 34 | public function componentsTable() |
| 35 | { | 35 | { |
| 36 | return $this->hasMany('App\Models\Component', 'temp_id') | 36 | return $this->hasMany('App\Models\Component', 'temp_id') |
| 37 | - ->select(['id', 'temp_id', 'name', 'position', 'font_size', 'text_color', 'text_bg_color', 'text_bg_box','opacity']); | 37 | + ->select(['id', 'temp_id', 'name', 'position', 'font_size', 'text_color', 'draw', |
| 38 | + 'fade_time', 'text_bg_color', 'text_bg_box', 'opacity']); | ||
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | public function admin_make_video() | 41 | public function admin_make_video() | ... | ... |
| ... | @@ -40,7 +40,7 @@ | ... | @@ -40,7 +40,7 @@ |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | .poem-title { | 42 | .poem-title { |
| 43 | - font-size: 26px; | 43 | + font-size: 14px; |
| 44 | font-weight: bold; | 44 | font-weight: bold; |
| 45 | margin: 10px; | 45 | margin: 10px; |
| 46 | } | 46 | } |
| ... | @@ -51,7 +51,7 @@ | ... | @@ -51,7 +51,7 @@ |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | .poem-content { | 53 | .poem-content { |
| 54 | - font-size: 24px; | 54 | + font-size: 12px; |
| 55 | margin: 0; | 55 | margin: 0; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| ... | @@ -64,13 +64,13 @@ | ... | @@ -64,13 +64,13 @@ |
| 64 | <div class="text">模板</div> | 64 | <div class="text">模板</div> |
| 65 | <img src="{{asset('storage/images/mobile-head.png')}}" alt="" width="360" height="80"> | 65 | <img src="{{asset('storage/images/mobile-head.png')}}" alt="" width="360" height="80"> |
| 66 | <div class="bg-box"> | 66 | <div class="bg-box"> |
| 67 | - <img width="360" height="625" class="bg_img" style="display: none"> | 67 | + {{--<img width="360" height="625" class="bg_img" style="display: none">--}} |
| 68 | - <video width="360" height="625" id="bg_video" style="display: none"></video> | 68 | + {{--<video width="360" height="625" id="bg_video" style="display: none"></video>--}} |
| 69 | - <audio id="bg_audio" ></audio> | 69 | + {{--<audio id="bg_audio" ></audio>--}} |
| 70 | </div> | 70 | </div> |
| 71 | <div class="poem-block"> | 71 | <div class="poem-block"> |
| 72 | - <p class="poem-title">题破山寺后禅院</p> | 72 | + {{--<p class="poem-title">题破山寺后禅院</p>--}} |
| 73 | - <p class="poem-author">-- 常建</p> | 73 | + {{--<p class="poem-author">-- 常建</p>--}} |
| 74 | <p class="poem-content">清晨入古寺,初日照高林。</p> | 74 | <p class="poem-content">清晨入古寺,初日照高林。</p> |
| 75 | <p class="poem-content">曲径通幽处,禅房花木深。</p> | 75 | <p class="poem-content">曲径通幽处,禅房花木深。</p> |
| 76 | <p class="poem-content">山光悦鸟性,潭影空人心。</p> | 76 | <p class="poem-content">山光悦鸟性,潭影空人心。</p> |
| ... | @@ -86,20 +86,62 @@ | ... | @@ -86,20 +86,62 @@ |
| 86 | 86 | ||
| 87 | $(document).off('click', '.sync').on('click', '.sync', function () { | 87 | $(document).off('click', '.sync').on('click', '.sync', function () { |
| 88 | let ori_top = 80; | 88 | let ori_top = 80; |
| 89 | - let top = parseInt($('.field_top').val()) + ori_top; | 89 | + let top = 0 + ori_top; |
| 90 | - let left = $('.field_left').val(); | 90 | + let left = 0; |
| 91 | let font = $('.field_font_size').val(); | 91 | let font = $('.field_font_size').val(); |
| 92 | - let content_size = 12 + parseInt(font); | 92 | + let content_size = parseInt(font); |
| 93 | - let title_size = 14 + parseInt(font); | 93 | + let title_size = parseInt(font); |
| 94 | let text_color = $('.text_color').val() || 'whitesmoke'; | 94 | let text_color = $('.text_color').val() || 'whitesmoke'; |
| 95 | let text_bg_color = $('.text_bg_color').val() || '#5c6bc6'; | 95 | let text_bg_color = $('.text_bg_color').val() || '#5c6bc6'; |
| 96 | let opacity = parseInt($('.opacity').val()) / 100; | 96 | let opacity = parseInt($('.opacity').val()) / 100; |
| 97 | + let pos = $('.field_position').val(); | ||
| 97 | 98 | ||
| 98 | $('.poem-block').css('top', top + 'px').css('left', left + 'px') | 99 | $('.poem-block').css('top', top + 'px').css('left', left + 'px') |
| 99 | .css('background-color', text_bg_color).css('opacity', opacity); | 100 | .css('background-color', text_bg_color).css('opacity', opacity); |
| 100 | $('.poem-title').css('font-size', title_size + 'px').css('color', text_color); | 101 | $('.poem-title').css('font-size', title_size + 'px').css('color', text_color); |
| 101 | $('.poem-content').css('font-size', content_size + 'px').css('color', text_color); | 102 | $('.poem-content').css('font-size', content_size + 'px').css('color', text_color); |
| 102 | 103 | ||
| 104 | + let block_w = $('.poem-block').width(); | ||
| 105 | + let block_h = $('.poem-block').height(); | ||
| 106 | + switch (pos) { | ||
| 107 | + case 'topLeft': | ||
| 108 | + top = 0 + ori_top; | ||
| 109 | + left = 0; | ||
| 110 | + break; | ||
| 111 | + case 'topMiddle': | ||
| 112 | + top = 0 + ori_top; | ||
| 113 | + left = (360 - block_w) / 2; | ||
| 114 | + break; | ||
| 115 | + case 'topRight': | ||
| 116 | + top = 0 + ori_top; | ||
| 117 | + left = 360 - block_w; | ||
| 118 | + break; | ||
| 119 | + case 'midLeft': | ||
| 120 | + top = (640 - block_h) / 2 + ori_top; | ||
| 121 | + left = 0; | ||
| 122 | + break; | ||
| 123 | + case 'midMiddle': | ||
| 124 | + top = (640 - block_h) / 2 + ori_top; | ||
| 125 | + left = (360 - block_w) / 2; | ||
| 126 | + break; | ||
| 127 | + case 'midRight': | ||
| 128 | + top = (640 - block_h) / 2 + ori_top; | ||
| 129 | + left = 360 - block_w; | ||
| 130 | + break; | ||
| 131 | + case 'botLeft': | ||
| 132 | + top = 640 - block_h + ori_top; | ||
| 133 | + left = 0; | ||
| 134 | + break; | ||
| 135 | + case 'botMiddle': | ||
| 136 | + top = 640 - block_h + ori_top; | ||
| 137 | + left = (360 - block_w) / 2; | ||
| 138 | + break; | ||
| 139 | + case 'botRight': | ||
| 140 | + top = 640 - block_h + ori_top; | ||
| 141 | + left = 360 - block_w; | ||
| 142 | + break; | ||
| 143 | + } | ||
| 144 | + $('.poem-block').css('top', top + 'px').css('left', left + 'px') | ||
| 103 | 145 | ||
| 104 | let bg_img_url = $('.bg_img_url').find("input[type='hidden'][name='bg_url']").val(); | 146 | let bg_img_url = $('.bg_img_url').find("input[type='hidden'][name='bg_url']").val(); |
| 105 | if (bg_img_url !== '') { | 147 | if (bg_img_url !== '') { | ... | ... |
-
Please register or login to post a comment