diff --git a/packages/cpro/readme.md b/packages/cpro/readme.md index d83efb676b..06f1caa963 100644 --- a/packages/cpro/readme.md +++ b/packages/cpro/readme.md @@ -107,7 +107,7 @@ emcc -g main.cpp -o main.html 如果需要调用一个在 C 语言自定义的函数,你可以使用 Emscripten 中的 ccall() 函数,以及 EMSCRIPTEN_KEEPALIVE 声明 -> Emscripten 会消除未从编译代码中调用的函数的死代码。虽然这确实最大限度地减少了代码大小,但它可以删除您计划自己调用的函数(在已编译的代码之外)。比如通过 EMSCRIPTEN_KEEPALIVE 和 EXPORTED_FUNCTIONS 去指定需要导出的函数。EMSCRIPTEN_KEEPALIVE 的作用是告诉编译器和链接器保留符号并将其导出,就像将其添加到 EXPORTED_FUNCTIONS 中一样。 +> Emscripten 会消除未从编译代码中调用的函数的死代码。虽然这确实最大限度地减少了代码大小,但它可以删除您计划自己调用的函数(在已编译的代码之外)。比如通过 EMSCRIPTEN_KEEPALIVE 和 EXPORTED_FUNCTIONS 去指定需要导出的函数。EMSCRIPTEN_KEEPALIVE 的作用是告诉编译器和链接器保留符号并将其导出,就像将其添加到 EXPORTED_FUNCTIONS 中一样。 默认情况下,Emscripten 生成的代码只会调用 main() 函数,其他的函数将被视为无用代码。在一个函数名之前添加 EMSCRIPTEN_KEEPALIVE 能够防止这样的事情发生。你需要导入 emscripten.h 库来使用 EMSCRIPTEN_KEEPALIVE。 @@ -129,25 +129,24 @@ EXPORTED_FUNCTIONS: emcc -sEXPORTED_FUNCTIONS=_main,_my_func ... ``` -> 如果您有 main() 函数,则_main 应该位于导出列表中,如该示例所示。否则,它将作为死代码被删除;默认情况下没有特殊的逻辑来保持 main() 的活动。 +> 如果您有 main() 函数,则\_main 应该位于导出列表中,如该示例所示。否则,它将作为死代码被删除;默认情况下没有特殊的逻辑来保持 main() 的活动。 ```html - - - + ``` + [](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html) ```sh @@ -179,27 +178,25 @@ emcc hello.c -o hello.js -s EXPORTED_RUNTIME_METHODS=['cwrap','ccall'] 接下来,你可以在 JavaScript 中这样使用这些导出的方法: ```html - - + - + Hello Emscripten - - + + - + - ``` 在这个例子中,我们通过 Module.cwrap 方法创建了一个 JavaScript 包装函数 sayHello,并调用了它。由于 say_hello 是一个无返回值且无参数的 C 函数,因此我们在 cwrap 中传入了 null 和一个空数组 []。 @@ -224,7 +221,7 @@ Module.cwrap('function_name', 'return_type', ['arg_type1', 'arg_type2', ...]) #### 2. ccall: - 用于直接调用编译后的 WebAssembly 函数。 -语法: + 语法: ```js Module.ccall('function_name', 'return_type', ['arg_type1', 'arg_type2', ...], [arg1, arg2, ...]) @@ -233,29 +230,29 @@ Module.ccall('function_name', 'return_type', ['arg_type1', 'arg_type2', ...], [a #### 3. UTF8ToString: - 将指向 UTF-8 编码字符串的指针转换为 JavaScript 字符串。 -语法: + 语法: ```js -UTF8ToString(ptr) +UTF8ToString(ptr); ``` #### 4. allocate: - 在 Emscripten 堆中分配内存。 -语法: + 语法: ```js -Module._malloc(size) +Module._malloc(size); ``` #### 5. HEAP8 / HEAP16 / HEAP32 / HEAPU8 / HEAPU16 / HEAPU32 / HEAPF32 / HEAPF64: - 直接访问 Emscripten 堆内存的视图,允许读取和写入不同类型的数据。 -例如:Module.HEAP32[ptr >> 2] 读取 ptr 位置的 32 位整数。 + 例如:Module.HEAP32[ptr >> 2] 读取 ptr 位置的 32 位整数。 Emscripten 提供了一系列 API 函数和视图,用于直接访问和操作 WebAssembly 内存。这些 API 和视图在处理复杂的数据结构、字符串、数组等方面非常有用。下面是 allocate 和各种 HEAP 视图的用法。 -allocate 函数用于在 Emscripten 堆中分配内存。该函数在较新的 Emscripten 版本中已经不推荐使用,通常推荐使用 _malloc 代替。 +allocate 函数用于在 Emscripten 堆中分配内存。该函数在较新的 Emscripten 版本中已经不推荐使用,通常推荐使用 \_malloc 代替。 ```js // 分配 1024 字节的内存 @@ -277,7 +274,7 @@ Emscripten 提供了多个 HEAP 视图,用于访问 WebAssembly 内存中的 - HEAPF32: 32-bit floating point (Float32Array) - HEAPF64: 64-bit floating point (Float64Array) -以下是一个完整的示例,展示如何使用 _malloc 分配内存,并使用 HEAPU8 视图操作数据: +以下是一个完整的示例,展示如何使用 \_malloc 分配内存,并使用 HEAPU8 视图操作数据: ```c++ #include @@ -298,34 +295,34 @@ emcc memory.c -o memory.js -s EXPORTED_RUNTIME_METHODS=['_malloc', '_free', 'cca JavaScript 代码 ```html - + - + Emscripten Memory Example - - + + - + ``` @@ -356,41 +353,39 @@ emcc array.c -o array.js -s EXPORTED_RUNTIME_METHODS=['_malloc', '_free', 'ccall JavaScript 代码 ```html - - + - + Emscripten Array Example - - + + - + - ``` 在这个示例中,我们分配了一块足够大的内存以存储一个整数数组,并使用 HEAP32 视图将 JavaScript 数组复制到 Emscripten 堆中。然后,我们调用 C 函数修改数组,并使用 HEAP32 视图读取修改后的数组。 @@ -402,16 +397,16 @@ JavaScript 代码 语法: ```js -Module.addFunction(func, 'sig') +Module.addFunction(func, 'sig'); ``` #### 7. removeFunction: - 从 WebAssembly 表中移除函数指针。 -语法: + 语法: ```js -Module.removeFunction(func_ptr) +Module.removeFunction(func_ptr); ``` 下面是一个完整的示例,演示如何使用 addFunction 和 removeFunction: @@ -443,44 +438,42 @@ emcc call_js.c -o call_js.js -s EXPORTED_RUNTIME_METHODS=['addFunction','removeF 在 JavaScript 中调用这个函数: ```html - - + - + Emscripten addFunction Example - - + + - + - ``` -在这个示例中,我们首先定义了一个 JavaScript 函数 add,并使用 Module.addFunction 将其添加到 WebAssembly 表中。然后,我们调用 WebAssembly 函数 _call_js_function,传入函数指针和参数。最后,我们使用 Module.removeFunction 从 WebAssembly 表中移除了函数指针。 +在这个示例中,我们首先定义了一个 JavaScript 函数 add,并使用 Module.addFunction 将其添加到 WebAssembly 表中。然后,我们调用 WebAssembly 函数 \_call_js_function,传入函数指针和参数。最后,我们使用 Module.removeFunction 从 WebAssembly 表中移除了函数指针。 #### 8. getValue 和 setValue: - 用于读取和写入 Emscripten 堆内存中的值。 -语法: + 语法: ```js Module.getValue(ptr, type) 和 Module.setValue(ptr, value, type) @@ -495,7 +488,7 @@ var value = Module.getValue(ptr, type); ``` ptr 是内存地址(指针)。 -type 是值的类型,可以是 'i8', 'i16', 'i32', 'i64', 'float', 'double', 'i8*', 'i16*', 'i32*' 等。 +type 是值的类型,可以是 'i8', 'i16', 'i32', 'i64', 'float', 'double', 'i8*', 'i16*', 'i32\*' 等。 setValue 用于向指定内存地址写入值。其语法如下: @@ -503,7 +496,7 @@ Module.setValue(ptr, value, type); ptr 是内存地址(指针)。 value 是要写入的值。 -type 是值的类型,可以是 'i8', 'i16', 'i32', 'i64', 'float', 'double', 'i8*', 'i16*', 'i32*' 等。 +type 是值的类型,可以是 'i8', 'i16', 'i32', 'i64', 'float', 'double', 'i8*', 'i16*', 'i32\*' 等。 下面是一个示例,展示如何使用 getValue 和 setValue 读取和写入内存中的值。 @@ -603,43 +596,43 @@ emcc struct.c -o struct.js -s EXPORTED_RUNTIME_METHODS=['getValue', 'setValue', JavaScript 代码 ```html - + - + Emscripten Struct Example - - + + - + ``` @@ -648,7 +641,7 @@ JavaScript 代码 #### 9. FS (File System API): - 用于在 Emscripten 虚拟文件系统中操作文件。 -常用方法包括:FS.createDataFile, FS.readFile, FS.writeFile, FS.unlink 等。 + 常用方法包括:FS.createDataFile, FS.readFile, FS.writeFile, FS.unlink 等。 #### 10. stackSave, stackRestore, stackAlloc: @@ -675,22 +668,22 @@ emcc hello.c -o hello.js -s EXPORTED_RUNTIME_METHODS=['ccall','UTF8ToString'] 在 JavaScript 中调用这个函数: ```html - + - + Hello Emscripten - - + + - + ``` @@ -703,15 +696,14 @@ emcc hello.c -o hello.js -s EXPORTED_RUNTIME_METHODS=['ccall','UTF8ToString'] ```html - + ``` - ### Embind https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html?highlight=emscripten_bindings @@ -732,11 +724,13 @@ EMSCRIPTEN_BINDINGS(my_module) { function("lerp", &lerp); } ``` + 为了使用 `embin` 编译上面的示例,我们使用 `bind` 选项调用 `emcc:` ```sh emcc -lembind -o main.js main.cpp ``` + 生成的`main.js`文件可以作为节点模块或通过 ` @@ -760,6 +754,7 @@ emcc -lembind -o main.js main.cpp ```sh emcc -lembind -o library.js -Wl,--whole-archive library.a -Wl,--no-whole-archive ``` + 向 JavaScript 公开类需要更复杂的绑定语句。例如: ```cpp @@ -798,28 +793,30 @@ EMSCRIPTEN_BINDINGS(my_class_example) { } ``` -绑定块定义了临时 class_ 对象上的成员函数调用链(在 Boost.Python 中使用了相同的样式)。这些函数注册类、其 constructor() 、成员 function() 、class_function() (静态)和 property() . +绑定块定义了临时 class\_ 对象上的成员函数调用链(在 Boost.Python 中使用了相同的样式)。这些函数注册类、其 constructor() 、成员 function() 、class_function() (静态)和 property() . 然后可以在 JavaScript 中创建和使用 的 MyClass 实例,如下所示: ```js -var instance = new Module.MyClass(10, "hello"); +var instance = new Module.MyClass(10, 'hello'); instance.incrementX(); instance.x; // 11 instance.x = 20; // 20 Module.MyClass.getStringFromInstance(instance); // "hello" instance.delete(); ``` + 为了防止闭包编译器重命名上述示例代码中的符号,需要按如下方式重写: ```js -var instance = new Module["MyClass"](10, "hello"); -instance["incrementX"](); -instance["x"]; // 11 -instance["x"] = 20; // 20 -Module["MyClass"]["getStringFromInstance"](instance); // "hello" +var instance = new Module['MyClass'](10, 'hello'); +instance['incrementX'](); +instance['x']; // 11 +instance['x'] = 20; // 20 +Module['MyClass']['getStringFromInstance'](instance); // "hello" instance.delete(); ``` + 请注意,只有优化程序看到的代码才需要这样做,例如,如 in --pre-js 或 上所述,或在 EM_ASM 或 EM_JS --post-js .对于未通过闭包编译器优化的其他代码,您无需进行此类更改。如果您在构建时没有 --closure 1 启用闭包编译器,则也不需要它。 ### clone @@ -832,16 +829,16 @@ clone() JavaScript 方法返回一个新的句柄。它最终还必须与 delete ```js async function myLongRunningProcess(x, milliseconds) { - // sleep for the specified number of milliseconds - await new Promise(resolve => setTimeout(resolve, milliseconds)); - x.method(); - x.delete(); + // sleep for the specified number of milliseconds + await new Promise((resolve) => setTimeout(resolve, milliseconds)); + x.method(); + x.delete(); } -const y = new Module.MyClass; // refCount = 1 +const y = new Module.MyClass(); // refCount = 1 myLongRunningProcess(y.clone(), 5000); // refCount = 2 myLongRunningProcess(y.clone(), 3000); // refCount = 3 -y.delete(); // refCount = 2 +y.delete(); // refCount = 2 // (after 3000ms) refCount = 1 // (after 5000ms) refCount = 0 -> object is deleted @@ -858,10 +855,10 @@ emcc -lembind -o main.js main.cpp -sEXPORTED_FUNCTIONS=_quick_sort,_main -sEXPOR ### 基于内存的方式 1. 声明和分配内存 -在 WebAssembly 中,内存是通过 WebAssembly.Memory 对象管理的。Emscripten 通常会自动处理内存分配,但你也可以手动管理。 + 在 WebAssembly 中,内存是通过 WebAssembly.Memory 对象管理的。Emscripten 通常会自动处理内存分配,但你也可以手动管理。 2. 在 C/C++ 中访问内存 -在 C/C++ 代码中,你可以通过指针直接访问和操作内存。 + 在 C/C++ 代码中,你可以通过指针直接访问和操作内存。 ```c++ #include @@ -905,34 +902,33 @@ Emscripten 会为你提供一个 HEAP 对象,可以用来直接访问 WebAssem - HEAPF64: 64-bit floating-point array ```html - + - + Memory Access Example - - + + - + - ``` 5. 更复杂的数据类型 @@ -974,41 +970,39 @@ emcc struct_example.cpp -o struct_example.js -s EXPORTED_FUNCTIONS='["_set_struc JS 代码: ```html - - + - + Struct Memory Access Example - - + + - + - ``` 通过这些步骤,你可以在 JavaScript 和 C/C++ 之间通过共享内存进行高效的通信。这种方法特别适合需要频繁交互或传递大量数据的场景。 @@ -1029,6 +1023,7 @@ JS 代码: - 频繁的内存访问:尽管共享内存访问比函数调用更快,但频繁的内存读写仍可能带来性能开销。应尽量减少不必要的内存操作。 - 内存分配和释放:频繁的内存分配和释放可能导致内存碎片,从而影响性能。 + 4. 内存管理 - 手动内存管理:需要手动管理内存的分配和释放。忘记释放分配的内存可能导致内存泄漏。 @@ -1041,8 +1036,8 @@ JS 代码: 6. 数据转换 - 字符串处理:C/C++ 中的字符串和 JavaScript 中的字符串处理方式不同。需要进行适当的转换。 -从 C/C++ 到 JavaScript:使用 UTF8ToString。 -从 JavaScript 到 C/C++:使用 stringToUTF8。 + 从 C/C++ 到 JavaScript:使用 UTF8ToString。 + 从 JavaScript 到 C/C++:使用 stringToUTF8。 7. 并发和线程 @@ -1090,39 +1085,38 @@ extern "C" { JavaScript 代码(改进内存对齐和字符串处理) ```html - + - + Memory Access Example - - + + - + - ``` 通过注意上述限制和改进建议,你可以更高效和安全地在 JavaScript 和 WebAssembly(C/C++)之间通过共享内存进行通信。 @@ -1144,7 +1138,7 @@ WebAssembly 目前支持多线程,通过 SharedArrayBuffer 和 Web Workers 实 示例项目 1. 创建一个 C++ 文件 -假设你的 C++ 文件名为 threads_example.cpp。 + 假设你的 C++ 文件名为 threads_example.cpp。 ```c++ #include @@ -1170,32 +1164,31 @@ extern "C" { ``` 2. 编译 C++ 文件 -使用 Emscripten 编译文件,并启用线程支持。 + 使用 Emscripten 编译文件,并启用线程支持。 ```sh emcc threads_example.cpp -o threads_example.js -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=4 -s EXPORTED_FUNCTIONS='["_create_thread"]' -s ALLOW_MEMORY_GROWTH=1 ``` 3. 创建 HTML 文件 -创建一个 HTML 文件以加载和运行编译后的 WebAssembly 模块。 + 创建一个 HTML 文件以加载和运行编译后的 WebAssembly 模块。 ```html - + - + WebAssembly Multithreading Example - - + + - + - ``` 说明: @@ -1209,7 +1202,7 @@ C++ 代码 JavaScript 代码 - Module.onRuntimeInitialized:等待 WebAssembly 模块初始化完成。 -- Module._create_thread:调用导出的 create_thread 函数创建新线程。 +- Module.\_create_thread:调用导出的 create_thread 函数创建新线程。 多线程注意事项 @@ -1282,6 +1275,7 @@ extern "C" { ``` + 通过 Emscripten 和 WebAssembly,你可以利用多线程来提高性能和响应能力。确保处理好线程安全和同步问题,以避免数据竞争和其他多线程相关的问题。 以下是一些关键点: @@ -1417,29 +1411,27 @@ extern "C" { 通过以下 JavaScript 代码来初始化线程池并添加任务: ```html - - + - + WebAssembly Multithreading Example - - + + - + - ``` 通过注意上述多线程编程中的注意事项,可以有效地利用 WebAssembly 和 Emscripten 提供的多线程功能,实现高性能和高效的并发处理。确保正确处理数据竞争、同步和资源管理,以避免常见的多线程问题。 diff --git a/packages/debug/koaStatic/index.ts b/packages/debug/koaStatic/index.ts index 5deb0bbe6e..60ee374093 100644 --- a/packages/debug/koaStatic/index.ts +++ b/packages/debug/koaStatic/index.ts @@ -9,9 +9,9 @@ const __dirname = path.dirname(__filename); const app = new Koa(); -const PORT = 5555 +const PORT = 5555; -const STATIC_DIR = 'dist' +const STATIC_DIR = 'dist'; // Serve static files from the 'dist' directory app.use(serve(path.join(__dirname, STATIC_DIR))); @@ -20,4 +20,3 @@ app.use(serve(path.join(__dirname, STATIC_DIR))); app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); }); - diff --git a/packages/debug/nginxconf/readme.md b/packages/debug/nginxconf/readme.md index 3f4e55408a..1b04e80766 100644 --- a/packages/debug/nginxconf/readme.md +++ b/packages/debug/nginxconf/readme.md @@ -1,4 +1,3 @@ - 1. 使用命令行参数指定配置文件路径 ```sh @@ -12,7 +11,9 @@ nginx -c /path/to/your/nginx.conf ```sh nginx -t -c /path/to/your/nginx.conf ``` + 重启 + ```sh nginx -s reload ``` @@ -55,13 +56,17 @@ brew services restart nginx 你也可以直接使用 Nginx 的-s 参数来停止服务。有两种停止方式: 快速停止(不等待处理完当前请求): + ```sh sudo nginx -s stop ``` + 优雅停止(等待处理完当前请求后再停止): + ```sh sudo nginx -s quit ``` + 4. 关闭 进入 Nginx 安装目录的 sbin 文件夹(如果尚未进入)。 @@ -70,9 +75,11 @@ sudo nginx -s quit 在某些情况下,你可能需要手动停止 Nginx 服务。这通常涉及到找到 Nginx 的主进程号(PID),并使用 kill 命令发送相应的信号来停止进程。 查找 Nginx 主进程的 PID:可以使用 ps 命令结合 grep 来查找,如: + ```sh ps -ef | grep nginx ``` + 发送停止信号:根据找到的 PID,使用 kill 命令发送 TERM(快速停止)或 INT(优雅停止)信号。例如,kill -TERM 或 kill -INT 。此外,kill -HUP 也可以用于平滑重启 Nginx,但这实际上是发送了一个挂起信号,而不是停止信号。 使用 brew 服务命令: diff --git a/packages/docs/.vitepress/langs/cn/index.ts b/packages/docs/.vitepress/langs/cn/index.ts index 17cfd98c9b..038b88b95e 100644 --- a/packages/docs/.vitepress/langs/cn/index.ts +++ b/packages/docs/.vitepress/langs/cn/index.ts @@ -142,6 +142,14 @@ const themeCnConfig: DefaultTheme.Config = { text: '可视化渲染引擎', link: '/cn/src/article/visual.md', }, + { + text: 'web 端文档预览方案', + link: '/cn/src/article/docPreview.md', + }, + { + text: '实现自适应码率 Web 视频加密播放:前后端的挑战与解决方案', + link: '/cn/src/article/video.md', + }, ], }, ], diff --git a/packages/docs/assets/article/docPreview/ali_doc.webp b/packages/docs/assets/article/docPreview/ali_doc.webp new file mode 100644 index 0000000000..eeb0a272f3 Binary files /dev/null and b/packages/docs/assets/article/docPreview/ali_doc.webp differ diff --git a/packages/docs/assets/article/docPreview/firefox_pdf.webp b/packages/docs/assets/article/docPreview/firefox_pdf.webp new file mode 100644 index 0000000000..0e88d14b7b Binary files /dev/null and b/packages/docs/assets/article/docPreview/firefox_pdf.webp differ diff --git a/packages/docs/assets/article/docPreview/google_doc_view.webp b/packages/docs/assets/article/docPreview/google_doc_view.webp new file mode 100644 index 0000000000..1110e795dd Binary files /dev/null and b/packages/docs/assets/article/docPreview/google_doc_view.webp differ diff --git a/packages/docs/assets/article/docPreview/kkfile.webp b/packages/docs/assets/article/docPreview/kkfile.webp new file mode 100644 index 0000000000..81fbbb5beb Binary files /dev/null and b/packages/docs/assets/article/docPreview/kkfile.webp differ diff --git a/packages/docs/assets/article/docPreview/kkfile_des.webp b/packages/docs/assets/article/docPreview/kkfile_des.webp new file mode 100644 index 0000000000..be09d2c3da Binary files /dev/null and b/packages/docs/assets/article/docPreview/kkfile_des.webp differ diff --git a/packages/docs/assets/article/docPreview/kkfile_doc.webp b/packages/docs/assets/article/docPreview/kkfile_doc.webp new file mode 100644 index 0000000000..d962f41bec Binary files /dev/null and b/packages/docs/assets/article/docPreview/kkfile_doc.webp differ diff --git a/packages/docs/assets/article/docPreview/kkfile_output.webp b/packages/docs/assets/article/docPreview/kkfile_output.webp new file mode 100644 index 0000000000..45b774e157 Binary files /dev/null and b/packages/docs/assets/article/docPreview/kkfile_output.webp differ diff --git a/packages/docs/assets/article/docPreview/mdn_pdf.webp b/packages/docs/assets/article/docPreview/mdn_pdf.webp new file mode 100644 index 0000000000..6ba803f486 Binary files /dev/null and b/packages/docs/assets/article/docPreview/mdn_pdf.webp differ diff --git a/packages/docs/assets/article/docPreview/ms_answer.webp b/packages/docs/assets/article/docPreview/ms_answer.webp new file mode 100644 index 0000000000..2d92dabee5 Binary files /dev/null and b/packages/docs/assets/article/docPreview/ms_answer.webp differ diff --git a/packages/docs/assets/article/docPreview/ms_answer_2.webp b/packages/docs/assets/article/docPreview/ms_answer_2.webp new file mode 100644 index 0000000000..c0ce5e59ef Binary files /dev/null and b/packages/docs/assets/article/docPreview/ms_answer_2.webp differ diff --git a/packages/docs/assets/article/docPreview/ms_excel.webp b/packages/docs/assets/article/docPreview/ms_excel.webp new file mode 100644 index 0000000000..dd29ef3d99 Binary files /dev/null and b/packages/docs/assets/article/docPreview/ms_excel.webp differ diff --git a/packages/docs/assets/article/docPreview/ms_file_not.webp b/packages/docs/assets/article/docPreview/ms_file_not.webp new file mode 100644 index 0000000000..a3912844dd Binary files /dev/null and b/packages/docs/assets/article/docPreview/ms_file_not.webp differ diff --git a/packages/docs/assets/article/docPreview/ms_ppt.webp b/packages/docs/assets/article/docPreview/ms_ppt.webp new file mode 100644 index 0000000000..d3a443daf1 Binary files /dev/null and b/packages/docs/assets/article/docPreview/ms_ppt.webp differ diff --git a/packages/docs/assets/article/docPreview/ms_word.webp b/packages/docs/assets/article/docPreview/ms_word.webp new file mode 100644 index 0000000000..5b04c96c62 Binary files /dev/null and b/packages/docs/assets/article/docPreview/ms_word.webp differ diff --git a/packages/docs/assets/article/docPreview/ow365.webp b/packages/docs/assets/article/docPreview/ow365.webp new file mode 100644 index 0000000000..80d5400e2c Binary files /dev/null and b/packages/docs/assets/article/docPreview/ow365.webp differ diff --git a/packages/docs/assets/article/docPreview/wps_office.webp b/packages/docs/assets/article/docPreview/wps_office.webp new file mode 100644 index 0000000000..dae2ee8489 Binary files /dev/null and b/packages/docs/assets/article/docPreview/wps_office.webp differ diff --git a/packages/docs/assets/article/docPreview/wps_office_price.webp b/packages/docs/assets/article/docPreview/wps_office_price.webp new file mode 100644 index 0000000000..58bc565c1b Binary files /dev/null and b/packages/docs/assets/article/docPreview/wps_office_price.webp differ diff --git a/packages/docs/assets/article/docPreview/xdoc.webp b/packages/docs/assets/article/docPreview/xdoc.webp new file mode 100644 index 0000000000..495397f25e Binary files /dev/null and b/packages/docs/assets/article/docPreview/xdoc.webp differ diff --git a/packages/docs/assets/article/docPreview/xml.webp b/packages/docs/assets/article/docPreview/xml.webp new file mode 100644 index 0000000000..d19c5f5e88 Binary files /dev/null and b/packages/docs/assets/article/docPreview/xml.webp differ diff --git a/packages/docs/assets/article/video/aqiyi_demo.webp b/packages/docs/assets/article/video/aqiyi_demo.webp new file mode 100644 index 0000000000..ba3f6c3e96 Binary files /dev/null and b/packages/docs/assets/article/video/aqiyi_demo.webp differ diff --git a/packages/docs/assets/article/video/bili_demo.webp b/packages/docs/assets/article/video/bili_demo.webp new file mode 100644 index 0000000000..51778f4e13 Binary files /dev/null and b/packages/docs/assets/article/video/bili_demo.webp differ diff --git a/packages/docs/assets/article/video/bili_demo_url.webp b/packages/docs/assets/article/video/bili_demo_url.webp new file mode 100644 index 0000000000..a3a011160b Binary files /dev/null and b/packages/docs/assets/article/video/bili_demo_url.webp differ diff --git a/packages/docs/assets/article/video/bilibili_video_code.webp b/packages/docs/assets/article/video/bilibili_video_code.webp new file mode 100644 index 0000000000..8baf5b006d Binary files /dev/null and b/packages/docs/assets/article/video/bilibili_video_code.webp differ diff --git a/packages/docs/assets/article/video/bilibili_video_m4s.webp b/packages/docs/assets/article/video/bilibili_video_m4s.webp new file mode 100644 index 0000000000..095b94023f Binary files /dev/null and b/packages/docs/assets/article/video/bilibili_video_m4s.webp differ diff --git a/packages/docs/assets/article/video/firefox_support_media.webp b/packages/docs/assets/article/video/firefox_support_media.webp new file mode 100644 index 0000000000..f9ac109d03 Binary files /dev/null and b/packages/docs/assets/article/video/firefox_support_media.webp differ diff --git a/packages/docs/assets/article/video/ms_support.webp b/packages/docs/assets/article/video/ms_support.webp new file mode 100644 index 0000000000..fa495ed3a0 Binary files /dev/null and b/packages/docs/assets/article/video/ms_support.webp differ diff --git a/packages/docs/assets/article/video/red_book.webp b/packages/docs/assets/article/video/red_book.webp new file mode 100644 index 0000000000..aa853cceba Binary files /dev/null and b/packages/docs/assets/article/video/red_book.webp differ diff --git a/packages/docs/assets/article/video/rplayer_demo.webp b/packages/docs/assets/article/video/rplayer_demo.webp new file mode 100644 index 0000000000..e218fcb29a Binary files /dev/null and b/packages/docs/assets/article/video/rplayer_demo.webp differ diff --git a/packages/docs/assets/article/video/safari_support_media.webp b/packages/docs/assets/article/video/safari_support_media.webp new file mode 100644 index 0000000000..dcd17e58bc Binary files /dev/null and b/packages/docs/assets/article/video/safari_support_media.webp differ diff --git a/packages/docs/assets/article/video/tiktik_video_demo.webp b/packages/docs/assets/article/video/tiktik_video_demo.webp new file mode 100644 index 0000000000..b9ce833bdb Binary files /dev/null and b/packages/docs/assets/article/video/tiktik_video_demo.webp differ diff --git a/packages/docs/assets/article/video/tiktok_video.webp b/packages/docs/assets/article/video/tiktok_video.webp new file mode 100644 index 0000000000..3686c0da76 Binary files /dev/null and b/packages/docs/assets/article/video/tiktok_video.webp differ diff --git a/packages/docs/assets/article/video/ts_demo.webp b/packages/docs/assets/article/video/ts_demo.webp new file mode 100644 index 0000000000..f895430e47 Binary files /dev/null and b/packages/docs/assets/article/video/ts_demo.webp differ diff --git a/packages/docs/assets/article/video/video_format.webp b/packages/docs/assets/article/video/video_format.webp new file mode 100644 index 0000000000..2d6a4a7430 Binary files /dev/null and b/packages/docs/assets/article/video/video_format.webp differ diff --git a/packages/docs/assets/article/video/xgplayer_docs.webp b/packages/docs/assets/article/video/xgplayer_docs.webp new file mode 100644 index 0000000000..3fc242eb98 Binary files /dev/null and b/packages/docs/assets/article/video/xgplayer_docs.webp differ diff --git a/packages/docs/cn/src/article/docPreview.md b/packages/docs/cn/src/article/docPreview.md new file mode 100644 index 0000000000..9f8c124395 --- /dev/null +++ b/packages/docs/cn/src/article/docPreview.md @@ -0,0 +1,695 @@ +--- +theme: fancy +--- + +最近遇到了文件预览的需求,但一搜索发现,这还不是一个简单的功能。于是又去查询了很多资料,调研了一些方案,也踩了好多坑。最后总结方案如下 + +1. 花钱解决 (使用市面上现有的文件预览服务) + 1. 微软 + 2. google + 3. 阿里云 IMM + 4. XDOC + 5. Office Web 365 + 6. wps 开放平台 +2. 前端方案 + 1. pptx 的预览方案 + 2. pdf 的预览方案 + 3. docx 的预览方案 + 4. xlsx(excel) 的预览方案 + 5. 前端预览方案总结 +3. 服务端方案 + 1. openOffice + 2. kkFileView + 3. onlyOffice + +如果有其他人也遇到了同样的问题,有了这篇文章,希望能更方便的解决。 + +基本涵盖了所有解决方案。因此,标题写上 **最全** 的文件预览方案调研总结,应该不为过吧。 + +# 一。市面上现有的文件预览服务 + +## 1.微软 + +`docx`,`pptx`,`xlsx`可以说是`office`三件套,那自然得看一下 **微软官方** 提供的文件预览服务。使用方法特别简单,只需要将文件链接,拼接到参数后面即可。 + +记得`encodeURL` + +```js +https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(url)} +``` + +### (1).PPTX 预览效果: + +![image.png](../../../assets/article/docPreview/ms_ppt.webp) + +- 优点:还原度很高,功能很丰富,可以选择翻页,甚至支持点击播放动画。 +- 缺点:不知道是不是墙的原因,加载稍慢。 + +### (2).Excel 预览效果: + +![image.png](../../../assets/article/docPreview/ms_excel.webp) + +### (3).Doxc 预览效果 + +![image.png](../../../assets/article/docPreview/ms_word.webp) + +### (4).PDF 预览效果 + +这个我测试没有成功,返回了一个错误,其他人可以试试。 + +![image.png](../../../assets/article/docPreview/ms_file_not.webp) + +### (5).总的来说 + +对于`docx`,`pptx`,`xlsx`都有较好的支持,`pdf`不行。 + +还有一个坑点是:这个服务是否稳定,有什么限制,是否收费,都查不到一个定论。在`office`官方网站上甚至找不到介绍这个东西的地方。 + +目前只能找到一个`Q&A`:https://answers.microsoft.com/en-us/msoffice/forum/all/what-is-the-status-of-viewofficeappslivecom/830fd75c-9b47-43f9-89c9-4303703fd7f6 + +微软官方人员回答表示: + +![image.png](../../../assets/article/docPreview/ms_answer.webp) + +翻译翻译,就是:几乎永久使用,没有收费计划,不会存储预览的文件数据,限制文件`10MB`,建议用于 **查看互联网上公开的文件**。 + +但经过某些用户测试发现: + +![image.png](../../../assets/article/docPreview/ms_answer_2.webp) + +使用了微软的文件预览服务,然后删除了文件地址,仍然可访问,但过一段时间会失效。 + +## 2.Google Drive 查看器 + +接入简单,同 `Office Web Viewer`,只需要把 `src` 改为`https://drive.google.com/viewer?url=${encodeURIComponent(url)}`即可。 + +限制`25MB`,支持以下格式: + +![image.png](../../../assets/article/docPreview/google_doc_view.webp) + +测试效果,支持`docx,pptx,xlsx,pdf`预览,但`pptx`预览的效果不如微软,没有动画效果,样式有小部分会错乱。 + +**由于某些众所周知的原因,不可用** + +## 3.阿里云 IMM + +官方文档如下:https://help.aliyun.com/document_detail/63273.html + +![image.png](../../../assets/article/docPreview/ali_doc.webp) + +付费使用 + +## 4.XDOC 文档预览 + +说了一些大厂的,在介绍一些其他的,**需要自行分辨** + +官网地址:https://view.xdocin.com/view-xdocin-com_6x5f4x.htm + +![image.png](../../../assets/article/docPreview/xdoc.webp) + +## 5.Office Web 365 + +需要注意的是,虽然名字很像`office`,但我们看网页的`Copyright`可以发现,其实是一个西安的公司,**不是微软**。 + +但毕竟也提供了文件预览的服务 + +官网地址:https://www.officeweb365.com/ + +![image.png](../../../assets/article/docPreview/ow365.webp) + +## 6.WPS 开放平台 + +官方地址:https://solution.wps.cn/ + +![image.png](../../../assets/article/docPreview/wps_office.webp) + +付费使用,价格如下: + +![image.png](../../../assets/article/docPreview/wps_office_price.webp) + +# 二。前端处理方案 + +## 1.pptx 的预览方案 + +先查一下有没有现成的轮子,目前`pptx`的开源预览方案能找到的只有这个:https://github.com/g21589/PPTX2HTML。但已经六七年没有更新,也没有维护,笔者使用的时候发现有很多兼容性问题。 + +简单来说就是,没有。对于这种情况,我们可以自行解析,主要步骤如下: + +1. 查询`pptx`的国际标准 +2. 解析`pptx`文件 +3. 渲染成`html`或者`canvas`进行展示 + +我们先去找一下`pptx`的国际标准,官方地址:[officeopenxml](http://officeopenxml.com/) + +先解释下什么是`officeopenxml`: + +> Office OpenXML,也称为 OpenXML 或 OOXML,是一种基于 XML 的办公文档格式,包括文字处理文档、电子表格、演示文稿以及图表、图表、形状和其他图形材料。该规范由微软开发,并于 2006 年被 ECMA 国际采用为 ECMA-376。第二个版本于 2008 年 12 月发布,第三个版本于 2011 年 6 月发布。该规范已被 ISO 和 IEC 采用为 ISO/IEC 29500。 + +> 虽然 Microsoft 继续支持较旧的二进制格式 (.doc、.xls 和.ppt),但 OOXML 现在是所有 Microsoft Office 文档 (.docx、.xlsx 和.pptx) 的默认格式。 + +由此可见,`Office OpenXML`由微软开发,目前已经是国际标准。接下来我们看一下`pptx`里面有哪些内容,具体可以看`pptx`的官方标准:[officeopenxml-pptx](http://officeopenxml.com/anatomyofOOXML-pptx.php) + +> PresentationML 或.pptx 文件是一个**zip 文件**,其中包含许多“部分”(通常是 UTF-8 或 UTF-16 编码)或 XML 文件。该包还可能包含其他媒体文件,例如图像。该结构根据 OOXML 标准 ECMA-376 第 2 部分中概述的开放打包约定进行组织。 + +![image.png](../../../assets/article/docPreview/xml.webp) + +根据国际标准,我们知道,`pptx`文件本质就是一个`zip`文件,其中包含许多部分: + +> 部件的数量和类型将根据演示文稿中的内容而有所不同,但始终会有一个 [Content_Types].xml、一个或多个关系(.rels)部件和一个演示文稿部件(演示文稿.xml),它位于 ppt 文件夹中,用于 Microsoft Powerpoint 文件。通常,还将至少有一个幻灯片部件,以及一张母版幻灯片和一张版式幻灯片,从中形成幻灯片。 + +那么`js`如何读取`zip`呢? + +找到一个工具:https://www.npmjs.com/package/jszip + +于是我们可以开始尝试解析`pptx`了。 + +```ts +import JSZip from 'jszip'; +// 加载 pptx 数据 +const zip = await JSZip.loadAsync(pptxData); +``` + +- 解析`[Content_Types].xml` + +每个`pptx`必然会有一个 `[Content_Types].xml`。此文件包含包中部件的所有内容类型的列表。每个部件及其类型都必须列在 `[Content_Types].xml` 中。通过它里面的内容,可以解析其他的文件数据 + +```ts +const filesInfo = await getContentTypes(zip); + +async function getContentTypes(zip: JSZip) { + const ContentTypesJson = await readXmlFile(zip, '[Content_Types].xml'); + const subObj = ContentTypesJson['Types']['Override']; + const slidesLocArray = []; + const slideLayoutsLocArray = []; + for (let i = 0; i < subObj.length; i++) { + switch (subObj[i]['attrs']['ContentType']) { + case 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml': + slidesLocArray.push(subObj[i]['attrs']['PartName'].substr(1)); + break; + case 'application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml': + slideLayoutsLocArray.push(subObj[i]['attrs']['PartName'].substr(1)); + break; + default: + } + } + return { + slides: slidesLocArray, + slideLayouts: slideLayoutsLocArray, + }; +} +``` + +- 解析演示文稿 + +先获取`ppt`目录下的`presentation.xml`演示文稿的大小 + +由于演示文稿是`xml`格式,要真正的读取内容需要执行 `readXmlFile` + +```ts +const slideSize = await getSlideSize(zip); +async function getSlideSize(zip: JSZip) { + const content = await readXmlFile(zip, 'ppt/presentation.xml'); + const sldSzAttrs = content['p:presentation']['p:sldSz']['attrs']; + return { + width: (parseInt(sldSzAttrs['cx']) * 96) / 914400, + height: (parseInt(sldSzAttrs['cy']) * 96) / 914400, + }; +} +``` + +- 加载主题 + +根据 `officeopenxml`的标准解释 + +> 每个包都包含一个关系部件,用于定义其他部件之间的关系以及与包外部资源的关系。这样可以将关系与内容分开,并且可以轻松地更改关系,而无需更改引用目标的源。 + +> 除了包的关系部分之外,作为一个或多个关系源的每个部件都有自己的关系部分。每个这样的关系部件都可以在部件的\_rels 子文件夹中找到,并通过在部件名称后附加“.rels”来命名。 + +其中主题的相关信息就在`ppt/_rels/presentation.xml.rels`中 + +```ts +async function loadTheme(zip: JSZip) { + const preResContent = await readXmlFile(zip, 'ppt/_rels/presentation.xml.rels'); + const relationshipArray = preResContent['Relationships']['Relationship']; + let themeURI; + if (relationshipArray.constructor === Array) { + for (let i = 0; i < relationshipArray.length; i++) { + if ( + relationshipArray[i]['attrs']['Type'] === + 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme' + ) { + themeURI = relationshipArray[i]['attrs']['Target']; + break; + } + } + } else if ( + relationshipArray['attrs']['Type'] === 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme' + ) { + themeURI = relationshipArray['attrs']['Target']; + } + + if (themeURI === undefined) { + throw Error("Can't open theme file."); + } + + return readXmlFile(zip, 'ppt/' + themeURI); +} +``` + +后续`ppt`里面的其他内容,都可以这么去解析。根据`officeopenxml`标准,可能包含: +Part | Description | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Comments Authors | Contains information about each author who has added a comment to the presentation. | +| Comments | Contains comments for a single slide. | +| Handout Master | Contains the look, position, and size of the slides, notes, header and footer text, date, or page number on the presentation's handout. There can be only one such part. | +| Notes Master | Contains information about the content and formatting of all notes pages. There can be only one such part. | +| Notes Slide | Contains the notes for a single slide. | +| Presentation | Contains the definition of a slide presentation. There must be one and only one such part. See [Presentation](http://officeopenxml.com/PrPresentation.php). | +| Presentation Properties | Contains all of the presentation's properties. There must be one and only one such part. | +| Slide | Contains the content of a single slide. | +| Slide Layout | Contains the definition for a slide template. It defines the default appearance and positioning of drawing objects on the slide. There must be one or more such parts. | +| Slide Master | Contains the master definition of formatting, text, and objects that appear on each slide in the presentation that is derived from the slide master. There must be one or more such parts. | +| Slide Synchronization Data | Contains properties specifying the current state of a slide that is being synchronized with a version of the slide stored on a central server. | +| User-Defined Tags | Contains a set of user-defined properties for an object in a presentation. There can be zero or more such parts. | +| View Properties | Contains display properties for the presentation. + +等等内容,我们根据标准一点点解析并渲染就好了。 + +完整源码:[ranui](https://github.com/chaxus/ran/tree/main/packages/ranui) + +使用文档:[preview 组件](https://chaxus.github.io/ran/src/ranui/preview/) + +## 2.pdf 的预览方案 + +### (1).iframe 和 embed + +`pdf`比较特别,一般的浏览器默认支持预览`pdf`。因此,我们可以使用浏览器的能力: + +```html +