// Copyright (c) 2005, Rodrigo Braz Monteiro // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of the Aegisub Group nor the names of its contributors // may be used to endorse or promote products derived from this software // without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // // ----------------------------------------------------------------------------- // // AEGISUB // // Website: http://aegisub.cellosoft.com // Contact: mailto:zeratul@cellosoft.com // //////////// // Includes #include "ass_style.h" #include ///////////////////////// AssColor ////////////////////////// //////////////// // Constructors AssColor::AssColor () { r=g=b=a=0; } AssColor::AssColor (wxColour &color) { SetWXColor(color); } ////////////////// // Parse from ASS void AssColor::ParseASS (const wxString _value) { // Prepare wxString value = _value; value.Trim(false); value.Trim(true); value.UpperCase(); // Remove leading and ending crap if (value.Left(1) == _T("&")) value = value.Mid(1); if (value.Left(1) == _T("H")) value = value.Mid(1); if (value.Right(1) == _T("&")) value = value.Left(value.Length()-1); // Read colours long temp[4] = { 0, 0, 0, 0 }; bool ok; for (int i=0;i<4;i++) { if (value.Length() > 0) { ok = value.Right(2).ToLong(&temp[i],16); if (!ok) temp[i] = 0; value.Truncate(value.Length()-2); } else break; } // Copy r = temp[0]; g = temp[1]; b = temp[2]; a = temp[3]; } ////////////////// // Parse from SSA void AssColor::ParseSSA (wxString value) { value.Trim(true); value.Trim(false); // Check if the moron who wrote it used ASS style in SSA if (value.Left(2) == _T("&H")) { ParseASS(value); return; } // Parse SSA long val; value.ToLong(&val); b = (val >> 16) & 0xFF; g = (val >> 8) & 0xFF; r = val & 0xFF; a = 0; } /////////////////// // Gets a wxColour wxColour AssColor::GetWXColor() { return wxColour(r,g,b); } ////////////////////// // Sets color from wx void AssColor::SetWXColor(wxColor &color) { r = color.Red(); g = color.Green(); b = color.Blue(); } /////////////////////////////// // Get formatted in ASS format wxString AssColor::GetASSFormatted (bool alpha,bool stripped,bool isStyle) { wxString work; if (!stripped) work += _T("&H"); if (alpha) work += wxString::Format(_T("%02X"),a); work += wxString::Format(_T("%02X%02X%02X"),b,g,r); if (!stripped && !isStyle) work += _T("&"); return work; } ///////////////////////// // Get decimal formatted wxString AssColor::GetSSAFormatted () { return wxString::Format(_T("%i"),(b<<16)+(g<<8)+r); } ///////////////////////// AssStyle ///////////////////////// /////////////////////// // Default Constructor AssStyle::AssStyle() { Type = ENTRY_STYLE; group = _T("[V4+ Styles]"); name = _T("Default"); font = _T("Arial"); fontsize = 20; primary.r = 255; primary.g = 255; primary.b = 255; primary.a = 0; secondary.r = 255; secondary.g = 255; secondary.b = 0; secondary.a = 0; outline.r = 0; outline.g = 0; outline.b = 0; outline.a = 0; shadow.r = 0; shadow.g = 0; shadow.b = 0; shadow.a = 0; bold = false; italic = false; underline = false; strikeout = false; scalex = 100; scaley = 100; spacing = 0; angle = 0.0; borderstyle = 1; outline_w = 2.0; shadow_w = 2.0; alignment = 2; MarginL = 10; MarginR = 10; MarginV = 10; encoding = 0; UpdateData(); } /////////////// // Constructor AssStyle::AssStyle(wxString _data,bool IsSSA) { Type = ENTRY_STYLE; data = _data; Valid = Parse(IsSSA); if (!Valid) { throw _T("[Error] Failed parsing line."); } UpdateData(); } ////////////// // Destructor AssStyle::~AssStyle() { } ////////////////////////////// // Parses value from ASS data bool AssStyle::Parse(bool IsSSA) { wxString temp; long templ; wxStringTokenizer tkn(data.Mid(6),_T(","),wxTOKEN_RET_EMPTY_ALL); // Read name if (!tkn.HasMoreTokens()) return false; name = tkn.GetNextToken(); name.Trim(true); name.Trim(false); // Read font name if (!tkn.HasMoreTokens()) return false; font = tkn.GetNextToken(); font.Trim(true); font.Trim(false); // Read font size if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToLong(&templ); fontsize = templ; if (!IsSSA) { // Read primary color if (!tkn.HasMoreTokens()) return false; primary.ParseASS(tkn.GetNextToken()); // Read secondary color if (!tkn.HasMoreTokens()) return false; secondary.ParseASS(tkn.GetNextToken()); // Read outline color if (!tkn.HasMoreTokens()) return false; outline.ParseASS(tkn.GetNextToken()); // Read shadow color if (!tkn.HasMoreTokens()) return false; shadow.ParseASS(tkn.GetNextToken()); } else { // Read primary color if (!tkn.HasMoreTokens()) return false; primary.ParseSSA(tkn.GetNextToken()); // Read secondary color if (!tkn.HasMoreTokens()) return false; secondary.ParseSSA(tkn.GetNextToken()); // Read and discard tertiary color if (!tkn.HasMoreTokens()) return false; tkn.GetNextToken(); // Read shadow/outline color if (!tkn.HasMoreTokens()) return false; outline.ParseSSA(tkn.GetNextToken()); shadow = outline; } // Read bold if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToLong(&templ); bold = true; if (templ == 0) bold = false; // Read italics if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToLong(&templ); italic = true; if (templ == 0) italic = false; if (!IsSSA) { // Read underline if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToLong(&templ); underline = true; if (templ == 0) underline = false; // Read strikeout if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToLong(&templ); strikeout = true; if (templ == 0) strikeout = false; // Read scale x if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToLong(&templ); scalex = templ; // Read scale y if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToLong(&templ); scaley = templ; // Read spacing if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToDouble(&spacing); //spacing = templ; // Read angle if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToDouble(&angle); } else { // SSA defaults shadow.a = 128; underline = false; strikeout = false; scalex = 100; scaley = 100; spacing = 0; angle = 0.0; } // Read border style if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToLong(&templ); borderstyle = templ; // Read outline width if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToDouble(&outline_w); // Read shadow width if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToDouble(&shadow_w); // Read alignment if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToLong(&templ); if (IsSSA) { switch(templ) { case 1: alignment = 1; break; case 2: alignment = 2; break; case 3: alignment = 3; break; case 5: alignment = 7; break; case 6: alignment = 8; break; case 7: alignment = 9; break; case 9: alignment = 4; break; case 10: alignment = 5; break; case 11: alignment = 6; break; default: alignment = 2; break; } } else alignment = templ; // Read left margin if (!tkn.HasMoreTokens()) return false; SetMarginString(tkn.GetNextToken(),1); // Read right margin if (!tkn.HasMoreTokens()) return false; SetMarginString(tkn.GetNextToken(),2); // Read vertical margin if (!tkn.HasMoreTokens()) return false; SetMarginString(tkn.GetNextToken(),3); if (IsSSA) { // Read alpha level if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); } // Read encoding if (!tkn.HasMoreTokens()) return false; temp = tkn.GetNextToken(); temp.ToLong(&templ); encoding = templ; // End if (tkn.HasMoreTokens()) return false; return true; } ////////////////////////////////// // Writes data back to ASS format void AssStyle::UpdateData() { // Prepare data = _T("Style: "); // Write all data name.Replace(_T(","),_T(";")); font.Replace(_T(","),_T(";")); data += name + _T(","); data += font + _T(","); data += wxString::Format(_T("%i"),fontsize) + _T(","); data += primary.GetASSFormatted(true,false,true) + _T(","); data += secondary.GetASSFormatted(true,false,true) + _T(","); data += outline.GetASSFormatted(true,false,true) + _T(","); data += shadow.GetASSFormatted(true,false,true) + _T(","); data += wxString::Format(_T("%i"),bold?-1:0) + _T(","); data += wxString::Format(_T("%i"),italic?-1:0) + _T(","); data += wxString::Format(_T("%i"),underline?-1:0) + _T(","); data += wxString::Format(_T("%i"),strikeout?-1:0) + _T(","); data += wxString::Format(_T("%i"),scalex) + _T(","); data += wxString::Format(_T("%i"),scaley) + _T(","); data += wxString::Format(_T("%.2f"),spacing) + _T(","); data += wxString::Format(_T("%.2f"),angle) + _T(","); data += wxString::Format(_T("%i"),borderstyle) + _T(","); data += wxString::Format(_T("%.2f"),outline_w) + _T(","); data += wxString::Format(_T("%.2f"),shadow_w) + _T(","); data += wxString::Format(_T("%i"),alignment) + _T(","); data += wxString::Format(_T("%i"),MarginL) + _T(","); data += wxString::Format(_T("%i"),MarginR) + _T(","); data += wxString::Format(_T("%i"),MarginV) + _T(","); data += wxString::Format(_T("%i"),encoding); } ///////////////////////////// // Sets margin from a string void AssStyle::SetMarginString(const wxString str,int which) { wxString work = str; work.Trim(false); work.Trim(true); if (!work.IsNumber()) throw _T("Invalid margin value"); long value; work.ToLong(&value); if (value < 0) value = 0; if (value > 9999) value = 9999; switch (which) { case 1: MarginL = value; break; case 2: MarginR = value; break; case 3: MarginV = value; break; default: throw _T("Invalid margin"); } } ////////////////////////// // Gets string for margin wxString AssStyle::GetMarginString(int which) { int value; switch (which) { case 1: value = MarginL; break; case 2: value = MarginR; break; case 3: value = MarginV; break; default: throw _T("Invalid margin"); } wxString result = wxString::Format(_T("%04i"),value); return result; } /////////////////////////////// // Convert style to SSA string wxString AssStyle::GetSSAText() { // Prepare wxString output = _T("Style: "); // Write all data name.Replace(_T(","),_T(";")); font.Replace(_T(","),_T(";")); output += name + _T(","); output += font + _T(","); output += wxString::Format(_T("%i"),fontsize) + _T(","); output += primary.GetSSAFormatted() + _T(","); output += secondary.GetSSAFormatted() + _T(","); output += _T("0,"); output += shadow.GetSSAFormatted() + _T(","); output += wxString::Format(_T("%i"),bold?-1:0) + _T(","); output += wxString::Format(_T("%i"),italic?-1:0) + _T(","); output += wxString::Format(_T("%i"),borderstyle) + _T(","); output += wxString::Format(_T("%.2f"),outline_w) + _T(","); output += wxString::Format(_T("%.2f"),shadow_w) + _T(","); int align = 0; switch (alignment) { case 1: align = 1; break; case 2: align = 2; break; case 3: align = 3; break; case 4: align = 9; break; case 5: align = 10; break; case 6: align = 11; break; case 7: align = 5; break; case 8: align = 6; break; case 9: align = 7; break; } output += wxString::Format(_T("%i"),align) + _T(","); output += wxString::Format(_T("%i"),MarginL) + _T(","); output += wxString::Format(_T("%i"),MarginR) + _T(","); output += wxString::Format(_T("%i"),MarginV) + _T(","); output += _T("0,"); output += wxString::Format(_T("%i"),encoding); return output; }