コントラスト比のISO・WCAG基準は不適切(特に白抜きの文字の場合)

文字と背景色のコントラスト比について、ISO/WCAGで推奨値が定められている。解説ページは色々あるが、とりあえずWCAG2.0の日本語訳解説はこちら。ISO-9241-3及びANSI-HFES-100-1988に基づいているとされている。

達成基準 1.4.3 を理解する | WCAG 2.0解説書

達成基準 1.4.6 を理解する | WCAG 2.0解説書

これを鵜呑みにしている解説記事の多いこと…。で、文字が白抜きの場合にこの推奨値を適用するとおかしいだろという話。

"contrast white text"とかでググってみるといくつか記事が見つかった。

For many of us, some of these combinations are not very readable. That is why 4.5:1 is a minimal contrast ratio.

多くの人にとって、これらの組み合わせの中には、あまり読みやすくないものもあります。だからこそ、4.5:1は最低限のコントラスト比なのです。

WebAIM: Contrast and Color Accessibility - Understanding WCAG 2 Contrast and Color Requirements

Myth 1: The WCAG requirements are always optimal

One case where the WCAG standards aren’t applicable is with the brightness contrast of white text.

迷信1:WCAG要件は常に最適である

WCAG規格が適用されないケースの一つに、白文字の明るさのコントラストがあります。

The Myths of Color Contrast Accessibility

もう少し探してみると、この「The Myths of Color Contrast Accessibility」の記事に対する返答の記事を見つけた。

There is no "Myths of Color Contrast Accessibility"

この中で、WCAG2.2および3.0に向けて以下の議論が行われていることが分かった。

Contrast Ratio Math and Related Visual Issues · Issue #695 · w3c/wcag · GitHub

The W3C's specification for determining sRGB contrast as discussed in "Understanding WCAG 2.0 and 2.1, Minimum Contrast 1.4.3" is not perceptually uniform and as a result creates "contrast ratios" that are not meaningful.

「Understanding WCAG 2.0 and 2.1, Minimum Contrast 1.4.3」で説明されているsRGBコントラストを決定するためのW3Cの仕様は、知覚的に均一ではなく、その結果、意味のない「コントラスト比」が作成されます。

...

we've found that the issue is not so much using "simple contrast" as it is the manner (or lack of) considering ambient lighting, the nature of illuminated displays, and/or a lack of math that better models human non-linear perception.

問題は「単純なコントラスト」を使用しているからというよりも、環境照明、ディスプレイの性質、および/または人間の非線形知覚をよりよくモデル化する数学が欠如しているからということがわかりました。

...

With a random set of colors, about 50% false passes and 22% false fails compared to a perceptually uniform prediction model such as SAPC.

ランダムな色の組を評価すると、SAPCのような知覚的に均一な予測モデルと比較して、約50%の偽合格と約22%の偽失敗が発生します。

...

The new methods are part of 3.0, as they are a complete break from the current methods. As such, discussing the current methods is somewhat moot — those are not going to change.

新しい手法は3.0の一部であり、現在の手法から完全に脱却したものです。このように、現在の手法を議論することはやや無意味です - それらは変更されないでしょう。

やはり、現状のコントラスト比の計算方法・推奨値は問題が多く当てにならないようだ。根本的に計算方法を変更する必要があるため3.0での更新を目指している模様。

開発中のツールも紹介されていて参考にはなるが、議論を斜め読みするだけでも相当複雑な問題領域であることが分かるので、現時点では実際のUIで実際のハードウェアで実際の使用環境において色々な人に見てもらって評価した結果を重視しよう、というのが私の結論。同じ配色でも、フォント・サイズ・ウェイトや文字の使われ方(本文かヘッダかボタンキャプションか)、ディスプレイの明るさや解像度によって妥当かどうかはものすごく変わる。

とりあえず、文字が白抜きの場合は太字にすること。

SQL Serverの変更検出のメモ

SQL Serverで特定のテーブルに変更が発生したことを検出して色々したい。できれば、どの行が追加/編集/削除されたかが欲しい。

