bilibili 탄막 회전 ass 프로그램 제작 방향 및 과정
xml 파일 을 캡 처 하 는 작업 은 더 이상 말 하지 않 습 니 다.간단 한 일 입 니 다.재생 페이지 에서 원본 파일 을 보면 xml 파일 의 주 소 를 확인 하여 캡 처 할 수 있 습 니 다.
본 고 는 주로 xml 내의 탄막 이 자막 으로 돌아 가 는 과정 을 다 루 고 있다.
xml 파일 의 시작 부분 에 있 는 칠 칠 팔 팔 팔 팔 을 제외 하고 탄막 주 체 는 다음 과 같 습 니 다.
<d p="51.593,5,25,16711680,1408852480,0,7fa769b4,576008622"> up !</d>
<d p="10.286,1,25,16777215,1408852600,0,a3af4d0d,576011065"> ?</d>
<d p="12.65,1,25,16777215,1408852761,0,24570b5a,576014281"> !</d>
<d p="19.033,1,25,16777215,1408852789,0,cb20d1c7,576014847"> !!!</d>
<d p="66.991,1,25,16777215,1408852886,0,a78e484d,576016806"> </d>
만약 그것 이 탄막 의 각종 속성 을 나 누 어 표시 한다 면 나 는 encoding/xml 패키지 로 디 코딩 을 할 것 이다.그러나 가장귀 가 탄막 의 속성 을 모두 p 안에 넣 었 기 때문에 나 는 정규 표현 식 을 사용 하여 추출 한 것 이다.
。 ,p , , , 。
1 25 ;
16777215, ( FFFFFF);
1408852480, , unix , (d), :d/86400/365.2425+1970, 2014.6。 unix 。 。
0, , , 0, 。
7fa769b4, ID, xml , , hash 4 。
576008622, , , ID 。
사후에 다시 한 번 확인 해 보 니 과연 1 은 탄막 의 유형(오른쪽 에서 왼쪽으로 이동 하 는 구나,아래 나 위 에 나타 나 는 구나...),25 는 글씨체 크기,167777125 는 글씨체 색 이다.그래서 우 리 는 모든 탄막 의 시간,유형,크기,색깔,텍스트 만 포착 하면 된다.
정규 표현 식:
<d\sp="([\d\.]+),([145]),(\d+),(\d+),\d+,\d+,\w+,\d+">([^<>]+?)</d>
탄막 을 포획 하 는 것 은 매우 간단 하 며,관건 은 탄막 을 자막 으로 배열 하 는 알고리즘 이다.이 알고리즘 에 대하 여 나 는 아버지의 엉망진창 인 알고리즘 을 만 들 었 는데 고정 이동 속도,최소 중첩 의 배열 원칙 을 채택 했다.
유동 탄막 에 대해 서 는 다음 줄 의 위 치 를 선택 하 는 경향 이 있 으 며,겹 칠 경우 다음 줄(최소 줄 이 맨 위 줄 로 순환)을 선택 하고,겹 치지 않 는 줄 이 없 으 면 겹 치지 않 는 텍스트 가 가장 적은 줄 을 선택 합 니 다.
위 현 은/아래 현 은의 고정 탄막 에 대해 위/아래 에 가장 가 깝 고 겹 치지 않 는 줄 을 선택 합 니 다.겹 치지 않 는 줄 이 없 으 면 겹 치 는 시간 이 가장 짧 은 줄 을 선택 하고 중간 에 자막 을 넣는다.
기본 글꼴 마이크로소프트 검은색,기본 크기 25,기본 흰색 검은색;기본 값 으로 전체 화면 을 차지 합 니 다.모두 12 줄 입 니 다.기본 화면 크기 640 x 360.
이렇게 하면 주로 ass 자막 의 효과 가 원시 탄막 의 효과 에 더욱 가 깝 게 하기 위해 서 이다.
고급 탄막 은 정말 나의 능력 범 위 를 넘 어 섰 으 니 모두 무시 해라.
go 소스 코드 는 다음 과 같 습 니 다.
// bilibili xml ass 。
// xml , :
// <d p="32.066,1,25,16777215,1409046965,0,017d3f58,579516441"> </d>
// p 、 、 、 、 、?、 ID、 ID。
// p , 4 ass , 。 <d> </d> 。
// 、 、 。
package main
import (
"fmt"
"io"
"io/ioutil"
"math"
"os"
"regexp"
"sort"
"strconv"
"strings"
)
// ass
const header = `[Script Info]
ScriptType: v4.00+
Collisions: Normal
playResX: 640
playResY: 360
[V4+ Styles]
Format: Name, Fontname, Fontsize, primaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: Default, Microsoft YaHei, 28, &H00FFFFFF, &H00FFFFFF, &H00000000, &H00000000, 0, 0, 0, 0, 100, 100, 0.00, 0.00, 1, 1, 0, 2, 10, 10, 10, 0
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
`
//
var line = regexp.MustCompile(`<d\sp="([\d\.]+),([145]),(\d+),(\d+),\d+,\d+,\w+,\d+">([^<>]+?)</d>`)
//
type Danmu struct {
text string
time float64
kind byte
size int
color int
}
// []Danmu sort.Interface ,
type Danmus []Danmu
func (d Danmus) Len() int {
return len(d)
}
func (d Danmus) Less(i, j int) bool {
return d[i].time < d[j].time
}
func (d Danmus) Swap(i, j int) {
d[i], d[j] = d[j], d[i]
}
// Danmu
func fill(d *Danmu, s [][]byte) {
d.time, _ = strconv.ParseFloat(string(s[1]), 64)
d.kind = s[2][0] - '0'
d.size, _ = strconv.Atoi(string(s[3]))
bgr, _ := strconv.Atoi(string(s[4]))
d.color = ((bgr >> 16) & 255) | (bgr & (255 << 8)) | ((bgr & 255) << 16)
d.text = string(s[5])
}
// , ascii 0.5 , 1
func length(s string) float64 {
l := 0.0
for _, r := range s {
if r < 127 {
l += 0.5
} else {
l += 1
}
}
return l
}
// ass :`0:00:00.00`
func timespot(f float64) string {
h, f := math.Modf(f / 3600)
m, f := math.Modf(f * 60)
return fmt.Sprintf("%d:%02d:%05.2f", int(h), int(m), f*60)
}
//
func open(name string) ([]Danmu, error) {
data, err := ioutil.ReadFile(name)
if err != nil {
return nil, err
}
dan := line.FindAllSubmatch(data, -1)
ans := make([]Danmu, len(dan))
for i := len(dan) - 1; i >= 0; i-- {
fill(&ans[i], dan[i])
}
return ans, nil
}
// w, 、
func save(w io.Writer, dans []Danmu) {
p1 := make([]float64, 36)
p2 := make([]float64, 36)
p3 := make([]float64, 36)
t := 0
max := func(x []float64) float64 {
i := x[0]
for _, j := range x[1:] {
if i < j {
i = j
}
}
return i
}
set := func(x []float64, f float64) {
for i, _ := range x {
x[i] = f
}
}
find := func(p []float64, f float64, i, d int) int {
i = (i/d + 1) * d % 36
m, k := f+10000, 0
for j := 0; j < 36; j += d {
t := (i + j) % 36
if n := max(p[t : t+d]); n <= f {
k = t
break
} else if m > n {
k = t
m = n
}
}
return k
}
for _, dan := range dans {
s, l := "", length(dan.text)
if l == 0 {
continue
}
switch {
case dan.size < 25:
dan.size, l, s = 2, l*18, "\\fs18"
case dan.size == 25:
dan.size, l = 3, l*28
case dan.size > 25:
dan.size, l, s = 4, l*38, "\\fs38"
}
if dan.color != 0x00FFFFFF {
s += fmt.Sprintf("\\c&H%06X", dan.color)
}
switch dan.kind {
case 1: //
t := find(p1, dan.time, t, dan.size)
set(p1[t:t+dan.size], dan.time+8)
h := (t+dan.size)*10 - 1
s += fmt.Sprintf("\\move(%d,%d,%d,%d)", 640+int(l/2), h, -int(l/2), h)
fmt.Fprintf(w, "Dialogue: 1,%s,%s,Default,,0000,0000,0000,,{%s}%s
",
timespot(dan.time+0),
timespot(dan.time+8), s, dan.text)
case 4: //
j := find(p2, dan.time, 35, dan.size)
set(p2[j:j+dan.size], dan.time+4)
s += fmt.Sprintf("\\pos(%d,%d)", 320, (36-j)*10-1)
fmt.Fprintf(w, "Dialogue: 2,%s,%s,Default,,0000,0000,0000,,{%s}%s
",
timespot(dan.time+0),
timespot(dan.time+4), s, dan.text)
case 5: //
j := find(p3, dan.time, 35, dan.size)
set(p3[j:j+dan.size], dan.time+4)
s += fmt.Sprintf("\\pos(%d,%d)", 320, (j+dan.size)*10-1)
fmt.Fprintf(w, "Dialogue: 3,%s,%s,Default,,0000,0000,0000,,{%s}%s
",
timespot(dan.time+0),
timespot(dan.time+4), s, dan.text)
}
}
}
// ,
func main() {
if len(os.Args) <= 1 {
os.Exit(0)
}
for _, name := range os.Args[1:] {
dans, err := open(name)
if err != nil {
os.Exit(1)
}
if n := strings.LastIndex(name, "."); n != -1 {
name = name[:n]
}
name += ".ass"
file, err := os.Create(name)
if err != nil {
os.Exit(2)
}
file.WriteString(header)
sort.Sort(Danmus(dans))
save(file, dans)
file.Close()
}
}
2014.9.2 9:30am 업데이트:글꼴 배열 을 수정 하 였 습 니 다.2014.9.2 9:50am 업데이트:알고리즘 은 고정 출현 시간,최소 중첩 배열,최종 버 전 으로 수정 되 었 습 니 다.
over。여러분 의 평론 을 환영 합 니 다.차라리 여러분 이 많은 평론 을 하 는 것 이 낫 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
python 에서 빌 리 빌 리 를 대량으로 합성 한 m4s 캐 시 파일 은 MP4 형식 ver 2.5 입 니 다.이전 버 전에 비해 업데이트 내용: ※내 보 낸 동 영상 은 UP 주 분류 에 따라 저 장 됩 니 다. ※제목 형식 추가 메모:ffmpeg 를 설치 해 야 사용 할 수 있 습 니 다. ffmpeg 다운로드 주소: f...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.