色を反転させる Xor Color - C#

色(Color)を反転させるメソッドがないので自分で作ってみました。

二つできたので一応処理速度も比較してみましたが、違いはないのでお好みで。
必要ならAlpha値も追加すべきですが、Alpha値は反転させる対象にしない方が無難ですね。

ちなみに「0xff」は255、「0xffffff」は16777215でも何の問題もない。

Sample1

Color XorColor1(Color color)
{
    return Color.FromArgb(
        color.R ^ 0xff,
        color.G ^ 0xff,
        color.B ^ 0xff);
}

Sample2

Color XorColor2(Color color)
{
    return Color.FromArgb(
        (byte)~color.R,
        (byte)~color.G,
        (byte)~color.B);
}


他にも絶対値を返すMath.absを使用して
Color XorColor3(Color color)
{
Color.FromArgb(
        Math.Abs(color.R - 0xff),
        Math.Abs(color.G - 0xff),
        Math.Abs(color.B - 0xff));
}
このように書いてみたが、あまりスマートに感じられなかったので個人的な感覚で却下。
一応これでも可能です。


シンプルな形で。

Sample4

Color XorColor4(Color color)
{
    return Color.FromArgb(
        0xff - color.R,
        0xff - color.G,
        0xff - color.B);
}


Sample5

Color XorColor5(Color color)
{
    return Color.FromArgb(color.ToArgb() ^ 0xffffff);
}

ProcessCmdKeyでトラップされる順番 - C#

コントロールでキーストロークをトラップ方法として、ProcessCmdKeyをオーバーライドする方法が紹介されていますが、フォームとそのフォームに置かれているコントロールではどちらが先にキーストロークをトラップするのか。

結論から言えばフォームに配置されたコントロールが先にトラップします。
当たり前ですが、フォーカスを取得できるコントロールのみがトラップ可能です。

KeyDownイベントよりも先に発生します。

戻り値にtrueを返すことでKeyDownイベントでトラップされなくなります。
また、それより上階層のコントロール(フォームなど)にもトラップされなくなります。

using System.Windows.Forms;
using System.Text;

namespace ShortCutKey_Capture_Sample
{
    class xTextBox : TextBox
    {
        private bool fastFlag;
        public xTextBox()
        {
            fastFlag = false;
            this.KeyDown +=new KeyEventHandler(xTextBox_KeyDown);
        }

        void xTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            ShowFaster("KeyDown", e.KeyData);
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            const int WM_KEYDOWN = 0x100;
            const int WM_SYSKEYDOWN = 0x104;

            if ((msg.Msg == WM_KEYDOWN) ||
                (msg.Msg == WM_SYSKEYDOWN))
            {
                ShowFaster("ProcessCmdKey", keyData);
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

        void ShowFaster(string methodName, Keys keyData)
        {
            switch (keyData)
            {
                case Keys.Control | Keys.N:
                    if (fastFlag)
                    {
                        fastFlag = false;
                    }
                    else
                    {
                        fastFlag = true;
                        this.Text = methodName + " Captured.";
                    }
                    break;
            }
        }
    }
}


キーの組み合わせはこのような書き方で取得することができます。
switch (e.KeyData)
{
    case Keys.Control | Keys.N:
        this.Text = "KeyDown <CTRL> + n Captured";
        break;
    case Keys.Shift | Keys.N:
        this.Text = "<SHIFT> + n Captured";
        break;
    case Keys.Alt | Keys.N:
        this.Text = "<ALT> + n Captured";
        break;
    case Keys.Alt | Keys.Control | Keys.N:
        this.Text = "<ALT> + <CTRL> + n Captured";
        break;
}

BackgroundWorkerの使い方 - C#

インスタンスを生成します。

BackgroundWorker  bw = new BackgroundWorker();
ここからは「bw」という名前で生成したインスタンスを使い、話を進めます。


バックグラウンド処理を実行する


DoWorkイベントにバックグラウンドで行う処理(イベントハンドラ)をフックします。
bw.DoWork += new DoWorkEventHandler(bw_DoWork);


バックグラウンド処理を実行する。
bw.RunWorkerAsync();

引数を渡す場合の例)
bw.RunWorkerAsync(100);

DoWorkイベントハンドラ内で渡された引数を使用する例)
int arg = (int)e.Argument;

DoWorkイベントハンドラの例)
void bw_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker bw = sender as BackgroundWorker;

    int i = 0, count = (int)e.Argument;

    while (i < count)
    {
        Thread.Sleep(100);
        bw.ReportProgress(++i);
        if (bw.CancellationPending)
        {
            e.Cancel = true;
            break;
        }
    }
}



