Respect for
小一時間暇だったので自動ルビ振り機能とかを搭載したクレしんタイトルコールジェネレーターを作ってみたゾ
https://tools.ic731.net/kureshin/
使い方
アクセスしてテキストボックスに上段と下段に表示したいテキストを入力するゾ
あとは自動でルビ振りされたテキストがタイトルコール風に表示されるゾ
仕組み
もう語尾辞めていいっすか…
- 描画やフロントエンドはVue.jsで書いています
- 画像出力機能はhtml2canvasを使いました。これ超便利だから使って見て下さい
- 自動ルビ振り機能はPHP上でYahoo!ルビ振りAPIをリクエスト→HTMLとして返却することで実装しました
画面レイアウト
また、デザインやCSSは@yhattさんの投稿をパクって参考にしてアスペクト比4:3で設計しました。有難うございます!
もう特に書くことは無いのでソースコード載せときます。自分でお試しあれ(GitHubにもあげてます)
HTML+Vue(フロント)
Vueやhtml2canvas
index.html
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- Style by https://qiita.com/yhatt/items/4cd0c21b6bf5cf8af456 -->
<style>
@import url('https://fonts.googleapis.com/css2?family=Kosugi+Maru&display=swap');
.preview {
aspect-ratio: 4 / 3;
background: linear-gradient(to bottom, rgb(94% 51% 64%), rgb(95% 95% 50%));
display: grid;
place-content: center;
width: 600px;
}
h1 {
color: purple;
font-family: 'Kosugi Maru', sans-serif;
font-size: 30px;
padding-left: 1em;
line-height: 1.5;
}
h1::before {
content: '';
margin-left: -1em;
}
button {
margin-top: 1em;
height: 40px;
}
</style>
</head>
<body>
<div id="app">
<div class="preview">
<h1 v-html="title"></h1>
</div>
<label>上段:
<input type="text" v-model="top">
</label>
<br>
<label>下段:
<input type="text" v-model="bottom">
</label>
<br>
<button @click="AddText">反映</button>
<br>
<button @click="generate">
画像として保存
</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.3.2/dist/html2canvas.min.js"></script>
<script>
new Vue({
el: "#app",
data: {
top: "",
bottom: "",
title: "上段と下段を<br>入力してください"
},
methods: {
AddText() {
if (!this.top == "" || !this.buttom == "") {
fetch("./addruby.php?sentence=" + this.top)
.then(res => res.text())
.then(data => {
this.title = data + "<br>";
return fetch("./addruby.php?sentence=" + this.bottom);
})
.then(res => res.text())
.then(data => {
this.title += data;
});
} else {
alert("入力してください");
}
},
generate() {
html2canvas(document.querySelector('.preview')).then((canvas) => {
const link = document.createElement('a')
link.href = canvas.toDataURL()
link.download = `image.png`
link.click()
})
}
},
})
</script>
</body>
</html>
PHPコード(ルビ振り処理)
一部省略しています。割と冗長かもしれんが短く書いたつもり…
addruby.php
<?php
$ch = curl_init();
$apikey = '<APIキー>';
$sentence = htmlspecialchars($_GET['sentence']);
$jayParsedAry = [
'id' => '1234-1',
'jsonrpc' => '2.0',
'method' => 'jlp.furiganaservice.furigana',
'params' => [
'q' => $sentence,
'grade' => 2
]
];
// CURLでリクエスト
curl_setopt($ch, CURLOPT_URL, 'https://jlp.yahooapis.jp/FuriganaService/V2/furigana');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($jayParsedAry, JSON_UNESCAPED_UNICODE));
$headers = [];
$headers = [
'Content-Type: application/json',
'User-Agent: Yahoo AppID: ' . $apikey
];
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
curl_close($ch);
$result = json_decode($result, true);
$surface = '';
// 各配列のsurfaceを結合
foreach ($result['result']['word'] as $value) {
if (isset($value['furigana'])) {
// もし["subword"]があればforeachで繰り返して結合
if (isset($value['subword'])) {
foreach ($value['subword'] as $subvalue) {
// furiganaとsurfaceが同値だったら結合しない
if ($subvalue['furigana'] === $subvalue['surface']) {
$surface .= $subvalue['furigana'];
} else {
$surface .= '<ruby>' . $subvalue['surface'] . '<rt>' . $subvalue['furigana'] . '</rt></ruby>';
}
}
} else {
$surface .= '<ruby>' . $value['surface'] . '<rt>' . $value['furigana'] . '</rt></ruby>';
}
} else {
$surface .= $value['surface'];
}
}
echo $surface;