Rework unit animations as frame-by-frame sheets
@@ -19,6 +19,21 @@ SOURCE_ATLAS = ROOT / "src" / "assets" / "images" / "unit-sources" / "three-king
|
||||
|
||||
DIRECTIONS = ("south", "east", "north", "west")
|
||||
ACTION_ORDER = ("attack", "strategy", "item", "hurt", "celebrate")
|
||||
IDLE_FRAME_COUNT = 8
|
||||
MOVE_FRAME_COUNT = 8
|
||||
BASE_FRAMES_PER_DIRECTION = IDLE_FRAME_COUNT + MOVE_FRAME_COUNT
|
||||
ACTION_FRAME_COUNTS = {
|
||||
"attack": 10,
|
||||
"strategy": 8,
|
||||
"item": 8,
|
||||
"hurt": 4,
|
||||
"celebrate": 6,
|
||||
}
|
||||
ACTION_FRAME_OFFSETS = {
|
||||
action: sum(ACTION_FRAME_COUNTS[previous] for previous in ACTION_ORDER[:index])
|
||||
for index, action in enumerate(ACTION_ORDER)
|
||||
}
|
||||
ACTION_FRAMES_PER_DIRECTION = sum(ACTION_FRAME_COUNTS.values())
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -65,11 +80,11 @@ TEMPLATES: dict[str, Template] = {
|
||||
}
|
||||
|
||||
ROLE_SPECS: dict[str, RoleSpec] = {
|
||||
"infantry": RoleSpec(286, 274, 4, (1.0, 0.985, 1.015, 1.0), (1.0, 1.018, 0.992, 1.01), (0, 0, 0, 0)),
|
||||
"polearm": RoleSpec(292, 282, 4, (1.0, 0.986, 1.014, 1.0), (1.0, 1.018, 0.992, 1.01), (0, 0, 0, 0)),
|
||||
"cavalry": RoleSpec(292, 304, 3, (1.0, 1.012, 0.988, 1.008), (1.0, 1.014, 0.99, 1.008), (0, 1, 0, -1)),
|
||||
"strategist": RoleSpec(276, 250, 5, (1.0, 0.988, 1.012, 1.0), (1.0, 1.018, 0.994, 1.01), (0, 0, 0, 0)),
|
||||
"archer": RoleSpec(282, 276, 4, (1.0, 0.986, 1.012, 1.0), (1.0, 1.016, 0.992, 1.01), (0, 0, 0, 0)),
|
||||
"infantry": RoleSpec(286, 274, 4, (1.0, 0.992, 0.986, 0.996, 1.008, 1.015, 1.006, 1.0), (1.0, 1.012, 1.02, 1.012, 0.998, 0.99, 0.997, 1.0), (0, 0, -1, 0, 0, 1, 0, 0)),
|
||||
"polearm": RoleSpec(292, 282, 4, (1.0, 0.992, 0.986, 0.996, 1.008, 1.014, 1.006, 1.0), (1.0, 1.012, 1.02, 1.012, 0.998, 0.99, 0.997, 1.0), (0, 0, -1, 0, 0, 1, 0, 0)),
|
||||
"cavalry": RoleSpec(292, 304, 3, (1.0, 1.008, 1.014, 1.006, 0.996, 0.988, 0.996, 1.0), (1.0, 1.01, 1.016, 1.008, 0.998, 0.99, 0.998, 1.0), (0, 1, 1, 0, 0, -1, -1, 0)),
|
||||
"strategist": RoleSpec(276, 250, 5, (1.0, 0.993, 0.988, 0.997, 1.006, 1.012, 1.005, 1.0), (1.0, 1.012, 1.019, 1.012, 0.998, 0.994, 0.998, 1.0), (0, 0, -1, 0, 0, 1, 0, 0)),
|
||||
"archer": RoleSpec(282, 276, 4, (1.0, 0.993, 0.987, 0.996, 1.006, 1.012, 1.004, 1.0), (1.0, 1.011, 1.018, 1.01, 0.998, 0.992, 0.998, 1.0), (0, 0, -1, 0, 0, 1, 0, 0)),
|
||||
}
|
||||
|
||||
SIGNATURE_PLANS: dict[str, UnitPlan] = {
|
||||
@@ -209,12 +224,16 @@ def despill_key_edges(image: Image.Image) -> Image.Image:
|
||||
|
||||
|
||||
def draw_base_sheet(source: Image.Image, template: Template, stem: str, plan: UnitPlan) -> Image.Image:
|
||||
sheet = Image.new("RGBA", (FRAME_SIZE * GRID_SIZE, FRAME_SIZE * GRID_SIZE), (0, 0, 0, 0))
|
||||
sheet = Image.new("RGBA", (FRAME_SIZE * BASE_FRAMES_PER_DIRECTION, FRAME_SIZE * len(DIRECTIONS)), (0, 0, 0, 0))
|
||||
fitted = fit_sprite(source, template, plan)
|
||||
for row, direction in enumerate(DIRECTIONS):
|
||||
directed = orient_sprite(fitted, direction)
|
||||
for col in range(GRID_SIZE):
|
||||
frame = frame_variant(directed, template, stem, direction, col)
|
||||
for col in range(IDLE_FRAME_COUNT):
|
||||
frame = frame_variant(directed, template, stem, direction, "idle", col)
|
||||
sheet.alpha_composite(frame, (col * FRAME_SIZE, row * FRAME_SIZE))
|
||||
for frame_index in range(MOVE_FRAME_COUNT):
|
||||
col = IDLE_FRAME_COUNT + frame_index
|
||||
frame = frame_variant(directed, template, stem, direction, "move", frame_index)
|
||||
sheet.alpha_composite(frame, (col * FRAME_SIZE, row * FRAME_SIZE))
|
||||
return sheet
|
||||
|
||||
@@ -245,12 +264,16 @@ def orient_sprite(sprite: Image.Image, direction: str) -> Image.Image:
|
||||
return sprite
|
||||
|
||||
|
||||
def frame_variant(sprite: Image.Image, template: Template, stem: str, direction: str, frame_index: int) -> Image.Image:
|
||||
def frame_variant(sprite: Image.Image, template: Template, stem: str, direction: str, pose: str, frame_index: int) -> Image.Image:
|
||||
canvas = Image.new("RGBA", (FRAME_SIZE, FRAME_SIZE), (0, 0, 0, 0))
|
||||
seed = stable_int(f"{stem}:{direction}")
|
||||
spec = ROLE_SPECS[template.role]
|
||||
frame = idle_pose(sprite, spec, frame_index)
|
||||
dx = spec.idle_dx[frame_index]
|
||||
if pose == "move":
|
||||
frame = move_pose(sprite, spec, template.role, direction, frame_index)
|
||||
dx = move_body_dx(template.role, direction, frame_index)
|
||||
else:
|
||||
frame = idle_pose(sprite, spec, direction, frame_index)
|
||||
dx = spec.idle_dx[frame_index % len(spec.idle_dx)]
|
||||
if direction == "west":
|
||||
dx = -dx
|
||||
if direction == "north":
|
||||
@@ -260,52 +283,153 @@ def frame_variant(sprite: Image.Image, template: Template, stem: str, direction:
|
||||
left = round((FRAME_SIZE - frame.width) / 2 + dx)
|
||||
top = round(bottom - frame.height)
|
||||
canvas.alpha_composite(frame, (left, top))
|
||||
if pose == "move":
|
||||
draw_step_contact(canvas, template.role, direction, frame_index)
|
||||
return finish_frame(canvas)
|
||||
|
||||
|
||||
def idle_pose(sprite: Image.Image, spec: RoleSpec, frame_index: int) -> Image.Image:
|
||||
sx = spec.idle_scale_x[frame_index]
|
||||
sy = spec.idle_scale_y[frame_index]
|
||||
def idle_pose(sprite: Image.Image, spec: RoleSpec, direction: str, frame_index: int) -> Image.Image:
|
||||
index = frame_index % IDLE_FRAME_COUNT
|
||||
sx = spec.idle_scale_x[index]
|
||||
sy = spec.idle_scale_y[index]
|
||||
width = max(1, round(sprite.width * sx))
|
||||
height = max(1, round(sprite.height * sy))
|
||||
return sprite.resize((width, height), Image.Resampling.LANCZOS)
|
||||
resized = sprite.resize((width, height), Image.Resampling.LANCZOS)
|
||||
sway = 1.2 if direction in ("south", "north") else 1.8
|
||||
return row_wave(resized, sway, index / IDLE_FRAME_COUNT * math.tau, upper_bias=0.88)
|
||||
|
||||
|
||||
def move_pose(sprite: Image.Image, spec: RoleSpec, role: str, direction: str, frame_index: int) -> Image.Image:
|
||||
index = frame_index % MOVE_FRAME_COUNT
|
||||
phase = index / MOVE_FRAME_COUNT * math.tau
|
||||
stride = math.sin(phase)
|
||||
contact = abs(math.cos(phase))
|
||||
mounted = role == "cavalry"
|
||||
sx = 1.0 + (0.025 if mounted else 0.018) * math.cos(phase)
|
||||
sy = 1.0 + (0.018 if mounted else 0.012) * contact
|
||||
width = max(1, round(sprite.width * sx))
|
||||
height = max(1, round(sprite.height * sy))
|
||||
resized = sprite.resize((width, height), Image.Resampling.LANCZOS)
|
||||
upper, lower = split_subject(resized, 0.58 if mounted else 0.62)
|
||||
upper_shift = round(stride * (3 if mounted else 2))
|
||||
lower_shift = -round(stride * (5 if mounted else 4))
|
||||
if direction == "west":
|
||||
upper_shift = -upper_shift
|
||||
lower_shift = -lower_shift
|
||||
if direction == "north":
|
||||
upper_shift = round(upper_shift * 0.5)
|
||||
lower_shift = round(lower_shift * 0.5)
|
||||
composed = Image.new("RGBA", (resized.width + 16, resized.height), (0, 0, 0, 0))
|
||||
composed.alpha_composite(upper, (8 + upper_shift, 0))
|
||||
composed.alpha_composite(row_wave(lower, 2.6 if mounted else 2.0, phase + math.pi, upper_bias=0.4), (8 + lower_shift, upper.height))
|
||||
return row_wave(composed, 3.4 if mounted else 2.4, phase, upper_bias=0.7)
|
||||
|
||||
|
||||
def split_subject(sprite: Image.Image, split_ratio: float) -> tuple[Image.Image, Image.Image]:
|
||||
split_y = max(1, min(sprite.height - 1, round(sprite.height * split_ratio)))
|
||||
return sprite.crop((0, 0, sprite.width, split_y)), sprite.crop((0, split_y, sprite.width, sprite.height))
|
||||
|
||||
|
||||
def row_wave(sprite: Image.Image, amplitude: float, phase: float, upper_bias: float) -> Image.Image:
|
||||
if amplitude <= 0:
|
||||
return sprite
|
||||
padding = math.ceil(abs(amplitude)) + 3
|
||||
output = Image.new("RGBA", (sprite.width + padding * 2, sprite.height), (0, 0, 0, 0))
|
||||
denominator = max(1, sprite.height - 1)
|
||||
for y in range(sprite.height):
|
||||
vertical = y / denominator
|
||||
weight = (1 - vertical) * upper_bias + vertical * (1 - upper_bias)
|
||||
dx = round(math.sin(phase + vertical * math.pi * 1.6) * amplitude * weight)
|
||||
output.alpha_composite(sprite.crop((0, y, sprite.width, y + 1)), (padding + dx, y))
|
||||
bbox = output.getbbox()
|
||||
return output.crop(bbox) if bbox else output
|
||||
|
||||
|
||||
def wave_frame_subject(frame: Image.Image, amplitude: float, phase: float, upper_bias: float) -> Image.Image:
|
||||
bbox = frame.getbbox()
|
||||
if not bbox:
|
||||
return frame
|
||||
subject = frame.crop(bbox)
|
||||
waved = row_wave(subject, amplitude, phase, upper_bias)
|
||||
canvas = Image.new("RGBA", frame.size, (0, 0, 0, 0))
|
||||
left = bbox[0] - max(0, (waved.width - subject.width) // 2)
|
||||
top = bbox[3] - waved.height
|
||||
canvas.alpha_composite(waved, (left, top))
|
||||
return canvas
|
||||
|
||||
|
||||
def move_body_dx(role: str, direction: str, frame_index: int) -> int:
|
||||
if direction in ("north", "south"):
|
||||
return 0
|
||||
mounted = role == "cavalry"
|
||||
stride = math.sin(frame_index / MOVE_FRAME_COUNT * math.tau)
|
||||
return round(stride * (4 if mounted else 3))
|
||||
|
||||
|
||||
def draw_step_contact(canvas: Image.Image, role: str, direction: str, frame_index: int) -> None:
|
||||
draw = ImageDraw.Draw(canvas)
|
||||
phase = frame_index / MOVE_FRAME_COUNT * math.tau
|
||||
contact = abs(math.cos(phase))
|
||||
if contact < 0.42:
|
||||
return
|
||||
y = FRAME_SIZE - 7
|
||||
center = FRAME_SIZE // 2
|
||||
mounted = role == "cavalry"
|
||||
spread = 46 if mounted else 28
|
||||
alpha = round(54 + contact * 52)
|
||||
color = (54, 45, 34, alpha)
|
||||
if direction in ("east", "west"):
|
||||
draw.ellipse((center - spread, y - 5, center - spread + 26, y + 2), fill=color)
|
||||
draw.ellipse((center + spread - 26, y - 4, center + spread, y + 2), fill=color)
|
||||
else:
|
||||
draw.ellipse((center - spread // 2, y - 5, center + spread // 2, y + 2), fill=color)
|
||||
|
||||
|
||||
def draw_action_sheet(base_sheet: Image.Image, template: Template, stem: str) -> Image.Image:
|
||||
output = Image.new("RGBA", (FRAME_SIZE * GRID_SIZE * len(ACTION_ORDER), FRAME_SIZE * len(DIRECTIONS)), (0, 0, 0, 0))
|
||||
output = Image.new("RGBA", (FRAME_SIZE * ACTION_FRAMES_PER_DIRECTION, FRAME_SIZE * len(DIRECTIONS)), (0, 0, 0, 0))
|
||||
for row, direction in enumerate(DIRECTIONS):
|
||||
for action_index, action in enumerate(ACTION_ORDER):
|
||||
for frame_index in range(GRID_SIZE):
|
||||
frame = base_sheet.crop((frame_index * FRAME_SIZE, row * FRAME_SIZE, (frame_index + 1) * FRAME_SIZE, (row + 1) * FRAME_SIZE)).convert("RGBA")
|
||||
frame_count = ACTION_FRAME_COUNTS[action]
|
||||
start_col = ACTION_FRAME_OFFSETS[action]
|
||||
for frame_index in range(frame_count):
|
||||
idle_index = min(IDLE_FRAME_COUNT - 1, round(frame_index * (IDLE_FRAME_COUNT - 1) / max(1, frame_count - 1)))
|
||||
frame = base_sheet.crop((idle_index * FRAME_SIZE, row * FRAME_SIZE, (idle_index + 1) * FRAME_SIZE, (row + 1) * FRAME_SIZE)).convert("RGBA")
|
||||
output.alpha_composite(
|
||||
action_frame(frame, template, stem, direction, action, frame_index),
|
||||
((action_index * GRID_SIZE + frame_index) * FRAME_SIZE, row * FRAME_SIZE)
|
||||
action_frame(frame, template, stem, direction, action, frame_index, frame_count),
|
||||
((start_col + frame_index) * FRAME_SIZE, row * FRAME_SIZE)
|
||||
)
|
||||
return output
|
||||
|
||||
|
||||
def action_frame(frame: Image.Image, template: Template, stem: str, direction: str, action: str, frame_index: int) -> Image.Image:
|
||||
def action_frame(frame: Image.Image, template: Template, stem: str, direction: str, action: str, frame_index: int, frame_count: int) -> Image.Image:
|
||||
if action == "hurt":
|
||||
return hurt_frame(frame, direction, frame_index)
|
||||
if action == "celebrate":
|
||||
return celebrate_frame(frame, direction, frame_index)
|
||||
return celebrate_frame(frame, direction, frame_index, frame_count)
|
||||
|
||||
effect = Image.new("RGBA", frame.size, (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(effect)
|
||||
if action == "attack":
|
||||
if frame_index >= 2:
|
||||
draw_attack_effect(draw, template, direction, frame_index)
|
||||
lunge = [0, 5, 13, 7][frame_index] if template.role != "cavalry" else [0, 8, 18, 10][frame_index]
|
||||
lift = [0, -2, -4, -1][frame_index]
|
||||
impact_start = max(3, round(frame_count * 0.42))
|
||||
impact_end = min(frame_count - 1, impact_start + 3)
|
||||
if impact_start <= frame_index <= impact_end:
|
||||
draw_attack_effect(draw, template, direction, frame_index - impact_start + 2)
|
||||
lunge_values = (0, -3, -6, 2, 11, 19, 15, 9, 4, 0)
|
||||
mounted_lunge_values = (0, -4, -8, 4, 16, 26, 20, 12, 5, 0)
|
||||
lift_values = (0, 0, -2, -5, -6, -4, -2, -1, 0, 0)
|
||||
lunge = sequence_value(mounted_lunge_values if template.role == "cavalry" else lunge_values, frame_index, frame_count)
|
||||
lift = sequence_value(lift_values, frame_index, frame_count)
|
||||
dx, dy = direction_offset(direction, lunge)
|
||||
body = offset_subject(frame, dx, dy + lift)
|
||||
body = offset_subject(wave_frame_subject(frame, 3.0 if template.role == "cavalry" else 2.2, frame_index / frame_count * math.tau, 0.82), dx, dy + lift)
|
||||
result = Image.alpha_composite(effect, body)
|
||||
elif action == "strategy":
|
||||
draw_strategy_effect(draw, frame_index)
|
||||
result = Image.alpha_composite(effect, offset_subject(frame, 0, [0, -3, -5, -2][frame_index]))
|
||||
draw_strategy_effect(draw, frame_index, frame_count)
|
||||
lift = sequence_value((0, -2, -5, -7, -5, -3, -1, 0), frame_index, frame_count)
|
||||
result = Image.alpha_composite(effect, offset_subject(frame, 0, lift))
|
||||
else:
|
||||
draw_item_effect(draw, direction, frame_index)
|
||||
result = Image.alpha_composite(offset_subject(frame, 0, [0, -2, -3, -1][frame_index]), effect)
|
||||
draw_item_effect(draw, direction, frame_index, frame_count)
|
||||
lift = sequence_value((0, -1, -3, -5, -4, -2, -1, 0), frame_index, frame_count)
|
||||
result = Image.alpha_composite(offset_subject(frame, 0, lift), effect)
|
||||
return finish_frame(result)
|
||||
|
||||
|
||||
@@ -343,9 +467,9 @@ def draw_attack_effect(draw: ImageDraw.ImageDraw, template: Template, direction:
|
||||
draw.arc(inset, start=start + 4, end=end - 4, fill=bright, width=max(4, width - 10))
|
||||
|
||||
|
||||
def draw_strategy_effect(draw: ImageDraw.ImageDraw, frame_index: int = 0) -> None:
|
||||
def draw_strategy_effect(draw: ImageDraw.ImageDraw, frame_index: int = 0, frame_count: int = 4) -> None:
|
||||
center = (156, 151)
|
||||
pulse = (0, 8, 16, 6)[frame_index]
|
||||
pulse = round((1 - math.cos(frame_index / max(1, frame_count - 1) * math.tau)) * 9)
|
||||
for radius, color, width in ((88 + pulse, (39, 94, 156, 66), 4), (58 + pulse // 2, (46, 142, 174, 106), 4), (28 + pulse // 3, (236, 184, 74, 134), 5)):
|
||||
draw.ellipse((center[0] - radius, center[1] - radius, center[0] + radius, center[1] + radius), outline=color, width=width)
|
||||
for angle in range(0, 360, 60):
|
||||
@@ -354,7 +478,7 @@ def draw_strategy_effect(draw: ImageDraw.ImageDraw, frame_index: int = 0) -> Non
|
||||
draw.polygon([(x, y - 7), (x + 5, y), (x, y + 7), (x - 5, y)], fill=(236, 184, 74, 126))
|
||||
|
||||
|
||||
def draw_item_effect(draw: ImageDraw.ImageDraw, direction: str, frame_index: int = 0) -> None:
|
||||
def draw_item_effect(draw: ImageDraw.ImageDraw, direction: str, frame_index: int = 0, frame_count: int = 4) -> None:
|
||||
positions = {
|
||||
"south": (184, 145),
|
||||
"east": (220, 146),
|
||||
@@ -362,7 +486,7 @@ def draw_item_effect(draw: ImageDraw.ImageDraw, direction: str, frame_index: int
|
||||
"west": (92, 146),
|
||||
}
|
||||
x, y = positions[direction]
|
||||
y += [0, -8, -12, -6][frame_index]
|
||||
y += sequence_value((0, -5, -11, -15, -12, -7, -2, 0), frame_index, frame_count)
|
||||
draw.rounded_rectangle((x - 20, y - 16, x + 20, y + 20), radius=7, fill=(126, 79, 39, 235), outline=(25, 18, 14, 235), width=3)
|
||||
line(draw, [(x - 27, y + 1), (x + 27, y + 1)], (226, 178, 72, 196), 4)
|
||||
draw.ellipse((x - 11, y - 31, x + 11, y - 9), fill=(76, 178, 112, 200), outline=(24, 18, 14, 220), width=2)
|
||||
@@ -389,9 +513,9 @@ def hurt_frame(frame: Image.Image, direction: str, frame_index: int = 0) -> Imag
|
||||
return finish_frame(Image.alpha_composite(body, effect))
|
||||
|
||||
|
||||
def celebrate_frame(frame: Image.Image, direction: str, frame_index: int = 0) -> Image.Image:
|
||||
lift = [0, -8, -3, -11][frame_index]
|
||||
sway = [0, -2, 2, 0][frame_index]
|
||||
def celebrate_frame(frame: Image.Image, direction: str, frame_index: int = 0, frame_count: int = 4) -> Image.Image:
|
||||
lift = sequence_value((0, -6, -11, -5, -9, 0), frame_index, frame_count)
|
||||
sway = sequence_value((0, -2, 1, 3, -1, 0), frame_index, frame_count)
|
||||
if direction == "west":
|
||||
sway = -sway
|
||||
body = offset_subject(frame, sway, lift)
|
||||
@@ -399,7 +523,7 @@ def celebrate_frame(frame: Image.Image, direction: str, frame_index: int = 0) ->
|
||||
draw = ImageDraw.Draw(effect)
|
||||
cx = 156 + sway
|
||||
cy = 92 + lift
|
||||
if frame_index in (1, 3):
|
||||
if frame_index in (1, 2, 4):
|
||||
draw.ellipse((cx - 42, cy - 26, cx + 42, cy + 58), outline=(255, 220, 114, 118), width=5)
|
||||
for angle in range(20, 360, 72):
|
||||
x = cx + math.cos(math.radians(angle)) * 54
|
||||
@@ -408,6 +532,16 @@ def celebrate_frame(frame: Image.Image, direction: str, frame_index: int = 0) ->
|
||||
return finish_frame(Image.alpha_composite(body, effect))
|
||||
|
||||
|
||||
def sequence_value(values: tuple[int, ...], frame_index: int, frame_count: int) -> int:
|
||||
if frame_count <= 1 or len(values) <= 1:
|
||||
return values[0]
|
||||
position = frame_index * (len(values) - 1) / max(1, frame_count - 1)
|
||||
left = math.floor(position)
|
||||
right = min(len(values) - 1, left + 1)
|
||||
mix = position - left
|
||||
return round(values[left] * (1 - mix) + values[right] * mix)
|
||||
|
||||
|
||||
def unit_plan(stem: str) -> UnitPlan:
|
||||
if stem in SIGNATURE_PLANS:
|
||||
return SIGNATURE_PLANS[stem]
|
||||
|
||||
|
Before Width: | Height: | Size: 942 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 336 KiB After Width: | Height: | Size: 880 KiB |
|
Before Width: | Height: | Size: 820 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 286 KiB After Width: | Height: | Size: 658 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 966 KiB |
|
Before Width: | Height: | Size: 948 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 860 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 966 KiB |
|
Before Width: | Height: | Size: 907 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 319 KiB After Width: | Height: | Size: 712 KiB |
|
Before Width: | Height: | Size: 953 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 334 KiB After Width: | Height: | Size: 864 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 966 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 384 KiB After Width: | Height: | Size: 969 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 400 KiB After Width: | Height: | Size: 955 KiB |
|
Before Width: | Height: | Size: 993 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 354 KiB After Width: | Height: | Size: 889 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 442 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 441 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 820 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 286 KiB After Width: | Height: | Size: 658 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 407 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 966 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 966 KiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 966 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 406 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 405 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 406 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 406 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 406 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 406 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 818 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 285 KiB After Width: | Height: | Size: 656 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 879 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 879 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 307 KiB After Width: | Height: | Size: 688 KiB |
|
Before Width: | Height: | Size: 878 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 307 KiB After Width: | Height: | Size: 687 KiB |
|
Before Width: | Height: | Size: 307 KiB After Width: | Height: | Size: 688 KiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 2.0 MiB |
|
Before Width: | Height: | Size: 462 KiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 462 KiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 383 KiB After Width: | Height: | Size: 970 KiB |
|
Before Width: | Height: | Size: 383 KiB After Width: | Height: | Size: 972 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 383 KiB After Width: | Height: | Size: 971 KiB |
|
Before Width: | Height: | Size: 383 KiB After Width: | Height: | Size: 972 KiB |
|
Before Width: | Height: | Size: 888 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 888 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 310 KiB After Width: | Height: | Size: 695 KiB |
|
Before Width: | Height: | Size: 888 KiB After Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 310 KiB After Width: | Height: | Size: 694 KiB |
|
Before Width: | Height: | Size: 310 KiB After Width: | Height: | Size: 695 KiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 436 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 438 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 436 KiB After Width: | Height: | Size: 1.0 MiB |
|
Before Width: | Height: | Size: 945 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 945 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 858 KiB |
|
Before Width: | Height: | Size: 946 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 858 KiB |
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 858 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 966 KiB |
|
Before Width: | Height: | Size: 1.0 MiB After Width: | Height: | Size: 1.7 MiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 966 KiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 966 KiB |
|
Before Width: | Height: | Size: 946 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 946 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 858 KiB |
|
Before Width: | Height: | Size: 944 KiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 332 KiB After Width: | Height: | Size: 855 KiB |
|
Before Width: | Height: | Size: 333 KiB After Width: | Height: | Size: 858 KiB |
|
Before Width: | Height: | Size: 820 KiB After Width: | Height: | Size: 1.3 MiB |