
Yandexが一部のユーザーに新製品Yandex Browserを喜ばせてから、ほぼ2か月が経過しました。 この分野(ChromeとFirefox)での製品開発の驚くべきダイナミクスにもかかわらず、Yandexはブラウザに多くの新しいアイデアをもたらしました。
このブラウザのすべての機能の中で、私は「スピードダイヤル」のウェブサイト画像に関する設計上の決定に最も夢中になりました。 人々は自分の目で愛しているので、新しいタブで空白の白いページではなく、カラフルな写真を見るのは素晴らしいことです。 唯一の問題は、個人的に、ほとんどの場合、この写真の下またはファビコンの署名を見るということです。サイトのスクリーンショットからそれを認識するのは非常に難しいからです。 私の意見では、Yandexのデザイナーはこの問題を非常にエレガントに解決しました。 この投稿では、クライアント側でこのアイデアを実装する方法について説明します。
アイデアの本質は次のとおりです。
- ファビコンサイトを取得する
- ファビコンで支配的な色を定義する
- 支配的な色の長方形を描き、ファビコンを貼り付けます。
- 魅力を高めるために、上からグラデーションが適用されます。
とても簡単に聞こえます。 ここで最も難しい点は、ファビコンの支配的な色を決定することです。 これを行うには、3つの問題を解決する必要があります。
- ファビコンを取得します。
- 画像の各ピクセルの値にアクセスします。
- 支配的な色を決定するためのアルゴリズムを決定します。
ファビコンを取得する
ファビコンを取得するには、ドメインでファビコンを検索して返すサーバーで特定のハンドラーを作成するか、Yandexブラウザーがそれをどのように実行するかを確認できます。 たとえば、次のクエリ:
GET favicon.yandex.net/favicon/habrahabr.ru
ここにそのような画像が返されます:
画像ピクセルアクセス
2番目のタスクについて-クライアント側で画像のピクセル値にアクセスする唯一の方法は、要素を使用することです。 キャンバスに画像をロードすることにより、任意のピクセルの値を取得できます。
ただし、いくつかの問題があります。 canvasタグを使用して画像ピクセルにアクセスできるのは、画像を処理するページと同じドメインから読み込まれた画像のみです(クロスドメインブラウザポリシーが機能します)。
したがって、キャンバス要素を使用してファビコンの主要な色を見つけるには、ファビコンをダウンロードするプロキシをサーバー上で整理し(たとえば、favicon.yandex.ruサービスから)、ページに戻す必要があります。
この点で、悲しいかな、純粋にクライアント側でのサイトのこのようなプレビューの実装は機能しません。 実際、画像のプロキシとしてサーバーが必要なので、アイコンではなく色に戻って、支配的な色の計算をサーバーに転送できます。 ただし、サーバー側でこれを実装する方法は、サーバーで使用される言語(Python、PHP、Java)に応じて実装が異なるため、それほど興味深いものではなく、非常に異質です。 したがって、キャンバス要素を使用してクライアントでこれを行う方法を見ていきます。
ドミナントカラーアルゴリズム
画像の支配的な色を決定するための多くのアルゴリズムがあります。 これらのアルゴリズムの一般的な考え方は次のとおりです。 各画像ピクセルは、R、G、B、Aの4つの数値を表します。すべてのピクセルを調べて、特別な方法でそれらのコンポーネントを分析します。
私たちの場合、実装するとき、2つの機能を考慮する必要があります。
I.多くのファビコンには透明なピクセルがあり、キャンバス要素にレンダリングされると、rgba(0、0、0、0)として表されます。 アルファチャネルを無視するため、これらのピクセルは黒(#000000)のように見えますが、これは正しくありません。 これを修正するには、ファビコンを描画する前にキャンバスを白くペイントします。
II。 ファビコンは白い円に収まるという考え方なので、画像の主要な色が白の場合、要素の円または境界線は表示されません。 これを回避するには、各アルゴリズムの白いピクセルを単に無視します。
複雑さを増して支配的な色を決定するための3つの異なるアルゴリズムを検討します。
アルゴリズム1.平均色値
最初の最も簡単なアルゴリズムは次のとおりです。 単純にすべてのピクセルを調べて、対応する色の算術平均を計算します。 コードで記事を
煩雑にしないために、すべてのソースは
gihubで利用可能です。私は彼らの仕事の結果だけを示します。

アルゴリズム2.ユークリッド距離
このアルゴリズムはもう少し複雑で、次のもので構成されています。 各色は、3次元空間(r、g、b)のベクトルです。 各ピクセルを調べて、他のすべてのピクセルまでの距離(2つのベクトル間のユークリッド距離)を考慮します。 次に、他のすべてのピクセルに最も近いピクセルを探します。 このピクセルの色は、希望する色です。 このアルゴリズムは、前のアルゴリズムとは異なり、新しい色を作成するのではなく、この画像の既存の色からのみ選択することに注意してください。

アルゴリズム3. k-meansをクラスタリングする方法
このアルゴリズムの本質は次のとおりです。 異なる色の画像のkピクセル(中心)をランダムに選択します。 他のすべてのピクセルを調べて、互いの近接度に基づいて各ピクセルを中心の1つに割り当てます(アルゴリズム2と同様にユークリッド距離を考慮します)。 次に、中心を再計算します-割り当てられたすべてのピクセルの平均に等しい値を設定します(アルゴリズム1のように)。 再びすべてのピクセルを調べて、それらを新しいセンターに配布します。 センターの価値が変化しなくなるまで、これをすべて行います。 必要な色は、ほとんどのピクセルを持つ中心値になります。 このメソッドは、Chromeブラウザーで
同じ目的で使用されることに注意してください。 k = 3に対する彼の仕事の結果は次のとおりです。
k = 5の場合:
(パラメータkの残りの値については、結果はそれほど示唆的ではありません)
おわりに
これらのアルゴリズムのどちらが優れているかという問題は議論の余地があります。
- 平均的なアルゴリズムは非常にシンプルで一般的には機能しますが、かなり汚い結果をもたらす可能性があります。
- 私の好みでは、ユークリッド距離による計算はかなり良い結果をもたらし、実装は簡単です。
- クラスタリングアルゴリズムは最も複雑です。 最も鮮明な画像が得られ、最も多くの計算が必要です。
PS Github-user static-labは、「コントラスト付きYUVの平均」という別のアルゴリズムを提案および実装しましたが、これも非常に良い結果をもたらします。

ブラウザで実行できる例(Base64でエンコードされたファビコン):
DEMOここのソース:
github