C#

C#で映画のエンドロールみたいな その2

投稿日:

はじめに

前回の改良版になります。

今回の改良ポイントは、行ごとにフォントサイズを変更出来るようにしました。

それからテキスト以外にもロゴなどの画像もスクロール出来るようにしました。

さらに表示した内容をAVI形式の動画として保存出来るようにしました。

 

出来上がりイメージ

できあがる動画(AVI形式)のサイズが大きいので、Windows10標準の「フォト」でトリミングしてMP4形式で保存してあります。

ソースのダウンロード

VisualStudio 2019 Comunityで作成したソースファイルをzip圧縮してあります。

ちょこっと解説

動画の保存には、Accord Video for Windowsを利用してみました。

インストールは、VisualStudio のツールメニューから

「NuGetパッケージマネージャ」の「ソリューションのNuGetパッケージ管理」を実行して表示された画面の左上の「参照」をクリックします。

検索欄にvfwと入力すると「Accord.Video.VFW」が表示されるのでクリックします。

プロジェクトを選択してインストールできます。

動画関連で追加したコード【RollForm.cs】

11行目 using Accord.Video.VFW; を追加

31行目 AVIWriter mAviWriter = new AVIWriter(); を追加

93行目 mAviWriter.FrameRate = 60; を追加。フレームレートを60で設定

94行目 mAviWriter.Open("EndRoll.avi", SCR_WIDTH, SCR_HEIGHT); を追加。動画ファイル名をEndRoll.aviとしてRollFormのサイズでオープンします。

140行目 mAviWriter.AddFrame(mScreen); を追加。ここで表示画面を動画に追加してます。

149行目~153行目 に画面が閉じる際に動画ファイルをクローズするようにしてます。

mAviWriter.Close();

ほんの数行で簡単に実装できました。

フォントサイズで追加・変更となったコード

前回は表示テキストをひとまとめにしてましたが、行ごとに分割しました。

73行目 mRollText = this.RollText.Split('\n');

改行コードで分割して配列に格納してます。

 

RollForm_Paintでテキストを出力していましたが、OutputText(Graphics g)を作成してテキスト出力部分を移動しました。179行目以降

 

今回、出力するテキストの先頭に種類とフォントサイズを指定出来るようにしました。指定方法は以下の通りです。

TXT,11;ここに出力される文字

セミコロン”;”で区切ります。”ここに出力される文字”を11ポイントで出力できます。

ロゴなどの画像の指定は以下の通りです。

IMG,327,54;画像.jpg

TXTと同様にセミコロン”;”で区切ります。IMGの後の数字は画像サイズです。327が幅で54が高さです。

 

ソースコード

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Accord.Video.VFW;


namespace EndRoll
{
    public partial class RollForm : Form
    {
        static readonly int TILE_SIZE = 8;
        static readonly int TIMER_INTERVAL = 16;
        static readonly int MAP_WIDTH = 80;
        static readonly int MAP_HEIGHT = 50;
        static readonly int SCR_WIDTH = MAP_WIDTH * TILE_SIZE;
        static readonly int SCR_HEIGHT = MAP_HEIGHT * TILE_SIZE;
        static readonly int WND_WIDTH = SCR_WIDTH * 2;
        static readonly int WND_HEIGHT = SCR_HEIGHT * 2;
        //static readonly int WAIT = 60;
        static readonly int DPI = 96;
        static readonly float POINT_TO_PIXEL = (int)(DPI / 72 * 100) / 100;
        static readonly int LINE_SPACE = 8;

        AVIWriter mAviWriter = new AVIWriter();

        Bitmap mScreen = new Bitmap(SCR_WIDTH, SCR_HEIGHT);
        Bitmap[] mTile;
        byte[,] mTileLayout;

        int mTimer;
        int mKeyEsc;
        bool mCancel;
        bool mEnd;
        int mX, mY, mDX, mDY;
        int mRowsCount;
        Random mRnd = new Random();
        int mLen;

        public string RollText { get; set; }

        private string[] mRollText;


        public RollForm()
        {
            InitializeComponent();
        }