まずクエリ通知というのが見つかる。クエリの結果に変更がある場合に通知してくれるが、どの行に変更があったのかは分からない代物。ともかく試してみる。

SQL Server のクエリ通知 - ADO.NET | Microsoft Docs

手順はここに説明があるが、

SqlDependency を使用した変更の検出 - ADO.NET | Microsoft Docs

詳細な手順はここが参考になる。

Using SqlDependency To Monitor SQL Database Changes - C# Tutorials | Dream.In.Code

OnChangeイベントは一度しか発生しないらしい。

c# - SQLDependency_OnChange-Event fires only one single Time - Stack Overflow

Delete/Insert/Updateのどれかが発生したことは分かるが、やはりそれだけだった。クエリ結果を画面に表示している場合などで、常にクエリ結果を最新に保つ目的に特化していると分かった。

どの行に変更があったのかを知る方法は標準ではなさそう。このライブラリを使うのが良いらしい。まだ試していない。

GitHub - christiandelbianco/monitor-table-change-with-sqltabledependency: Get SQL Server notification on record table change

How to monitor SQL Server table changes by using c#? - Stack Overflow

BinaryFormatterによるDeep Copyと明示的実装の違い

お手軽にDeep Copyを実現するなら、BinaryFormatterが使われることがあるが、かなり処理時間がかかるため、速度を重視するなら明示的にDeep Copyを実装する必要がある。ぶら下がっている型全てで明示的に実装する必要はあるが、大抵は特に問題なく実装できるだろう。しかし、BinaryFormatterによるDeep Copyと、典型的な明示的実装には一部大きな違いがある。

下図の構造のインスタンスがあったとする。BinaryFormatterによるDeep Copyでは、オブジェクトグラフを完全に複製する。一方で、典型的な明示的実装ではツリー構造に変化してしまう。これは明示的実装でなくとも、XMLJSONなどへ単にシリアライズ・デシリアライズすることでDeep Copyした場合も同じだ。

元の構造を維持したい場合、それなりに工夫する必要がある。

例えば、そのオブジェクトグラフにおいて各インスタンスのIdが必ずユニークであるという前提があるならそれを利用して、一度コピーしたIdのインスタンスは再度コピーしないようにキャッシュすればよい。連鎖的なコピーの最初にキャッシュを作って持ちまわる。

GitHubでコントリビュートする流れメモ

たまにしかやらなくてTFSと勝手が違ってていつも調べるのでメモ。

  • オリジナルのリポジトリからFork(自分のリポジトリを作成)して、自分のリポジトリからClone(ローカルへ取り込み)する。
  • 自分のリポジトリでPull Request用にブランチを切って作業する。TFSと違い、コミットではなくブランチをマージすることになる。
  • 無印のmasterブランチとかがローカルのリポジトリで、remoteとついているのがGitHub側。remote/originがGitHubの自分のリポジトリ
    • オリジナルのリポジトリgit remote add upstream git://github.com/octocat/Spoon-Knife.gitで登録しておく。remote/upstreamになる。この操作はVisual Studio上では出来なさそう。
  • upstreamの最新を取り込むときは、Fetchしてマージしてoriginへpushする流れ。
  • あとはPull Requestを出すだけだが、出した後もそのブランチへのコミットはPull Requestに反映されていくことに注意。(Pull Requestは出した時点までのコミットの取り込みではなく、ブランチの取り込みを要求する)

参考:

Github で Fork して PullRequest を送るのはこんなに簡単 - Qiita

GitHubでフォーク元の差分を取り込む - Qiita

リポジトリのcloneとforkの違い - Qiita

LINQで非同期ラムダを待機する

System.Linq.Asyncのバージョン4.0.0で、LINQの各メソッドに非同期ラムダを受けて待機するバリエーションである~Awaitシリーズが追加された。以前までは自分で用意する必要があって微妙でIssueもいくつか立っていたが、パッケージに含まれるようになったので楽!

例)

var array = new[] { 1, 2, 3 };
var tasks = array.Select((x) => GetAsync(x));
// Task.WhenAll(tasks) ...

