# PPTX Exporter

一个基于 PptxGenJS 的 PowerPoint 导出工具，支持将自定义数据结构转换为 PPTX 文件。

## 📋 项目说明

本项目基于 [PPTist](https://github.com/pipipi-pikachu/PPTist) 项目，为 PPTist 在线演示文稿应用提供无界面导出功能。

**PPTist** 是一个在线演示文稿应用，复制了 MS PowerPoint 的大部分常用功能，支持在线编辑和演示 PPT，并支持 AIPPT。

本项目作为 PPTist 的配套工具，专注于将 PPTist 的数据格式转换为标准的 PPTX 文件，实现无界面导出功能。

## 安装

```bash
npm install pptx-exporter
```

## 基本使用

### 在Node.js中使用

```typescript
import { PPTXExporter } from 'pptx-exporter';

const pptData = {
  title: '我的演示文稿',
  width: 960,
  height: 540,
  theme: {
    backgroundColor: '#ffffff',
  },
  slides: [
    // 你的幻灯片数据
  ],
};

const exporter = new PPTXExporter(pptData);

// 检查运行环境
console.log('当前环境:', exporter.getEnvironment());
console.log('支持的格式:', exporter.getSupportedFormats());

// 智能导出（根据环境自动选择最佳格式）
const result = await exporter.smartExport();

// 导出为文件
await exporter.toFile('presentation.pptx');

// 根据环境选择合适的导出方式
if (exporter.getEnvironment() === 'node') {
  const buffer = await exporter.toBuffer();
} else if (exporter.getEnvironment() === 'browser') {
  const blob = await exporter.toBlob(true); // 启用压缩
}
```

### 在浏览器中使用

#### 方式一：直接引用UMD文件

```html
<!DOCTYPE html>
<html>
  <head>
    <title>PPTX Exporter 示例</title>
  </head>
  <body>
    <!-- 引入PPTX Exporter -->
    <script src="./dist/browser/pptx-exporter.umd.js"></script>

    <button onclick="exportPPTX()">导出PPTX</button>

    <script>
      const pptData = {
        title: '我的演示文稿',
        width: 960,
        height: 540,
        theme: {
          backgroundColor: '#ffffff',
        },
        slides: [
          {
            elements: [
              {
                type: 'text',
                content: '欢迎使用 PPTX Exporter',
                x: 100,
                y: 100,
                width: 760,
                height: 80,
                fontSize: 32,
                fontWeight: 'bold',
                color: '#333333',
                textAlign: 'center',
              },
            ],
          },
        ],
      };

      async function exportPPTX() {
        // 创建导出器实例
        const exporter = new PPTXExporter(pptData);

        // 方式1: 直接下载文件
        await exporter.downloadFile('my-presentation.pptx');

        // 方式2: 在新标签页预览
        // await exporter.openInNewTab();

        // 方式3: 导出为其他格式
        // const blob = await exporter.toBlob();
        // const base64 = await exporter.toBase64();
        // const arrayBuffer = await exporter.toArrayBuffer();
      }

      // 检查环境和支持的格式
      console.log('当前环境:', new PPTXExporter(pptData).getEnvironment());
      console.log(
        '支持的格式:',
        new PPTXExporter(pptData).getSupportedFormats()
      );
    </script>
  </body>
</html>
```

#### 方式二：从CDN引用

```html
<!-- 从jsdelivr CDN引用 -->
<script src="https://cdn.jsdelivr.net/npm/pptx-exporter@latest/dist/browser/pptx-exporter.umd.js"></script>

<!-- 或从unpkg CDN引用 -->
<script src="https://unpkg.com/pptx-exporter@latest/dist/browser/pptx-exporter.umd.js"></script>
```

#### 浏览器专用方法

在浏览器环境中，PPTXExporter 提供了额外的便捷方法：

```javascript
const exporter = new PPTXExporter(pptData);

// 下载文件到本地
await exporter.downloadFile('presentation.pptx', true); // 第二个参数为是否压缩

// 在新标签页中预览
await exporter.openInNewTab();

// 智能导出（浏览器环境下返回Blob）
const result = await exporter.smartExport();
```

#### 开发和测试

```bash
# 构建浏览器版本
npm run build:browser

# 启动开发服务器测试浏览器版本
npm run dev:browser
```

### 作为CLI工具使用

#### 全局安装

```bash
# 从npm安装
npm install -g pptx-exporter

# 或从Git仓库安装
npm install -g git+https://gitee.com/devoink/pptx-exporter.git
```

#### 基本用法

```bash
# 基本导出
pptx-exporter data.json

# 指定输出文件
pptx-exporter data.json presentation.pptx

# 启用压缩
pptx-exporter data.json presentation.pptx --compression

# 显示详细信息
pptx-exporter data.json presentation.pptx --verbose

# 组合使用
pptx-exporter data.json presentation.pptx --compression --verbose
```

#### CLI选项

- `-c, --compression`: 启用压缩（减小文件大小）
- `-v, --verbose`: 显示详细信息
- `-h, --help`: 显示帮助信息

## 环境检测与兼容性

PPTX Exporter 会自动检测运行环境并确保导出方法的兼容性：

### 支持的环境

- **Node.js** - 支持 Buffer、ArrayBuffer、Uint8Array
- **浏览器** - 支持 Blob、ArrayBuffer、Uint8Array
- **Deno** - 支持 Blob、ArrayBuffer、Uint8Array
- **Bun** - 支持 Buffer、ArrayBuffer、Uint8Array

### 环境检测方法

```typescript
const exporter = new PPTXExporter(pptData);

// 获取当前环境
const environment = exporter.getEnvironment(); // 'node' | 'browser' | 'deno' | 'bun' | 'unknown'

// 获取支持的导出格式
const formats = exporter.getSupportedFormats(); // ['nodebuffer', 'blob', 'arraybuffer', ...]
```

### 智能导出

```typescript
// 根据环境自动选择最佳导出格式
const result = await exporter.smartExport();
```

## 导出格式支持

根据 [PptxGenJS 官方文档](https://gitbrent.github.io/PptxGenJS/docs/usage-saving/)，支持以下导出格式：

### 文件导出

```typescript
// 导出为文件（支持压缩）
await exporter.toFile('presentation.pptx', true); // 启用压缩
```

### 内存导出

```typescript
// 导出为 Buffer (Node.js)
const buffer = await exporter.toBuffer();

// 导出为 Blob (浏览器)
const blob = await exporter.toBlob(true); // 启用压缩

// 导出为 Base64 字符串
const base64 = await exporter.toBase64(true); // 启用压缩

// 导出为 ArrayBuffer
const arrayBuffer = await exporter.toArrayBuffer(true); // 启用压缩

// 导出为 BinaryString
const binaryString = await exporter.toBinaryString(true); // 启用压缩

// 导出为 Uint8Array
const uint8Array = await exporter.toUint8Array(true); // 启用压缩
```

### 流式导出 (Node.js)

```typescript
// 导出为流，适用于 HTTP 响应
const stream = await exporter.toStream();

// Express.js 示例
app.get('/download', async (req, res) => {
  const stream = await exporter.toStream();
  res.writeHead(200, {
    'Content-disposition': 'attachment;filename=presentation.pptx',
    'Content-Length': stream.length,
  });
  res.end(new Buffer(stream, 'binary'));
});
```

### 通用导出方法

```typescript
// 使用通用方法指定输出格式
const result = await exporter.export({
  outputType: 'base64',
  compression: true,
});
```

## 输出格式说明

| 格式           | 描述              | 适用场景                    | 环境支持     |
| -------------- | ----------------- | --------------------------- | ------------ |
| `blob`         | 浏览器默认格式    | 浏览器环境下载              | 浏览器、Deno |
| `arraybuffer`  | 二进制数组缓冲区  | WebAssembly 或二进制工具    | 所有环境     |
| `base64`       | Base64 编码字符串 | API 上传（如 Google Drive） | 所有环境     |
| `nodebuffer`   | Node.js Buffer    | Node.js 文件写入            | Node.js、Bun |
| `binarystring` | 二进制字符串      | 流式传输                    | 所有环境     |
| `uint8array`   | 无符号8位整数数组 | 现代 JavaScript 环境        | 所有环境     |

## 压缩选项

所有导出方法都支持压缩选项，可以显著减少文件大小：

```typescript
// 启用压缩（导出时间更长但文件更小）
const compressedBuffer = await exporter.toBuffer();
const compressedBase64 = await exporter.toBase64(true);
```

## 错误处理

PPTX Exporter 会在不兼容的环境中抛出有意义的错误信息：

```typescript
const exporter = new PPTXExporter(pptData);

try {
  // 在浏览器环境中尝试使用 Buffer
  const buffer = await exporter.toBuffer();
} catch (error) {
  console.error(error.message);
  // 输出: "Buffer not supported in browser environment. Use toArrayBuffer() or toUint8Array() instead."

  // 使用兼容的替代方案
  const arrayBuffer = await exporter.toArrayBuffer();
}

try {
  // 在 Node.js 环境中尝试使用 Blob
  const blob = await exporter.toBlob(true); // 启用压缩
} catch (error) {
  console.error(error.message);
  // 输出: "Blob not supported in node environment. Use toBuffer() or toArrayBuffer() instead."

  // 使用兼容的替代方案
  const buffer = await exporter.toBuffer();
}
```

## 配置选项

```typescript
const exporter = new PPTXExporter(pptData, {
  masterOverwrite: false, // 是否覆盖母版
  ignoreMedia: false, // 是否忽略媒体文件
  onProgress: progress => {
    // 进度追踪回调函数
    console.log(
      `${progress.current}/${progress.total} 张幻灯片 - ${progress.percentage}%`
    );
  },
});
```

## 导出进度追踪

PPTX Exporter 支持实时追踪导出进度，特别适用于大型演示文稿的导出：

### 基本用法

```typescript
import { PPTXExporter } from 'pptx-exporter';

const pptData = {
  // 你的演示文稿数据
};

// 创建带进度追踪的导出器
const exporter = new PPTXExporter(pptData, {
  onProgress: progress => {
    const { current, total, percentage, completed } = progress;
    console.log(`${current}/${total} 张幻灯片 - ${percentage}%`);
  },
});

// 导出时会自动触发进度回调
await exporter.toFile('presentation.pptx');
```

### 进度信息说明

进度回调函数会接收包含以下信息的对象：

```typescript
interface ProgressInfo {
  current: number; // 当前处理的幻灯片数
  total: number; // 总幻灯片数
  percentage: number; // 完成百分比 (0-100)
  completed: boolean; // 是否完成
}
```

### 进度说明

- **current**: 当前正在处理的幻灯片编号
- **total**: 总幻灯片数量
- **percentage**: 完成百分比 (0-100)
- **completed**: 是否完成整个导出过程

进度追踪会在处理每张幻灯片时触发，提供实时的导出状态信息。

### 实用的进度条示例

```typescript
function createProgressBar(progress) {
  const { current, total, percentage, completed } = progress;

  // 创建可视化进度条
  const barLength = 30;
  const filledLength = Math.round((percentage / 100) * barLength);
  const bar = '█'.repeat(filledLength) + '░'.repeat(barLength - filledLength);

  // 清除当前行并显示新进度
  process.stdout.clearLine(0);
  process.stdout.cursorTo(0);
  process.stdout.write(
    `[${bar}] ${percentage}% | ${current}/${total} 张幻灯片`
  );

  if (completed) {
    console.log(' | ✅ 完成');
  }
}

const exporter = new PPTXExporter(pptData, {
  onProgress: createProgressBar,
});
```

### 浏览器环境中的进度追踪

```html
<!DOCTYPE html>
<html>
  <head>
    <title>导出进度示例</title>
  </head>
  <body>
    <button onclick="exportWithProgress()">导出PPTX</button>
    <div id="progress-container" style="display: none;">
      <div
        id="progress-bar"
        style="width: 0%; height: 20px; background: #4caf50;"
      ></div>
      <div id="progress-text">0%</div>
    </div>

    <script src="./dist/browser/pptx-exporter.umd.js"></script>
    <script>
      function updateProgress(progress) {
        const container = document.getElementById('progress-container');
        const bar = document.getElementById('progress-bar');
        const text = document.getElementById('progress-text');

        container.style.display = 'block';
        bar.style.width = progress.percentage + '%';
        text.textContent = `${progress.percentage}% - ${progress.message}`;

        if (progress.stage === 'complete') {
          setTimeout(() => {
            container.style.display = 'none';
          }, 2000);
        }
      }

      async function exportWithProgress() {
        const pptData = {
          title: '我的演示文稿',
          slides: [
            /* 你的数据 */
          ],
        };

        const exporter = new PPTXExporter(pptData, {
          onProgress: updateProgress,
        });

        await exporter.downloadFile('presentation.pptx');
      }
    </script>
  </body>
</html>
```

### CLI 进度追踪

使用 `-V` 参数启用详细模式和进度显示：

```bash
# 位置参数方式
pptx-exporter input.json output.pptx -V
pptx-exporter input.json output.pptx -c -V

# 命名参数方式
pptx-exporter -i input.json -o output.pptx -V
pptx-exporter -i input.json -o output.pptx -c -V
```

输出示例：

```
🔍 开始处理...
📁 输入文件: input.json
📄 输出文件: output.pptx
🗜️  压缩: 启用
📊 开始导出...
[██████████████████████████████] 100% | 36/36 张幻灯片 | ✅ 完成
✅ PPTX 文件已成功导出到: output.pptx
```

### PHP 进度追踪

```php
$exporter = new PPTXExporter();

$result = $exporter->exportToFile($pptData, './output.pptx', true, function($progress) {
    $barLength = 30;
    $filledLength = round(($progress['percentage'] / 100) * $barLength);
    $bar = str_repeat('█', $filledLength) . str_repeat('░', $barLength - $filledLength);

    echo "\r[{$bar}] {$progress['percentage']}% | {$progress['current']}/{$progress['total']} 张幻灯片";

    if ($progress['completed']) {
        echo " | ✅ 完成\n";
    }
});
```

### Node.js Web服务器中的进度追踪

```javascript
// Express.js 示例
app.post('/export', async (req, res) => {
  const { pptData } = req.body;

  // 使用服务器发送事件(SSE)推送进度
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    Connection: 'keep-alive',
  });

  const exporter = new PPTXExporter(pptData, {
    onProgress: progress => {
      res.write(`data: ${JSON.stringify(progress)}\n\n`);
    },
  });

  try {
    const buffer = await exporter.toBuffer();
    res.write(
      `data: ${JSON.stringify({ type: 'complete', buffer: buffer.toString('base64') })}\n\n`
    );
    res.end();
  } catch (error) {
    res.write(
      `data: ${JSON.stringify({ type: 'error', message: error.message })}\n\n`
    );
    res.end();
  }
});
```

## 类型定义

完整的 TypeScript 类型定义请参考 `src/types/slides.ts` 文件。

## 🔗 与 PPTist 集成

### PPTist 数据格式支持

本项目完全兼容 PPTist 的数据格式，可以直接使用 PPTist 导出的 JSON 数据：

```typescript
import { PPTXExporter } from 'pptx-exporter';

// 从 PPTist 导出的数据
const pptistData = {
  title: 'PPTist 演示文稿',
  width: 960,
  height: 540,
  theme: {
    backgroundColor: '#ffffff',
  },
  slides: [
    {
      elements: [
        {
          type: 'text',
          content: '<p>PPTist 文本内容</p>',
          x: 100,
          y: 100,
          width: 760,
          height: 80,
          fontSize: 32,
          fontWeight: 'bold',
          color: '#333333',
          textAlign: 'center',
        },
        {
          type: 'shape',
          shape: 'rect',
          x: 200,
          y: 200,
          width: 200,
          height: 100,
          fill: '#ff6b6b',
          outline: {
            color: '#333333',
            width: 2,
          },
        },
      ],
    },
  ],
};

const exporter = new PPTXExporter(pptistData);
await exporter.toFile('pptist-presentation.pptx');
```

### 在 PPTist 项目中使用

如果你正在开发基于 PPTist 的应用，可以这样集成：

```typescript
// 在 PPTist 的导出功能中添加
import { PPTXExporter } from 'pptx-exporter';

// 获取当前 PPTist 的演示文稿数据
const currentPresentationData = getCurrentPresentationData();

// 创建导出器并导出
const exporter = new PPTXExporter(currentPresentationData);

// 提供多种导出选项
const exportOptions = {
  '下载 PPTX': () => exporter.downloadFile('presentation.pptx'),
  '导出为 Base64': () => exporter.toBase64(),
  '导出为 Buffer': () => exporter.toBuffer(),
};
```

### 数据格式转换

PPTX Exporter 会自动处理 PPTist 特有的数据格式：

- **文本内容**: 自动解析 HTML 标签
- **形状元素**: 支持 PPTist 的所有形状类型
- **图片元素**: 支持 Base64 和 URL 图片
- **动画效果**: 转换为 PPTX 兼容的动画
- **主题设置**: 保持 PPTist 的主题配置

## 🐘 PHP 集成

### 快速开始

1. **安装 pptx-exporter**：

   ```bash
   npm install -g pptx-exporter
   ```

2. **在PHP中使用**：

   ```php
   <?php
   require_once 'examples/php-integration.php';

   $exporter = new PPTXExporter();

   // PPTist 格式的数据
   $pptData = [
       'title' => '我的演示文稿',
       'width' => 960,
       'height' => 540,
       'slides' => [
           [
               'elements' => [
                   [
                       'type' => 'text',
                       'content' => '<p>欢迎使用 PPTX Exporter</p>',
                       'x' => 100,
                       'y' => 100,
                       'width' => 760,
                       'height' => 80,
                       'fontSize' => 32,
                       'color' => '#333333',
                   ]
               ]
           ]
       ]
   ];

   // 导出为文件
   $result = $exporter->exportToFile($pptData, 'presentation.pptx', true);
   if ($result['success']) {
       echo "导出成功！";
   }

   // 导出为Base64
   $base64Result = $exporter->exportToBase64($pptData, true);
   if ($base64Result['success']) {
       $base64Data = $base64Result['base64'];
       // 可以用于API返回或数据库存储
   }
   ?>
   ```

### 主要功能

- **自动安装检查**: 自动检查并安装 pptx-exporter
- **多种导出格式**: 支持文件、Base64、Buffer、智能导出
- **压缩支持**: 所有导出方法都支持压缩选项
- **环境检测**: 自动检测Node.js环境和支持的格式
- **错误处理**: 完整的错误信息和调试支持

### 方法说明

| 方法               | 描述                   | 参数                                  |
| ------------------ | ---------------------- | ------------------------------------- |
| `exportToFile()`   | 导出为PPTX文件         | `$pptData, $outputFile, $compression` |
| `exportToBase64()` | 导出为Base64字符串     | `$pptData, $compression`              |
| `exportToBuffer()` | 导出为Buffer(Base64)   | `$pptData, $compression`              |
| `smartExport()`    | 智能导出(自动选择格式) | `$pptData, $compression`              |
| `getEnvironment()` | 获取环境信息           | 无                                    |
| `isInstalled()`    | 检查是否已安装         | 无                                    |
| `install()`        | 安装pptx-exporter      | 无                                    |

### 测试示例

运行PHP集成测试：

```bash
php examples/php-integration.php
```

## 📄 许可证

本项目基于 MIT 许可证开源。

**注意**: 本项目基于 [PPTist](https://github.com/pipipi-pikachu/PPTist) 项目开发，PPTist 使用 AGPL-3.0 许可证。如果你在商业项目中使用 PPTist 相关功能，请确保遵守相应的许可证要求。
