Skip to content

Instantly share code, notes, and snippets.

@setanarut
Created February 27, 2026 04:46
Show Gist options
  • Select an option

  • Save setanarut/7129a3839e5c096d42686d664dc68342 to your computer and use it in GitHub Desktop.

Select an option

Save setanarut/7129a3839e5c096d42686d664dc68342 to your computer and use it in GitHub Desktop.
Krita Halftone script
from krita import Krita
import array, math, time
# ─── AYARLAR ──────────────────────────────────────────────────
WAVE_COUNT = 24
TOTAL_FRAMES = 10
WAVEFORM = "sawtooth" # "triangle" | "sawtooth" | "sine"
REVERSE = False
FPS = 10
SRC_LAYER = "dem" # kaynak katman adı
ANIM_LAYER = "anim" # hedef animasyon katmanı adı
# ──────────────────────────────────────────────────────────────
app = Krita.instance()
doc = app.activeDocument()
w, h = doc.width(), doc.height()
depth = doc.colorDepth()
model = doc.colorModel()
MAX_VAL = 65535 if depth == "U16" else 255
fmt = "H" if depth == "U16" else "B"
WAVE_SPACING = MAX_VAL / WAVE_COUNT
CH_COUNT = {"GRAYA": 2, "RGBA": 4, "CMYKA": 5}.get(model, 4)
CHANNEL_IDX = {"GRAYA": 0, "RGBA": 2, "CMYKA": 0}.get(model, 0)
ALPHA_IDX = {"GRAYA": 1, "RGBA": 3, "CMYKA": 4}.get(model, CH_COUNT - 1)
print(f"Model: {model}, Derinlik: {depth}, Kanal: {CH_COUNT}")
# ─── KATMAN BUL ───────────────────────────────────────────────
def find_layer(name, node=None):
if node is None:
node = doc.rootNode()
for child in node.childNodes():
if child.name() == name:
return child
found = find_layer(name, child)
if found:
return found
return None
anim_layer = find_layer(ANIM_LAYER)
src_layer = find_layer(SRC_LAYER)
if anim_layer is None:
print(f"HATA: '{ANIM_LAYER}' katmanı bulunamadı.")
raise SystemExit
if src_layer is None:
print(f"HATA: '{SRC_LAYER}' katmanı bulunamadı.")
raise SystemExit
print(f"Anim: '{anim_layer.name()}', Kaynak: '{src_layer.name()}'")
# ─── KAYNAK OKU ───────────────────────────────────────────────
raw = src_layer.pixelData(0, 0, w, h)
vals = array.array(fmt)
vals.frombytes(raw)
print(f"Kaynak sıfırdan farklı: {sum(1 for v in vals if v != 0)}")
# ─── KEYFRAME TESPİT ──────────────────────────────────────────
keyframes = [i for i in range(TOTAL_FRAMES) if anim_layer.hasKeyframeAtTime(i)]
print(f"Bulunan keyframe'ler: {keyframes}")
if not keyframes:
print(f"HATA: '{ANIM_LAYER}' katmanında hiç keyframe yok.")
raise SystemExit
if len(keyframes) != TOTAL_FRAMES:
print(f"UYARI: {TOTAL_FRAMES} beklendi, {len(keyframes)} bulundu.")
# ─── ZAMAN ADIMLARI ───────────────────────────────────────────
n = len(keyframes)
step = 1.0 / n
frames_t = [i * step for i in range(n)]
if REVERSE:
frames_t = list(reversed(frames_t))
# ─── ALGORİTMA ────────────────────────────────────────────────
def fract(x):
return x - math.floor(x)
def wave(frac):
if WAVEFORM == "triangle":
return 1.0 - abs(2.0 * frac - 1.0)
elif WAVEFORM == "sawtooth":
return frac
elif WAVEFORM == "sine":
return 0.5 + 0.5 * math.sin(frac * 2 * math.pi)
return frac
def get_frame(vals, t):
out = array.array(fmt, [0] * (w * h * CH_COUNT))
for i in range(w * h):
v = vals[i * CH_COUNT + CHANNEL_IDX]
frac = fract(v / WAVE_SPACING + t)
val = round(wave(frac) * MAX_VAL)
base = i * CH_COUNT
for ch in range(CH_COUNT):
out[base + ch] = MAX_VAL if ch == ALPHA_IDX else val
return out.tobytes()
# ─── KARE KARE YAZ ────────────────────────────────────────────
doc.setFramesPerSecond(FPS)
doc.setFullClipRangeEndTime(TOTAL_FRAMES - 1)
doc.setPlayBackRange(0, TOTAL_FRAMES - 1)
total_start = time.time()
for idx, frame_num in enumerate(keyframes):
now = time.time()
t = frames_t[idx]
doc.setCurrentTime(frame_num)
doc.waitForDone()
anim_layer.setPixelData(get_frame(vals, t), 0, 0, w, h)
doc.waitForDone()
print(f"[{idx+1}/{n}] frame:{frame_num} t={t:.3f} {time.time()-now:.1f}s")
doc.setCurrentTime(0)
doc.refreshProjection()
print(f"\nToplam: {time.time()-total_start:.1f}s")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment