2016-02-08 21:11:03 +01:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.IO.Compression ;
using System.Text ;
using System.Xml ;
using System.Xml.Schema ;
namespace Nikse.SubtitleEdit.Core.SubtitleFormats
{
public class DCinemaSmpte2010 : SubtitleFormat
{
//<?xml version="1.0" encoding="UTF-8"?>
//<dcst:SubtitleReel xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:dcst="http://www.smpte-ra.org/schemas/428-7/2010/DCST">
// <Id>urn:uuid:7be835a3-cfb4-43d0-bb4b-f0b4c95e962e</Id>
// <ContentTitleText>2001, A Space Odissey</ContentTitleText>
// <AnnotationText>This is a subtitle file</AnnotationText>
// <IssueDate>2012-06-26T12:33:59.000-00:00</IssueDate>
// <ReelNumber>1</ReelNumber>
// <Language>fr</Language>
// <EditRate>25 1</EditRate>
// <TimeCodeRate>25</TimeCodeRate>
// <StartTime>00:00:00:00</StartTime>
// <LoadFont ID="theFontId">urn:uuid:3dec6dc0-39d0-498d-97d0-928d2eb78391</LoadFont>
// <SubtitleList
// <Font ID="theFontId" Size="39" Weight="normal" Color="FFFFFFFF">
// <Subtitle FadeDownTime="00:00:00:00" FadeUpTime="00:00:00:00" TimeOut="00:00:00:01" TimeIn="00:00:00:00" SpotNumber="1">
// <Text Vposition="10.0" Valign="bottom">Hallo</Text>
// </Subtitle>
// </SubtitleList
//</dcst:SubtitleReel>
public string Errors { get ; private set ; }
private double _frameRate = 24 ;
public int Version { get ; set ; }
2017-08-03 12:43:52 +02:00
public override string Extension = > ".xml" ;
2016-02-08 21:11:03 +01:00
2017-08-03 12:43:52 +02:00
public override string Name = > "D-Cinema SMPTE 2010" ;
2016-02-08 21:11:03 +01:00
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 ( "http://www.smpte-ra.org/schemas/428-7/2007/DCST" ) )
return false ;
if ( xmlAsString . Contains ( "<dcst:SubtitleReel" ) | | xmlAsString . Contains ( "<SubtitleReel" ) )
{
var xml = new XmlDocument { XmlResolver = null } ;
try
{
xmlAsString = xmlAsString . Replace ( "<dcst:" , "<" ) . Replace ( "</dcst:" , "</" ) ;
xmlAsString = xmlAsString . Replace ( "xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\"" , string . Empty ) ;
xml . LoadXml ( xmlAsString ) ;
var subtitles = xml . DocumentElement . SelectNodes ( "//Subtitle" ) ;
return subtitles ! = null & & subtitles . Count > 0 ;
}
catch ( Exception ex )
{
System . Diagnostics . Debug . WriteLine ( ex . Message ) ;
return false ;
}
}
2016-03-30 20:35:27 +02:00
return false ;
2016-02-08 21:11:03 +01:00
}
public override string ToText ( Subtitle subtitle , string title )
{
Errors = null ;
var ss = Configuration . Settings . SubtitleSettings ;
if ( ! string . IsNullOrEmpty ( ss . CurrentDCinemaEditRate ) )
{
string [ ] temp = ss . CurrentDCinemaEditRate . Split ( new [ ] { ' ' } , StringSplitOptions . RemoveEmptyEntries ) ;
double d1 , d2 ;
if ( temp . Length = = 2 & & double . TryParse ( temp [ 0 ] , out d1 ) & & double . TryParse ( temp [ 1 ] , out d2 ) )
_frameRate = d1 / d2 ;
}
string xmlStructure =
"<dcst:SubtitleReel xmlns:dcst=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">" + Environment . NewLine +
" <dcst:Id>urn:uuid:7be835a3-cfb4-43d0-bb4b-f0b4c95e962e</dcst:Id>" + Environment . NewLine +
" <dcst:ContentTitleText></dcst:ContentTitleText> " + Environment . NewLine +
" <dcst:AnnotationText>This is a subtitle file</dcst:AnnotationText>" + Environment . NewLine +
" <dcst:IssueDate>2012-06-26T12:33:59.000-00:00</dcst:IssueDate>" + Environment . NewLine +
" <dcst:ReelNumber>1</dcst:ReelNumber>" + Environment . NewLine +
" <dcst:Language>en</dcst:Language>" + Environment . NewLine +
" <dcst:EditRate>25 1</dcst:EditRate>" + Environment . NewLine +
" <dcst:TimeCodeRate>25</dcst:TimeCodeRate>" + Environment . NewLine +
" <dcst:StartTime>00:00:00:00</dcst:StartTime> " + Environment . NewLine +
" <dcst:LoadFont ID=\"theFontId\">urn:uuid:3dec6dc0-39d0-498d-97d0-928d2eb78391</dcst:LoadFont>" + Environment . NewLine +
" <dcst:SubtitleList>" + Environment . NewLine +
" <dcst:Font ID=\"theFontId\" Size=\"39\" Weight=\"normal\" Color=\"FFFFFFFF\" Effect=\"border\" EffectColor=\"FF000000\">" + Environment . NewLine +
" </dcst:Font>" + Environment . NewLine +
" </dcst:SubtitleList>" + Environment . NewLine +
"</dcst:SubtitleReel>" ;
var xml = new XmlDocument ( ) ;
xml . LoadXml ( xmlStructure ) ;
xml . PreserveWhitespace = true ;
var nsmgr = new XmlNamespaceManager ( xml . NameTable ) ;
nsmgr . AddNamespace ( "dcst" , xml . DocumentElement . NamespaceURI ) ;
if ( string . IsNullOrEmpty ( ss . CurrentDCinemaMovieTitle ) )
ss . CurrentDCinemaMovieTitle = title ;
if ( ss . CurrentDCinemaFontSize = = 0 | | string . IsNullOrEmpty ( ss . CurrentDCinemaFontEffect ) )
Configuration . Settings . SubtitleSettings . InitializeDCinameSettings ( true ) ;
xml . DocumentElement . SelectSingleNode ( "dcst:ContentTitleText" , nsmgr ) . InnerText = ss . CurrentDCinemaMovieTitle ;
if ( string . IsNullOrEmpty ( ss . CurrentDCinemaSubtitleId ) | | ! ss . CurrentDCinemaSubtitleId . StartsWith ( "urn:uuid:" ) )
ss . CurrentDCinemaSubtitleId = "urn:uuid:" + Guid . NewGuid ( ) ;
xml . DocumentElement . SelectSingleNode ( "dcst:Id" , nsmgr ) . InnerText = ss . CurrentDCinemaSubtitleId ;
xml . DocumentElement . SelectSingleNode ( "dcst:ReelNumber" , nsmgr ) . InnerText = ss . CurrentDCinemaReelNumber ;
xml . DocumentElement . SelectSingleNode ( "dcst:IssueDate" , nsmgr ) . InnerText = ss . CurrentDCinemaIssueDate ;
if ( string . IsNullOrEmpty ( ss . CurrentDCinemaLanguage ) )
ss . CurrentDCinemaLanguage = "en" ;
xml . DocumentElement . SelectSingleNode ( "dcst:Language" , nsmgr ) . InnerText = ss . CurrentDCinemaLanguage ;
if ( ss . CurrentDCinemaEditRate = = null & & ss . CurrentDCinemaTimeCodeRate = = null )
{
2017-04-27 17:25:12 +02:00
if ( Math . Abs ( Configuration . Settings . General . CurrentFrameRate - 24 ) < 0.01 )
2016-02-08 21:11:03 +01:00
{
ss . CurrentDCinemaEditRate = "24 1" ;
ss . CurrentDCinemaTimeCodeRate = "24" ;
}
else
{
ss . CurrentDCinemaEditRate = "25 1" ;
ss . CurrentDCinemaTimeCodeRate = "25" ;
}
}
xml . DocumentElement . SelectSingleNode ( "dcst:EditRate" , nsmgr ) . InnerText = ss . CurrentDCinemaEditRate ;
xml . DocumentElement . SelectSingleNode ( "dcst:TimeCodeRate" , nsmgr ) . InnerText = ss . CurrentDCinemaTimeCodeRate ;
if ( string . IsNullOrEmpty ( ss . CurrentDCinemaStartTime ) )
ss . CurrentDCinemaStartTime = "00:00:00:00" ;
xml . DocumentElement . SelectSingleNode ( "dcst:StartTime" , nsmgr ) . InnerText = ss . CurrentDCinemaStartTime ;
xml . DocumentElement . SelectSingleNode ( "dcst:LoadFont" , nsmgr ) . InnerText = ss . CurrentDCinemaFontUri ;
int fontSize = ss . CurrentDCinemaFontSize ;
string loadedFontId = "Font1" ;
if ( ! string . IsNullOrEmpty ( ss . CurrentDCinemaFontId ) )
loadedFontId = ss . CurrentDCinemaFontId ;
xml . DocumentElement . SelectSingleNode ( "dcst:LoadFont" , nsmgr ) . Attributes [ "ID" ] . Value = loadedFontId ;
xml . DocumentElement . SelectSingleNode ( "dcst:SubtitleList/dcst:Font" , nsmgr ) . Attributes [ "Size" ] . Value = fontSize . ToString ( ) ;
xml . DocumentElement . SelectSingleNode ( "dcst:SubtitleList/dcst:Font" , nsmgr ) . Attributes [ "Color" ] . Value = "FF" + Utilities . ColorToHex ( ss . CurrentDCinemaFontColor ) . TrimStart ( '#' ) . ToUpper ( ) ;
xml . DocumentElement . SelectSingleNode ( "dcst:SubtitleList/dcst:Font" , nsmgr ) . Attributes [ "ID" ] . Value = loadedFontId ;
xml . DocumentElement . SelectSingleNode ( "dcst:SubtitleList/dcst:Font" , nsmgr ) . Attributes [ "Effect" ] . Value = ss . CurrentDCinemaFontEffect ;
xml . DocumentElement . SelectSingleNode ( "dcst:SubtitleList/dcst:Font" , nsmgr ) . Attributes [ "EffectColor" ] . Value = "FF" + Utilities . ColorToHex ( ss . CurrentDCinemaFontEffectColor ) . TrimStart ( '#' ) . ToUpper ( ) ;
XmlNode mainListFont = xml . DocumentElement . SelectSingleNode ( "dcst:SubtitleList/dcst:Font" , nsmgr ) ;
int no = 0 ;
foreach ( Paragraph p in subtitle . Paragraphs )
{
if ( p . Text ! = null )
{
XmlNode subNode = xml . CreateElement ( "dcst:Subtitle" , "dcst" ) ;
XmlAttribute id = xml . CreateAttribute ( "SpotNumber" ) ;
id . InnerText = ( no + 1 ) . ToString ( ) ;
subNode . Attributes . Append ( id ) ;
XmlAttribute fadeUpTime = xml . CreateAttribute ( "FadeUpTime" ) ;
fadeUpTime . InnerText = "00:00:00:00" ; //Configuration.Settings.SubtitleSettings.DCinemaFadeUpDownTime.ToString();
subNode . Attributes . Append ( fadeUpTime ) ;
XmlAttribute fadeDownTime = xml . CreateAttribute ( "FadeDownTime" ) ;
fadeDownTime . InnerText = "00:00:00:00" ; //Configuration.Settings.SubtitleSettings.DCinemaFadeUpDownTime.ToString();
subNode . Attributes . Append ( fadeDownTime ) ;
XmlAttribute start = xml . CreateAttribute ( "TimeIn" ) ;
start . InnerText = ConvertToTimeString ( p . StartTime ) ;
subNode . Attributes . Append ( start ) ;
XmlAttribute end = xml . CreateAttribute ( "TimeOut" ) ;
end . InnerText = ConvertToTimeString ( p . EndTime ) ;
subNode . Attributes . Append ( end ) ;
2016-03-30 20:35:27 +02:00
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
2016-02-08 21:11:03 +01:00
2016-03-30 20:35:27 +02:00
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
2016-02-08 21:11:03 +01:00
2016-03-30 20:35:27 +02:00
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
2016-02-08 21:11:03 +01:00
2016-03-30 20:35:27 +02:00
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
2016-02-08 21:11:03 +01:00
2016-03-30 20:35:27 +02:00
string text = Utilities . RemoveSsaTags ( p . Text ) ;
2016-02-08 21:11:03 +01:00
var lines = text . SplitToLines ( ) ;
2017-11-26 17:35:00 +01:00
int vPos = 1 + lines . Count * 7 ;
2016-02-08 21:11:03 +01:00
int vPosFactor = ( int ) Math . Round ( fontSize / 7.4 ) ;
if ( alignVTop )
{
vPos = Configuration . Settings . SubtitleSettings . DCinemaBottomMargin ; // Bottom margin is normally 8
}
else if ( alignVCenter )
{
2017-11-26 17:35:00 +01:00
vPos = ( int ) Math . Round ( ( lines . Count * vPosFactor * - 1 ) / 2.0 ) ;
2016-02-08 21:11:03 +01:00
}
else
{
2017-11-26 17:35:00 +01:00
vPos = ( lines . Count * vPosFactor ) - vPosFactor + Configuration . Settings . SubtitleSettings . DCinemaBottomMargin ; // Bottom margin is normally 8
2016-02-08 21:11:03 +01:00
}
bool isItalic = false ;
int fontNo = 0 ;
Stack < string > fontColors = new Stack < string > ( ) ;
foreach ( string line in lines )
{
XmlNode textNode = xml . CreateElement ( "dcst:Text" , "dcst" ) ;
XmlAttribute vPosition = xml . CreateAttribute ( "Vposition" ) ;
vPosition . InnerText = vPos . ToString ( ) ;
textNode . Attributes . Append ( vPosition ) ;
XmlAttribute vAlign = xml . CreateAttribute ( "Valign" ) ;
if ( alignVTop )
vAlign . InnerText = "top" ;
else if ( alignVCenter )
vAlign . InnerText = "center" ;
else
vAlign . InnerText = "bottom" ;
textNode . Attributes . Append ( vAlign ) ; textNode . Attributes . Append ( vAlign ) ;
XmlAttribute hAlign = xml . CreateAttribute ( "Halign" ) ;
if ( alignLeft )
hAlign . InnerText = "left" ;
else if ( alignRight )
hAlign . InnerText = "right" ;
else
hAlign . InnerText = "center" ;
textNode . Attributes . Append ( hAlign ) ;
XmlAttribute direction = xml . CreateAttribute ( "Direction" ) ;
direction . InnerText = "ltr" ;
textNode . Attributes . Append ( direction ) ;
int i = 0 ;
var txt = new StringBuilder ( ) ;
var html = new StringBuilder ( ) ;
XmlNode nodeTemp = xml . CreateElement ( "temp" ) ;
while ( i < line . Length )
{
2017-04-27 17:25:12 +02:00
if ( ! isItalic & & line . Substring ( i ) . StartsWith ( "<i>" , StringComparison . Ordinal ) )
2016-02-08 21:11:03 +01:00
{
if ( txt . Length > 0 )
{
nodeTemp . InnerText = txt . ToString ( ) ;
html . Append ( nodeTemp . InnerXml ) ;
2017-01-20 22:25:06 +01:00
txt . Clear ( ) ;
2016-02-08 21:11:03 +01:00
}
isItalic = true ;
i + = 2 ;
}
2017-04-27 17:25:12 +02:00
else if ( isItalic & & line . Substring ( i ) . StartsWith ( "</i>" , StringComparison . Ordinal ) )
2016-02-08 21:11:03 +01:00
{
if ( txt . Length > 0 )
{
XmlNode fontNode = xml . CreateElement ( "dcst:Font" , "dcst" ) ;
XmlAttribute italic = xml . CreateAttribute ( "Italic" ) ;
italic . InnerText = "yes" ;
fontNode . Attributes . Append ( italic ) ;
2017-04-27 17:25:12 +02:00
if ( line . Length > i + 5 & & line . Substring ( i + 4 ) . StartsWith ( "</font>" , StringComparison . Ordinal ) )
2016-02-08 21:11:03 +01:00
{
XmlAttribute 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 ) ;
2017-01-20 22:25:06 +01:00
txt . Clear ( ) ;
2016-02-08 21:11:03 +01:00
}
isItalic = false ;
i + = 3 ;
}
2017-04-27 17:25:12 +02:00
else if ( line . Substring ( i ) . StartsWith ( "<font color=" , StringComparison . Ordinal ) & & line . Substring ( i + 3 ) . Contains ( '>' ) )
2016-02-08 21:11:03 +01:00
{
int endOfFont = line . IndexOf ( '>' , i ) ;
if ( txt . Length > 0 )
{
nodeTemp . InnerText = txt . ToString ( ) ;
html . Append ( nodeTemp . InnerXml ) ;
2017-01-20 22:25:06 +01:00
txt . Clear ( ) ;
2016-02-08 21:11:03 +01:00
}
string c = line . Substring ( i + 12 , endOfFont - ( i + 12 ) ) ;
c = c . Trim ( '"' ) . Trim ( '\'' ) . Trim ( ) ;
if ( c . StartsWith ( '#' ) )
c = c . TrimStart ( '#' ) . ToUpper ( ) . PadLeft ( 8 , 'F' ) ;
fontColors . Push ( c ) ;
fontNo + + ;
i + = endOfFont - i ;
}
2017-04-27 17:25:12 +02:00
else if ( fontNo > 0 & & line . Substring ( i ) . StartsWith ( "</font>" , StringComparison . Ordinal ) )
2016-02-08 21:11:03 +01:00
{
if ( txt . Length > 0 )
{
XmlNode fontNode = xml . CreateElement ( "dcst:Font" , "dcst" ) ;
XmlAttribute fontColor = xml . CreateAttribute ( "Color" ) ;
fontColor . InnerText = fontColors . Pop ( ) ;
fontNode . Attributes . Append ( fontColor ) ;
2017-04-27 17:25:12 +02:00
if ( line . Length > i + 9 & & line . Substring ( i + 7 ) . StartsWith ( "</i>" , StringComparison . Ordinal ) )
2016-02-08 21:11:03 +01:00
{
XmlAttribute italic = xml . CreateAttribute ( "Italic" ) ;
italic . InnerText = "yes" ;
fontNode . Attributes . Append ( italic ) ;
isItalic = false ;
i + = 4 ;
}
fontNode . InnerText = HtmlUtil . RemoveHtmlTags ( txt . ToString ( ) ) ;
html . Append ( fontNode . OuterXml ) ;
2017-01-20 22:25:06 +01:00
txt . Clear ( ) ;
2016-02-08 21:11:03 +01:00
}
fontNo - - ;
i + = 6 ;
}
else
{
txt . Append ( line [ i ] ) ;
}
i + + ;
}
if ( fontNo > 0 )
{
if ( txt . Length > 0 )
{
XmlNode fontNode = xml . CreateElement ( "dcst:Font" , "dcst" ) ;
XmlAttribute fontColor = xml . CreateAttribute ( "Color" ) ;
fontColor . InnerText = fontColors . Peek ( ) ;
fontNode . Attributes . Append ( fontColor ) ;
if ( isItalic )
{
XmlAttribute italic = xml . CreateAttribute ( "Italic" ) ;
italic . InnerText = "yes" ;
fontNode . Attributes . Append ( italic ) ;
}
fontNode . InnerText = HtmlUtil . RemoveHtmlTags ( txt . ToString ( ) ) ;
html . Append ( fontNode . OuterXml ) ;
}
2017-04-27 17:25:12 +02:00
else if ( html . Length > 0 & & html . ToString ( ) . StartsWith ( "<dcst:Font " , StringComparison . Ordinal ) )
2016-02-08 21:11:03 +01:00
{
XmlDocument temp = new XmlDocument ( ) ;
temp . LoadXml ( "<root>" + html . ToString ( ) . Replace ( "dcst:Font" , "Font" ) + "</root>" ) ;
XmlNode fontNode = xml . CreateElement ( "dcst:Font" ) ;
fontNode . InnerXml = temp . DocumentElement . SelectSingleNode ( "Font" ) . InnerXml ;
foreach ( XmlAttribute a in temp . DocumentElement . SelectSingleNode ( "Font" ) . Attributes )
{
XmlAttribute newA = xml . CreateAttribute ( a . Name ) ;
newA . InnerText = a . InnerText ;
fontNode . Attributes . Append ( newA ) ;
}
XmlAttribute fontColor = xml . CreateAttribute ( "Color" ) ;
fontColor . InnerText = fontColors . Peek ( ) ;
fontNode . Attributes . Append ( fontColor ) ;
2017-01-20 22:25:06 +01:00
html . Clear ( ) ;
2016-02-08 21:11:03 +01:00
html . Append ( fontNode . OuterXml ) ;
}
}
else if ( isItalic )
{
if ( txt . Length > 0 )
{
XmlNode fontNode = xml . CreateElement ( "dcst:Font" , "dcst" ) ;
XmlAttribute italic = xml . CreateAttribute ( "Italic" ) ;
italic . InnerText = "yes" ;
fontNode . Attributes . Append ( italic ) ;
fontNode . InnerText = HtmlUtil . RemoveHtmlTags ( line ) ;
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 )
vPos + = vPosFactor ;
else
vPos - = vPosFactor ;
}
if ( subNode . InnerXml . Length = = 0 )
{ // Empty text is just one space
XmlNode textNode = xml . CreateElement ( "dcst:Text" , "dcst" ) ;
textNode . InnerXml = " " ;
subNode . AppendChild ( textNode ) ;
XmlAttribute vPosition = xml . CreateAttribute ( "Vposition" ) ;
vPosition . InnerText = vPos . ToString ( ) ;
textNode . Attributes . Append ( vPosition ) ;
XmlAttribute vAlign = xml . CreateAttribute ( "Valign" ) ;
vAlign . InnerText = "bottom" ;
textNode . Attributes . Append ( vAlign ) ;
}
mainListFont . AppendChild ( subNode ) ;
no + + ;
}
}
string result = ToUtf8XmlString ( xml ) . Replace ( "encoding=\"utf-8\"" , "encoding=\"UTF-8\"" ) . Replace ( " xmlns:dcst=\"dcst\"" , string . Empty ) ;
const string res = "Nikse.SubtitleEdit.Resources.SMPTE-428-7-2010-DCST.xsd.gz" ;
System . Reflection . Assembly asm = System . Reflection . Assembly . GetExecutingAssembly ( ) ;
Stream strm = asm . GetManifestResourceStream ( res ) ;
if ( strm ! = null )
{
try
{
var xmld = new XmlDocument ( ) ;
var rdr = new StreamReader ( strm ) ;
var zip = new GZipStream ( rdr . BaseStream , CompressionMode . Decompress ) ;
xmld . LoadXml ( result ) ;
using ( var xr = XmlReader . Create ( zip ) )
{
xmld . Schemas . Add ( null , xr ) ;
xmld . Validate ( ValidationCallBack ) ;
}
}
catch ( Exception exception )
{
Errors = "Error validating xml via SMPTE-428-7-2010-DCST.xsd: " + exception . Message ;
}
}
2017-01-20 21:39:13 +01:00
return FixDcsTextSameLine ( result ) ;
}
/// <summary>
/// All space characters present inside the content of a Text element shall be rendered
/// </summary>
internal static string FixDcsTextSameLine ( string xml )
{
int index = xml . IndexOf ( "<dcst:Text" , StringComparison . Ordinal ) ;
2017-04-27 16:38:07 +02:00
int endIndex = 1 ;
while ( index > 0 & & endIndex > 0 )
2017-01-20 21:39:13 +01:00
{
2017-04-27 16:38:07 +02:00
endIndex = xml . IndexOf ( "</dcst:Text>" , index , StringComparison . Ordinal ) ;
2017-01-20 21:39:13 +01:00
if ( endIndex > 0 )
{
var part = xml . Substring ( index , endIndex - index ) ;
if ( part . Contains ( Environment . NewLine ) )
{
part = part . Replace ( Environment . NewLine , " " ) ;
while ( part . Contains ( " " ) )
{
part = part . Replace ( " " , " " ) ;
}
part = part . Replace ( "> <" , "><" ) ;
}
xml = xml . Remove ( index , endIndex - index ) . Insert ( index , part ) ;
index = xml . IndexOf ( "<dcst:Text" , endIndex , StringComparison . Ordinal ) ;
}
}
return xml ;
2016-02-08 21:11:03 +01:00
}
private void ValidationCallBack ( object sender , ValidationEventArgs e )
{
throw new Exception ( e . Message ) ;
}
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 ( ) . Replace ( "<dcst:" , "<" ) . Replace ( "</dcst:" , "</" ) . Replace ( "xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\"" , string . Empty ) ) ; // tags might be prefixed with namespace (or not)... so we just remove them
var ss = Configuration . Settings . SubtitleSettings ;
try
{
ss . InitializeDCinameSettings ( true ) ;
XmlNode node = xml . DocumentElement . SelectSingleNode ( "Id" ) ;
if ( node ! = null )
ss . CurrentDCinemaSubtitleId = node . InnerText ;
node = xml . DocumentElement . SelectSingleNode ( "ReelNumber" ) ;
if ( node ! = null )
ss . CurrentDCinemaReelNumber = node . InnerText ;
node = xml . DocumentElement . SelectSingleNode ( "EditRate" ) ;
if ( node ! = null )
ss . CurrentDCinemaEditRate = node . InnerText ;
node = xml . DocumentElement . SelectSingleNode ( "TimeCodeRate" ) ;
if ( node ! = null )
{
ss . CurrentDCinemaTimeCodeRate = node . InnerText ;
if ( ss . CurrentDCinemaEditRate = = "24" )
Configuration . Settings . General . CurrentFrameRate = 24 ;
else if ( ss . CurrentDCinemaEditRate = = "25" )
Configuration . Settings . General . CurrentFrameRate = 24 ;
2016-06-01 20:59:22 +02:00
if ( BatchSourceFrameRate . HasValue )
{
Configuration . Settings . General . CurrentFrameRate = BatchSourceFrameRate . Value ;
}
2016-02-08 21:11:03 +01:00
}
node = xml . DocumentElement . SelectSingleNode ( "StartTime" ) ;
if ( node ! = null )
ss . CurrentDCinemaStartTime = node . InnerText ;
node = xml . DocumentElement . SelectSingleNode ( "Language" ) ;
if ( node ! = null )
ss . CurrentDCinemaLanguage = node . InnerText ;
node = xml . DocumentElement . SelectSingleNode ( "ContentTitleText" ) ;
if ( node ! = null )
ss . CurrentDCinemaMovieTitle = node . InnerText ;
node = xml . DocumentElement . SelectSingleNode ( "IssueDate" ) ;
if ( node ! = null )
ss . CurrentDCinemaIssueDate = node . InnerText ;
node = xml . DocumentElement . SelectSingleNode ( "LoadFont" ) ;
if ( node ! = null )
ss . CurrentDCinemaFontUri = node . InnerText ;
node = xml . DocumentElement . SelectSingleNode ( "SubtitleList/Font" ) ;
if ( node ! = null )
{
if ( node . Attributes [ "ID" ] ! = null )
ss . CurrentDCinemaFontId = node . Attributes [ "ID" ] . InnerText ;
if ( node . Attributes [ "Size" ] ! = null )
ss . CurrentDCinemaFontSize = Convert . ToInt32 ( node . Attributes [ "Size" ] . InnerText ) ;
if ( node . Attributes [ "Color" ] ! = null )
ss . CurrentDCinemaFontColor = System . Drawing . ColorTranslator . FromHtml ( "#" + node . Attributes [ "Color" ] . InnerText ) ;
if ( node . Attributes [ "Effect" ] ! = null )
ss . CurrentDCinemaFontEffect = node . Attributes [ "Effect" ] . InnerText ;
if ( node . Attributes [ "EffectColor" ] ! = null )
ss . CurrentDCinemaFontEffectColor = System . Drawing . ColorTranslator . FromHtml ( "#" + node . Attributes [ "EffectColor" ] . InnerText ) ;
}
}
catch ( Exception exception )
{
System . Diagnostics . Debug . WriteLine ( exception . Message ) ;
}
foreach ( XmlNode node in xml . DocumentElement . SelectNodes ( "//Subtitle" ) )
{
try
{
2017-01-20 22:25:06 +01:00
var pText = new StringBuilder ( ) ;
2016-02-08 21:11:03 +01:00
string lastVPosition = string . Empty ;
foreach ( XmlNode innerNode in node . ChildNodes )
{
switch ( innerNode . Name )
{
case "Text" :
if ( innerNode . Attributes [ "Vposition" ] ! = null )
{
string vPosition = innerNode . Attributes [ "Vposition" ] . InnerText ;
if ( vPosition ! = lastVPosition )
{
if ( pText . Length > 0 & & lastVPosition . Length > 0 )
pText . AppendLine ( ) ;
lastVPosition = vPosition ;
}
}
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" )
alignLeft = true ;
else if ( hAlign = = "right" )
alignRight = true ;
}
if ( innerNode . Attributes [ "Valign" ] ! = null )
{
string hAlign = innerNode . Attributes [ "Valign" ] . InnerText ;
if ( hAlign = = "top" )
alignVTop = true ;
else if ( hAlign = = "center" )
alignVCenter = true ;
}
if ( alignLeft | | alignRight | | alignVCenter | | alignVTop )
{
2017-04-27 17:25:12 +02:00
if ( ! pText . ToString ( ) . StartsWith ( "{\\an" , StringComparison . Ordinal ) )
2016-02-08 21:11:03 +01:00
{
string pre = string . Empty ;
if ( alignVTop )
{
if ( alignLeft )
pre = "{\\an7}" ;
else if ( alignRight )
pre = "{\\an9}" ;
else
pre = "{\\an8}" ;
}
else if ( alignVCenter )
{
if ( alignLeft )
pre = "{\\an4}" ;
else if ( alignRight )
pre = "{\\an6}" ;
else
pre = "{\\an5}" ;
}
else
{
if ( alignLeft )
pre = "{\\an1}" ;
else if ( alignRight )
pre = "{\\an3}" ;
}
string temp = pre + pText ;
2017-01-20 22:25:06 +01:00
pText . Clear ( ) ;
2016-02-08 21:11:03 +01:00
pText . Append ( temp ) ;
}
}
if ( innerNode . ChildNodes . Count = = 0 )
{
pText . Append ( innerNode . InnerText ) ;
}
else
{
foreach ( XmlNode innerInnerNode in innerNode )
{
if ( innerInnerNode . Name = = "Font" & & innerInnerNode . Attributes [ "Italic" ] ! = null & &
innerInnerNode . Attributes [ "Italic" ] . InnerText . Equals ( "yes" , StringComparison . OrdinalIgnoreCase ) )
{
if ( innerInnerNode . Attributes [ "Color" ] ! = null )
2018-03-04 10:24:04 +01:00
pText . Append ( "<i><font color=\"" + DCinemaInterop . GetColorStringFromDCinema ( innerInnerNode . Attributes [ "Color" ] . Value ) + "\">" + innerInnerNode . InnerText + "</font><i>" ) ;
2016-02-08 21:11:03 +01:00
else
pText . Append ( "<i>" + innerInnerNode . InnerText + "</i>" ) ;
}
else if ( innerInnerNode . Name = = "Font" & & innerInnerNode . Attributes [ "Color" ] ! = null )
{
if ( innerInnerNode . Attributes [ "Italic" ] ! = null & & innerInnerNode . Attributes [ "Italic" ] . InnerText . Equals ( "yes" , StringComparison . OrdinalIgnoreCase ) )
2018-03-04 10:24:04 +01:00
pText . Append ( "<i><font color=\"" + DCinemaInterop . GetColorStringFromDCinema ( innerInnerNode . Attributes [ "Color" ] . Value ) + "\">" + innerInnerNode . InnerText + "</font><i>" ) ;
2016-02-08 21:11:03 +01:00
else
2018-03-04 10:24:04 +01:00
pText . Append ( "<font color=\"" + DCinemaInterop . GetColorStringFromDCinema ( innerInnerNode . Attributes [ "Color" ] . Value ) + "\">" + innerInnerNode . InnerText + "</font>" ) ;
2016-02-08 21:11:03 +01:00
}
else
{
pText . Append ( innerInnerNode . InnerText ) ;
}
}
}
break ;
default :
pText . Append ( innerNode . InnerText ) ;
break ;
}
}
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 ) & &
! pText . ToString ( ) . Contains ( "<i>" ) )
{
string text = pText . ToString ( ) ;
2017-04-27 17:25:12 +02:00
if ( text . StartsWith ( "{\\an" , StringComparison . Ordinal ) & & text . Length > 6 )
2016-02-08 21:11:03 +01:00
text = text . Insert ( 6 , "<i>" ) + "</i>" ;
else
text = "<i>" + text + "</i>" ;
pText = new StringBuilder ( text ) ;
}
subtitle . Paragraphs . Add ( new Paragraph ( GetTimeCode ( start ) , GetTimeCode ( end ) , pText . ToString ( ) ) ) ;
}
catch ( Exception ex )
{
System . Diagnostics . Debug . WriteLine ( ex . Message ) ;
_errorCount + + ;
}
}
if ( subtitle . Paragraphs . Count > 0 )
subtitle . Header = xml . OuterXml ; // save id/language/font for later use
subtitle . Renumber ( ) ;
}
private TimeCode GetTimeCode ( string s )
{
2016-05-03 14:56:37 +02:00
var parts = s . Split ( new [ ] { ':' , '.' , ',' } ) ;
2016-02-08 21:11:03 +01:00
int milliseconds = ( int ) Math . Round ( int . Parse ( parts [ 3 ] ) * ( TimeCode . BaseUnit / _frameRate ) ) ;
if ( milliseconds > 999 )
milliseconds = 999 ;
return new TimeCode ( int . Parse ( parts [ 0 ] ) , int . Parse ( parts [ 1 ] ) , int . Parse ( parts [ 2 ] ) , milliseconds ) ;
}
public static int MsToFramesMaxFrameRate ( double milliseconds , double frameRate )
{
int frames = ( int ) Math . Round ( milliseconds / ( TimeCode . BaseUnit / frameRate ) ) ;
if ( frames > = Configuration . Settings . General . CurrentFrameRate )
frames = ( int ) ( frameRate - 0.01 ) ;
return frames ;
}
private string ConvertToTimeString ( TimeCode time )
{
return string . Format ( "{0:00}:{1:00}:{2:00}:{3:00}" , time . Hours , time . Minutes , time . Seconds , MsToFramesMaxFrameRate ( time . Milliseconds , _frameRate ) ) ;
}
}
}