(hatena (diary ’Nobuhisa)) このページをアンテナに追加 RSSフィード

18/03/26 :

[][] 全角・半角・ひらがな・カタカナ

アルファベットの大文字/小文字を区別せずに文字列を比較するのはよくあることですが、

全角・半角・ひらがな・カタカナに対応する方法もあるようです。


以前せっかく調べたので忘れないようにメモしておこう。

open System.Globalization

let contains (value:string) source =
    let compareInfo = CompareInfo.GetCompareInfo("ja-JP")
    let options =
        CompareOptions.IgnoreCase         // 大文字・小文字区別なし
        ||| CompareOptions.IgnoreKanaType // ひらがな・カタカナ区別なし
        ||| CompareOptions.IgnoreWidth    // 全角・半角区別なし
        
    compareInfo.IndexOf(source, value, options) > -1
    
let test () =
    "雨ニモマケズ" |> contains "まけず" |> printfn "%b" // true
    "全角でF#" |> contains "F#" |> printfn "%b" // true
    "F♯" |> contains "F#" |> printfn "%b" // false

09/09/30 : 2週間ほど入院していました

[][]君達はHD Photoを忘れてないか

最近はJPEG XR(Wikipedia)とも呼ばれているらしいHD Photo.

君達はその存在を忘れてはいないだろうか。

僕は忘れていました・・・。


.NET Framework 3.0からサポートされているため、我々はそれをプログラミングすることが出来る。

GDI+ではなくWPFでの扱いになっているようで、WPF素人の僕は何箇所か躓きましたが、何とか動いたので以下にメモしておきます。

HD Photoだけじゃなく、他のフォーマットも扱い方は同じみたいだ。これに気付くのに時間がかかってしまった。


C#すごい久しぶりに触ったなぁ・・・。

まずは要所を抜粋したもの。

public static BitmapSource Decode( string uri )
{
	// WmpBitmapDecoder を使うとHD Photo以外を受け付けなくなる
	var decoder = BitmapDecoder.Create(
		new Uri( uri ),
		BitmapCreateOptions.PreservePixelFormat,
		BitmapCacheOption.Default
	);
	return decoder.Frames[ 0 ];
}

public static void Encode( BitmapSource source, string outUri, float quality = 0.8f )
{
	using ( var stream = new FileStream( outUri, FileMode.OpenOrCreate ) )
	{
		var encoder = new WmpBitmapEncoder();
		encoder.ImageQualityLevel = quality;
		encoder.Frames.Add( BitmapFrame.Create( source ) );
		encoder.Save( stream );
	}
}

JPEGだとかPNGのような他のものもBitmap(En|De)coderを継承しているため、HD Photoに限らずWPFで画像を扱う際は似たような感じになるみたいです。

Decodeメソッド内のコメントにあるように、(当たり前ですが)WmpBitmapDecoderを使うとHD Photo以外の画像を開けない(例外が発生する)ので、今回は親クラスであるBitmapDecoderを使用しました(このようにするとフォーマットを自動で判別してくれるらしい)。

EncodeのほうはHD Photoでの書き出しに特化しています。クォリティは適当に0.8f。ちなみにオプショナル引数はC#4.0で追加された新しい仕様であります。


VistaはHD Photoにもともと対応しているので、保存した画像は標準のViewerで確認できます。

ファイルの拡張子は*.hdpか*.wdpらしいですが、僕の環境では*.hdpを画像ファイルとして認識してくれない・・・。



最後に、一応すべてのプログラムを掲載しておきます。おまけでXAMLも。

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" WindowStyle="ThreeDBorderWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="480" Width="640" HorizontalAlignment="Left" VerticalAlignment="Top">
    <Grid Name="main">
        <ScrollViewer Name="scrollViewer1" CanContentScroll="True" HorizontalScrollBarVisibility="Visible" HorizontalContentAlignment="Left" VerticalContentAlignment="Top" Margin="0,41,0,0" Background="#FF524F4F">
            <Image HorizontalAlignment="Stretch" Name="image1" Stretch="None" VerticalAlignment="Stretch" StretchDirection="Both" />
        </ScrollViewer>
        
        <Button Content="Open" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button_Open" VerticalAlignment="Top" Width="75" Click="button_Open_Click" />
        <Button Content="Convert" Height="23" HorizontalAlignment="Left" Margin="93,12,0,0" Name="button_Convert" VerticalAlignment="Top" Width="75" Click="button_Convert_Click" />
        
    </Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.IO;
