2018-03-04 10:24:04 +01:00
using System ;
using System.Collections.Generic ;
using System.Globalization ;
using System.Linq ;
using System.Text ;
using System.Xml ;
namespace Nikse.SubtitleEdit.Core.SubtitleFormats
{
//<?xml version="1.0" encoding="UTF-8"?>
//<DCSubtitle Version="1.0">
// <SubtitleID>4EB245B8-4D3A-4158-9516-95DD20E8322E</SubtitleID>
// <MovieTitle>Unknown</MovieTitle>
// <ReelNumber>1</ReelNumber>
// <Language>Swedish</Language>
// <Font Italic="no">
// <Subtitle SpotNumber="1" TimeIn="00:00:06:040" TimeOut="00:00:08:040" FadeUpTime="20" FadeDownTime="20">
// <Text Direction="horizontal" HAlign="center" HPosition="0.0" VAlign="bottom" VPosition="6.0">DETTA HAR HÄNT...</Text>
// </Subtitle>
// </Font>
//</DCSubtitle>
public class DCinemaInterop : SubtitleFormat
{
internal class SubtitleLine
{
internal string Text { get ; set ; }
internal string VerticalPosition { get ; set ; }
internal string VerticalAlignment { get ; set ; }
internal SubtitleLine ( string text , string verticalPosition , string verticalAlignment )
{
Text = text ;
VerticalPosition = verticalPosition ;
VerticalAlignment = verticalAlignment ;
}
internal int GetVerticalPositionAsNumber ( )
{
double d ;
if ( double . TryParse ( VerticalPosition , out d ) )
{
return ( int ) d ;
}
return 0 ;
}
}
public override string Extension = > ".xml" ;
public override string Name = > "D-Cinema interop" ;
public override bool IsMine ( List < string > lines , string fileName )
{
var sb = new StringBuilder ( ) ;
lines . ForEach ( line = > sb . AppendLine ( line ) ) ;
string xmlAsString = sb . ToString ( ) . Trim ( ) ;
if ( xmlAsString . Contains ( "<DCSubtitle" ) )
{
var xml = new XmlDocument { XmlResolver = null } ;
try
{
xml . LoadXml ( xmlAsString ) ;
if ( xml . DocumentElement ! = null )
{
var subtitles = xml . DocumentElement . SelectNodes ( "//Subtitle" ) ;
return subtitles ! = null & & subtitles . Count > 0 ;
}
}
catch ( Exception ex )
{
System . Diagnostics . Debug . WriteLine ( ex . Message ) ;
return false ;
}
}
return false ;
}
public override string ToText ( Subtitle subtitle , string title )
{
string languageEnglishName ;
try
{
string languageShortName = LanguageAutoDetect . AutoDetectGoogleLanguage ( subtitle ) ;
var ci = CultureInfo . CreateSpecificCulture ( languageShortName ) ;
languageEnglishName = ci . EnglishName ;
int indexOfStartP = languageEnglishName . IndexOf ( '(' ) ;
if ( indexOfStartP > 1 )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
languageEnglishName = languageEnglishName . Remove ( indexOfStartP ) . Trim ( ) ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
}
catch
{
languageEnglishName = "English" ;
}
string hex = Guid . NewGuid ( ) . ToString ( ) . RemoveChar ( '-' ) ;
hex = hex . Insert ( 8 , "-" ) . Insert ( 13 , "-" ) . Insert ( 18 , "-" ) . Insert ( 23 , "-" ) ;
string xmlStructure = "<DCSubtitle Version=\"1.0\">" + Environment . NewLine +
2019-01-21 09:53:15 +01:00
" <SubtitleID>" + hex . ToLowerInvariant ( ) + "</SubtitleID>" + Environment . NewLine +
2018-03-04 10:24:04 +01:00
" <MovieTitle></MovieTitle>" + Environment . NewLine +
" <ReelNumber>1</ReelNumber>" + Environment . NewLine +
" <Language>" + languageEnglishName + "</Language>" + Environment . NewLine +
" <LoadFont URI=\"" + Configuration . Settings . SubtitleSettings . DCinemaFontFile + "\" Id=\"Font1\"/>" + Environment . NewLine +
" <Font Id=\"Font1\" Color=\"FFFFFFFF\" Effect=\"border\" EffectColor=\"FF000000\" Italic=\"no\" Underlined=\"no\" Script=\"normal\" Size=\"42\">" + Environment . NewLine +
" </Font>" + Environment . NewLine +
"</DCSubtitle>" ;
var xml = new XmlDocument ( ) ;
xml . LoadXml ( xmlStructure ) ;
xml . PreserveWhitespace = true ;
var ss = Configuration . Settings . SubtitleSettings ;
string loadedFontId = "Font1" ;
if ( ! string . IsNullOrEmpty ( ss . CurrentDCinemaFontId ) )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
loadedFontId = ss . CurrentDCinemaFontId ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if ( string . IsNullOrEmpty ( ss . CurrentDCinemaMovieTitle ) )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaMovieTitle = title ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if ( ss . CurrentDCinemaFontSize = = 0 | | string . IsNullOrEmpty ( ss . CurrentDCinemaFontEffect ) )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
Configuration . Settings . SubtitleSettings . InitializeDCinameSettings ( true ) ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
xml . DocumentElement . SelectSingleNode ( "MovieTitle" ) . InnerText = ss . CurrentDCinemaMovieTitle ;
xml . DocumentElement . SelectSingleNode ( "SubtitleID" ) . InnerText = ss . CurrentDCinemaSubtitleId . Replace ( "urn:uuid:" , string . Empty ) ;
xml . DocumentElement . SelectSingleNode ( "ReelNumber" ) . InnerText = ss . CurrentDCinemaReelNumber ;
xml . DocumentElement . SelectSingleNode ( "Language" ) . InnerText = ss . CurrentDCinemaLanguage ;
xml . DocumentElement . SelectSingleNode ( "LoadFont" ) . Attributes [ "URI" ] . InnerText = ss . CurrentDCinemaFontUri ;
xml . DocumentElement . SelectSingleNode ( "LoadFont" ) . Attributes [ "Id" ] . InnerText = loadedFontId ;
int fontSize = ss . CurrentDCinemaFontSize ;
xml . DocumentElement . SelectSingleNode ( "Font" ) . Attributes [ "Id" ] . InnerText = loadedFontId ;
2019-01-21 09:53:15 +01:00
xml . DocumentElement . SelectSingleNode ( "Font" ) . Attributes [ "Color" ] . InnerText = "FF" + Utilities . ColorToHex ( ss . CurrentDCinemaFontColor ) . TrimStart ( '#' ) . ToUpperInvariant ( ) ;
2018-03-04 10:24:04 +01:00
xml . DocumentElement . SelectSingleNode ( "Font" ) . Attributes [ "Effect" ] . InnerText = ss . CurrentDCinemaFontEffect ;
2019-01-21 09:53:15 +01:00
xml . DocumentElement . SelectSingleNode ( "Font" ) . Attributes [ "EffectColor" ] . InnerText = "FF" + Utilities . ColorToHex ( ss . CurrentDCinemaFontEffectColor ) . TrimStart ( '#' ) . ToUpperInvariant ( ) ;
2018-03-04 10:24:04 +01:00
xml . DocumentElement . SelectSingleNode ( "Font" ) . Attributes [ "Size" ] . InnerText = ss . CurrentDCinemaFontSize . ToString ( ) ;
var mainListFont = xml . DocumentElement . SelectSingleNode ( "Font" ) ;
int no = 0 ;
foreach ( Paragraph p in subtitle . Paragraphs )
{
if ( ! string . IsNullOrEmpty ( p . Text ) )
{
var subNode = xml . CreateElement ( "Subtitle" ) ;
var id = xml . CreateAttribute ( "SpotNumber" ) ;
id . InnerText = ( no + 1 ) . ToString ( ) ;
subNode . Attributes . Append ( id ) ;
var fadeUpTime = xml . CreateAttribute ( "FadeUpTime" ) ;
fadeUpTime . InnerText = Configuration . Settings . SubtitleSettings . DCinemaFadeUpTime . ToString ( ) ;
subNode . Attributes . Append ( fadeUpTime ) ;
var fadeDownTime = xml . CreateAttribute ( "FadeDownTime" ) ;
fadeDownTime . InnerText = Configuration . Settings . SubtitleSettings . DCinemaFadeDownTime . ToString ( ) ;
subNode . Attributes . Append ( fadeDownTime ) ;
var start = xml . CreateAttribute ( "TimeIn" ) ;
start . InnerText = ConvertToTimeString ( p . StartTime ) ;
subNode . Attributes . Append ( start ) ;
var end = xml . CreateAttribute ( "TimeOut" ) ;
end . InnerText = ConvertToTimeString ( p . EndTime ) ;
subNode . Attributes . Append ( end ) ;
bool alignLeft = p . Text . StartsWith ( "{\\a1}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\a5}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\a9}" , StringComparison . Ordinal ) | | // sub station alpha
p . Text . StartsWith ( "{\\an1}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\an4}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\an7}" , StringComparison . Ordinal ) ; // advanced sub station alpha
bool alignRight = p . Text . StartsWith ( "{\\a3}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\a7}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\a11}" , StringComparison . Ordinal ) | | // sub station alpha
p . Text . StartsWith ( "{\\an3}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\an6}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\an9}" , StringComparison . Ordinal ) ; // advanced sub station alpha
bool alignVTop = p . Text . StartsWith ( "{\\a5}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\a6}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\a7}" , StringComparison . Ordinal ) | | // sub station alpha
p . Text . StartsWith ( "{\\an7}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\an8}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\an9}" , StringComparison . Ordinal ) ; // advanced sub station alpha
bool alignVCenter = p . Text . StartsWith ( "{\\a9}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\a10}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\a11}" , StringComparison . Ordinal ) | | // sub station alpha
p . Text . StartsWith ( "{\\an4}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\an5}" , StringComparison . Ordinal ) | | p . Text . StartsWith ( "{\\an6}" , StringComparison . Ordinal ) ; // advanced sub station alpha
string text = Utilities . RemoveSsaTags ( p . Text ) ;
var lines = text . SplitToLines ( ) ;
int vPos ;
int vPosFactor = ( int ) Math . Round ( fontSize / 7.4 ) ;
if ( alignVTop )
{
vPos = Configuration . Settings . SubtitleSettings . DCinemaBottomMargin ; // Bottom margin is normally 8
}
else if ( alignVCenter )
{
vPos = ( int ) Math . Round ( ( lines . Count * vPosFactor * - 1 ) / 2.0 ) ;
}
else
{
vPos = ( lines . Count * vPosFactor ) - vPosFactor + Configuration . Settings . SubtitleSettings . DCinemaBottomMargin ; // Bottom margin is normally 8
}
bool isItalic = false ;
int fontNo = 0 ;
var fontColors = new Stack < string > ( ) ;
foreach ( string line in lines )
{
var textNode = xml . CreateElement ( "Text" ) ;
var vPosition = xml . CreateAttribute ( "VPosition" ) ;
vPosition . InnerText = vPos . ToString ( ) ;
textNode . Attributes . Append ( vPosition ) ;
if ( Math . Abs ( Configuration . Settings . SubtitleSettings . DCinemaZPosition ) > 0.01 )
{
var zPosition = xml . CreateAttribute ( "ZPosition" ) ;
zPosition . InnerText = string . Format ( CultureInfo . InvariantCulture , "{0:0.00}" , Configuration . Settings . SubtitleSettings . DCinemaZPosition ) ;
textNode . Attributes . Append ( zPosition ) ;
}
var vAlign = xml . CreateAttribute ( "VAlign" ) ;
if ( alignVTop )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
vAlign . InnerText = "top" ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else if ( alignVCenter )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
vAlign . InnerText = "center" ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
vAlign . InnerText = "bottom" ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
textNode . Attributes . Append ( vAlign ) ;
var hAlign = xml . CreateAttribute ( "HAlign" ) ;
if ( alignLeft )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
hAlign . InnerText = "left" ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else if ( alignRight )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
hAlign . InnerText = "right" ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
hAlign . InnerText = "center" ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
textNode . Attributes . Append ( hAlign ) ;
var direction = xml . CreateAttribute ( "Direction" ) ;
direction . InnerText = "horizontal" ;
textNode . Attributes . Append ( direction ) ;
int i = 0 ;
var txt = new StringBuilder ( ) ;
var html = new StringBuilder ( ) ;
XmlNode nodeTemp = xml . CreateElement ( "temp" ) ;
while ( i < line . Length )
{
if ( ! isItalic & & line . Substring ( i ) . StartsWith ( "<i>" , StringComparison . Ordinal ) )
{
if ( txt . Length > 0 )
{
nodeTemp . InnerText = txt . ToString ( ) ;
html . Append ( nodeTemp . InnerXml ) ;
txt . Clear ( ) ;
}
isItalic = true ;
i + = 2 ;
}
else if ( isItalic & & line . Substring ( i ) . StartsWith ( "</i>" , StringComparison . Ordinal ) )
{
if ( txt . Length > 0 )
{
var fontNode = xml . CreateElement ( "Font" ) ;
var italic = xml . CreateAttribute ( "Italic" ) ;
italic . InnerText = "yes" ;
fontNode . Attributes . Append ( italic ) ;
if ( ! string . IsNullOrEmpty ( ss . CurrentDCinemaFontEffect ) )
{
var fontEffect = xml . CreateAttribute ( "Effect" ) ;
fontEffect . InnerText = ss . CurrentDCinemaFontEffect ;
fontNode . Attributes . Append ( fontEffect ) ;
}
if ( line . Length > i + 5 & & line . Substring ( i + 4 ) . StartsWith ( "</font>" , StringComparison . Ordinal ) )
{
var fontColor = xml . CreateAttribute ( "Color" ) ;
fontColor . InnerText = fontColors . Pop ( ) ;
fontNode . Attributes . Append ( fontColor ) ;
fontNo - - ;
i + = 7 ;
}
fontNode . InnerText = HtmlUtil . RemoveHtmlTags ( txt . ToString ( ) ) ;
html . Append ( fontNode . OuterXml ) ;
txt . Clear ( ) ;
}
isItalic = false ;
i + = 3 ;
}
else if ( line . Substring ( i ) . StartsWith ( "<font color=" , StringComparison . Ordinal ) & & line . Substring ( i + 3 ) . Contains ( '>' ) )
{
int endOfFont = line . IndexOf ( '>' , i ) ;
if ( txt . Length > 0 )
{
nodeTemp . InnerText = txt . ToString ( ) ;
html . Append ( nodeTemp . InnerXml ) ;
txt . Clear ( ) ;
}
string c = line . Substring ( i + 12 , endOfFont - ( i + 12 ) ) ;
c = c . Trim ( '"' ) . Trim ( '\'' ) . Trim ( ) ;
if ( c . StartsWith ( '#' ) )
2019-01-19 14:40:37 +01:00
{
2019-01-21 09:53:15 +01:00
c = c . TrimStart ( '#' ) . ToUpperInvariant ( ) . PadLeft ( 8 , 'F' ) ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
fontColors . Push ( c ) ;
fontNo + + ;
2018-03-07 08:10:26 +01:00
i = endOfFont ;
2018-03-04 10:24:04 +01:00
}
else if ( fontNo > 0 & & line . Substring ( i ) . StartsWith ( "</font>" , StringComparison . Ordinal ) )
{
if ( txt . Length > 0 )
{
var fontNode = xml . CreateElement ( "Font" ) ;
var fontColor = xml . CreateAttribute ( "Color" ) ;
fontColor . InnerText = fontColors . Pop ( ) ;
fontNode . Attributes . Append ( fontColor ) ;
if ( line . Length > i + 9 & & line . Substring ( i + 7 ) . StartsWith ( "</i>" , StringComparison . Ordinal ) )
{
var italic = xml . CreateAttribute ( "Italic" ) ;
italic . InnerText = "yes" ;
fontNode . Attributes . Append ( italic ) ;
isItalic = false ;
i + = 4 ;
}
if ( ! string . IsNullOrEmpty ( ss . CurrentDCinemaFontEffect ) )
{
var fontEffect = xml . CreateAttribute ( "Effect" ) ;
fontEffect . InnerText = ss . CurrentDCinemaFontEffect ;
fontNode . Attributes . Append ( fontEffect ) ;
}
fontNode . InnerText = HtmlUtil . RemoveHtmlTags ( txt . ToString ( ) ) ;
html . Append ( fontNode . OuterXml ) ;
txt . Clear ( ) ;
}
fontNo - - ;
i + = 6 ;
}
else
{
txt . Append ( line [ i ] ) ;
}
i + + ;
}
if ( fontNo > 0 )
{
if ( txt . Length > 0 )
{
var fontNode = xml . CreateElement ( "Font" ) ;
var fontColor = xml . CreateAttribute ( "Color" ) ;
fontColor . InnerText = fontColors . Peek ( ) ;
fontNode . Attributes . Append ( fontColor ) ;
if ( isItalic )
{
var italic = xml . CreateAttribute ( "Italic" ) ;
italic . InnerText = "yes" ;
fontNode . Attributes . Append ( italic ) ;
}
if ( ! string . IsNullOrEmpty ( ss . CurrentDCinemaFontEffect ) )
{
var fontEffect = xml . CreateAttribute ( "Effect" ) ;
fontEffect . InnerText = ss . CurrentDCinemaFontEffect ;
fontNode . Attributes . Append ( fontEffect ) ;
}
fontNode . InnerText = HtmlUtil . RemoveHtmlTags ( txt . ToString ( ) ) ;
html . Append ( fontNode . OuterXml ) ;
}
else if ( html . Length > 0 & & html . ToString ( ) . StartsWith ( "<Font " , StringComparison . Ordinal ) )
{
var temp = new XmlDocument ( ) ;
temp . LoadXml ( "<root>" + html + "</root>" ) ;
var fontNode = xml . CreateElement ( "Font" ) ;
fontNode . InnerXml = temp . DocumentElement . SelectSingleNode ( "Font" ) . InnerXml ;
foreach ( XmlAttribute a in temp . DocumentElement . SelectSingleNode ( "Font" ) . Attributes )
{
var newA = xml . CreateAttribute ( a . Name ) ;
newA . InnerText = a . InnerText ;
fontNode . Attributes . Append ( newA ) ;
}
var fontColor = xml . CreateAttribute ( "Color" ) ;
fontColor . InnerText = fontColors . Peek ( ) ;
fontNode . Attributes . Append ( fontColor ) ;
if ( ! string . IsNullOrEmpty ( ss . CurrentDCinemaFontEffect ) )
{
var fontEffect = xml . CreateAttribute ( "Effect" ) ;
fontEffect . InnerText = ss . CurrentDCinemaFontEffect ;
fontNode . Attributes . Append ( fontEffect ) ;
}
html . Clear ( ) ;
html . Append ( fontNode . OuterXml ) ;
}
}
else if ( isItalic )
{
if ( txt . Length > 0 )
{
var fontNode = xml . CreateElement ( "Font" ) ;
var italic = xml . CreateAttribute ( "Italic" ) ;
italic . InnerText = "yes" ;
fontNode . Attributes . Append ( italic ) ;
if ( ! string . IsNullOrEmpty ( ss . CurrentDCinemaFontEffect ) )
{
var fontEffect = xml . CreateAttribute ( "Effect" ) ;
fontEffect . InnerText = ss . CurrentDCinemaFontEffect ;
fontNode . Attributes . Append ( fontEffect ) ;
}
fontNode . InnerText = HtmlUtil . RemoveHtmlTags ( txt . ToString ( ) ) ;
html . Append ( fontNode . OuterXml ) ;
}
}
else
{
if ( txt . Length > 0 )
{
nodeTemp . InnerText = txt . ToString ( ) ;
html . Append ( nodeTemp . InnerXml ) ;
}
}
textNode . InnerXml = html . ToString ( ) ;
subNode . AppendChild ( textNode ) ;
if ( alignVTop )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
vPos + = vPosFactor ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
vPos - = vPosFactor ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
}
mainListFont . AppendChild ( subNode ) ;
no + + ;
}
}
string s = ToUtf8XmlString ( xml ) . Replace ( "encoding=\"utf-8\"" , "encoding=\"UTF-8\"" ) ;
while ( s . Contains ( "</Font> " ) | | s . Contains ( " <Font " ) | | s . Contains ( Environment . NewLine + "<Font " ) | | s . Contains ( "</Font>" + Environment . NewLine ) )
{
while ( s . Contains ( " Font" ) )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
s = s . Replace ( " <Font " , " <Font " ) ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
while ( s . Contains ( "\tFont" ) )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
s = s . Replace ( "\t<Font " , " <Font " ) ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
s = s . Replace ( "</Font> " , "</Font> " ) ;
s = s . Replace ( " <Font " , " <Font " ) ;
s = s . Replace ( "\r\n<Font " , "<Font " ) ;
s = s . Replace ( "\r\n <Font " , "<Font " ) ;
s = s . Replace ( Environment . NewLine + "<Font " , "<Font " ) ;
s = s . Replace ( Environment . NewLine + " <Font " , "<Font " ) ;
s = s . Replace ( "</Font>\r\n" , "</Font>" ) ;
s = s . Replace ( "</Font>" + Environment . NewLine , "</Font>" ) ;
s = s . Replace ( "><" , "> <" ) ;
s = s . Replace ( "</Font> </Text>" , "</Font></Text>" ) ;
s = s . Replace ( "horizontal\"> <Font" , "horizontal\"><Font" ) ;
}
return s ;
}
public override void LoadSubtitle ( Subtitle subtitle , List < string > lines , string fileName )
{
_errorCount = 0 ;
var sb = new StringBuilder ( ) ;
lines . ForEach ( line = > sb . AppendLine ( line ) ) ;
var xml = new XmlDocument { XmlResolver = null } ;
xml . LoadXml ( sb . ToString ( ) . Trim ( ) ) ;
if ( xml . DocumentElement = = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
return ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
var ss = Configuration . Settings . SubtitleSettings ;
try
{
ss . InitializeDCinameSettings ( false ) ;
XmlNode node = xml . DocumentElement . SelectSingleNode ( "SubtitleID" ) ;
if ( node ! = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaSubtitleId = node . InnerText ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
node = xml . DocumentElement . SelectSingleNode ( "ReelNumber" ) ;
if ( node ! = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaReelNumber = node . InnerText ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
node = xml . DocumentElement . SelectSingleNode ( "Language" ) ;
if ( node ! = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaLanguage = node . InnerText ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
node = xml . DocumentElement . SelectSingleNode ( "MovieTitle" ) ;
if ( node ! = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaMovieTitle = node . InnerText ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
node = xml . DocumentElement . SelectSingleNode ( "LoadFont" ) ;
if ( node ? . Attributes ? [ "URI" ] ! = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaFontUri = node . Attributes [ "URI" ] . InnerText ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
node = xml . DocumentElement . SelectSingleNode ( "Font" ) ;
if ( node ! = null )
{
if ( node . Attributes ? [ "ID" ] ! = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaFontId = node . Attributes [ "ID" ] . InnerText ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if ( node . Attributes ? [ "Size" ] ! = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaFontSize = Convert . ToInt32 ( node . Attributes [ "Size" ] . InnerText ) ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if ( node . Attributes ? [ "Color" ] ! = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaFontColor = System . Drawing . ColorTranslator . FromHtml ( "#" + node . Attributes [ "Color" ] . InnerText ) ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if ( node . Attributes ? [ "Effect" ] ! = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaFontEffect = node . Attributes [ "Effect" ] . InnerText ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if ( node . Attributes ? [ "EffectColor" ] ! = null )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
ss . CurrentDCinemaFontEffectColor = System . Drawing . ColorTranslator . FromHtml ( "#" + node . Attributes [ "EffectColor" ] . InnerText ) ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
}
}
catch ( Exception exception )
{
System . Diagnostics . Debug . WriteLine ( exception . Message ) ;
}
foreach ( XmlNode node in xml . DocumentElement . SelectNodes ( "//Subtitle" ) )
{
try
{
var textLines = new List < SubtitleLine > ( ) ;
var pText = new StringBuilder ( ) ;
var vAlignment = string . Empty ;
string lastVPosition = string . Empty ;
foreach ( XmlNode innerNode in node . ChildNodes )
{
2019-01-19 12:29:38 +01:00
if ( innerNode . Name = = "Text" )
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
if ( innerNode . Attributes [ "VPosition" ] ! = null )
{
string vPosition = innerNode . Attributes [ "VPosition" ] . InnerText ;
var vAlignmentNode = innerNode . Attributes [ "VAlign" ] ;
if ( vAlignmentNode ! = null )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
vAlignment = vAlignmentNode . InnerText ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
if ( vPosition ! = lastVPosition )
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
if ( pText . Length > 0 & & lastVPosition . Length > 0 )
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
textLines . Add ( new SubtitleLine ( pText . ToString ( ) , lastVPosition , vAlignment ) ) ;
pText . Clear ( ) ;
2018-03-04 10:24:04 +01:00
}
2019-01-19 12:29:38 +01:00
lastVPosition = vPosition ;
2018-03-04 10:24:04 +01:00
}
2019-01-19 12:29:38 +01:00
}
2018-03-04 10:24:04 +01:00
2019-01-19 12:29:38 +01:00
bool alignLeft = false ;
bool alignRight = false ;
bool alignVTop = false ;
bool alignVCenter = false ;
if ( innerNode . Attributes [ "HAlign" ] ! = null )
{
string hAlign = innerNode . Attributes [ "HAlign" ] . InnerText ;
if ( hAlign = = "left" )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
alignLeft = true ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else if ( hAlign = = "right" )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
alignRight = true ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
2018-03-04 10:24:04 +01:00
2019-01-19 12:29:38 +01:00
if ( innerNode . Attributes [ "VAlign" ] ! = null )
{
string hAlign = innerNode . Attributes [ "VAlign" ] . InnerText ;
if ( hAlign = = "top" )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
alignVTop = true ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else if ( hAlign = = "center" )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
alignVCenter = true ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
if ( alignLeft | | alignRight | | alignVCenter | | alignVTop )
{
if ( ! pText . ToString ( ) . StartsWith ( "{\\an" , StringComparison . Ordinal ) )
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
string pre = string . Empty ;
if ( alignVTop )
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
if ( alignLeft )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an7}" ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else if ( alignRight )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an9}" ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an8}" ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
else if ( alignVCenter )
{
if ( alignLeft )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an4}" ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else if ( alignRight )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an6}" ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an5}" ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
else
{
if ( alignLeft )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an1}" ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else if ( alignRight )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pre = "{\\an3}" ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
}
2019-01-19 12:29:38 +01:00
string temp = pre + pText ;
pText . Clear ( ) ;
pText . Append ( temp ) ;
2018-03-04 10:24:04 +01:00
}
2019-01-19 12:29:38 +01:00
}
if ( innerNode . ChildNodes . Count = = 0 )
{
pText . Append ( innerNode . InnerText ) ;
}
else
{
foreach ( XmlNode innerInnerNode in innerNode )
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
if ( innerInnerNode . Name = = "Font" & & innerInnerNode . Attributes [ "Italic" ] ! = null & &
innerInnerNode . Attributes [ "Italic" ] . InnerText . Equals ( "yes" , StringComparison . OrdinalIgnoreCase ) )
{
if ( innerInnerNode . Attributes [ "Color" ] ! = null )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pText . Append ( "<i><font color=\"" + GetColorStringFromDCinema ( innerInnerNode . Attributes [ "Color" ] . Value ) + "\">" + innerInnerNode . InnerText + "</font><i>" ) ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
else
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pText . Append ( "<i>" + innerInnerNode . InnerText + "</i>" ) ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
else if ( innerInnerNode . Name = = "Font" & & innerInnerNode . Attributes [ "Color" ] ! = null )
2018-03-04 10:24:04 +01:00
{
2019-01-19 12:29:38 +01:00
if ( innerInnerNode . Attributes [ "Italic" ] ! = null & & innerInnerNode . Attributes [ "Italic" ] . InnerText . Equals ( "yes" , StringComparison . OrdinalIgnoreCase ) )
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pText . Append ( "<i><font color=\"" + GetColorStringFromDCinema ( innerInnerNode . Attributes [ "Color" ] . Value ) + "\">" + innerInnerNode . InnerText + "</font><i>" ) ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2019-01-19 12:29:38 +01:00
pText . Append ( "<font color=\"" + GetColorStringFromDCinema ( innerInnerNode . Attributes [ "Color" ] . Value ) + "\">" + innerInnerNode . InnerText + "</font>" ) ;
2019-01-19 14:40:37 +01:00
}
2019-01-19 12:29:38 +01:00
}
else
{
pText . Append ( innerInnerNode . InnerText ) ;
2018-03-04 10:24:04 +01:00
}
}
2019-01-19 12:29:38 +01:00
}
}
else
{
pText . Append ( innerNode . InnerText ) ;
2018-03-04 10:24:04 +01:00
}
}
if ( pText . Length > 0 )
{
textLines . Add ( new SubtitleLine ( pText . ToString ( ) , lastVPosition , vAlignment ) ) ;
}
string text ;
if ( textLines . All ( p = > p . VerticalAlignment . ToLowerInvariant ( ) = = "top" ) )
{
text = string . Join ( Environment . NewLine , textLines . OrderBy ( p = > p . GetVerticalPositionAsNumber ( ) ) . Select ( p = > p . Text ) ) ;
}
else
{
text = string . Join ( Environment . NewLine , textLines . OrderByDescending ( p = > p . GetVerticalPositionAsNumber ( ) ) . Select ( p = > p . Text ) ) ;
}
text = text . Replace ( Environment . NewLine + "{\\an1}" , Environment . NewLine ) ;
text = text . Replace ( Environment . NewLine + "{\\an2}" , Environment . NewLine ) ;
text = text . Replace ( Environment . NewLine + "{\\an3}" , Environment . NewLine ) ;
text = text . Replace ( Environment . NewLine + "{\\an4}" , Environment . NewLine ) ;
text = text . Replace ( Environment . NewLine + "{\\an5}" , Environment . NewLine ) ;
text = text . Replace ( Environment . NewLine + "{\\an6}" , Environment . NewLine ) ;
text = text . Replace ( Environment . NewLine + "{\\an7}" , Environment . NewLine ) ;
text = text . Replace ( Environment . NewLine + "{\\an8}" , Environment . NewLine ) ;
text = text . Replace ( Environment . NewLine + "{\\an9}" , Environment . NewLine ) ;
string start = node . Attributes [ "TimeIn" ] . InnerText ;
string end = node . Attributes [ "TimeOut" ] . InnerText ;
if ( node . ParentNode . Name = = "Font" & & node . ParentNode . Attributes [ "Italic" ] ! = null & & node . ParentNode . Attributes [ "Italic" ] . InnerText . Equals ( "yes" , StringComparison . OrdinalIgnoreCase ) & &
! text . Contains ( "<i>" ) )
{
if ( text . StartsWith ( "{\\an" , StringComparison . Ordinal ) & & text . Length > 6 )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
text = text . Insert ( 6 , "<i>" ) + "</i>" ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
else
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
text = "<i>" + text + "</i>" ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
}
subtitle . Paragraphs . Add ( new Paragraph ( GetTimeCode ( start ) , GetTimeCode ( end ) , text ) ) ;
}
catch ( Exception ex )
{
System . Diagnostics . Debug . WriteLine ( ex . Message ) ;
_errorCount + + ;
}
}
if ( subtitle . Paragraphs . Count > 0 )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
subtitle . Header = xml . OuterXml ; // save id/language/font for later use
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
subtitle . Renumber ( ) ;
}
internal static string GetColorStringFromDCinema ( string s )
{
if ( string . IsNullOrWhiteSpace ( s ) )
{
return s ;
}
var hex = s . TrimStart ( '#' ) ;
for ( int i = s . Length - 1 ; i > = 0 ; i - - )
{
if ( ! CharUtils . IsHexadecimal ( s [ i ] ) )
{
return s ;
}
}
return "#" + hex ;
}
private static TimeCode GetTimeCode ( string s )
{
var parts = s . Split ( ':' , '.' , ',' ) ;
int milliseconds = int . Parse ( parts [ 3 ] ) * 4 ; // 000 to 249
if ( s . Contains ( '.' ) )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
milliseconds = int . Parse ( parts [ 3 ] . PadRight ( 3 , '0' ) ) ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
if ( milliseconds > 999 )
2019-01-19 14:40:37 +01:00
{
2018-03-04 10:24:04 +01:00
milliseconds = 999 ;
2019-01-19 14:40:37 +01:00
}
2018-03-04 10:24:04 +01:00
return new TimeCode ( int . Parse ( parts [ 0 ] ) , int . Parse ( parts [ 1 ] ) , int . Parse ( parts [ 2 ] ) , milliseconds ) ;
}
public static string ConvertToTimeString ( TimeCode time )
{
return $"{time.Hours:00}:{time.Minutes:00}:{time.Seconds:00}:{time.Milliseconds / 4:000}" ;
}
}
}