Презентация PowerPoint – это набор слайдов. Каждый слайд – холст с текстовыми полями, фигурами, картинками, таблицами и диаграммами. Есть и всякие продвинутые штуки вроде анимаций, SmartArt и видео, но для 90% рабочих слайдов они не нужны.

Файл PowerPoint – место, где весь этот контент хранится так, чтобы его мог прочитать компьютер. Внутри лежит и текст, который вы набрали для заголовка диаграммы, и встроенные файлы Excel с данными для этой диаграммы, и .png-файлы с логотипом вашей компании, и свойства, которые определяют, как всё это отрисуется на экране: размер шрифта заголовка, цвет подписей данных, высота строк таблицы, показывать ли сетку на диаграмме.

Ниже понятным языком разберём, как устроен самый популярный в мире формат презентаций.

Как файл хранит всю информацию?

Можно попробовать записать всё в текстовый файл. Перечислить каждый элемент и его свойства. Вот примитивный пример: пустой слайд с единственным текстовым полем, где написано «Hello world!».

Пустой слайд с одним текстовым блоком по центру, где написано Hello world!
Пустой слайд с одним текстовым блоком по центру, где написано Hello world!

Можно открыть «Блокнот» и набрать .txt-файл примерно такого вида:

Слайд 1
- Ширина = 13.33 дюйма
- Высота = 7.5 дюйма
- Фон = белый
- Текстовый блок 1
  - Текст = "Hello world!"
  - Семейство шрифтов = Arial
  - Размер шрифта = 18
  - Цвет шрифта = чёрный
  - Позиция = 5.9 дюйма от левого края, 3.5 дюйма от верхнего края

Допустим, вы добавляете ещё один простенький слайд.

Слайд с текстом This is a circle над красным кругом
Слайд с текстом This is a circle над красным кругом

В .txt-файл добавится вот это:

Слайд 2
- Ширина = 13.33 дюйма
- Высота = 7.5 дюйма
- Фон = белый
- Текстовый блок 1
  - Текст = "This is a circle"
  - Семейство шрифтов = Arial
  - Размер шрифта = 18
  - Цвет шрифта = чёрный
  - Позиция = 5.9 дюйма от левого края, 2 дюйма от верхнего края
- Фигура 1
  - Тип фигуры = круг
  - Заливка = красная
  - Высота = 2 дюйма
  - Ширина = 2 дюйма
  - Позиция = 5.7 дюйма от левого края, 2.75 дюйма от верхнего края

Смотрите вы на это и думаете: «Хм, я переписываю одни и те же свойства. У всех слайдов одинаковая ширина и высота, да и шрифт я собираюсь использовать однотипный. Дай-ка соберу всё это в одном месте».

Презентация
- Ширина слайда = 13.33 дюйма
- Высота слайда = 7.5 дюйма
- Фон = белый
- Цвет шрифта = чёрный
- Семейство шрифтов = Arial
- Размер шрифта = 18

Слайд 1
- Текстовый блок 1
  - Текст = "Hello world!"
  - Позиция = 5.9 дюйма от левого края, 3.5 дюйма от верхнего края

Слайд 2
- Текстовый блок 1
  - Текст = "This is a circle"
  - Позиция = 5.9 дюйма от левого края, 2 дюйма от верхнего края
- Фигура 1
  - Тип фигуры = круг
  - Заливка = красная
  - Высота = 2 дюйма
  - Ширина = 2 дюйма
  - Позиция = 5.7 дюйма от левого края, 2.75 дюйма от верхнего края

Так лучше. Но когда у вас будет нормальная колода на 30 страниц, файл раздуется до огромных размеров. Поэтому вы решаете разбить его на файлы поменьше и разложить по папкам.

presentation/
├── presentation_properties.txt
└── slides/
    ├── slide1.txt
    └── slide2.txt

Диаграммы и картинки