みたいな書き方をすると、非同期ラムダ式の戻り型はTaskなので、複数のTaskが生成されてGetAsyncが全て並列に動く(正確にはawaitのタイミングでTaskが返って次が走り始める)。これを、1つずつ直列にただし非同期で動かしたいとする。

var array = new[] { 1, 2, 3 };
var tasks = array.Select((x) => GetAsync(x));
foreach (var task in tasks)
{
    var value = await task;
    // ...
}

これだけならTaskを1つずつawaitすれば事足りる。しかしSelectの後段でLINQメソッドをつなげたい場合はIAsyncEnumerableで扱うと効果的。SelectではなくSelectAwaitを使える。

var array = new[] { 1, 2, 3 };
var values = array
    .ToAsyncEnumerable()
    .SelectAwait(async (x) => await GetAsync(x))
    .ToArray();

以前の自前実装したものとSelectAwaitを使ったものと、両方こちらの回答に書いた。

stackoverflow.com

SelectAwaitに限らず、ForEachAwaitAsyncなどIAsyncEnumerableの各種LINQメソッドに~Awaitシリーズが追加されているので是非活用してほしい。

C#アプリのAPIをOPC UAサーバとして公開したいので下調べ

2022/12/19追記

試した結果をまとめました。 qiita.com


OPC UAサーバを開発するために情報を集めた。C#アプリケーションのRPC的なAPIを公開することが念頭にあるので、C言語向けだったりPLC向けだったり情報を垂れ流すのみ系は無視している。

OPC UAサーバを開発する方法

OPC UA対応を行うには、一般的には専用のハードウェアを使用するか、OPC Foundationが提供するOPC UA StackもしくはSDK(Software Development Kit)を活用してOPC UAを装置に組み込むという2つの方法がある。

OPC UAの技術進化、Pub-Sub通信やセキュリティ技術など実用面強化:いまさら聞けないOPC UA入門(3)(1/2 ページ) - MONOist

OPC UA Stackをまず見てみる。

GitHub - OPCFoundation/UA-.NETStandard: OPC Unified Architecture .NET Standard

サンプルを動かしてみたがなんかややこしい印象。XMLからクラスとか生成するにはUA Model Compilerを使うっぽい。GUIツールなどはなくXMLはベタ書きするらしい。

GitHub - OPCFoundation/UA-ModelCompiler: ModelCompiler converts XML files into C# and ANSI C

情報モデルを自作する方法についてはこちらが参考になりそう。

How to create custom OPC UA Information Models • OPC UA rocks

SDKの必要性

OPC UA SDKs and Toolkits | OPCconnect.com

While a stack and examples provides the basic communications infrastructure, a full SDK adds significant application layer libraries and classes to speed up application development. UA developers are recommended to look to one of the third-party vendors listed on this page.

公式実装は、OPC UA Stackとしてインフラストラクチャを提供するが、アプリケーション層の機能を提供する3rdパーティ製のSDKを使うことが推奨されている。なるほど、公式サンプルでの印象は間違っていなかった。

C#でOPC UAサーバを開発できるSDKを探してみると、Unified Automationのがドキュメント・サポートも含めて評判が良い。

OPC-UA client SDK for C#.NET application development - Stack Overflow

Choose SDK - Unified Automation

確かにOPC UA Stackの上にSDKレイヤが載っている。

SDK以外だと、汎用のOPC UAサーバプロセスの上で追加実装することで、既存インターフェースをOPC UAに変換するソリューションも見つかった。

東芝インフラシステムズのは.NET Framework 4.5と書いてあるので使えるかも。

https://www.toshiba.co.jp/sis/seigyo/cnt/prod/ciemac/opcua/index_j.htm

EmpressのはC/C++っぽいので使えない/使いにくそう。

OPC UA ソリューション | 菱洋エレクトロ株式会社

どう開発するか

