office-fixture.ts 4.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. /** Small binary Office and OOXML documents for exercising the installed converter through the Web preview. */
  2. import { readFileSync } from 'node:fs'
  3. import { strToU8, zipSync } from 'fflate'
  4. const REL_NS = 'http://schemas.openxmlformats.org/package/2006/relationships'
  5. const OFFICE_REL_NS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
  6. const CONTENT_NS = 'http://schemas.openxmlformats.org/package/2006/content-types'
  7. const TEXT = 'Office preview 中文文档'
  8. /**
  9. * Create a valid one-page Office document containing Latin and Chinese text.
  10. * @param extension - Office application and format to exercise.
  11. * @param font - Latin family requested by generated OOXML documents; binary fixtures retain their stored fonts.
  12. * @returns Compressed document bytes accepted by the production converter.
  13. */
  14. export function realOfficeBytes(extension: 'doc' | 'docx' | 'xls' | 'xlsx' | 'ppt' | 'pptx', font = 'Liberation Sans'): Uint8Array {
  15. const files: Record<string, string> = {}
  16. let main: string
  17. let parts: Record<string, string>
  18. switch (extension) {
  19. case 'doc': case 'xls': case 'ppt':
  20. return readFileSync(new URL(`./fixtures/office/preview.${extension}`, import.meta.url))
  21. case 'docx':
  22. main = 'word/document.xml'
  23. parts = { [main]: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml' }
  24. files[main] = `<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body><w:p><w:r><w:rPr><w:rFonts w:ascii="${font}" w:hAnsi="${font}" w:eastAsia="宋体"/></w:rPr><w:t>${TEXT}</w:t></w:r></w:p><w:sectPr><w:pgSz w:w="12240" w:h="15840"/></w:sectPr></w:body></w:document>`
  25. break
  26. case 'xlsx':
  27. main = 'xl/workbook.xml'
  28. parts = {
  29. [main]: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml',
  30. 'xl/worksheets/sheet1.xml': 'application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml',
  31. }
  32. files[main] = `<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="${OFFICE_REL_NS}"><sheets><sheet name="Preview" sheetId="1" r:id="rId1"/></sheets></workbook>`
  33. files['xl/_rels/workbook.xml.rels'] = `<Relationships xmlns="${REL_NS}"><Relationship Id="rId1" Type="${OFFICE_REL_NS}/worksheet" Target="worksheets/sheet1.xml"/></Relationships>`
  34. files['xl/worksheets/sheet1.xml'] = `<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><cols><col min="1" max="1" width="45" customWidth="1"/></cols><sheetData><row r="1"><c r="A1" t="inlineStr"><is><t>${TEXT}</t></is></c></row></sheetData></worksheet>`
  35. break
  36. case 'pptx':
  37. main = 'ppt/presentation.xml'
  38. parts = {
  39. [main]: 'application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml',
  40. 'ppt/slides/slide1.xml': 'application/vnd.openxmlformats-officedocument.presentationml.slide+xml',
  41. }
  42. files[main] = `<p:presentation xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" xmlns:r="${OFFICE_REL_NS}"><p:sldIdLst><p:sldId id="256" r:id="rId1"/></p:sldIdLst><p:sldSz cx="9144000" cy="6858000"/><p:notesSz cx="6858000" cy="9144000"/></p:presentation>`
  43. files['ppt/_rels/presentation.xml.rels'] = `<Relationships xmlns="${REL_NS}"><Relationship Id="rId1" Type="${OFFICE_REL_NS}/slide" Target="slides/slide1.xml"/></Relationships>`
  44. files['ppt/slides/slide1.xml'] = `<p:sld xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><p:cSld><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="0" cy="0"/><a:chOff x="0" y="0"/><a:chExt cx="0" cy="0"/></a:xfrm></p:grpSpPr><p:sp><p:nvSpPr><p:cNvPr id="2" name="Preview"/><p:cNvSpPr txBox="1"/><p:nvPr/></p:nvSpPr><p:spPr><a:xfrm><a:off x="914400" y="914400"/><a:ext cx="7315200" cy="1828800"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" sz="2400"><a:latin typeface="${font}"/><a:ea typeface="宋体"/></a:rPr><a:t>${TEXT}</a:t></a:r><a:endParaRPr lang="en-US"/></a:p></p:txBody></p:sp></p:spTree></p:cSld></p:sld>`
  45. break
  46. }
  47. files['_rels/.rels'] = `<Relationships xmlns="${REL_NS}"><Relationship Id="rId1" Type="${OFFICE_REL_NS}/officeDocument" Target="${main}"/></Relationships>`
  48. files['[Content_Types].xml'] = `<Types xmlns="${CONTENT_NS}"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/>${Object.entries(parts).map(([part, type]) => `<Override PartName="/${part}" ContentType="${type}"/>`).join('')}</Types>`
  49. return zipSync(Object.fromEntries(Object.entries(files).map(([path, content]) => [path, strToU8(content)])))
  50. }