Пока что на ваших слайдах живут только текст и фигуры. А как быть с логотипом компании?

Раз вы уже работаете с папками, просто добавьте папку pictures и складывайте туда .png- и .jpg-файлы.

presentation/
├── presentation_properties.txt
├── slides/
│   ├── slide1.txt
│   └── slide2.txt
└── pictures/
    └── logo.png

А в слайде вы просто ссылаетесь на файл картинки и указываете её размер и положение.

Приятный бонус такого подхода: если вы используете один и тот же логотип на нескольких слайдах, копию картинки для каждого из них хранить не нужно.

Слайд 3
- Картинка
  - Источник = logo.png
  - Высота = 7.5 дюйма
  - Ширина = 7.5 дюйма
  - Позиция = 2.92 дюйма от левого края, 0 дюймов от верхнего края
Слайд, заполненный логотипом editide
Слайд, заполненный логотипом editide

Ту же идею можно применить и к диаграммам. Файлы Excel удобны для хранения числовых данных, так что, вместо того чтобы изобретать велосипед, вы выделяете каждой диаграмме свой .xlsx-файл под её данные.

presentation/
├── presentation_properties.txt
├── slides/
│   ├── slide1.txt
│   ├── slide2.txt
│   └── slide3.txt
├── pictures/
│   └── logo.png
└── excel/
    └── book1.xlsx
Слайд со сгруппированной столбчатой диаграммой под названием Chart Title
Слайд со сгруппированной столбчатой диаграммой под названием Chart Title

Затем при описании диаграммы вы не забываете сослаться на этот файл:

Слайд 4
- Диаграмма
  - Источник = book1.xlsx
  - Высота = 6 дюймов
  - Ширина = 9 дюймов
  - Позиция = 2.17 дюйма от левого края, 0.75 дюйма от верхнего края
  - Заголовок = Chart Title
  - Показывать сетку = true
  - Максимум оси = 6
  - Шаг оси = 1
  .
  .
  .
  - Заливка ряда 3 = серая

Эти три точки делают очень много работы. У диаграмм очень много свойств. Можно сделать жирной одну-единственную букву в подписи данных, можно сделать линию горизонтальной оси толще.

Скорее всего, у вас будут слайды с несколькими диаграммами, так что ради собственного душевного спокойствия вы решаете вынести диаграммы в отдельные файлы и применить ту же стратегию ссылок, что и для картинок с файлами Excel.

Вы переносите свойства диаграммы в отдельный файл chart1.txt и упрощаете slide4.txt до:

Слайд 4
- Диаграмма
  - Источник = chart1.txt
  - Высота = 6 дюймов
  - Ширина = 9 дюймов
  - Позиция = 2.17 дюйма от левого края, 0.75 дюйма от верхнего края

В итоге финальная папка выглядит примерно так:

presentation/
├── presentation_properties.txt
├── slides/
│   ├── slide1.txt
│   ├── slide2.txt
│   ├── slide3.txt
│   └── slide4.txt
├── pictures/
│   └── logo.png
├── excel/
│   └── book1.xlsx
└── charts/
    └── chart1.txt

Поздравляю! Вы воссоздали базовую архитектуру .pptx-файлов.

Под капотом .pptx-файл – это ZIP-архив, содержащий множество отдельных файлов. И вместо нашего самодельного .txt-формата в нём используется структурированный текст в формате XML.

Попробуйте переименовать один из своих файлов PowerPoint из .pptx в .zip и убедитесь сами.

Корень распакованного pptx-файла с папками docProps, ppt и _rels
Корень распакованного pptx-файла с папками docProps, ppt и _rels

А вот что внутри папки slides:

Папка slides распакованного pptx-файла: по одному XML-файлу на каждый слайд
Папка slides распакованного pptx-файла: по одному XML-файлу на каждый слайд