using WinForms = System.Windows.Forms;
using System.Drawing.Imaging;

namespace WpfApplication1
{
	/// <summary>
	/// Interaction logic for Window1.xaml
	/// </summary>
	public partial class Window1 : Window
	{
		private WinForms.OpenFileDialog openFileDialog = new WinForms.OpenFileDialog();
		private WinForms.SaveFileDialog saveFileDialog = new WinForms.SaveFileDialog {
			AddExtension = true,
			Filter = "HD Photo ファイル|*.wdp;.*hdp;"
		};

		public Window1()
		{
			InitializeComponent();
		}

		private void button_Open_Click( object sender, RoutedEventArgs e )
		{
			if ( this.openFileDialog.ShowDialog() == WinForms.DialogResult.OK )
				this.image1.Source = JPEG_XR.Decode( this.openFileDialog.FileName );
		}

		private void button_Convert_Click( object sender, RoutedEventArgs e )
		{
			if ( this.image1.Source == null ) return;
			if ( this.saveFileDialog.ShowDialog() == WinForms.DialogResult.OK )
			{
				JPEG_XR.Encode(
					(BitmapSource)this.image1.Source,
					this.saveFileDialog.FileName );
			}
		}
	}

	public static class JPEG_XR
	{
		public static System.Windows.Controls.Image Convert( BitmapSource source )
		{
			var img = new System.Windows.Controls.Image() {
				Source = source,
				Stretch = System.Windows.Media.Stretch.None
			};
			return img;
		}

		public static BitmapSource Decode( string uri )
		{
			// WmpBitmapDecoder を使うとHD Photo以外を受け付けなくなる
			var decoder = BitmapDecoder.Create(
				new Uri( uri ),
				BitmapCreateOptions.PreservePixelFormat,
				BitmapCacheOption.Default
			);
			return decoder.Frames[ 0 ];
		}

		public static void Encode( BitmapSource source, string outUri, float quality = 0.8f )
		{
			using ( var stream = new FileStream( outUri, FileMode.OpenOrCreate ) )
			{
				var encoder = new WmpBitmapEncoder();
				encoder.ImageQualityLevel = quality;
				encoder.Frames.Add( BitmapFrame.Create( source ) );
				encoder.Save( stream );
			}
		}
	}
}

08/09/17 :

[][]AppDomain.Unload

AppDomain.UnloadによるスレッドのAbortと、抹殺されるスレッドの最後の抵抗(finally)によってCannotUnloadAppDomainExceptionが発生するまで。


親アプリケーション

public void Test1()
{
	string childPath = "(子アプリのパス)";
	AppDomain domain = AppDomain.CreateDomain( "UserDomain1" );
	Action thread = () => domain.ExecuteAssembly( childPath );

	thread.BeginInvoke( null, null );
	try
	{
		for ( int i = 0 ; i < 6 ; i++ )
		{
			Console.WriteLine( "parent" );
			System.Threading.Thread.Sleep( 1000 );
			if ( i == 3 ) AppDomain.Unload( domain );
		}
	}
	catch ( System.CannotUnloadAppDomainException )
	{
		Console.WriteLine( "cannot!" );
	}
}

子アプリケーション

static void Main( string[] args )
{
	try
	{
		for ( int i = 0 ; i < 6 ; i++ )
		{
			Console.WriteLine( "child" );
			System.Threading.Thread.Sleep( 1000 );
		}
	}
	catch ( System.Threading.ThreadAbortException )
	{
		Console.WriteLine( "abort !!!" );
	}
	finally
	{
		System.Threading.Thread.Sleep( 2000 ); //抵抗
		Console.WriteLine( "finally end" );
	}
}

Unload(Abort)するも、finallyブロックが実行されるため結局タイムアウトしてしまい、CannotUnloadAppDomainExceptionが発生する。



解説

.NET Framework Version 2.0 では、アプリケーション ドメインをアンロードするための専用のスレッドが使用されます。このバージョンの .NET Framework がホストされた環境では、これによって信頼性が向上します。スレッドから Unload が呼び出されると、ターゲット ドメインがアンロードの対象としてマークされます。専用のスレッドによって、そのドメインのアンロードが試みられ、そのドメインのすべてのスレッドが中止されます。アンマネージ コードを実行中である、または、finally ブロックを実行中である、などの理由からスレッドを終了できなかった場合は、一定時間の経過後に、Unload の呼び出し元スレッドで CannotUnloadAppDomainException がスローされます。最終的にスレッドを終了できなかった場合、ターゲット ドメインはアンロードされません。このように、.NET Framework Version 2.0 では、実行中のスレッドを中止できない場合があるため、domain が確実にアンロードされるという保証はありません。


