CAMPHOR- —京都のIT系学生コミュニティ—

セクション区切り

About

CAMPHOR-カンファーは京都のIT系学生コミュニティです。
エンジニアリング・デザイン・プロダクト開発などへの関心を共通点とする、 様々なバックグラウンドを持つ学生が集まっています。

CAMPHOR- HOUSE イメージ画像

CAMPHOR- HOUSE

CAMPHOR-のコミュニティースペースです。誰でも自由に訪れることが可能であり、日頃から作業・相談・議論が行われています。集まることのできる決まった場所があることによって、日頃のメンバー間の交流が促進されています。

創作活動 イメージ画像

メンバー同士の交流

CAMPHOR-にはITに関係する幅広い事柄に興味を持つメンバーが出入りしています。様々なスキルセットやスキルレベルを持つ学生により、教え合いや議論が普段から行われています。

イベント開催 イメージ画像

イベント・勉強会

トークイベントや勉強会を定期的に開催しています。学生が普段の取り組みについて発信し交流するものや、企業のデザイナーやエンジニアに来ていただくものがあります。

セクション区切り

House

学生が気軽に開発やデザインを行うことができる無償のコミュニティスペースです。
各種イベントもこちらで開催されており、様々な人が集まる場所となっています。

CAMPHOR- HOUSE 地図

CAMPHOR- HOUSEカンファーハウス

住所
〒606-8302
京都府京都市左京区吉田牛ノ宮町16番地
最寄駅・バス停
京阪 出町柳駅より徒歩9分
京都市バス 京大正門前より徒歩3分
Maps Schedule
セクション区切り
セクション区切り

Members' blog

CAMPHOR-カンファー運営メンバー個々人が綴るブログ記事を収集して表示しています。
メンバーの得た技術的・学術的・日常的な知見を共有します。

ブログのサムネイル画像
15
March

Vue.extend で TypeScript がエラーを吐いたときに確認すべきことhttps://qiita.com/dora1998/items/299d982eef24d6ab203c