処理をキャンセルする

BackgroundWorkerが非同期のキャンセルをサポートしているかどうかを示す値を設定します。
bw.WorkerSupportsCancellation = true;

キャンセルを要求します。
bw.CancelAsync();
CancellationPendingプロパティがtrueに設定されます。

処理がキャンセルされたかをDoWorkイベントハンドラ内でCancellationPendingプロパティを定期的にチェックする必要があります。
例)
BackgroundWorker worker = sender as BackgroundWorker;
if(worker.CancellationPending)
{
    //e.Cancel = true;
}

処理がキャンセルされた場合、RunWorkerCompletedイベントで処理がキャンセルされたことを知らせるにはDoWorkイベントハンドラ内で以下の処理を行います。
e.Cancel = true;

RunWorkerCompletedイベントにフックしたイベントハンドラで処理がキャンセルされたかどうかを取得する例を示します。
if (e.Cancelled) {
    MessageBox.Show("キャンセルされました。");
}

キャンセルの流れ
bw.CancelAsync()
    ↓
DoWorkイベントハンドラにて
worker.CancellationPendingプロパティがtrueになる。
    ↓
キャンセルされたことを知らせるため
e.Cancel = true
とする。
    ↓
処理を中断する。
    ↓
RunWorkerCompletedイベントハンドラにて
e.Cancelledプロパティがtrueになっている。



進行状況の更新

進行状況の更新を報告できるように設定します。
bw.WorkerReportsProgress = true;


ProgressChangedイベントにフックします。
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);


ProgressChangedイベントにフックするイベントハンドラの例)
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
}
ProgressChangedイベントハンドラ内ではメインスレッドのコントロールにアクセス可能です。


進捗状況を更新します。
worker.ReportProgress(progressPercentage);
ReportProgressメソッドを実行するとProgressChangedイベントが発生します。
このメソッドの引数として渡した値がProgressChangedイベントにフックしたイベントハンドラでe.ProgressPercentageとして受け取ることができます。

他の引数を一つ渡すことが出来ます。
worker.ReportProgress(progressPercentage, "Working...");


Sample Code

public partial class Form1 : Form
{
    BackgroundWorker bw;

    public Form1()
    {
        InitializeComponent();
        progressBar1.Maximum = 100;

        bw = new BackgroundWorker();

        //BackgroundWorker が非同期のキャンセルをサポートしているかどうかを
        //示す値を取得または設定します。
        bw.WorkerSupportsCancellation = true;

        //プログレスバー関連
        //BackgroundWorker が進行状況の更新を報告できるかどうかを示す値を取得または設定します。
        bw.WorkerReportsProgress = true;

        //ReportProgress が呼び出されたときに発生します。
        bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);

        //RunWorkerAsync が呼び出されたときに発生します。 
        //実際にバックグラウンド処理を行うイベントハンドラ
        //イベントにフックする。
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);

        //バックグラウンド操作の完了時、キャンセル時、
        //またはバックグラウンド操作によって例外が発生したときに発生します。
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
    }

    private void btnExec_Click(object sender, EventArgs e)
    {
        //IsBusy - BackgroundWorker が非同期操作を実行中かどうかを示す値を取得します。
        if (!bw.IsBusy)
        {
            //バックグラウンド操作の実行を開始します。
            bw.RunWorkerAsync(100);
        }
    }

    void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        this.progressBar1.Value = e.ProgressPercentage;
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker bw = sender as BackgroundWorker;

        int i = 0, count = (int)e.Argument;
        while (i < count)
        {
            Thread.Sleep(50);
            bw.ReportProgress(++i);
            if (bw.CancellationPending)
            {
                e.Cancel = true;
                break;
            }
        }
    }

    void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        string msg = string.Empty;

        if (e.Cancelled)
        {
            msg = "Cancelled";
        }
        else
        {
            msg = "Done";
        }

        MessageBox.Show(msg);

        progressBar1.Value = 0;
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        if (bw.IsBusy)
        {
            bw.CancelAsync();
        }
    }
}

Picasa ウェブ アルバムにアップロードするならPicasa3の「ウェブに同期」がラク

今現在、Picasaの最新のバージョンは3.1ですが、Picasa2.7を使用している場合、自動的にPicasa3には自動的にアップデートされないので、Picasaを起動してバージョン確認することをお勧めします。