メモ :

一部のケースでは、Unload を呼び出した直後に CannotUnloadAppDomainException が発生する場合があります (ファイナライザから呼び出した場合など)。


domain 内のスレッドは、Abort メソッドを使って終了され、そのスレッドで ThreadAbortException がスローされます。スレッドはすぐに終了する必要がありますが、finally 句が実行されている間は継続される場合があります。この時間は予測できません。

AppDomain.Unload メソッド

08/09/14 :

[][]

XML宣言がXDocument(XElement)のsaveメソッドを読んだときにしか追加されない(オブジェクト自体に追加されるわけではなく、保存されたファイルに追加される)ので、結局StringBuilderでXMLを書いています。XDocumentの方から宣言を設定もしくは取得するプロパティも有るんだけど、それを使ってもダメ。これはどうすれば。。。

はてなダイアリーにAtomPudで投稿する - INOHILOG

もうちょっと親切なクラスであれば嬉しいんですが、どうやらSaveメソッドを呼ぶしか無いみたい?(他にあれば伝授してください!)なのですが、ファイルではなくStringBuilderに出力することもできるので以下のように書けます。

var sb = new StringBuilder();
var settings = new XmlWriterSettings() { Indent = true, OmitXmlDeclaration = false };

// ここはほぼそのままコピペ
XNamespace xname = "http://purl.org.atom/ns#";
XDocument doc = new XDocument(
	new XDeclaration( "1.0", "utf-8", "no" ),
	new XElement( xname + "entry",
		new XElement( "title", "title2" ),
		new XElement( "content", new XAttribute( "type", "text/plain" ), "content2" ),
		new XElement( "updated",
		              DateTime.Now.ToString( "o", new System.Globalization.CultureInfo( "ja-jp" ))))
);

using ( XmlWriter writer = XmlWriter.Create( sb, settings ) )
{
	Console.WriteLine( doc.Declaration );
	Console.WriteLine();

	doc.Save( writer );
	writer.Flush();
	Console.WriteLine( sb );
}


<?xml version="1.0" encoding="utf-8" standalone="no"?>

<?xml version="1.0" encoding="utf-16" standalone="no"?>
<entry xmlns="http://purl.org.atom/ns#">
  <title xmlns="">title2</title>
  <content type="text/plain" xmlns="">content2</content>
  <updated xmlns="">2008-09-14T01:55:49.0410000+09:00</updated>
</entry>
続行するには何かキーを押してください . . .

しかしなぜか出力のencoding部分がおかしいです!必ずutf-16になってしまう。

色々試してみたけどダメだった。何がおかしいのでしょう。。。

XDeclaration.ToString()+XDocument.ToString()の方が早い気がしてきた今日この頃。

08/02/12 :

[][][][]MockとDIコンテナ

NMock

さりげなくMockってあまり使ったことありません。NUnit付属のものすら。


Spring.NET



NMockやらSpring.NETやらを試したことがない。食わず嫌いは良くないので試してみたいとは思うものの,どうもDIコンテナに対して半信半疑というか・・・(まだちゃんと理解していないせいもあるかも)。Mockは便利かなーという気がするんですが。。。


  • 抽象に依存するのってDIコンテナ以前の問題だし,テストが容易になるという売りはDIコンテナによるものなのかな?
  • 結局依存関係を記述する言語がC#(等)からXMLになっただけでは・・・
    • 依存性の注入・・・という観点からすればありなのかなぁ。。。
  • 人間にあまり優しくない(?)XMLが膨大になることはあまり嬉しいことじゃないような
  • よくIDEに名前変更のリファクタリング補助機能とかあるけど,もしインターフェイス等に名前の変更があったら,XMLは素手で修正だよね
  • 静的型付け言語で全面的にリフレクションを多用するとオーバーヘッドが結構でかそう

大して調べもしていないので変なこと書いちゃってるかもしれませんか・・・。ただ,別に嫌いというわけじゃなく純粋にこのような疑問を持っているだけです。笑

でもやっぱりJavaをはじめ広く使われてるようだから,効果があるんだろうなぁ。ビルド回数とかは減らせるかもしれませんね。

時間見つけて触ってみよう。テスト駆動開発も実際にやってみるまでは半信半疑でしたしね。笑