私の場合はAPIがまだないアプリケーションにOPC UAAPIを設けようとしている。選択肢は三つ。

  • アプリケーションに別途APIを用意してから、別ハードor別プロセスで動作する3rdパーティOPC UAサーバ製品から繋いで公開する
    • OPC UA部分を独立してフットワーク軽く将来の変更・拡張に対応できそう
    • アプリケーション中の別機能や複数のアプリケーションでOPC UA対応する場合に統一的な運用をしやすい
    • OPC UAでないAPIとOPC UAAPIをそれぞれ設計する必要がある分だけ二度手間な感じ
    • OPC UAでないAPIをネットワーク上に公開する場合、セキュリティを別に確保する必要がある
    • 間に別のプロセス・ハードが挟まる分だけオーバーヘッドがありそう
    • 別ハードor別プロセスとの連携絡みで考えることが増える
    • 原価が上がる
  • アプリケーションに別途APIを用意してから、別プロセスで動作するOPC UAサーバも自分で用意してそこから繋いで公開する
    • ローカルでの通信部分はセキュリティを気にしなくて良い
    • 原価は抑えられるが自分で考えることも増える
  • アプリケーションに直接OPC UAサーバを実装する
    • とりあえずミニマルにOPC UAでアクセスするAPI用意するだけならすぐできそう
      • OPC UAをフル活用しようとすると手間がかかるかもしれない(知らない)
    • アプリケーションとOPC UAが密結合する
      • OPC UA部分のメンテナンスでもアプリケーションのバージョンアップが必要
      • OPC UA以外でAPIを公開したくなった時に面倒かも
    • ローカル上でAPIを使う場合にもOPC UAを通すのは冗長かも

バランスが取れるのは2番目か。まず3番目で進めて評価とかして、後でOPC UAサーバ部分を分離する必要が出てから分離しても遅くはないか。

OPC UAの一般的な概要を理解するための記事

OPC UA最新技術解説 - MONOist

いまさら聞けないOPC UA入門 - MONOist

インダストリー4.0の推奨規格「OPC UA」、パブサブモデルでスマート工場に対応:産業用ネットワーク(1/2 ページ) - MONOist

インダストリー4.0で重要な役目を果たす、Windows生まれの「OPC UA」:IoT観測所(20)(1/3 ページ) - MONOist

OPC UAはなぜ「安全に」通信が行えるのか:OPC UA最新技術解説(3)(1/3 ページ) - MONOist

OPC UAとは何か?なぜ「製造業とITの橋渡し役」として最適なのか インダストリー4.0採用やOSS化で大注目|ビジネス+IT

オリジナル解説 OPC UAとは?- 第1回 OPC UAの概要 | オムロン制御機器

OPC UA ソリューション | 菱洋エレクトロ株式会社

産業IoT界隈では良く使われるらしい国際規格OPC-UAについて調べた - Qiita

OPC UA Companion Specifications (OPC UA CS) | OPCconnect.com

書籍

概要をつかむ系

https://www.amazon.co.jp/OPC-Unified-Architecture-Information-Technology/dp/1530505119

仕様をきっちり理解する系

https://www.amazon.co.jp/OPC-Unified-Architecture-Wolfgang-Mahnke/dp/3642088422/

COMポートの詳細設定画面をC#から開く

COMポート番号を変更したい場合、通常は以下のようにデバイスマネージャから詳細設定画面を開く必要がある。C#のアプリケーションでRS232C接続をする場合、RS232C-USB変換アダプタを使うのが一般的だと思うが、この時COMポート番号が不定になってしまい、環境ごとにデバイスマネージャからこの画面を開くのが手間で改善策を検討した。

f:id:cactuaroid:20200218235517p:plain

しかし、コマンドラインからCOMポート番号を変更するには恐らくレジストリを直接いじるような方法しか見当たらず、怖いので完全自動化は諦めて、以下を参考にして、必要なタイミングでこの詳細設定画面を直接プログラムから開いて手動設定する代替案を実装した。

stackoverflow.com

ついでに、SerialDisplayAdvancedSettingsがPInvoke.netに載っていなかったので追加した。

https://www.pinvoke.net/default.aspx/msports/SerialDisplayAdvancedSettings.html