File indexing completed on 2024-12-22 04:40:08
0001 /* 0002 SPDX-FileCopyrightText: 2007-2009 Sergio Pistone <sergio_pistone@yahoo.com.ar> 0003 SPDX-FileCopyrightText: 2010-2022 Mladen Milinkovic <max@smoothware.net> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #ifndef SUBSTATIONALPHAOUTPUTFORMAT_H 0009 #define SUBSTATIONALPHAOUTPUTFORMAT_H 0010 0011 #include "formats/outputformat.h" 0012 #include "core/formatdata.h" 0013 #include "core/richtext/richdocument.h" 0014 #include "core/subtitleiterator.h" 0015 0016 namespace SubtitleComposer { 0017 class SubStationAlphaOutputFormat : public OutputFormat 0018 { 0019 friend class FormatManager; 0020 0021 public: 0022 QString fromRichString(const RichString &text) const 0023 { 0024 0025 QString subtitle; 0026 0027 int prevStyle = 0; 0028 QRgb prevColor = 0; 0029 for(int i = 0, sz = text.length(); i < sz; i++) { 0030 int curStyle = text.styleFlagsAt(i); 0031 QRgb curColor = (curStyle & RichString::Color) != 0 ? text.styleColorAt(i) : 0; 0032 curStyle &= RichString::Bold | RichString::Italic | RichString::Underline; 0033 if(prevStyle != curStyle) { 0034 int diff = curStyle ^ prevStyle; 0035 subtitle += '{'; 0036 if(diff & RichString::Bold) 0037 subtitle += curStyle & RichString::Bold ? QStringLiteral("\\b1") : QStringLiteral("\\b0"); 0038 if(diff & RichString::Italic) 0039 subtitle += curStyle & RichString::Italic ? QStringLiteral("\\i1") : QStringLiteral("\\i0"); 0040 if(diff & RichString::Underline) 0041 subtitle += curStyle & RichString::Underline ? QStringLiteral("\\u1") : QStringLiteral("\\u0"); 0042 subtitle += "}"; 0043 } 0044 if(prevColor != curColor) { 0045 subtitle += QStringLiteral("{\\c&H"); 0046 if(curColor != 0) { 0047 subtitle += (QChar('0') + QString::number(qBlue(curColor), 16)).toUpper().right(2); 0048 subtitle += (QChar('0') + QString::number(qGreen(curColor), 16)).toUpper().right(2); 0049 subtitle += (QChar('0') + QString::number(qRed(curColor), 16)).toUpper().right(2); 0050 } else { 0051 subtitle += QStringLiteral("00"); 0052 } 0053 subtitle += QStringLiteral("&}"); 0054 } 0055 0056 subtitle += text.at(i); 0057 0058 prevStyle = curStyle; 0059 prevColor = curColor; 0060 } 0061 0062 if(prevStyle) { 0063 subtitle +='{'; 0064 if(prevStyle & RichString::Bold) 0065 subtitle += QStringLiteral("\\b0"); 0066 if(prevStyle & RichString::Italic) 0067 subtitle += QStringLiteral("\\i0"); 0068 if(prevStyle & RichString::Underline) 0069 subtitle += QStringLiteral("\\u0"); 0070 subtitle += '}'; 0071 } 0072 0073 subtitle = subtitle.replace(QStringLiteral("\r\n"), QStringLiteral("\\N")); 0074 subtitle = subtitle.replace(QStringLiteral("\n"), QStringLiteral("\\N")); 0075 subtitle = subtitle.replace(QStringLiteral("\r"), QStringLiteral("\\N")); 0076 0077 return subtitle; 0078 } 0079 0080 protected: 0081 static QString normalizeBlock(const QString &data) { 0082 int begin = 0, end = data.length() - 1; 0083 0084 while(data.at(begin).isSpace() && begin < end) 0085 begin++; 0086 0087 while(data.at(end).isSpace() && end >= begin) 0088 end--; 0089 0090 return data.mid(begin, end - begin + 1) + QStringLiteral("\n\n"); 0091 } 0092 0093 QString dumpSubtitles(const Subtitle &subtitle, bool primary) const override 0094 { 0095 FormatData *formatData = this->formatData(subtitle); 0096 0097 QString ret = normalizeBlock(formatData ? formatData->value(QStringLiteral("ScriptInfo")) : m_defaultScriptInfo) 0098 + normalizeBlock(formatData ? formatData->value(QStringLiteral("Styles")) : m_defaultStyles) 0099 + normalizeBlock(m_events); 0100 0101 for(SubtitleIterator it(subtitle); it.current(); ++it) { 0102 const SubtitleLine *line = it.current(); 0103 0104 const Time showTime = line->showTime(); 0105 const QString showTimeArg = QString::asprintf("%01d:%02d:%02d.%02d", 0106 showTime.hours(), 0107 showTime.minutes(), 0108 showTime.seconds(), 0109 (showTime.millis() + 5) / 10); 0110 0111 const Time hideTime = line->hideTime(); 0112 const QString hideTimeArg = QString::asprintf("%01d:%02d:%02d.%02d", 0113 hideTime.hours(), 0114 hideTime.minutes(), 0115 hideTime.seconds(), 0116 (hideTime.millis() + 5) / 10); 0117 0118 formatData = this->formatData(line); 0119 0120 RichString stext = (primary ? line->primaryDoc() : line->secondaryDoc())->toRichText(); 0121 ret += QString(formatData ? formatData->value(QStringLiteral("Dialogue")) : m_dialogueBuilder) 0122 .arg(showTimeArg, hideTimeArg, fromRichString(stext)); 0123 } 0124 return ret; 0125 } 0126 0127 SubStationAlphaOutputFormat( 0128 const QString &name = QStringLiteral("SubStation Alpha"), 0129 const QStringList &extensions = QStringList(QStringLiteral("ssa")), 0130 const QString &scriptInfo = s_defaultScriptInfo, 0131 const QString &styles = s_defaultStyles, 0132 const QString &events = s_events, 0133 const QString &dialogueBuilder = s_dialogueBuilder) : 0134 OutputFormat(name, extensions), 0135 m_defaultScriptInfo(scriptInfo), 0136 m_defaultStyles(styles), 0137 m_events(events), 0138 m_dialogueBuilder(dialogueBuilder) 0139 {} 0140 0141 const QString m_defaultScriptInfo; 0142 const QString m_defaultStyles; 0143 const QString m_events; 0144 const QString m_dialogueBuilder; 0145 const QString m_textBuilder; 0146 0147 static const char *s_defaultScriptInfo; 0148 static const char *s_defaultStyles; 0149 static const char *s_events; 0150 static const char *s_dialogueBuilder; 0151 }; 0152 0153 const char *SubStationAlphaOutputFormat::s_defaultScriptInfo = "[Script Info]\n" 0154 "Title: Untitled\n" 0155 "ScriptType: V4.00\n" 0156 "Collisions: Normal\n" 0157 "Timer: 100\n" 0158 "WrapStyle: 0\n"; 0159 const char *SubStationAlphaOutputFormat::s_defaultStyles = "[V4 Styles]\n" 0160 "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, " 0161 "Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\n" 0162 "Style: Default, Sans, 24, 16777215, 16777215, 16777215, 12632256, -1, 0, 1, 1, 1, 6, 30, 30, 415, 0, 0\n"; 0163 const char *SubStationAlphaOutputFormat::s_events = "[Events]\n" 0164 "Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n"; 0165 const char *SubStationAlphaOutputFormat::s_dialogueBuilder = "Dialogue: Marked=0,%1,%2,Default,,0000,0000,0000,,%3\n"; 0166 0167 class AdvancedSubStationAlphaOutputFormat : public SubStationAlphaOutputFormat 0168 { 0169 friend class FormatManager; 0170 0171 protected: 0172 AdvancedSubStationAlphaOutputFormat() : 0173 SubStationAlphaOutputFormat(QStringLiteral("Advanced SubStation Alpha"), QStringList(QStringLiteral("ass")), s_defaultScriptInfo, s_defaultStyles, s_events, s_dialogueBuilder) 0174 {} 0175 0176 static const char *s_defaultScriptInfo; 0177 static const char *s_defaultStyles; 0178 static const char *s_events; 0179 static const char *s_dialogueBuilder; 0180 }; 0181 0182 const char *AdvancedSubStationAlphaOutputFormat::s_defaultScriptInfo = "[Script Info]\n" 0183 "Title: Untitled\n" 0184 "ScriptType: V4.00+\n" 0185 "Collisions: Normal\n" 0186 "Timer: 100\n" 0187 "WrapStyle: 0\n"; 0188 const char *AdvancedSubStationAlphaOutputFormat::s_defaultStyles = "[V4+ Styles]\n" 0189 "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeThrough, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n" 0190 "Style: Default, Sans, 16, &H00FFFFFF, &H00FFFFFF, &H00674436, &HFFFFFFF8, -1, 0, 0, 0, 100, 90, 0, 0, 1, 2.1, 0.5, 2, 15, 15, 15, 0\n"; 0191 const char *AdvancedSubStationAlphaOutputFormat::s_events = "[Events]\n" 0192 "Format: Layer, Start, End, Style, Actor, MarginL, MarginR, MarginV, Effect, Text\n"; 0193 const char *AdvancedSubStationAlphaOutputFormat::s_dialogueBuilder = "Dialogue: 0,%1,%2,Default,,0000,0000,0000,,%3\n"; 0194 } 0195 0196 #endif