5 // Created by TYPCN on 2015/4/8.
9 #include "AssClass.hpp"
20 void Ass::init(const char *filename
){
21 std::remove(filename
);
25 void Ass::SetDuration(int dm
,int ds
){
26 duration_marquee
= dm
;
30 void Ass::WriteHead(int width
,int height
,const char *font
,float fontsize
,float alpha
){
38 // Write a♂ss head info
39 out
<< "[Script Info]\nScript Updated By: Danmaku2ASS_native (https://github.com/typcn/danmaku2ass_native)\nScriptType: v4.00+" << endl
;
40 out
<< "PlayResX: " << width
<< endl
;
41 out
<< "PlayResY: " << height
<< endl
;
42 out
<< "Aspect Ratio: " << width
<< ":" << height
<< endl
;
43 out
<< "Collisions: Normal" << endl
;
44 out
<< "WrapStyle: 2" << endl
;
45 out
<< "ScaledBorderAndShadow: yes" << endl
;
46 out
<< "YCbCr Matrix: TV.601" << endl
<< endl
;
49 sprintf(alpha_hex
, "%02X", 255-round_int(alpha
*255));
51 // Write ass styles , maybe disorder , See https://en.wikipedia.org/wiki/SubStation_Alpha
52 out
<< "[V4+ Styles]"<< endl
;
53 out
<< "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding"<< endl
;
57 ss
<< "TYCM_" << rand() % (int)(9999 + 1);
61 style_name
<< "," << // Style name
62 font
<< ", " << // Font name
63 fontsize
<< ", " << // Font size
64 "&H"<< alpha_hex
<<"FFFFFF, " << // Primary Color
65 "&H"<< alpha_hex
<<"FFFFFF, " << // Secondary Color
66 "&H"<< alpha_hex
<<"000000, " << // Outline Color
67 "&H"<< alpha_hex
<<"000000, " << // Back Color
68 "0, 0, 0, 0, 100, 100, 0.00, 0.00, 1, 1, 0, 7, 0, 0, 0, 0" << endl
<< endl
;
70 out
<< "[Events]" << endl
;
71 out
<< "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" << endl
;
74 void Ass::AppendComment(float appear_time
,int comment_mode
,int font_color
,const char *content
){
81 size_t strLength
= Utf8StringSize(str
);
87 int ContentFontLen
= (int)strLength
*FontSize
;
91 sprintf(effect
,"\\move(%d, [MROW], %d, [MROW])",VideoWidth
,-ContentFontLen
);
92 duration
= duration_marquee
;
93 }else if(comment_mode
== 4){
94 sprintf(effect
,"\\an2\\pos(%d,[BottomROW])",VideoWidth
/2);
95 duration
= duration_still
;
96 }else if(comment_mode
== 5){
97 sprintf(effect
,"\\an8\\pos(%d,[TopROW])",VideoWidth
/2);
98 duration
= duration_still
;
102 string
effectStr(effect
);
104 if(font_color
!= 16777215){
105 if(font_color
== 0x000000){
106 color
= "\\c&H000000&";
107 }else if(font_color
== 0xffffff){
108 color
= "\\c&HFFFFFF&";
110 int R
= (font_color
>> 16) & 0xff;
111 int G
= (font_color
>> 8) & 0xff;
112 int B
= font_color
& 0xff;
114 sprintf(hexcolor
, "%02X%02X%02X",B
,G
,R
);
116 string
strcolor(hexcolor
);
117 color
= "\\c&H" + strcolor
+ "&";
122 ss
<< "Dialogue: 2," << TS2t(appear_time
) << "," << TS2t(appear_time
+ duration
) << "," << style_name
<< ",,0000,0000,0000,,{" << effectStr
<< color
<< "}" << str
;
124 pair
<int,std::string
> contentPair
= make_pair(ContentFontLen
,ss
.str());
126 comment_map
.insert( std::pair
<float, std::pair
<int,std::string
>>(appear_time
,contentPair
) );
130 inline void Ass::stripStr(string in
){
131 std::replace(in
.begin(), in
.end(), '\r', '\n');
132 std::replace(in
.begin(), in
.end(), '\n', ' ');
135 int Ass::round_int( double r
) {
136 return (r
> 0.0) ? (r
+ 0.5) : (r
- 0.5);
139 inline string
Ass::TS2t(double timestamp
){
141 int ts
= (int)timestamp
*100.0;
142 int hour
,minute
,second
,centsecond
;
145 second
= minute
%6000;
146 minute
= minute
/6000;
147 centsecond
= second
%100;
150 sprintf(buff
,"%d:%02d:%02d.%02d", hour
,minute
,second
,centsecond
);
154 template<typename _Iterator1
, typename _Iterator2
>
155 inline size_t IncUtf8StringIterator(_Iterator1
& it
, const _Iterator2
& last
) {
156 if(it
== last
) return 0;
159 for(++it
; last
!= it
; ++it
, ++res
) {
161 if(!(c
&0x80) || ((c
&0xC0) == 0xC0)) break;
167 inline size_t Ass::Utf8StringSize(const std::string
& str
) {
169 std::string::const_iterator it
= str
.begin();
170 for(; it
!= str
.end(); IncUtf8StringIterator(it
, str
.end()))
176 static inline std::string
ReplaceAll(std::string str
, const std::string
& from
, const std::string
& to
) {
177 size_t start_pos
= 0;
178 while((start_pos
= str
.find(from
, start_pos
)) != std::string::npos
) {
179 str
.replace(start_pos
, from
.length(), to
);
180 start_pos
+= to
.length(); // Handles case where 'to' is a substring of 'from'
185 void Ass::WriteToDisk(std::vector
<int> disallowModes
){
188 int Dropped_Rows
= 0;
190 typedef std::map
<float, pair
<int,std::string
>>::iterator it_type
;
193 float BottomTime
= 0;
198 int line
= ceil(VideoHeight
/FontSize
);
200 double *rows_dismiss_time
= new double[line
]; // The time of scroll comment dismiss
201 double *rows_visible_time
= new double[line
]; // The time of last char visible on screen
203 for (int i
= 0 ; i
< line
; i
++) {
204 rows_dismiss_time
[i
] = 0;
205 rows_visible_time
[i
] = 0;
211 for (auto i
= disallowModes
.begin();i
!= disallowModes
.end(); i
++ ){
222 for(it_type iterator
= comment_map
.begin(); iterator
!= comment_map
.end(); iterator
++) {
226 string r
= iterator
->second
.second
;
228 int playbackTime
= iterator
->first
;
229 double TextWidth
= iterator
->second
.first
+ 2.0; // Add some space between texts
230 double act_time
= TextWidth
/ (((double)VideoWidth
+ TextWidth
)/ (double)duration_marquee
); // duration of last char visible on screen
232 if(r
.find("[MROW]") != std::string::npos
){
236 bool Replaced
= false;
237 for(int i
=0;i
< line
;i
++){
238 double Time_Arrive_Border
= (playbackTime
+ (double)duration_marquee
) - act_time
; // The time of first char reach left border of video
239 if(Time_Arrive_Border
> rows_dismiss_time
[i
] && playbackTime
> rows_visible_time
[i
]){
240 rows_dismiss_time
[i
] = playbackTime
+ (double) duration_marquee
;
241 rows_visible_time
[i
] = playbackTime
+ act_time
;
242 r
= ReplaceAll(r
,"[MROW]",to_string(i
*FontSize
));
251 }else if(r
.find("[TopROW]") != std::string::npos
){
255 float timeago
= iterator
->first
- TopTime
;
256 if(timeago
> duration_still
){
258 TopTime
= iterator
->first
;
262 r
= ReplaceAll(r
,"[TopROW]",to_string(TopROW
*FontSize
));
263 }else if(r
.find("[BottomROW]") != std::string::npos
){
267 float timeago
= iterator
->first
- BottomTime
;
268 if(timeago
> duration_still
){
270 BottomTime
= iterator
->first
;
274 r
= ReplaceAll(r
,"[BottomROW]",to_string(VideoHeight
-BottomROW
*FontSize
));
288 cout
<< "Comments:" << All_Rows
<< " Dropped:" << Dropped_Rows
<< endl
;
289 delete[] rows_dismiss_time
;
290 delete[] rows_visible_time
;