// 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 Project http://www.aegisub.org/ // // $Id$ /// @file ass_style.cpp /// @brief Class for style definitions in subtitles /// @ingroup subs_storage /// #include "config.h" #ifndef AGI_PRE #include #include #include #endif #include "ass_style.h" #include "utils.h" AssColor::AssColor () { r=g=b=a=0; } AssColor::AssColor(int r, int g, int b, int a) : r(r) , g(g) , b(b) , a(a) { } AssColor::AssColor(const wxColour &color) : a(0) { SetWXColor(color); } /// @brief Parse from SSA/ASS /// @param value void AssColor::Parse(wxString const& value) { if (value.size() > 0 && value[0] == '#') { // HTML colour SetWXColor(wxColor(value)); return; } // Prepare char ostr[12]; int oindex = 11; bool ishex = false; ostr[11] = 0; for(size_t i = value.size(); i > 0 && oindex >= 0; i--) { unsigned char c = value[i - 1]; if (isxdigit(c) || c == '-') { ostr[--oindex] = c; if (c >= 'A') ishex = true; } else if (c == 'H' || c == 'h') ishex = true; } unsigned long outval = strtoul(ostr + oindex, 0, ishex ? 16 : 10); r = outval & 0xFF; g = (outval>>8) & 0xFF; b = (outval>>16) & 0xFF; a = (outval>>24) & 0xFF; } /// @brief Gets a wxColour /// @return wxColour AssColor::GetWXColor() const { return wxColour(r,g,b,255-a); } /// @brief Sets color from wx /// @param color void AssColor::SetWXColor(const wxColor &color) { r = color.Red(); g = color.Green(); b = color.Blue(); //a = color.Alpha(); } /// @brief Get formatted in ASS format /// @param alpha /// @param stripped /// @param isStyle /// @return wxString AssColor::GetASSFormatted(bool alpha,bool stripped,bool isStyle) const { wxString work; if (!stripped) work += "&H"; if (alpha) work += wxString::Format("%02X",a); work += wxString::Format("%02X%02X%02X",b,g,r); if (!stripped && !isStyle) work += "&"; return work; } /// @brief Get decimal formatted /// @return wxString AssColor::GetSSAFormatted() const { long color = (a<<24)+(b<<16)+(g<<8)+r; wxString output=wxString::Format("%li",(long)color); return output; } bool AssColor::operator==(const AssColor &col) const { return r==col.r && g==col.g && b==col.b && a==col.a; } bool AssColor::operator!=(const AssColor &col) const { return !(*this == col); } AssStyle::AssStyle() : AssEntry(wxString(), wxS("[V4+ Styles]")) , name("Default") , font("Arial") , fontsize(20.) , primary(255, 255, 255) , secondary(255, 0, 0) , outline(0, 0, 0) , shadow(0, 0, 0) , bold(false) , italic(false) , underline(false) , strikeout(false) , scalex(100.) , scaley(100.) , spacing(0.) , angle(0.) , borderstyle(1) , outline_w(2.) , shadow_w(2.) , alignment(2) , encoding(1) , relativeTo(1) { for (int i = 0; i < 4; i++) Margin[i] = 10; UpdateData(); } static wxString get_next_string(wxStringTokenizer &tok) { if (!tok.HasMoreTokens()) throw "Malformed style: not enough fields"; return tok.GetNextToken(); } static int get_next_int(wxStringTokenizer &tok) { long temp; if (!get_next_string(tok).ToLong(&temp)) throw "Malformed style: could not parse int field"; return temp; } static double get_next_double(wxStringTokenizer &tok) { double temp; if (!get_next_string(tok).ToDouble(&temp)) throw "Malformed style: could not parse double field"; return temp; } AssStyle::AssStyle(wxString rawData, int version) : AssEntry(wxString(), wxS("[V4+ Styles]")) { wxStringTokenizer tkn(rawData.Trim(false).Mid(6), ",", wxTOKEN_RET_EMPTY_ALL); name = get_next_string(tkn).Trim(true).Trim(false); font = get_next_string(tkn).Trim(true).Trim(false); fontsize = get_next_double(tkn); if (version != 0) { primary.Parse(get_next_string(tkn)); secondary.Parse(get_next_string(tkn)); outline.Parse(get_next_string(tkn)); shadow.Parse(get_next_string(tkn)); } else { primary.Parse(get_next_string(tkn)); secondary.Parse(get_next_string(tkn)); // Read and discard tertiary color get_next_string(tkn); // Read shadow/outline color outline.Parse(get_next_string(tkn)); shadow = outline; } bold = !!get_next_int(tkn); italic = !!get_next_int(tkn); if (version != 0) { underline = !!get_next_int(tkn); strikeout = !!get_next_int(tkn); scalex = get_next_double(tkn); scaley = get_next_double(tkn); spacing = get_next_double(tkn); angle = get_next_double(tkn); } else { // SSA defaults underline = false; strikeout = false; scalex = 100; scaley = 100; spacing = 0; angle = 0.0; } borderstyle = get_next_int(tkn); outline_w = get_next_double(tkn); shadow_w = get_next_double(tkn); alignment = get_next_int(tkn); if (version == 0) alignment = SsaToAss(alignment); // Read left margin Margin[0] = mid(0, get_next_int(tkn), 9999); // Read right margin Margin[1] = mid(0, get_next_int(tkn), 9999); // Read top margin Margin[2] = mid(0, get_next_int(tkn), 9999); // Read bottom margin if (version == 2) Margin[3] = mid(0, get_next_int(tkn), 9999); else Margin[3] = Margin[2]; // Skip alpha level if (version == 0) get_next_string(tkn); // Read encoding encoding = get_next_int(tkn); // Read relative to if (version == 2) relativeTo = get_next_int(tkn); if (tkn.HasMoreTokens()) throw "Malformed style: too many fields"; UpdateData(); } AssStyle& AssStyle::operator=(AssStyle const& rgt) { name = rgt.name; font = rgt.font; fontsize = rgt.fontsize; primary = rgt.primary; secondary = rgt.secondary; outline = rgt.outline; shadow = rgt.shadow; bold = rgt.bold; italic = rgt.italic; underline = rgt.underline; strikeout = rgt.strikeout; scalex = rgt.scalex; scaley = rgt.scaley; spacing = rgt.spacing; angle = rgt.angle; borderstyle = rgt.borderstyle; outline_w = rgt.outline_w; shadow_w = rgt.shadow_w; alignment = rgt.alignment; encoding = rgt.encoding; relativeTo = rgt.relativeTo; memcpy(Margin, rgt.Margin, sizeof(Margin)); SetEntryData(rgt.GetEntryData()); return *this; } void AssStyle::UpdateData() { wxString final; name.Replace(",",";"); font.Replace(",",";"); final = wxString::Format("Style: %s,%s,%g,%s,%s,%s,%s,%d,%d,%d,%d,%g,%g,%g,%g,%d,%g,%g,%i,%i,%i,%i,%i", name, font, fontsize, primary.GetASSFormatted(true,false,true), secondary.GetASSFormatted(true,false,true), outline.GetASSFormatted(true,false,true), shadow.GetASSFormatted(true,false,true), (bold? -1 : 0), (italic ? -1 : 0), (underline?-1:0),(strikeout?-1:0), scalex,scaley,spacing,angle, borderstyle,outline_w,shadow_w,alignment, Margin[0],Margin[1],Margin[2],encoding); SetEntryData(final); } wxString AssStyle::GetSSAText() const { wxString output; int align = AssToSsa(alignment); wxString n = name; n.Replace(",", ";"); wxString f = font; f.Replace(",", ";"); output = wxString::Format("Style: %s,%s,%g,%s,%s,0,%s,%d,%d,%d,%g,%g,%d,%d,%d,%d,0,%i", n, f, fontsize, primary.GetSSAFormatted(), secondary.GetSSAFormatted(), shadow.GetSSAFormatted(), (bold? -1 : 0), (italic ? -1 : 0), borderstyle,outline_w,shadow_w,align, Margin[0],Margin[1],Margin[2],encoding); return output; } AssEntry *AssStyle::Clone() const { return new AssStyle(*this); } void AssStyle::GetEncodings(wxArrayString &encodingStrings) { encodingStrings.Clear(); encodingStrings.Add(wxString("0 - ") + _("ANSI")); encodingStrings.Add(wxString("1 - ") + _("Default")); encodingStrings.Add(wxString("2 - ") + _("Symbol")); encodingStrings.Add(wxString("77 - ") + _("Mac")); encodingStrings.Add(wxString("128 - ") + _("Shift_JIS")); encodingStrings.Add(wxString("129 - ") + _("Hangeul")); encodingStrings.Add(wxString("130 - ") + _("Johab")); encodingStrings.Add(wxString("134 - ") + _("GB2312")); encodingStrings.Add(wxString("136 - ") + _("Chinese BIG5")); encodingStrings.Add(wxString("161 - ") + _("Greek")); encodingStrings.Add(wxString("162 - ") + _("Turkish")); encodingStrings.Add(wxString("163 - ") + _("Vietnamese")); encodingStrings.Add(wxString("177 - ") + _("Hebrew")); encodingStrings.Add(wxString("178 - ") + _("Arabic")); encodingStrings.Add(wxString("186 - ") + _("Baltic")); encodingStrings.Add(wxString("204 - ") + _("Russian")); encodingStrings.Add(wxString("222 - ") + _("Thai")); encodingStrings.Add(wxString("238 - ") + _("East European")); encodingStrings.Add(wxString("255 - ") + _("OEM")); } int AssStyle::AssToSsa(int ass_align) { switch (ass_align) { case 1: return 1; case 2: return 2; case 3: return 3; case 4: return 9; case 5: return 10; case 6: return 11; case 7: return 5; case 8: return 6; case 9: return 7; default: return 2; } } int AssStyle::SsaToAss(int ssa_align) { switch(ssa_align) { case 1: return 1; case 2: return 2; case 3: return 3; case 5: return 7; case 6: return 8; case 7: return 9; case 9: return 4; case 10: return 5; case 11: return 6; default: return 2; } }