画像を右クリックすると塗り絵用の線画を表示します。スライダーで濃さを調整できます。
by
hitode909
02/22 [2025/02/22 20:37:40]
濃さを調整したあと印刷して、塗り絵として使ってください。X.comなど、うまく動かない場合は画像をタブで開いてから実行してください。
/*
* @title 画像を右クリックすると塗り絵用の線画を表示します。スライダーで濃さを調整できます。
* @description 濃さを調整したあと印刷して、塗り絵として使ってください。
* @include http://*
* @license MIT License
* @require
*/
(function() {
alert("画像を右クリックすると塗り絵用の線画を表示します。\nスライダーで濃さを調整できます。");
function handleContextMenu(event) {
let target = event.target;
if (target.tagName === "IMG") {
event.preventDefault(); // 右クリックのデフォルト動作を防ぐ
processImage(target.src, target.width, target.height);
}
}
document.addEventListener("contextmenu", handleContextMenu, false);
function processImage(imgUrl, width, height) {
let newTab = window.open(); // ポップアップブロック回避
if (!newTab) {
alert("ポップアップブロックを解除してください!");
return;
}
let sliderValue = 50; // 初期値(中間)
function getFilter() {
let slope, intercept;
if (sliderValue <= 50) {
// 左側: (0.5, -0.25) → (10, -5) の線形変化
let t = sliderValue / 50;
slope = 0.5 + (10 - 0.5) * t;
intercept = -0.25 + (-5 + 0.25) * t;
} else {
// 右側: (10, -5) → (10, 0) の線形変化
let t = (sliderValue - 50) / 50;
slope = 10;
intercept = -5 + (0 + 5) * t;
}
return `
<filter id="edge">
<feColorMatrix type="saturate" values="0"></feColorMatrix>
<feComponentTransfer>
<feFuncR type="linear" slope="${slope}" intercept="${intercept}"></feFuncR>
<feFuncG type="linear" slope="${slope}" intercept="${intercept}"></feFuncG>
<feFuncB type="linear" slope="${slope}" intercept="${intercept}"></feFuncB>
</feComponentTransfer>
</filter>`;
}
let svgTemplate = `
<div class="print-container">
<svg xmlns="http://www.w3.org/2000/svg" id="mainSVG" width="100%" height="100%" viewBox="0 0 ${width} ${height}" preserveAspectRatio="xMidYMid meet">
<defs id="defs">${getFilter()}</defs>
<image id="image" href="${imgUrl}" x="0" y="0" width="${width}" height="${height}" filter="url(#edge)"/>
</svg>
</div>`;
let style = `
<style>
body { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; background: white; margin: 0; padding: 0; }
.print-container { width: 100vw; height: 90vh; display: flex; justify-content: center; align-items: center; }
svg { max-width: 100%; max-height: 100%; }
.controls { display: flex; flex-direction: column; align-items: center; gap: 10px; width: 80%; max-width: 400px; }
.slider-label { font-size: 14px; font-weight: bold; }
input[type="range"] { width: 100%; }
@media print {
.controls { display: none; } /* 印刷時にスライダーを非表示 */
.print-container { width: 100vw; height: 100vh; display: flex; justify-content: center; align-items: center; }
svg { width: 100vw; height: 100vh; max-width: 100%; max-height: 100%; }
}
</style>`;
let controls = `
<div class="controls">
<label class="slider-label">濃さを調整</label>
<input type="range" id="contrastSlider" min="0" max="100" value="${sliderValue}" step="1">
</div>`;
newTab.document.open();
newTab.document.write(`
<!DOCTYPE html>
<html>
<head>${style}</head>
<body>${svgTemplate}${controls}</body>
</html>
`);
newTab.document.close();
// スライダーイベントを追加
newTab.onload = function() {
let contrastSlider = newTab.document.getElementById("contrastSlider");
function updateFilter() {
sliderValue = parseFloat(contrastSlider.value);
let newFilter = getFilter();
newTab.document.getElementById("defs").innerHTML = newFilter;
}
contrastSlider.addEventListener("input", updateFilter);
};
}
})();
- Permalink
- このページへの個別リンクです。
- RAW
- 書かれたコードへの直接のリンクです。
- Packed
- 文字列が圧縮された書かれたコードへのリンクです。
- Userscript
- Greasemonkey 等で利用する場合の .user.js へのリンクです。
- Loader
- @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
- Metadata
- コード中にコメントで @xxx と書かれたメタデータの JSON です。