File size: 5,417 Bytes
d03debd e5648d6 d03debd aa112fe d03debd 570e9e3 d03debd e5648d6 d03debd e5648d6 d03debd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | import gradio as gr
from PIL import Image
# ─── Доступные размеры для даунскейла ───
SIZES = ["8×8", "16×16", "32×32", "64×64", "128×128"]
def parse_size(label: str) -> tuple[int, int]:
"""'16×16' → (16, 16)"""
w, h = label.split("×")
return int(w), int(h)
def downscale(
image: Image.Image,
target_size: str,
preview_scale: int,
) -> tuple[Image.Image, Image.Image, str]:
"""
1) Даунскейлит входное изображение до target_size методом NEAREST.
2) Апскейлит результат обратно (preview) чтобы пиксели были видны.
Возвращает (маленькое, превью, инфо-строку).
"""
if image is None:
raise gr.Error("Загрузи изображение!")
# Принудительно RGBA (текстуры Minecraft часто с альфой)
image = image.convert("RGBA")
tw, th = parse_size(target_size)
# ── Nearest-Neighbor даунскейл ──
small = image.resize((tw, th), resample=Image.NEAREST)
# ── Превью: масштабируем обратно, чтобы пиксели были чётко видны ──
preview_w = tw * preview_scale
preview_h = th * preview_scale
preview = small.resize((preview_w, preview_h), resample=Image.NEAREST)
info = (
f"Оригинал: {image.size[0]}×{image.size[1]}\n"
f"Результат: {tw}×{th}\n"
f"Превью: {preview_w}×{preview_h} (×{preview_scale})"
)
print(info)
return small, preview, info
# ─── Интерфейс ───────────────────────────────────────────────
with gr.Blocks(
title="Minecraft Texture Downscaler",
theme=gr.themes.Soft(),
css="""
/* чёткие пиксели при зуме в браузере */
.pixelated img {
image-rendering: pixelated !important;
image-rendering: -moz-crisp-edges !important;
image-rendering: crisp-edges !important;
}
""",
) as demo:
gr.Markdown(
"""
# 🟩 Minecraft Texture Downscaler
Загрузи текстуру любого размера — получи чёткий **Nearest Neighbor**
даунскейл без размытия (без bilinear / bicubic).
> Идеально для конвертации HD-текстур (128×, 256×, 512×)
> в ванильный формат 16×16.
"""
)
with gr.Row():
# ── Левая колонка: входные параметры ──
with gr.Column(scale=1):
img_input = gr.Image(
label="📥 Входная текстура",
type="pil",
image_mode="RGBA",
sources=["upload", "clipboard"],
)
target_size = gr.Dropdown(
label="🎯 Целевой размер",
choices=SIZES,
value="16×16",
)
preview_scale = gr.Slider(
label="🔍 Множитель превью",
minimum=1,
maximum=32,
step=1,
value=16,
info="Во сколько раз увеличить для наглядности",
)
btn = gr.Button("⚡ Даунскейлить", variant="primary", size="lg")
# ── Правая колонка: результаты ──
with gr.Column(scale=2):
with gr.Row(equal_height=True):
img_small = gr.Image(
label="📤 Результат (реальный размер)",
type="pil",
image_mode="RGBA",
format="png",
show_download_button=True,
elem_classes=["pixelated"],
)
img_preview = gr.Image(
label="🔎 Превью (увеличенное)",
type="pil",
image_mode="RGBA",
format="png",
elem_classes=["pixelated"],
)
info_box = gr.Textbox(
label="ℹ️ Информация",
interactive=False,
lines=3,
)
# ── Обработчик ──
btn.click(
fn=downscale,
inputs=[img_input, target_size, preview_scale],
outputs=[img_small, img_preview, info_box],
)
gr.Markdown(
"""
---
### Как использовать
1. Загрузи PNG-текстуру (например `diamond_ore.png` 128×128).
2. Выбери целевой размер — по умолчанию **16×16**.
3. Нажми **⚡ Даунскейлить**.
4. Скачай результат (кнопка ⬇️ на картинке).
**Nearest Neighbor** сохраняет резкие границы пикселей —
никакого мыла, как при Bilinear/Lanczos.
"""
)
# Запуск
if __name__ == "__main__":
demo.launch() |