using System; using System.Collections.Generic; using System.Text; using Plugin; using System.Drawing; using System.Drawing.Imaging; using System.Drawing.Drawing2D; using System.Windows.Forms; namespace NicoComment { public class NicoComment : IPlugin{ private List config = new List(); private List comments = new List(); public void ApplyLanguage( string language_code ) { } public string Name { get { return "Nico Comment"; } } public ulong Type { get { return 0; } } public string Abstract { get { return "ニコニコ動画ぽい字幕を、ニコニコ動画と同様なコマンドで追加できるプラグイン。"; } } public void Apply( ref Bitmap frame, float time, float e_begin, float e_end, ref string e_body ) { using ( Graphics g = Graphics.FromImage( frame ) ) { Rectangle rc = new Rectangle( 0, 0, frame.Width, frame.Height ); int skip_count_def = 0; bool first_def = true; bool first_shita = true; bool first_ue = true; int y_def = 0; int y_shita = rc.Height; int y_ue = 0; for ( int i = 0; i < comments.Count; i++ ) { if ( comments[i].time <= time && time < comments[i].time + 3.0 ) { double t = time - comments[i].time; int height = (int)comments[i].type.Size.Size; if ( comments[i].type.Position == NComTypePosition.def ) { if ( !first_def ) { y_def += height; if ( y_def > rc.Height ) { y_def -= rc.Height; skip_count_def++; } t += 0.1 * skip_count_def; } else { first_def = false; } if ( comments[i].y == NComment.NULL ) { comments[i].y = y_def; } } else if ( comments[i].type.Position == NComTypePosition.shita ) { if ( !first_shita ) { y_shita -= (int)(1.1f * height); if ( y_shita + height < 0 ) { y_shita += rc.Height; } } else { y_shita -= (int)(1.1f * height); first_shita = false; } if ( comments[i].y == NComment.NULL ) { comments[i].y = y_shita; } } else if ( comments[i].type.Position == NComTypePosition.ue ) { if ( !first_ue ) { y_ue += (int)(1.1f * height); if ( y_ue > rc.Height ) { y_ue += rc.Height; } } else { first_ue = false; } if ( comments[i].y == NComment.NULL ) { comments[i].y = y_ue; } } NComment entry = comments[i]; drawString( g, entry, rc, t, comments.Count ); comments[i] = entry; } } } } public string Config { get { string result = ""; if( config.Count > 0 ){ result = config[0]; } for ( int i = 1; i < config.Count; i++ ) { result += "\n" + config[i]; } return result; } set { List work_config = new List(); foreach ( string item in config ) { work_config.Add( item ); } config.Clear(); List work_comments = new List(); foreach ( NComment item in comments ) { work_comments.Add( item ); } comments.Clear(); //timing.Clear(); string[] result = value.Split( new char[] { '\n' } ); config.Add( result[0] ); for( int i = 1; i < result.Length; i++ ){ config.Add( result[i] ); string[] spl = result[i].Split( new char[] { '\t' } ); if ( spl.Length < 3 ) { config.Clear(); foreach ( string item in work_config ) { config.Add( item ); } work_config.Clear(); comments.Clear(); foreach ( NComment item in work_comments ) { comments.Add( item ); } work_comments.Clear(); MessageBox.Show( "コメントにエラーがありました。エラーのあった行は次の通りです\n" + i + "行目\n" + result[i] ); return; } //timing.Add( double.Parse( spl[0] ) ); float time; try { time = float.Parse( spl[0] ); } catch { config.Clear(); foreach ( string item in work_config ) { config.Add( item ); } work_config.Clear(); comments.Clear(); foreach ( NComment item in work_comments ) { comments.Add( item ); } work_comments.Clear(); MessageBox.Show( "コメントにエラーがありました。エラーのあった行は次の通りです\n" + i + "行目\n" + result[i] ); return; } comments.Add( new NComment( float.Parse( spl[0] ), spl[1], spl[2], i ) ); //MessageBox.Show( "Config::set; comments[i-1].type.Position.ToString()=" + comments[i - 1].type.Position.ToString() ); } comments.Sort(); } } public DialogResult EntrySetting( ref string entry_config ) { return DialogResult.Cancel; } public DialogResult BaseSetting() { FConfig fconf = new FConfig( Config ); DialogResult result = fconf.ShowDialog(); if ( result == DialogResult.OK ) { Config = fconf.ConfigString; } fconf.Dispose(); return result; } /// /// comで指定されたコメント・タイプのニコニココメントを、 /// Graphics gの位置xに描画します。 /// /// このコメントが表示され始めてからの経過時間 /// /// /// public static void drawString( Graphics g, NComment com, Rectangle rc, double time, int comment_num ) { const string font_name = "MS ゴシック"; Font font = new Font( font_name, com.type.Size.Size, FontStyle.Bold, GraphicsUnit.Pixel ); Color color = com.type.Color.Color; int axy = com.type.Position.getPosition( rc.Height, com.type.Size.Size ); int x; if ( com.type.Position == NComTypePosition.ue || com.type.Position == NComTypePosition.shita ) { x = (int)(rc.Width / 2.0f - com.width / 2.0f); } else { x = (int)(rc.Width - time * ((com.width + rc.Width) / 3.0f)); } GraphicsPath path = new GraphicsPath(); //FontFamily ff = new FontFamily( font_name ); FontFamily ff = font.FontFamily; path.AddString( com.message, ff, (int)FontStyle.Bold, com.type.Size.Size, new Point( 0, 0 ), StringFormat.GenericDefault ); using ( Bitmap tmp = new Bitmap( com.width, com.height, PixelFormat.Format32bppArgb ) ) { using ( Graphics gx = Graphics.FromImage( tmp ) ) { gx.Clear( Color.FromArgb( 0, Color.White ) ); Color shadow; if ( color != Color.Black ) { shadow = Color.Black; } else { shadow = Color.White; } gx.DrawPath( new Pen( Color.FromArgb( 50, shadow ), 3.5f ), path ); gx.DrawPath( new Pen( Color.FromArgb( 180, shadow ), 2.5f ), path ); gx.FillPath( new SolidBrush( color ), path ); //gx.DrawString( com.message, font, new SolidBrush( color ), new PointF( 0, 0 ) ); } float alpha = 0.6f + 0.4f * ((float)com.count / (float)comment_num); ColorMatrix cm = new ColorMatrix(); cm.Matrix00 = 1; cm.Matrix11 = 1; cm.Matrix22 = 1; cm.Matrix33 = alpha; cm.Matrix44 = 1; ImageAttributes ia = new ImageAttributes(); ia.SetColorMatrix( cm ); g.DrawImage( tmp, new Rectangle( x, com.y, tmp.Width, tmp.Height ), 0, 0, tmp.Width, tmp.Height, GraphicsUnit.Pixel, ia ); } } public void Render( Graphics g, Size size, float time, string mouth, string reserved ) { } } public class NComment : IComparable { public const int NULL = -999; public float time; public NComType type; public string message; public int width; public int height; public int count; public int y; public NComment( float time, string command, string message, int count ) { this.time = time; this.type = new NComType( command ); this.message = message; this.count = count; this.y = NULL; SizeF sizef; Bitmap dumy = new Bitmap( 1, 1 ); Font font = new Font( "MS ゴシック", this.type.Size.Size, FontStyle.Bold, GraphicsUnit.Pixel ); using ( Graphics g = Graphics.FromImage( dumy ) ) { sizef = g.MeasureString( message, font ); } this.width = (int)sizef.Width; this.height = (int)sizef.Height; dumy.Dispose(); font.Dispose(); } public int CompareTo( object obj ) { NComment com = (NComment)obj; if ( this.time > com.time ) { return 1; } else if ( this.time < com.time ) { return -1; } else { return 0; } } } public class NComType { public NComTypePosition Position; public NComTypeColor Color; public NComTypeSize Size; public NComType( string command ) { Position = NComTypePosition.def; Color = NComTypeColor.def; Size = NComTypeSize.def; string[] spl = command.Split( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries ); for ( int i = spl.Length - 1; i >= 0; i-- ) { NComTypePosition pos = NComTypePosition.fromCommand( spl[i] ); if ( pos != NComTypePosition.INVALID ) { Position = pos; continue; } NComTypeColor col = NComTypeColor.fromCommand( spl[i] ); if ( col != NComTypeColor.INVALID ) { Color = col; continue; } NComTypeSize size = NComTypeSize.fromCommand( spl[i] ); if ( size != NComTypeSize.INVALID ) { Size = size; continue; } } } } public class NComTypePosition { private int m_value; public static NComTypePosition ue = new NComTypePosition( 0 ); public static NComTypePosition shita = new NComTypePosition( 1 ); public static NComTypePosition def = new NComTypePosition( 2 ); public static NComTypePosition INVALID = new NComTypePosition( -1 ); private NComTypePosition( int value ) { m_value = value; } public static NComTypePosition fromCommand( string command ) { switch ( command ) { case "ue": return ue; case "shita": return shita; case "naka": return def; default: return INVALID; } } public int getPosition( float height, float fontsize ) { switch ( m_value ) { case 0: return 0; case 1: return (int)(height - fontsize * 1.2f); default: return -1; } } new public string ToString() { switch ( m_value ) { case 0: return "ue"; case 1: return "shita"; case 2: return "def"; default: return "INVALID"; } } } public class NComTypeColor { private int m_value; public static NComTypeColor white = new NComTypeColor( 0 ); public static NComTypeColor def = new NComTypeColor( 0 ); public static NComTypeColor red = new NComTypeColor( 1 ); public static NComTypeColor pink = new NComTypeColor( 2 ); public static NComTypeColor orange = new NComTypeColor( 3 ); public static NComTypeColor yellow = new NComTypeColor( 4 ); public static NComTypeColor green = new NComTypeColor( 5 ); public static NComTypeColor cyan = new NComTypeColor( 6 ); public static NComTypeColor blue = new NComTypeColor( 7 ); public static NComTypeColor purple = new NComTypeColor( 8 ); public static NComTypeColor niconicowhite = new NComTypeColor( 9 ); public static NComTypeColor truered = new NComTypeColor( 10 ); public static NComTypeColor passionorange = new NComTypeColor( 11 ); public static NComTypeColor madyellow = new NComTypeColor( 12 ); public static NComTypeColor elementalgreen = new NComTypeColor( 13 ); public static NComTypeColor marineblue = new NComTypeColor( 14 ); public static NComTypeColor nobleviolet = new NComTypeColor( 15 ); public static NComTypeColor black = new NComTypeColor( 16 ); public static NComTypeColor INVALID = new NComTypeColor( -1 ); private NComTypeColor( int value ) { m_value = value; } public static NComTypeColor fromCommand( string command ) { switch ( command ) { case "white": return white; case "red": return red; case "pink": return pink; case "orange": return orange; case "yellow": return yellow; case "green": return green; case "cyan": return cyan; case "blue": return blue; case "purple": return purple; case "niconicowhite": case "white2": return niconicowhite; case "truered": case "red2": return truered; case "passionorange": case "orange2": return passionorange; case "madyellow": case "yellow2": return madyellow; case "elementalgree": case "green2": return elementalgreen; case "marineblue": case "blue2": return marineblue; case "nobleviolet": case "purple2": return nobleviolet; case "black": return black; default: return INVALID; } } public Color Color { get { switch ( m_value ) { case 0: return Color.White; case 1: return Color.Red; case 2: return Color.Pink; case 3: return Color.Orange; case 4: return Color.Yellow; case 5: return Color.FromArgb( 0, 255, 0 ); case 6: return Color.Cyan; case 7: return Color.Blue; case 8: return Color.Purple; case 9: return Color.FromArgb( 204, 204, 153 ); case 10: return Color.FromArgb( 204, 0, 51 ); case 11: return Color.FromArgb( 255, 102, 0 ); case 12: return Color.FromArgb( 153, 153, 0 ); case 13: return Color.FromArgb( 0, 204, 102 ); case 14: return Color.FromArgb( 51, 255, 252 ); case 15: return Color.FromArgb( 102, 51, 204 ); case 16: return Color.Black; } return Color.White; } } } public class NComTypeSize { private int m_value; public static NComTypeSize big = new NComTypeSize( 0 ); public static NComTypeSize medium = new NComTypeSize( 1 ); public static NComTypeSize small = new NComTypeSize( 2 ); public static NComTypeSize def = new NComTypeSize( 1 ); public static NComTypeSize INVALID = new NComTypeSize( -1 ); private NComTypeSize( int value ) { m_value = value; } public static NComTypeSize fromCommand( string command ) { switch ( command ) { case "big": return big; case "medium": return medium; case "small": return small; default: return INVALID; } } public float Size { get { switch ( m_value ) { case 0: return 39f; case 1: return 24f; case 2: return 15f; default: return 24f; } } } } }