Vue の単一ファイルコンポーネントを TypeScript で書く方法はいくつかある。僕はなるべく JS に近い書き方をしたくて、Vue.extend を使っているのだが、時々下のような型エラーが発生する。 Property 'XXX' does not exist on type 'Vue'. なお、ここで言う XXX とは、SFC 内にある computed の変数だったり methods にある関数だったりする。このようなときに確認するべき場所を自分の備忘録も兼ねてまとめておく。 computed や methods の関数にアノテーションをつけているか Vue.extend() で型の推論を行っている場合、引数として書いたオブジェクトをもとに、そのオブジェクト内で使われる this の推論が行われる。そのため、型推論に頼っていると、しばしば失敗して this の型が正しく認識されなくなるのである。(雑な理解なので、詳しい方いたら教えてください) 対処法としては、computedやmethodsに書いた関数には、しっかり下のようにアノテーションを書いてあげれば良い。これは Vue の TypeScript サポートに関するページにも記載があるが、ちょくちょくフォーラムでも同様の質問があり、案外見落としがち(自分もハマった)。 import Vue from 'vue'; export default Vue.extend({ data() { return { msg: 'Hello' }; }, methods: { // アノテーションをしっかり書く greet(): string { return this.msg + ' world'; // ~~~ ← 書かないとここがエラーになることがある } }, computed: { // ここもアノテーションをしっかり書く greeting(): string { return this.greet() + '!'; // ~~~~~ ← 書かないとここがエラーになることがある } } }); TypeScript のサポート — Vue.js オプションなどをスペルミスしていないか 昨日ハマったのはこっち。例えば、下のようにpropsのオプションを書き間違えたとする。 export default Vue.extend({ props: { imageUrl: { type: String as PropType<string>, require: true // ← 本当は require"d" !!! } }, }); この場合にも、冒頭に書いたエラーがthisに生えている変数や関数すべてに発生してしまう。同様に type を tyep にスペルミスしたときとかにも起こるので気をつけたい。 参考: Vue/Typescript 3.5.1 Error: 'property' does not exist on type 'Vue' - Get Help - Vue Forum https://forum.vuejs.org/t/vue-typescript-3-5-1-error-property-does-not-exist-on-type-vue/65591 まとめ エラーメッセージが直接的ではない分、原因の特定に時間を食いがちなので気をつけましょう😇
ブログのサムネイル画像
10
March

ダークモードでもSlack絵文字をちゃんと見たい!https://qiita.com/dora1998/items/8db1a36c51ab5856cd84

Slackのカスタム絵文字、楽しいですよね。 さて、ダークモードで使ってる方ならあるあるかもしれませんが、ダークモードにしてしまうとこんな問題が発生します。 _人人人人人人人人人人_ > 絵文字が見えない <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y ̄ 絵文字の背景を透明ではなく白にすることで解決してらっしゃった記事もありましたが、今回は上の画像で黄色く囲んだ「オッ」のように、縁取りをする方法で解決したいと思います。 今回作成したソースコードは、以下のリポジトリに置いてあります。是非使ってみてください! 1. 絵文字を取り込む まずは、Slackから絵文字画像を取ってきます。これは比較的簡単で、emoji.list APIを使うと取得することができます。 emoji:read のスコープを設定したアプリケーションを作成してトークンを取得したら、以下のアドレスを叩くとJSONが得られます。 https://slack.com/api/emoji.list?token=xoxb-... { "ok": true, "emoji": { "bowtie": "https:\/\/emoji.slack-edge.com\/xxxxxx\/bowtie\/yyyyyy.png", "squirrel": "https:\/\/emoji.slack-edge.com\/xxxxxx\/squirrel\/zzzzzz.png", } } これをもとにPythonでシュシュっと取ってくるプログラムを書きます。 import os from time import sleep import requests def download_image(url): response = requests.get(url) if response.status_code != 200: print(f"HTTP Error: {response}") return None content_type = response.headers["content-type"] if 'image' not in content_type: print(f"Error: {content_type} is not image") return None return response.content def make_filename(base_dir, alias, url): ext = os.path.splitext(url)[1] filename = alias + ext fullpath = os.path.join(base_dir, filename) return fullpath def save_image(path, image): with open(path, "wb") as fout: fout.write(image) def main(): TOKEN = os.getenv('SLACK_TOKEN') BASE_DIR = './original/' os.makedirs(BASE_DIR, exist_ok=True) res = requests.get('https://slack.com/api/emoji.list', headers={'Authorization': f'Bearer {TOKEN}'}) emojis = res.json()['emoji'] for alias, emoji_url in emojis.items(): if (emoji_url.startswith('alias:')): continue img = download_image(emoji_url) if img is None: continue img_path = make_filename(BASE_DIR, alias, emoji_url) save_image(img_path, img) sleep(1) if __name__ == "__main__": main() 注意すべき点は、エイリアスを設定しているとそれも含まれてしまうので除外する処理が必要です。 2. フチを抽出する フチの抽出にはラプラシアンフィルタを使います。 今回は画像処理全般をPillowで行いました。当初、OpenCVも試しましたが、一部絵文字のアルファチャンネルが正常に読み込めなかったので諦めました。 f = Image.open('hoge.png') gf = f.convert('LA') edge = gf.filter(ImageFilter.FIND_EDGES) いい感じですね〜 3. 白でフチ取りする 抽出した輪郭をもとに、白で縁取りをします。 フィルタをかけた後のアルファチャンネルのみ活用し、色は全部白で塗ったものを用意しました。 l, a = edge.split() _l, _a = np.full_like(a, 255), np.array(a) img_array = np.stack([_l, _a], 2) border = Image.fromarray(np.uint8(img_array), "LA") ただ、残念ながらこのまま重ねても元画像と重なってしまいほとんど縁が見えません。 border_color = border.convert('RGBA') res = Image.alpha_composite(border_color, f) そのため、輪郭を太らせて重ねます。一般的にはモルフォロジー変換で行うことができるようです。 PillowではこのOpenCVにあるようなメソッドはありませんが、MaxFilterを使うことで同等のことができます。理由については、こちらの記事が詳しいです。 ただ、やっていることはあまり変わりませんが、今回はずらして重ねるという力技の方が見た目が良かったので、そちらを採用しました。 border_color = border.convert('RGBA') diff = [-border_size, border_size] res = f for xd in range(-border_size, border_size + 1): for yd in range(-border_size, border_size + 1): b = border_color.rotate(0, translate=(xd, yd)) res = Image.alpha_composite(b, res) 4. 微調整 平滑化 輪郭検出後の画像に平滑化フィルタ(ImageFilter.SMOOTH)をかけてあげると、少し綺麗になります。 (左が平滑化しない場合、右がした場合) アニメーションGIFの対応 このままだと、アニメGIFを読み込んだ際にエラーで落ちてしまうのでついでに対応してみます。 アニメGIFの場合、各フレームをImageSequence.IteratorやImageSequence.all_framesで取得することができます。 f = Image.open(file) duration, loop = f.info.get('duration', 0), f.info.get('loop', 0) frames = [] for frame in ImageSequence.Iterator(f): bf = make_border(frame.convert('RGBA'), BORDER_SIZE) frames.append(bf) if len(frames) > 1: frames[0].save(OUTPUT_DIR / file.name, save_all=True, append_images=frames[1:], optimize=False, duration=duration, loop=loop, transparency=255, disposal=2) else: frames[0].save(OUTPUT_DIR / file.name) これでおおよそのイメージはうまくいきますが、どうやらアニメGIFの読み書き周りはハマりどころが多く、透明色がパレットの255番じゃなかったりして正常に処理できない画像も一部ありました。 5. 置き換えるには? Slackの絵文字は同じ名前で後から差し替えることができないので、削除->追加の手順を取る必要があります。 APIはEnterprise Gridのみ カスタム絵文字の登録・削除に関するAPIは、実は提供自体はされています。しかし、これらはEnterprise Gridプランでのみ使うことができるので、おそらく使えない人が多いのではないかと思います。 非公開API or 管理画面からなんとかする 公式APIが使えない場合、管理画面から頑張って登録するか、管理画面で呼んでいるAPIを叩いてあげるしかなさそうです。 非公開APIのため、Qiitaでは触れませんが、一括処理できるスクリプトをリポジトリ内に置いたので、そちらをご覧ください。 ちなみに、一括登録のツールとしてはNeutral Face Emoji Toolsが有名ですが、大量の絵文字を登録しようとするとすぐレートリミットに引っかかるのでご注意ください。 まとめ 今回行った画像処理はごくごく簡単なものですが、意外とアニメGIFの処理やSlack側との出し入れに戸惑いました。 このツールで皆さんも快適にダークモードライフをお過ごしください👍
セクション区切り
セクション区切り

Sponsors

CAMPHOR- は、協賛企業・運営企業・個人のご協力によって活動を行っています。
また、私達の活動をご支援いただける企業を随時募集しております。

協賛企業
株式会社ディー・エヌ・エー

株式会社ディー・エヌ・エー ロゴ

協賛企業
チームラボ株式会社

チームラボ株式会社 ロゴ

協賛企業
株式会社マイクロアド

株式会社マイクロアド ロゴ

協賛企業
ピクシブ株式会社

ピクシブ株式会社 ロゴ

協賛企業
株式会社 idea spot(イデアスポット)

株式会社 idea spot(イデアスポット) ロゴ

ツールスポンサー
esa

esa ロゴ

運営企業
株式会社Vi-King

株式会社Vi-King ロゴ

セクション区切り

Contact

CAMPHOR- の見学・取材・協賛などのお問い合わせはこちらからお願いします。
企業の方も学生の方もお気軽にお問い合わせください。
もちろん CAMPHOR- HOUSE に直接お越しいただいても構いません。

セクション区切り

Twitter / Facebook