kazakhstan/create_pptx.py

344 lines
17 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""Презентация о Казахстане — чистый PPTX без кривых XML-анимаций."""
from pptx import Presentation
from pptx.util import Inches, Pt, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from pptx.oxml.ns import qn
import lxml.etree as etree
# ── Colors ──
INK = RGBColor(0x0F, 0x12, 0x18)
CYAN = RGBColor(0x00, 0xE5, 0xFF)
GOLD = RGBColor(0xE8, 0xB7, 0x30)
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
GRAY = RGBColor(0x5B, 0x65, 0x73)
BG_DARK = RGBColor(0x14, 0x1C, 0x28)
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
W = prs.slide_width
H = prs.slide_height
BLANK_LAYOUT = prs.slide_layouts[6]
def set_slide_transition(slide, transition_type='push', speed='med', advance_ms=None):
"""Set slide transition effect."""
timing = slide._element.find(qn('p:transition'))
if timing is None:
timing = etree.SubElement(slide._element, qn('p:transition'))
transitions = {
'push': ('push', {'advClick': '1'}),
'fade': ('fade', {'advClick': '1'}),
'wipe': ('wipe', {'dir': 'd', 'advClick': '1'}),
'cover': ('cover', {'dir': 'l', 'advClick': '1'}),
'cut': ('cut', {'advClick': '1'}),
'dissolve': ('dissolve', {'advClick': '1'}),
'zoom': ('zoom', {'advClick': '1'}),
}
tag_name, attrs = transitions.get(transition_type, transitions['push'])
el = etree.SubElement(timing, qn(f'p:{tag_name}'))
for k, v in attrs.items():
el.set(k, v)
if advance_ms:
timing.set('advTm', str(advance_ms))
def add_bg(slide, color):
bg = slide.background
fill = bg.fill
fill.solid()
fill.fore_color.rgb = color
def add_text(slide, text, left, top, width, height,
font_size=24, bold=False, color=INK, align=PP_ALIGN.LEFT,
font_name='Calibri'):
txBox = slide.shapes.add_textbox(left, top, width, height)
tf = txBox.text_frame
tf.word_wrap = True
p = tf.paragraphs[0]
p.text = text
p.font.size = Pt(font_size)
p.font.bold = bold
p.font.color.rgb = color
p.font.name = font_name
p.alignment = align
return txBox
def add_box(slide, left, top, width, height, fill_color=BG_DARK,
border_color=None):
shape = slide.shapes.add_shape(
MSO_SHAPE.ROUNDED_RECTANGLE, left, top, width, height
)
shape.fill.solid()
shape.fill.fore_color.rgb = fill_color
if border_color:
shape.line.color.rgb = border_color
shape.line.width = Pt(2)
else:
shape.line.fill.background()
return shape
def add_circle(slide, left, top, size, color):
c = slide.shapes.add_shape(MSO_SHAPE.OVAL, left, top, size, size)
c.fill.solid()
c.fill.fore_color.rgb = color
c.line.fill.background()
return c
def add_rect(slide, left, top, width, height, color):
r = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, height)
r.fill.solid()
r.fill.fore_color.rgb = color
r.line.fill.background()
return r
# ══════════════════════════════════════════════════════════════
# SLIDE 1 — Title
# ══════════════════════════════════════════════════════════════
s = prs.slides.add_slide(BLANK_LAYOUT)
add_bg(s, BG_DARK)
set_slide_transition(s, 'zoom')
add_circle(s, Inches(9.5), Inches(0.8), Inches(4.5), RGBColor(0x00, 0x3D, 0x5C))
add_circle(s, Inches(10.2), Inches(1.5), Inches(3), CYAN)
add_circle(s, Inches(-0.5), Inches(5.5), Inches(3), RGBColor(0x00, 0x3D, 0x5C))
add_circle(s, Inches(0), Inches(6), Inches(2), GOLD)
add_text(s, '🇰🇿', Inches(1), Inches(1.2), Inches(2), Inches(1.5), font_size=80, color=WHITE)
add_text(s, 'КАЗАХСТАН', Inches(1), Inches(2.8), Inches(8), Inches(1.5),
font_size=72, bold=True, color=WHITE)
add_text(s, 'Сердце Евразии — девятая по территории страна мира',
Inches(1), Inches(4.3), Inches(8), Inches(0.8),
font_size=24, color=GRAY)
stats = [('2.7 млн км²', 'Площадь'), ('20 млн', 'Население'),
('130+', 'Народов'), ('1 космодром', 'Байконур')]
for i, (val, lbl) in enumerate(stats):
x = Inches(1 + i * 3)
y = Inches(5.6)
add_box(s, x, y, Inches(2.7), Inches(1.2), RGBColor(0x1C, 0x26, 0x36))
add_text(s, val, x + Inches(0.2), y + Inches(0.1), Inches(2.3), Inches(0.6),
font_size=24, bold=True, color=CYAN)
add_text(s, lbl, x + Inches(0.2), y + Inches(0.65), Inches(2.3), Inches(0.4),
font_size=13, color=GRAY)
# ══════════════════════════════════════════════════════════════
# SLIDE 2 — Geography
# ══════════════════════════════════════════════════════════════
s = prs.slides.add_slide(BLANK_LAYOUT)
add_bg(s, WHITE)
set_slide_transition(s, 'push')
add_rect(s, 0, 0, W, Inches(1.4), BG_DARK)
add_text(s, 'ГЕОГРАФИЯ', Inches(0.8), Inches(0.3), Inches(8), Inches(0.8),
font_size=36, bold=True, color=CYAN)
add_text(s, 'От каспийских берегов до алтайских гор', Inches(0.8), Inches(1.4),
Inches(8), Inches(0.5), font_size=16, color=GRAY)
geo = [
('🏔️', 'Горы', 'Тянь-Шань, Чу-Илийские горы, Алтай.\nВысшая точка — Хан-Тенгри (7010 м)'),
('🌊', 'Каспийское море', 'Крупнейшее озеро мира.\nПобережье тянется на 1894 км'),
('🏜️', 'Степи', 'Бескрайние равнины —\nисторическая родина кочевников'),
('🌾', 'Озёра', 'Балхаш, Алаколь, Маркаколь —\nболее 45 000 озёр'),
]
for i, (em, nm, ds) in enumerate(geo):
col, row = i % 2, i // 2
x = Inches(0.8 + col * 6.2)
y = Inches(2.2 + row * 2.5)
add_box(s, x, y, Inches(5.6), Inches(2.2), RGBColor(0xF5, 0xF7, 0xFA))
add_text(s, em, x + Inches(0.3), y + Inches(0.15), Inches(1), Inches(0.7),
font_size=38)
add_text(s, nm, x + Inches(1.3), y + Inches(0.2), Inches(4), Inches(0.5),
font_size=22, bold=True, color=INK)
add_text(s, ds, x + Inches(1.3), y + Inches(0.75), Inches(4), Inches(1.2),
font_size=14, color=GRAY)
# ══════════════════════════════════════════════════════════════
# SLIDE 3 — Facts
# ══════════════════════════════════════════════════════════════
s = prs.slides.add_slide(BLANK_LAYOUT)
add_bg(s, BG_DARK)
set_slide_transition(s, 'fade')
add_text(s, 'ЦИФРЫ И ФАКТЫ', Inches(0.8), Inches(0.6), Inches(10), Inches(1),
font_size=40, bold=True, color=WHITE)
add_text(s, 'Казахстан в цифрах', Inches(0.8), Inches(1.4), Inches(6), Inches(0.5),
font_size=18, color=GRAY)
facts = [('9', 'по величине\nв мире'), ('1991', 'год\nнезависимости'),
('70+', 'тонн золота\nв год'), ('1', 'космодром\nБайконур'),
('3', 'столицы\nв истории')]
for i, (num, txt) in enumerate(facts):
x = Inches(0.5 + i * 2.5)
add_box(s, x, Inches(2.5), Inches(2.2), Inches(3.5),
RGBColor(0x1C, 0x26, 0x36), CYAN)
add_text(s, num, x + Inches(0.2), Inches(2.9), Inches(1.8), Inches(1.2),
font_size=52, bold=True, color=CYAN, align=PP_ALIGN.CENTER)
add_text(s, txt, x + Inches(0.2), Inches(4.2), Inches(1.8), Inches(1.4),
font_size=14, color=GRAY, align=PP_ALIGN.CENTER)
add_rect(s, Inches(0.8), Inches(6.5), Inches(11.7), Inches(0.04), CYAN)
# ══════════════════════════════════════════════════════════════
# SLIDE 4 — Culture
# ══════════════════════════════════════════════════════════════
s = prs.slides.add_slide(BLANK_LAYOUT)
add_bg(s, RGBColor(0xF0, 0xF4, 0xF8))
set_slide_transition(s, 'cover')
add_rect(s, 0, 0, W, Inches(1.4), BG_DARK)
add_text(s, 'КУЛЬТУРА И ТРАДИЦИИ', Inches(0.8), Inches(0.3), Inches(10), Inches(0.8),
font_size=36, bold=True, color=GOLD)
culture = [
('🦅', 'Беркутчи', 'Соколиная охота с орлами — наследие ЮНЕСКО'),
('🎪', 'Юрта', 'Легко разборное жилище — символ свободы'),
('🎶', 'Домбра', 'Двухструнный инструмент — душа кюев'),
('🤼', 'Байге', 'Конные скачки на длинные дистанции'),
('🎭', 'Наурыз', 'Праздник весны — 7 блюд, 22 марта'),
('📖', 'Абай', 'Великий поэт, философ, мыслитель'),
]
for i, (em, nm, ds) in enumerate(culture):
col, row = i % 3, i // 3
x = Inches(0.8 + col * 4.1)
y = Inches(1.8 + row * 2.6)
add_box(s, x, y, Inches(3.7), Inches(2.2), WHITE)
add_text(s, em, x + Inches(0.3), y + Inches(0.15), Inches(1), Inches(0.7),
font_size=36)
add_text(s, nm, x + Inches(1.2), y + Inches(0.2), Inches(2.2), Inches(0.5),
font_size=20, bold=True, color=INK)
add_text(s, ds, x + Inches(0.3), y + Inches(1), Inches(3.2), Inches(1),
font_size=14, color=GRAY)
# ══════════════════════════════════════════════════════════════
# SLIDE 5 — Cities
# ══════════════════════════════════════════════════════════════
s = prs.slides.add_slide(BLANK_LAYOUT)
add_bg(s, WHITE)
set_slide_transition(s, 'push')
add_text(s, 'ГОРОДА', Inches(0.8), Inches(0.6), Inches(10), Inches(1),
font_size=40, bold=True, color=INK)
add_text(s, 'Мегаполисы Казахстана', Inches(0.8), Inches(1.3), Inches(6), Inches(0.5),
font_size=18, color=GRAY)
cities = [
('АСТАНА', 'Столица с 1997 г.\nБайтерек, Хан-Шатыр,\nфонтаны «Танкіри»', CYAN),
('АЛМАТЫ', 'Бывшая столица\nГоры, Медеу, Шымбулак,\nалматинские яблоки', GOLD),
('ШЫМКЕНТ', 'Третий город\nЮжные ворота,\nжаркий климат', RGBColor(0x2A, 0x9D, 0x8F)),
]
for i, (nm, ds, clr) in enumerate(cities):
x = Inches(0.8 + i * 4.1)
add_box(s, x, Inches(2.2), Inches(3.7), Inches(4.5), RGBColor(0xF5, 0xF7, 0xFA))
add_rect(s, x, Inches(2.2), Inches(3.7), Inches(0.12), clr)
add_text(s, nm, x + Inches(0.4), Inches(2.7), Inches(3), Inches(0.6),
font_size=28, bold=True, color=INK)
add_text(s, ds, x + Inches(0.4), Inches(3.5), Inches(3), Inches(2.5),
font_size=15, color=GRAY)
# ══════════════════════════════════════════════════════════════
# SLIDE 6 — Food
# ══════════════════════════════════════════════════════════════
s = prs.slides.add_slide(BLANK_LAYOUT)
add_bg(s, RGBColor(0xFD, 0xF8, 0xEF))
set_slide_transition(s, 'wipe')
add_text(s, 'КУХНЯ', Inches(0.8), Inches(0.6), Inches(10), Inches(1),
font_size=40, bold=True, color=INK)
add_text(s, 'Вкус степи — просто и сытно', Inches(0.8), Inches(1.3), Inches(6), Inches(0.5),
font_size=18, color=GRAY)
foods = [
('🥟', 'Бешбармак', 'Главное блюдо — мясо с лапшой.\n«Пять пальцев» — едят руками'),
('🫕', 'Кумыс', 'Ферментированное кобылье\nмолоко — тонизирующий напиток'),
('🫓', 'Баурсаки', 'Жареные тестовые шарики\nна каждом празднике'),
('🍵', 'Чай с молоком', 'С солью — гостям наливают\nпервым, знак уважения'),
]
for i, (em, nm, ds) in enumerate(foods):
col, row = i % 2, i // 2
x = Inches(0.8 + col * 6.2)
y = Inches(2.2 + row * 2.4)
add_box(s, x, y, Inches(5.6), Inches(2), WHITE, GOLD)
add_text(s, em, x + Inches(0.3), y + Inches(0.15), Inches(1), Inches(0.7),
font_size=38)
add_text(s, nm, x + Inches(1.3), y + Inches(0.2), Inches(3.5), Inches(0.5),
font_size=22, bold=True, color=INK)
add_text(s, ds, x + Inches(1.3), y + Inches(0.8), Inches(3.8), Inches(1),
font_size=14, color=GRAY)
# ══════════════════════════════════════════════════════════════
# SLIDE 7 — History
# ══════════════════════════════════════════════════════════════
s = prs.slides.add_slide(BLANK_LAYOUT)
add_bg(s, WHITE)
set_slide_transition(s, 'dissolve')
add_text(s, 'ИСТОРИЯ', Inches(0.8), Inches(0.6), Inches(10), Inches(1),
font_size=40, bold=True, color=INK)
add_text(s, 'От кочевников до космоса', Inches(0.8), Inches(1.3), Inches(6), Inches(0.5),
font_size=18, color=GRAY)
add_rect(s, Inches(1.6), Inches(2.2), Inches(0.06), Inches(4.8), CYAN)
timeline = [
('1465', 'Казахское ханство', 'Формирование народа и кочевого уклада'),
('XVIII', 'Российская империя', 'Присоединение, оседлый образ жизни'),
('1955', 'Байконур', 'Запуск первого космодрома в мире'),
('1961', 'Гагарин', 'Первый полёт в космос с Байконура'),
('1991', 'Независимость', '16 декабря — последняя республика СССР'),
('1997', 'Новая столица', 'Перенос столицы в Акмолу (Астану)'),
]
for i, (yr, ttl, dsc) in enumerate(timeline):
y = Inches(2.2 + i * 0.8)
dot = add_circle(s, Inches(1.4), y + Inches(0.08), Inches(0.45),
CYAN if i % 2 == 0 else GOLD)
add_text(s, yr, Inches(2.2), y, Inches(1.2), Inches(0.6),
font_size=16, bold=True, color=INK)
add_text(s, f'{ttl}{dsc}', Inches(3.5), y, Inches(9), Inches(0.6),
font_size=14, color=GRAY)
# ══════════════════════════════════════════════════════════════
# SLIDE 8 — Thank You
# ══════════════════════════════════════════════════════════════
s = prs.slides.add_slide(BLANK_LAYOUT)
add_bg(s, BG_DARK)
set_slide_transition(s, 'zoom')
add_circle(s, Inches(10), Inches(0.5), Inches(3), RGBColor(0x00, 0x3D, 0x5C))
add_circle(s, Inches(10.5), Inches(1), Inches(2), CYAN)
add_circle(s, Inches(0.5), Inches(5), Inches(2.5), RGBColor(0x00, 0x3D, 0x5C))
add_circle(s, Inches(1), Inches(5.5), Inches(1.5), GOLD)
add_text(s, '🇰🇿', Inches(5.5), Inches(1), Inches(2.5), Inches(1.5),
font_size=80, color=WHITE, align=PP_ALIGN.CENTER)
add_text(s, 'СПАСИБО ЗА ВНИМАНИЕ!', Inches(1), Inches(2.8), Inches(11.3), Inches(1.2),
font_size=48, bold=True, color=WHITE, align=PP_ALIGN.CENTER)
add_text(s, 'Казахстан — древние традиции и современные мегаполисы,\nбескрайние степи и высокие горы',
Inches(2), Inches(4.2), Inches(9.3), Inches(1.2),
font_size=18, color=GRAY, align=PP_ALIGN.CENTER)
# ── Save ──
out = '/srv/opencode/workspaces/users/literally.ww/kazakhstan/Казахстан_Презентация.pptx'
prs.save(out)
print(f'✅ Saved: {out}')
print(f' Slides: {len(prs.slides)}')