Мы не затронули макеты (layouts) и образцы слайдов (masters), но ваши папки ложатся на реальную структуру один в один, если переименовать «excel» в «embeddings», а «pictures» – в «media».

Чем XML отличается от нашего простого текста?

Давайте-ка распакуем фрагмент того самого slide1.xml, где хранится ваш простенький пример «Hello world!».

<p:cSld>
  <p:spTree>
    <p:sp>
      <p:nvSpPr>
        <p:cNvPr id="5" name="TextBox 4">
          <a:extLst>...</a:extLst>
        </p:cNvPr>
        <p:cNvSpPr txBox="1"/>
      </p:nvSpPr>
      <p:spPr>
        <a:xfrm>
          <a:off x="5359675" y="3244334"/>
          <a:ext cx="1472650" cy="369332"/>
        </a:xfrm>
        <a:prstGeom prst="rect">
          <a:avLst/>
        </a:prstGeom>
        <a:noFill/>
      </p:spPr>
      <p:txBody>
        <a:bodyPr wrap="square" rtlCol="0">
          <a:spAutoFit/>
        </a:bodyPr>
        <a:lstStyle/>
        <a:p>
          <a:pPr algn="ctr"/>
          <a:r>
            <a:rPr lang="en-US" dirty="0"/>
            <a:t>Hello world!</a:t>
          </a:r>
        </a:p>
      </p:txBody>
    </p:sp>
  </p:spTree>
</p:cSld>

Нечитаемая машинная каша. Становится чуть лучше, если заменить сокращения на нормальные слова:

<CommonSlideData>
  <ShapeTree>
    <Shape>
      <NonVisualShapeProperties>
        <NonVisualDrawingProperties id="5" name="TextBox 4">
          <ExtensionList>...</ExtensionList>
        </NonVisualDrawingProperties>
        <NonVisualShapeDrawingProperties isTextBox="1"/>
      </NonVisualShapeProperties>
      <ShapeProperties>
        <Transform>
          <Offset x="5359675" y="3244334"/>
          <Extents width="1472650" height="369332"/>
        </Transform>
        <PresetGeometry shape="rectangle">
          <AdjustValues/>
        </PresetGeometry>
        <NoFill/>
      </ShapeProperties>
      <TextBody>
        <BodyProperties wrap="square" rightToLeftColumns="0">
          <ShapeAutoFit/>
        </BodyProperties>
        <ListStyle/>
        <Paragraph>
          <ParagraphProperties alignment="center"/>
          <Run>
            <RunProperties language="en-US" dirty="0"/>
            <Text>Hello world!</Text>
          </Run>
        </Paragraph>
      </TextBody>
    </Shape>
  </ShapeTree>
</CommonSlideData>

А если убрать XML-обвязку и менее важные атрибуты, получится что-то вроде:

Слайд
- Фигуры
  - TextBox 4
    - Координата X: 5 359 675
    - Координата Y: 3 244 334
    - Высота: 369 332
    - Ширина: 1 472 650
    - Preset Geometry: прямоугольник
    - Без заливки
    - Текст: Hello world!

Похоже на ваш исходный .txt-файл! Числа для позиции и размера указаны не в дюймах, а в единицах под названием EMU – English Metric Unit. Они огромные – это для того, чтобы обходиться без чисел с плавающей точкой и работать только с целыми числами.

Размера шрифта 18 и шрифта Arial здесь нет, но вы этого и ожидали. Шрифты и их размеры вы записали в presentation_properties.txt, чтобы не повторять их для каждого текстового блока.

В настоящем .pptx-файле семейства шрифтов темы могут жить в theme1.xml в папке theme:

<a:fontScheme name="Office">
  <a:majorFont>
    <a:latin typeface="Arial"/>
  </a:majorFont>
  <a:minorFont>
    <a:latin typeface="Arial"/>
  </a:minorFont>
</a:fontScheme>