Picasaを起動して、左側のフォルダツリーから同期させるフォルダを一つ選択します。
フォルダを選択すると以下のように同ウィンドウ右側に[ウェブに同期]ボタンが表示されます。

この[ウェブに同期]ボタンを押下すると、
同期するか確認するダイアログが表示されます。


「はい」を選択すると対象フォルダと同じ名前のウェブアルバムが作成されます。
後はこのフォルダにアップロードしたいファイルをブチ込んでおくだけでPicasaを起動したときに同期されます。


同期を無効にする

[▼]ボタンを押下し、[同期を無効にする]を選択すると同期を無効にすることができます。


Picasa → Picasa ウェブ アルバムに同期される変更
  • 写真の編集 (基本編集、調整、効果)
  • 追加または削除した写真
  • 説明、タグ、ジオタグに加えた変更
  • アルバムのプロパティ (名前、説明、場所)
  • 他のアプリケーションで行ってハード ドライブに保存した編集


同期されない変更
  • 写真の順序変更
  • ファイル名に対する変更
※[ウェブに同期] 機能で変更を同期できるのは、Picasa から Picasa ウェブ アルバムへのみです。


PYA

Picasa の基本
Picasa ウェブ アルバムとの変更の同期: [ウェブに同期] の基礎

別スレッドで処理を行うメリットはマルチCPUの恩恵みにある

比較に使用する処理
System.IO名前空間の「Directory.GetFiles」とSystem.Text.RegularExpressions名前空間の「Regex.IsMatch」を使用して特定のフォルダ以下にある全てのイメージファイルを取得する。
※当環境でファイル数が約50000弱,その内の約45000のファイルパスを取得する処理となる。

Sample Code

string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
string[] files = Directory.GetFiles(
    folderPath, "*", SearchOption.AllDirectories);

List<string> imgList = new List<string>();

for (int i = 0; i < files.Length; i++)
{
    //正規表現でイメージファイルかを判断し格納。
    if (regex.IsMatch(files[i])) imgList.Add(files[i]);
}


比較分類

  1. メインスレッド(シングルスレッド。通常の処理)で行う場合
  2. BackgroundWorkerを使用して別スレッドで行う場合

上記の処理を共に10回行い、処理に掛かる時間を比較する。

環境
  • OS:Windows Vista
  • CPU: Core2 Duo 2.66GHz
  • RAM: 2GB


1回の処理が終了するまで次の処理を行わない条件で計測する

1回の処理に掛かる時間の平均
  • メインスレッド:1225.477ms
  • 別スレッド:1236.175ms

結論
その差は約0.01秒。
相対的に比較して、この程度の処理で出される差は誤差と言える程度のものでしかなかった。


1回の処理が終了したかに関わらず、処理を行った場合

Sample Code(BackgroundWorkerを使用した処理のみ)
class Program
{
    static void Main(string[] args)
    {
        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);

        for (int i = 0; i < 10; i++)
        {
            if (!bw.IsBusy)
            {
                bw.RunWorkerAsync();
            }
            else
            {
                NewThread();
            }
        }
    }

    static void NewThread()
    {
        BackgroundWorker nbw = new BackgroundWorker();
        nbw.DoWork += new DoWorkEventHandler(bw_DoWork);
        nbw.RunWorkerAsync();
    }

    static void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        string[] files = Directory.GetFiles(
            Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
            "*",
            SearchOption.AllDirectories
            );

        List<string> imgList = new List<string>();
        Regex regex = new Regex(@"\.(BMP|DIB|RLE|JPG|JPEG|JPE|JFIF|GIF|EMF|WMF|TIF|TIFF|PNG|ICO)$");

        for (int i = 0; i < files.Length; i++)
        {
            if (regex.IsMatch(files[i])) imgList.Add(files[i]);
        }

        e.Result = imgList.ToArray();
    }
}

10回処理を行ったトータルの処理時間

  • メインスレッド:11977.108ms
  • 別スレッド:6786.517ms


メインスレッドでループを回した処理に掛かった時間は1回の処理時間×ループ回数とほぼ一致するが、別スレッドで行われた処理では明らかに処理に掛かった時間が短縮された。

タスクマネージャでCPU使用率を見るとデュアルコアCPU環境では、シングルスレッドで処理を行わせた場合、片方のCPUしか使用されていないが、別スレッドで次々に処理を行わせた場合ではCPUをフルに使用して処理を行っていることを確認できる。
このため、別スレッドで次々に処理を行う方が処理に掛かる時間が短くなったと言える。

Sony Style(ソニースタイル)
デル株式会社

Recent Posts