        private void RollForm_Load(object sender, EventArgs e)
        {
            string s = RollText;
            int ndx;
            Bitmap bm = new Bitmap("tile.png");

            ClientSize = new Size(WND_WIDTH, WND_HEIGHT);
            DoubleBuffered = true;

            mKeyEsc = 0;
            mCancel = false;
            mX = 0;
            mY = MAP_HEIGHT + 2;
            mDY = 0;
            mRowsCount = (s.Length - s.Replace("\r", "").Length) * TILE_SIZE;
            //mRowsCount = (s.Length - s.Replace("\r", "").Length);

            mRollText = this.RollText.Split('\n');

            mLen = bm.Width / TILE_SIZE;
            mTile = new Bitmap[mLen];
            for (int i = 0; i < mLen; i++)
            {
                mTile[i] = bm.Clone(new Rectangle(i * TILE_SIZE, 0, TILE_SIZE, TILE_SIZE), bm.PixelFormat);
            }

            mTileLayout = new byte[MAP_WIDTH, MAP_HEIGHT];
            for (int y = 0; y < MAP_HEIGHT; y++)
            {
                for (int x = 0; x < MAP_WIDTH; x++)
                {
                    ndx = mRnd.Next(mLen);
                    mTileLayout[x,y] = (byte)ndx;
                }
            }

            // AVI Writer
            mAviWriter.FrameRate = 60;
            mAviWriter.Open("EndRoll.avi", SCR_WIDTH, SCR_HEIGHT);

            Task.Run(() =>
            {
                mTimer = System.Environment.TickCount;
                while (!mEnd)
                {
                    OnTimer();
                    mTimer += TIMER_INTERVAL;
                    Task.Delay(Math.Max(1, mTimer - System.Environment.TickCount)).Wait();
                }

                this.DialogResult = DialogResult.OK;
                return;
            });
        }

        private void RollForm_Paint(object sender, PaintEventArgs e)
        {
            Graphics g = Graphics.FromImage(mScreen);
            //Font f = new Font("Meiryo", 11);
            //StringFormat sfmt = new StringFormat();
            //sfmt.Alignment = StringAlignment.Center;

            g.Clear(BackColor);

            for (int y = 0; y < MAP_HEIGHT; y++)
            {
                for (int x = 0; x < MAP_WIDTH; x++)
                {
                    g.DrawImage(mTile[mTileLayout[x,y]], x *TILE_SIZE, y *TILE_SIZE);
                }
            }
            
            if (mCancel)
            {
                this.DialogResult = DialogResult.Cancel;
                return;
            }
            //Debug.Print((mY * TILE_SIZE + mDY).ToString());
            //g.DrawString(RollText, f, Brushes.White, mX * TILE_SIZE + TILE_SIZE * MAP_WIDTH / 2, mY * TILE_SIZE + mDY, sfmt);
            OutputText(g);
            e.Graphics.DrawImage(mScreen, 0, 0, WND_WIDTH, WND_HEIGHT);

            //mScreen.Save("test.png");
            // AVI
            mAviWriter.AddFrame(mScreen);

        }

        private void RollForm_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape) mKeyEsc++;
        }

        private void RollForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            mAviWriter.Close();
            mAviWriter.Dispose();
        }

        private void OnTimer()
        {
            Tick();
            if (mKeyEsc > 0) mCancel = true;
            Invalidate();
        }

        private void Tick()
        {
            if (Math.Abs(mDY) < TILE_SIZE-1)
            {
                mDY--;
                return;
            }
            mDY = 0;

            if (mY < mRowsCount * -1)
            {
                mEnd = true;
                return;
            }
            mY--;
        }

        private void OutputText(Graphics g)
        {
            StringFormat sfmt = new StringFormat();
            sfmt.Alignment = StringAlignment.Center;
            Font f = new Font("Meiryo", 11);
            int l = mRollText.Length;
            string[] s, s2;
            int addY = 0;
            string flg;
            Bitmap bm;
            int bmX=0, bmY=0;

            for (int i = 0; i < l; i++)
            {
                s = new string[2];
                if (mRollText[i].Length > 3)
                {
                    s2 = mRollText[i].Split(';');
                    flg = s2[0].Split(',')[0];
                    if (flg == "TXT")
                    {
                        s[0] = s2[0].Split(',')[1];
                        s[1] = s2[1];
                    }
                    else if (flg == "IMG")
                    {
                        bmX = int.Parse(s2[0].Split(',')[1]);
                        bmY = int.Parse(s2[0].Split(',')[2]);
                        s[1] = s2[1];
                    }
                }
                else
                {
                    flg = "TXT";
                    s[0] = "11";
                    s[1] = "";
                }
                if (flg == "TXT")
                {
                    f = new Font("Meiryo", float.Parse(s[0]));
                    g.DrawString(s[1], f, Brushes.White, mX * TILE_SIZE + TILE_SIZE * MAP_WIDTH / 2, mY * TILE_SIZE + mDY + addY, sfmt);
                    addY += (int)(float.Parse(s[0]) * POINT_TO_PIXEL) + LINE_SPACE;
                }
                else if (flg == "IMG")
                {
                    bm = new Bitmap(s[1]);
                    g.DrawImage(bm, mX * TILE_SIZE + (TILE_SIZE * MAP_WIDTH - bmX) / 2, mY * TILE_SIZE + mDY + addY);
                    addY += bmY + LINE_SPACE;
                }
            }
        }
    }
}

最後に

前回、今回とはじめてYouTubeに動画をアップして記事中に埋め込んでみましたが意外と簡単にできてホットしております。

とりあえずやってみたかったことが大体実現できることがわかったので、ひとまず完了です。

 

スポンサードリンク

スポンサードリンク

-C#
-, , , ,

Copyright© あきらちんの技術メモ , 2024 All Rights Reserved Powered by STINGER.