То есть по сути .pptx-файл – это набор XML-файлов с данными презентации. Есть папка с отдельными файлами под каждый слайд. И есть ещё несколько XML-файлов под общие свойства вроде шрифтов, которые пришлось бы повторять снова и снова.

Значит, редактировать PPTX легко?

Звучит-то вроде просто. Выдай каждому слайду отдельный файл со списком его свойств, но сделай это эффективно, храня часто используемые свойства в общем месте.

Общая идея здравая, но вот реализация – невероятно грязная.

В 2005 году, под давлением правительств, требовавших открытых стандартов для документов, Microsoft подала форматы OOXML (Office Open XML) на стандартизацию в Ecma International. Ecma опубликовала стандарт в 2006 году, а в 2008-м он был принят как международный стандарт ISO.

Страница каталога ISO со стандартом на форматы файлов Office Open XML
Страница каталога ISO со стандартом на форматы файлов Office Open XML

Основной документ насчитывает больше 5000 страниц. Это как 4 полные трилогии «Властелина колец». Если распечатать его на одной стороне листа, стопка бумаги получится высотой около 50 см.

Кажется чересчур?

The Document Foundation (создатели LibreOffice – свободной альтернативы Microsoft Office) считает это намеренной уловкой Microsoft, чтобы намертво привязать пользователей к своей экосистеме:

К сожалению, XML-схема может быть как простой, так и излишне сложной, раздутой, запутанной и трудной в реализации без специального знания её особенностей.

Эта искусственная сложность проявляется в глубоко вложенной структуре тегов с избыточной абстракцией, в десятках и даже сотнях необязательных или перегруженных элементов, в неинтуитивных соглашениях об именовании, в повсеместном использовании точек расширения и подстановочных символов, в множественном импорте пространств имён и иерархий типов, а также в скудной или невнятной документации.

Теория приятная. Так и представляешь, как Билл Гейтс звонит Стиву Балмеру:

— Стив, мне нужны самые злобные инженеры, каких только сможешь найти. Пришли мне команду, которая работала над Clippy и Windows Update. Я хочу, чтобы наш Office был недоступен ни одному конкуренту.

— Без проблем, сниму их с проекта Vista и отправлю к тебе.

Это, безусловно, объяснило бы кучу странных решений в OOXML.

Есть и другая, менее приятная теория. PowerPoint создали в 1987 году, а на Windows он вышел в 1990-м. Инженеры тех лет никак не могли знать, чем PowerPoint станет и что ему в итоге придётся уметь. Учитель естествознания в средней школе использует его, чтобы читать лекции с анимациями. А инвестиционные банкиры на том же софте готовят материалы для заседания совета директоров, где одобряют слияние публичных компаний на миллиарды долларов.

Легко критиковать архитектуру 40 лет спустя, задним умом и с накопленным багажом знаний в разработке ПО. Самому OOXML всего около 20 лет, но ему пришлось описать десятилетия функций PowerPoint и уже существующие презентации. Вполне возможно, что OOXML – такой же бардак, как и любая 40-летняя кодовая база. Просто у обычного кода этот хаос спрятан внутри, а формат файла ломать нельзя: старые презентации должны открываться всегда. Поэтому все накопленные за десятилетия костыли ради совместимости и фичи, прикрученные сбоку, никуда не делись, а застыли в спецификации.

Заключение

Файл PowerPoint – это ZIP-архив, содержащий XML-файлы и бинарные ресурсы. В нём хранятся все свойства, которые вы задали в презентации PowerPoint, и он пытается разложить их по отдельным файлам, чтобы избежать повторов и упростить поиск нужного.

Увы, реализация – это минное поле из цепочек наследования, строгого порядка элементов, значений по умолчанию, задаваемых самим приложением, и прочих странных причуд. Именно из-за этого минного поля так сложно автоматизировать PowerPoint кодом. А значит, именно поэтому ИИ-агенты спотыкаются на, казалось бы, элементарных правках.