アプリで使うアイコンを探したい
アプリ内で読み込みや保存とかに使うよくあるアイコン画像。
MS様とかがSDKで公開しているものとかは、数百以上ありファイル別のディレクトリに分かれているのですがこれを一個ずつ見ていくのは大変すぎる。
そこで、アイコン一覧を作るスクリプトを作ってみた。
使い方
- 以下のコマンドを実行
python icon_list.py /path/to/icon/dir
ブラウザで出来る事
- 閲覧している画像サイズをスライダで調整
- 画像ファイル名でフィルタ(ありそうなファイル名を入れる。保存用アイコンだったらsave等)
- 画像をクリックすると、クリップボードにその画像のファイルパスがコピーされる
一度icons.htmlを作ってしまえば、それ以降はブラウザで開くだけでお手軽です。
ファイル構成
場所は何処でも良いので、icon_list.pyとtemplate.htmlを同じディレクトリに置く
配置イメージ
./icon_list.py
./template.html
icon_list.py
import os
from pathlib import Path
import glob
import sys
def create_image_gallery_html(directory_path, output_file):
"""
画像の一覧のhtmlを作成する
:param directory_path: 画像のあるディレクトリパス
:param output_file: 出力ファイル名(*.html)
"""
# PNG画像ファイルを検索
png_files = glob.glob(os.path.join(directory_path, "**/*.png"), recursive=True)
# ギャラリーアイテムのHTML生成
gallery_items = ""
for image_path in png_files:
relative_path = os.path.relpath(image_path, directory_path)
filename = os.path.basename(image_path)
gallery_items += f"""
<div class="item">
<div class="image">
<img src="{relative_path}" alt="{filename}" title="{relative_path}" loading="lazy">
</div>
<div class="caption">{filename}</div>
</div>
"""
# 最終的なHTMLの生成
# HTMLテンプレートファイルを読み込んで全内容を取得
with open("template.html", "r", encoding="utf-8") as file:
html_template = file.read() # ファイル全体を文字列として読み込む
html_content = html_template.replace("{0}", gallery_items)
# HTMLファイルの保存
output_path = os.path.join(directory_path, output_file)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(html_content)
print(f"Gallery has been created at: {output_path}")
return output_path
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python script.py <directory>")
sys.exit(1)
directory = sys.argv[1]
output_html_file = 'icons.html'
create_image_gallery_html(directory, output_html_file)
template.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Gallery</title>
<style>
body {
margin: 0;
padding: 20px;
font-family: Arial, sans-serif;
}
.slider {
position: fixed;
top: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.9);
padding: 10px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
width: 200px;
}
.gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 20px;
padding-top: 150px;
}
.item {
width: 100%;
background: #f5f5f5;
padding: 10px;
box-sizing: border-box;
border-radius: 5px;
display: flex;
flex-direction: column;
cursor: pointer;
transition: background-color 0.2s;
}
.item:hover {
background: #e0e0e0;
}
.item.copied {
background: #d4f7d4;
}
.image {
position: relative;
width: 100%;
padding-top: 75%; /* 4:3 aspect ratio */
overflow: hidden;
}
.item img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: contain;
object-position: center;
}
.caption {
margin-top: 5px;
font-size: 0.9em;
text-align: center;
word-break: break-all;
}
.filter {
width: 100%;
padding: 5px;
margin-top: 10px;
border: 1px solid #ccc;
border-radius: 3px;
}
.hidden {
display: none;
}
.copy-message {
position: fixed;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 10px 20px;
border-radius: 4px;
opacity: 0;
transition: opacity 0.3s;
z-index: 1001;
}
.copy-message.show {
opacity: 1;
}
</style>
</head>
<body>
<div class="slider">
<label for="size-slider">画像サイズ調整:</label><br>
<input type="range" id="size-slider" min="100" max="500" value="200">
<br>
<label for="filter-input">画像フィルター:</label><br>
<input type="text" id="filter-input" class="filter-input" placeholder="画像名を入力...">
</div>
<div class="gallery" id="image-gallery">
{0}
</div>
<div class="copy-message" id="copy-message">URLをコピーしました</div>
<script>
const slider = document.getElementById('size-slider');
const gallery = document.getElementById('image-gallery');
const filterInput = document.getElementById('filter-input');
const copyMessage = document.getElementById('copy-message');
slider.addEventListener('input', function () {
const value = this.value;
gallery.style.gridTemplateColumns = `repeat(auto-fill, minmax(${value}px, 1fr))`;
});
// フィルター機能の実装
filterInput.addEventListener('input', function () {
const filterValue = this.value.toLowerCase();
const galleryItems = document.querySelectorAll('.item');
galleryItems.forEach(item => {
const img = item.querySelector('img');
const altText = img.getAttribute('alt').toLowerCase();
if (altText.includes(filterValue)) {
item.classList.remove('hidden');
} else {
item.classList.add('hidden');
}
});
});
// クリップボードコピー機能
function setupCopyFunction() {
const items = document.querySelectorAll('.item');
items.forEach(item => {
item.addEventListener('click', function() {
const img = this.querySelector('img');
const imgSrc = img.getAttribute('src');
// クリップボードにコピー
navigator.clipboard.writeText(imgSrc)
.then(() => {
// コピー成功時の視覚的フィードバック
this.classList.add('copied');
setTimeout(() => {
this.classList.remove('copied');
}, 1000);
// コピーメッセージを表示
copyMessage.textContent = `${imgSrc} をコピーしました`;
copyMessage.classList.add('show');
setTimeout(() => {
copyMessage.classList.remove('show');
}, 2000);
})
.catch(err => {
console.error('クリップボードへのコピーに失敗しました:', err);
alert('クリップボードへのコピーに失敗しました。');
});
});
});
}
// 初期設定
setupCopyFunction();
function addNewGalleryItem(imageSrc, altText) {
const newItem = document.createElement('div');
newItem.className = 'item';
newItem.innerHTML = `
<div class="image">
<img src="${imageSrc}" alt="${altText}" title="${imageSrc}" loading="lazy">
</div>
<div class="caption">${altText}</div>
`;
gallery.appendChild(newItem);
setupCopyFunction();
}
</script>
</body>
</html>