Initial commit: organize Primary song slides repo
One folder per song under songs/. Tracks PPTX slide files and Python generation scripts. PDFs and videos excluded (too large for git; originals are in Google Drive). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,162 @@
|
||||
import fitz
|
||||
from pptx import Presentation
|
||||
from pptx.util import Inches, Pt
|
||||
from pptx.dml.color import RGBColor
|
||||
from pptx.enum.text import PP_ALIGN
|
||||
import io
|
||||
|
||||
PDF_PATH = r"C:\Users\jhodgkin\Documents\dev\primary-song-slides\BookOfMormonStories.pdf"
|
||||
OUT_PATH = r"C:\Users\jhodgkin\Documents\dev\primary-song-slides\BookOfMormonStories.pptx"
|
||||
DPI = 96
|
||||
|
||||
SLIDE_W = Inches(13.333)
|
||||
SLIDE_H = Inches(7.5)
|
||||
TEXT_BOX_H = Inches(2.1)
|
||||
FONT_SIZE = Pt(44)
|
||||
TEXT_COLOR = RGBColor(0x4A, 0x27, 0x11) # deep warm brown
|
||||
|
||||
# PDF pages 0-31 = illustration cards; page 32 = title page (skipped)
|
||||
# Verse 1 lyrics are from CS 118. Fill in the remaining verses with correct lyrics.
|
||||
#
|
||||
# Image guide (0-based page → subject):
|
||||
# 0 = teacher reading to children (intro)
|
||||
# 1 = Lehi's family on ancient scroll
|
||||
# 2 = three men sailing
|
||||
# 3 = righteous family with halos in jungle
|
||||
# 4 = large group gathering in jungle
|
||||
# 5 = lush jungle / hut
|
||||
# 6 = children springing from open Book of Mormon
|
||||
# 7 = family with halos (closer)
|
||||
# 8 = young man in red sash (Nephi? Alma?)
|
||||
# 9 = angel with wings
|
||||
# 10 = three men around a fallen figure (Alma struck down)
|
||||
# 11 = righteous youth with halo in jungle
|
||||
# 12 = man in chains
|
||||
# 13 = pile of chains
|
||||
# 14 = wicked king
|
||||
# 15 = gravestone with flowers
|
||||
# 16 = shepherd with sheep and staff
|
||||
# 17 = flock of many sheep
|
||||
# 18 = slingshot and sword
|
||||
# 19 = righteous shepherd with halo
|
||||
# 20 = four young warriors (shields and spears, no halos)
|
||||
# 21 = Jesus Christ in red robe, arms open
|
||||
# 22 = four warriors smiling
|
||||
# 23 = four warriors with halos in jungle
|
||||
# 24 = man standing triumphantly on stone wall
|
||||
# 25 = three arrows flying
|
||||
# 26 = young man preaching, arms wide
|
||||
# 27 = young man preaching with halo
|
||||
# 28 = crucifixion (three crosses)
|
||||
# 29 = Jesus hugging many children
|
||||
# 30 = portrait of Jesus Christ
|
||||
# 31 = five children with halos in jungle
|
||||
SLIDES = [
|
||||
# Verse 1 — Lehi's family / ancient Lamanites
|
||||
(0, "Book of Mormon stories that my teacher tells to me,"),
|
||||
(1, "Are about the Lamanites in ancient history."),
|
||||
(2, "Long ago their fathers came from far across the sea,"),
|
||||
(3, "Giv'n the land if they lived righteously."),
|
||||
|
||||
# Verse 2 — Lamanites and others in the promised land
|
||||
(4, "Lamanites met others who were seeking liberty,"),
|
||||
(5, "And the land soon welcomed all who wanted to be free."),
|
||||
(6, "Book of Mormon stories say that we must brothers be,"),
|
||||
(7, "Giv'n the land if we live righteously."),
|
||||
|
||||
# Verse 3 — Alma the Younger
|
||||
(8, "Alma was rebellious, and he fought against the right."),
|
||||
(9, "Then one day an angel came to turn him to the light."),
|
||||
(10, "Struck before his brethren, Alma learned humility."),
|
||||
(11, "Then he taught in the land righteously."),
|
||||
|
||||
# Verse 4 — Abinadi before King Noah
|
||||
(12, "Don't forget Abinadi, who stood before the king."),
|
||||
(13, "All chained up from head to toe, the gospel he did bring."),
|
||||
(14, "If he would deny it, then the king would set him free."),
|
||||
(15, "He was true, and he died righteously."),
|
||||
|
||||
# Verse 5 — Ammon the missionary
|
||||
(16, "Ammon was a missionary serving Lamanites,"),
|
||||
(17, "Tending King Lamoni's sheep for several days and nights."),
|
||||
(18, "Robbers came; he saved the sheep by fighting fearlessly."),
|
||||
(19, "He had learned he could live righteously."),
|
||||
|
||||
# Verse 6 — 2000 Stripling Warriors
|
||||
# Reordered: warriors (20) -> smiling march (22) -> Christ (21) -> halos (23)
|
||||
(20, "Once two thousand sons of God were called to fight the foe."),
|
||||
(22, "Marching as an army into battle they did go."),
|
||||
(21, "They believed that Christ the Lord their guardian would be."),
|
||||
(23, "They had learned they should live righteously."),
|
||||
|
||||
# Verse 7 — Samuel the Lamanite
|
||||
# Reordered: wall (24) -> preaching (26) -> arrows (25) -> righteous (27)
|
||||
(24, "Samuel the Lamanite, high on the city wall,"),
|
||||
(26, "Came to warn the people, and repentance was his call."),
|
||||
(25, "Arrows could not hit him, for a man of God was he,"),
|
||||
(27, "And he taught in the land righteously."),
|
||||
|
||||
# Verse 8 — Christ's atonement and visit to the Americas
|
||||
# Reordered: crucifixion (28) -> portrait (30) -> children (29) -> people (31)
|
||||
(28, "After Christ was crucified and died for you and me,"),
|
||||
(30, "He came forth to teach the truth to all who would be free."),
|
||||
(29, "Hands were laid upon each child. He blessed them tenderly,"),
|
||||
(31, "And they lived in the land righteously."),
|
||||
]
|
||||
|
||||
|
||||
def render_page(page):
|
||||
mat = fitz.Matrix(DPI / 72, DPI / 72)
|
||||
pix = page.get_pixmap(matrix=mat, alpha=False)
|
||||
return io.BytesIO(pix.tobytes("jpeg", jpg_quality=85)), pix.width, pix.height
|
||||
|
||||
|
||||
def add_slide(doc, prs, blank_layout, page_idx, lyric):
|
||||
page = doc[page_idx]
|
||||
img_bytes, pw, ph = render_page(page)
|
||||
slide = prs.slides.add_slide(blank_layout)
|
||||
|
||||
aspect = pw / ph
|
||||
h = SLIDE_H
|
||||
w = int(h * aspect)
|
||||
if w > SLIDE_W:
|
||||
w = SLIDE_W
|
||||
h = int(w / aspect)
|
||||
left = (SLIDE_W - w) // 2
|
||||
top = (SLIDE_H - h) // 2
|
||||
slide.shapes.add_picture(img_bytes, left, top, width=w, height=h)
|
||||
|
||||
tb_top = SLIDE_H - TEXT_BOX_H
|
||||
txBox = slide.shapes.add_textbox(Inches(0.25), tb_top, SLIDE_W - Inches(0.5), TEXT_BOX_H)
|
||||
tf = txBox.text_frame
|
||||
tf.word_wrap = True
|
||||
|
||||
lines = lyric.split("\n")
|
||||
for i, line in enumerate(lines):
|
||||
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
|
||||
p.alignment = PP_ALIGN.CENTER
|
||||
run = p.add_run()
|
||||
run.text = line
|
||||
run.font.bold = True
|
||||
run.font.size = FONT_SIZE
|
||||
run.font.color.rgb = TEXT_COLOR
|
||||
|
||||
print(f" Slide {len(prs.slides):2d} (pg {page_idx:2d}): {lyric[:60]}")
|
||||
|
||||
|
||||
def main():
|
||||
doc = fitz.open(PDF_PATH)
|
||||
prs = Presentation()
|
||||
prs.slide_width = SLIDE_W
|
||||
prs.slide_height = SLIDE_H
|
||||
blank_layout = prs.slide_layouts[6]
|
||||
|
||||
for page_idx, lyric in SLIDES:
|
||||
add_slide(doc, prs, blank_layout, page_idx, lyric)
|
||||
|
||||
prs.save(OUT_PATH)
|
||||
print(f"\nSaved: {OUT_PATH} ({len(SLIDES)} slides)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user