JavaScriptでアイデンティコンを生成するツールをつくったので、その説明をする。
具体的な処理は、以下の3つだ。
- 文字列からハッシュ値を取得する
- ハッシュ値からアイコン(SVG)を生成する
- SVGのアイコンをPNGで保存する
アイデンティコン とは
アイデンティコンとは、IPアドレスなどからハッシュ値を取得、それをもとに色や形を決めて生成したアイコンのこと。
今回実装するのは、5×5の25ブロックからなるアイデンティコンの生成ツール。ただし、アイコンはGitHubのような左右対称はなくランダムとなる。
やることは以下のとおり。
- 入力された文字列を、SHA-1で40桁のハッシュ値を生成する
- ハッシュの先頭25文字の文字コードにより、描画するかどうか判定する
- ハッシュの残り15文字をさらに3分割し、文字コードよりRGBのカラーコードを生成する
- SVGのパスを生成し、画面に表示する
- canvasを使って、SVGをPNGに変換しダウンロードする
アイデンティコンの生成ツールを実装する
<input type="text" id="source">
<button id="generate">generate</button>
<button id="download">download</button>
<div class="identity-icon">
</div>
const identityIcon = document.querySelector('.identity-icon');
const source = document.getElementById('source');
const generate = document.getElementById('generate');
const download = document.getElementById('download');
/**
* 文字列からRGBを取得する
* @param {string} val RGBに変換する文字列
* @return {Array} [r, g, b]で返す
*/
function generateRGBCode(val) {
if (!val) { return [0,0,0]; }
const len = Math.floor(val.length / 3);
// /[\s\S]{1,n}/g
const regexp = new RegExp(`[\\s\\S]{1,${len}}`, 'g');
const codes = val.match(regexp);
const rgb = [];
codes.forEach(a => {
let n = 0;
for (let x of a) {
n += x.charCodeAt();
}
rgb.push(n % 256);
});
return rgb;
}
/**
* IdentityIconを生成し、SVGのパスを返す
* @param {string} hash sha1などでハッシュ化した値(40桁)
* @param {number} size アイコンの横幅
* @return {string} SVGのパス
*/
function generateIcon(hash, size) {
const forDraw = hash.substr(0, 25);
const forColor = hash.substr(25);
// rgb(x, y, z)
const hue = `rgb(${generateRGBCode(forColor).join(',')}`;
const interval = size / 5;
let x = 0;
let y = 0;
let path = '';
for (let c of forDraw) {
const isDraw = c.charCodeAt() % 2 === 0;
path += `<rect x="${x}" y="${y}" width="${interval}" height="${interval}" fill="${isDraw ? hue : 'white'}" />`;
if (x < size - interval) {
x += interval;
} else {
x = 0;
y += interval;
}
}
return [
`<svg width="${size}" height="${size}">`,
'<g>',
path,
'</g>',
].join('');
}
/**
* generateボタン
*/
generate.addEventListener('click', () => {
const hash = sha1(source.value);
const size = 300;
identityIcon.innerHTML = generateIcon(hash, size);
});
/**
* downloadボタン
*/
download.addEventListener('click', () => {
const hash = sha1(source.value);
const size = 300;
identityIcon.innerHTML = generateIcon(hash, size);
const svg = identityIcon.querySelector('svg');
const svgData = new XMLSerializer().serializeToString(svg);
const canvas = document.createElement('canvas');
canvas.width = svg.width.baseVal.value;
canvas.height = svg.height.baseVal.value;
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0);
canvas.toBlob(blob => {
saveAs(blob, 'icon.png');
}, 'image/png');
};
img.src = "data:image/svg+xml;charset=utf-8;base64," + btoa(unescape(encodeURIComponent(svgData)));
});
入力された文字列のハッシュ化は「js-sha1」というハッシュ関数ライブラリを使用している。sha('文字列') でハッシュ値を生成してくれる。次にハッシュ値の先頭25桁を取得し、1文字ずつcharCodeAtで文字コードに変換し、2で割り切れたらブロックを描画(色を付ける)、割り切れなかったら白ブロックにする。
という具合に5×5のアイコンを生成している。
この部分を修正すれば、GitHubのような左右対称のアイコンも生成できる。
ハッシュ値の残り15桁で描画するブロックの色(RGB)を決める。
15桁を5桁ずつに3分割し、それぞれでcharCodeAtで文字コードを取得し合算する。それを255で割った余りをRed, Green, Blueに当てはめている。
ダウンロード機能は、一旦SVGを描画したあとにXMLSerializerを使いDOMツリーをテキストに変換。それをImageとして読み込み、canvasのdrawImageで描画し、toBlob関数とFileSaver.jsを使ってダウンロードしている。
関連記事
参考サイト
- SVGを画像に変換してダウンロードする方法 - Qiita
- HTMLCanvasElement.toBlob() - Web API インターフェイス | MDN
- XMLSerializer | MDN
以上
written by @bc_rikko
0 件のコメント :
コメントを投稿