pptx-glimpse 0.10.1 → 0.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1692,6 +1692,7 @@ var standardParser = new import_fast_xml_parser.XMLParser({
1692
1692
  attributeNamePrefix: "@_",
1693
1693
  removeNSPrefix: true,
1694
1694
  htmlEntities: true,
1695
+ trimValues: false,
1695
1696
  isArray: (_name, jpath, _isLeafNode, _isAttribute) => {
1696
1697
  const tag = String(jpath).split(".").pop() ?? "";
1697
1698
  return ARRAY_TAGS.has(tag);
@@ -3911,6 +3912,114 @@ function findMatchingPlaceholder(placeholderType, placeholderIdx, styles) {
3911
3912
  }
3912
3913
  return void 0;
3913
3914
  }
3915
+ function hasMultipleBulletPPr(p, orderedChildren) {
3916
+ const rawPPr = p.pPr;
3917
+ const pPrList = Array.isArray(rawPPr) ? rawPPr : rawPPr ? [rawPPr] : [];
3918
+ let bulletPPrCount = 0;
3919
+ let pPrCounter = 0;
3920
+ for (const child of orderedChildren) {
3921
+ const tag = Object.keys(child).find((k) => k !== ":@");
3922
+ if (tag === "pPr") {
3923
+ const pPrNode = pPrList[pPrCounter];
3924
+ if (pPrNode && (pPrNode.buChar !== void 0 || pPrNode.buAutoNum !== void 0 || pPrNode.buBlip !== void 0)) {
3925
+ bulletPPrCount++;
3926
+ if (bulletPPrCount >= 2) return true;
3927
+ }
3928
+ pPrCounter++;
3929
+ }
3930
+ }
3931
+ return false;
3932
+ }
3933
+ function splitInterleavedParagraph(p, orderedPChildren, colorResolver, rels, fontScheme, lstStyle) {
3934
+ const rawPPr = p.pPr;
3935
+ const pPrList = Array.isArray(rawPPr) ? rawPPr : rawPPr ? [rawPPr] : [];
3936
+ const rList = p.r ?? [];
3937
+ const fldList = p.fld ?? [];
3938
+ const brList = p.br ?? [];
3939
+ const groups = [];
3940
+ let currentGroup = null;
3941
+ let pPrCounter = 0;
3942
+ const tagCounters = {};
3943
+ for (const child of orderedPChildren) {
3944
+ const tag = Object.keys(child).find((k) => k !== ":@");
3945
+ if (!tag) continue;
3946
+ if (tag === "pPr") {
3947
+ const pPrNode = pPrList[pPrCounter];
3948
+ const hasBullet = pPrNode && (pPrNode.buChar !== void 0 || pPrNode.buAutoNum !== void 0 || pPrNode.buBlip !== void 0);
3949
+ if (hasBullet || !currentGroup) {
3950
+ if (currentGroup) groups.push(currentGroup);
3951
+ currentGroup = {
3952
+ pPrIdx: pPrCounter,
3953
+ rIndices: [],
3954
+ fldIndices: [],
3955
+ brIndices: [],
3956
+ orderedChildren: [child]
3957
+ };
3958
+ } else {
3959
+ currentGroup.orderedChildren.push(child);
3960
+ }
3961
+ pPrCounter++;
3962
+ } else if (tag === "endParaRPr") {
3963
+ } else {
3964
+ const globalIdx = tagCounters[tag] ?? 0;
3965
+ tagCounters[tag] = globalIdx + 1;
3966
+ if (!currentGroup) {
3967
+ currentGroup = {
3968
+ pPrIdx: -1,
3969
+ rIndices: [],
3970
+ fldIndices: [],
3971
+ brIndices: [],
3972
+ orderedChildren: []
3973
+ };
3974
+ }
3975
+ if (tag === "r") currentGroup.rIndices.push(globalIdx);
3976
+ else if (tag === "fld") currentGroup.fldIndices.push(globalIdx);
3977
+ else if (tag === "br") currentGroup.brIndices.push(globalIdx);
3978
+ currentGroup.orderedChildren.push(child);
3979
+ }
3980
+ }
3981
+ if (currentGroup) groups.push(currentGroup);
3982
+ const results = [];
3983
+ for (let g = 0; g < groups.length; g++) {
3984
+ const group = groups[g];
3985
+ const isLast = g === groups.length - 1;
3986
+ const syntheticP = {};
3987
+ if (group.pPrIdx >= 0 && pPrList[group.pPrIdx]) {
3988
+ syntheticP.pPr = pPrList[group.pPrIdx];
3989
+ }
3990
+ if (group.rIndices.length > 0) {
3991
+ syntheticP.r = group.rIndices.map((i) => rList[i]);
3992
+ }
3993
+ if (group.fldIndices.length > 0) {
3994
+ syntheticP.fld = group.fldIndices.map((i) => fldList[i]);
3995
+ }
3996
+ if (group.brIndices.length > 0) {
3997
+ syntheticP.br = group.brIndices.map((i) => brList[i]);
3998
+ }
3999
+ if (isLast && p.endParaRPr) {
4000
+ syntheticP.endParaRPr = p.endParaRPr;
4001
+ }
4002
+ const paragraph = parseParagraph(
4003
+ syntheticP,
4004
+ colorResolver,
4005
+ rels,
4006
+ fontScheme,
4007
+ lstStyle,
4008
+ group.orderedChildren
4009
+ );
4010
+ if (!isLast && paragraph.runs.length > 0) {
4011
+ const lastRun = paragraph.runs[paragraph.runs.length - 1];
4012
+ if (lastRun.text.endsWith("\n")) {
4013
+ paragraph.runs[paragraph.runs.length - 1] = {
4014
+ ...lastRun,
4015
+ text: lastRun.text.slice(0, -1)
4016
+ };
4017
+ }
4018
+ }
4019
+ results.push(paragraph);
4020
+ }
4021
+ return results;
4022
+ }
3914
4023
  function parseTextBody(txBody, colorResolver, rels, fontScheme, lstStyleOverride, orderedTxBody) {
3915
4024
  if (!txBody) return null;
3916
4025
  const bodyPr = txBody.bodyPr;
@@ -3955,9 +4064,23 @@ function parseTextBody(txBody, colorResolver, rels, fontScheme, lstStyleOverride
3955
4064
  const paragraphs = [];
3956
4065
  const pList = txBody.p ?? [];
3957
4066
  for (let i = 0; i < pList.length; i++) {
3958
- paragraphs.push(
3959
- parseParagraph(pList[i], colorResolver, rels, fontScheme, lstStyle, orderedParagraphs[i])
3960
- );
4067
+ const orderedChildren = orderedParagraphs[i];
4068
+ if (orderedChildren && hasMultipleBulletPPr(pList[i], orderedChildren)) {
4069
+ paragraphs.push(
4070
+ ...splitInterleavedParagraph(
4071
+ pList[i],
4072
+ orderedChildren,
4073
+ colorResolver,
4074
+ rels,
4075
+ fontScheme,
4076
+ lstStyle
4077
+ )
4078
+ );
4079
+ } else {
4080
+ paragraphs.push(
4081
+ parseParagraph(pList[i], colorResolver, rels, fontScheme, lstStyle, orderedChildren)
4082
+ );
4083
+ }
3961
4084
  }
3962
4085
  if (paragraphs.length === 0) return null;
3963
4086
  return { paragraphs, bodyProperties };
@@ -7938,7 +8061,7 @@ function renderTextBody(textBody, transform) {
7938
8061
  const firstParaFontSizePt = getParagraphFontSize(paragraphs[0], defaultFontSize) * fontScale;
7939
8062
  const firstLineBaselineOffsetPt = firstParaFontSizePt * defaultAscenderRatio;
7940
8063
  yStart += firstLineBaselineOffsetPt * PX_PER_PT3;
7941
- const textElement = `<text x="0" y="${yStart}">${tspans.join("")}</text>`;
8064
+ const textElement = `<text x="0" y="${yStart}" xml:space="preserve">${tspans.join("")}</text>`;
7942
8065
  if (isVerticalText(bodyProperties.vert)) {
7943
8066
  return `<g transform="translate(${originalWidth}, 0) rotate(90)">${textElement}</g>`;
7944
8067
  }
package/dist/index.js CHANGED
@@ -1655,6 +1655,7 @@ var standardParser = new XMLParser({
1655
1655
  attributeNamePrefix: "@_",
1656
1656
  removeNSPrefix: true,
1657
1657
  htmlEntities: true,
1658
+ trimValues: false,
1658
1659
  isArray: (_name, jpath, _isLeafNode, _isAttribute) => {
1659
1660
  const tag = String(jpath).split(".").pop() ?? "";
1660
1661
  return ARRAY_TAGS.has(tag);
@@ -3873,6 +3874,114 @@ function findMatchingPlaceholder(placeholderType, placeholderIdx, styles) {
3873
3874
  }
3874
3875
  return void 0;
3875
3876
  }
3877
+ function hasMultipleBulletPPr(p, orderedChildren) {
3878
+ const rawPPr = p.pPr;
3879
+ const pPrList = Array.isArray(rawPPr) ? rawPPr : rawPPr ? [rawPPr] : [];
3880
+ let bulletPPrCount = 0;
3881
+ let pPrCounter = 0;
3882
+ for (const child of orderedChildren) {
3883
+ const tag = Object.keys(child).find((k) => k !== ":@");
3884
+ if (tag === "pPr") {
3885
+ const pPrNode = pPrList[pPrCounter];
3886
+ if (pPrNode && (pPrNode.buChar !== void 0 || pPrNode.buAutoNum !== void 0 || pPrNode.buBlip !== void 0)) {
3887
+ bulletPPrCount++;
3888
+ if (bulletPPrCount >= 2) return true;
3889
+ }
3890
+ pPrCounter++;
3891
+ }
3892
+ }
3893
+ return false;
3894
+ }
3895
+ function splitInterleavedParagraph(p, orderedPChildren, colorResolver, rels, fontScheme, lstStyle) {
3896
+ const rawPPr = p.pPr;
3897
+ const pPrList = Array.isArray(rawPPr) ? rawPPr : rawPPr ? [rawPPr] : [];
3898
+ const rList = p.r ?? [];
3899
+ const fldList = p.fld ?? [];
3900
+ const brList = p.br ?? [];
3901
+ const groups = [];
3902
+ let currentGroup = null;
3903
+ let pPrCounter = 0;
3904
+ const tagCounters = {};
3905
+ for (const child of orderedPChildren) {
3906
+ const tag = Object.keys(child).find((k) => k !== ":@");
3907
+ if (!tag) continue;
3908
+ if (tag === "pPr") {
3909
+ const pPrNode = pPrList[pPrCounter];
3910
+ const hasBullet = pPrNode && (pPrNode.buChar !== void 0 || pPrNode.buAutoNum !== void 0 || pPrNode.buBlip !== void 0);
3911
+ if (hasBullet || !currentGroup) {
3912
+ if (currentGroup) groups.push(currentGroup);
3913
+ currentGroup = {
3914
+ pPrIdx: pPrCounter,
3915
+ rIndices: [],
3916
+ fldIndices: [],
3917
+ brIndices: [],
3918
+ orderedChildren: [child]
3919
+ };
3920
+ } else {
3921
+ currentGroup.orderedChildren.push(child);
3922
+ }
3923
+ pPrCounter++;
3924
+ } else if (tag === "endParaRPr") {
3925
+ } else {
3926
+ const globalIdx = tagCounters[tag] ?? 0;
3927
+ tagCounters[tag] = globalIdx + 1;
3928
+ if (!currentGroup) {
3929
+ currentGroup = {
3930
+ pPrIdx: -1,
3931
+ rIndices: [],
3932
+ fldIndices: [],
3933
+ brIndices: [],
3934
+ orderedChildren: []
3935
+ };
3936
+ }
3937
+ if (tag === "r") currentGroup.rIndices.push(globalIdx);
3938
+ else if (tag === "fld") currentGroup.fldIndices.push(globalIdx);
3939
+ else if (tag === "br") currentGroup.brIndices.push(globalIdx);
3940
+ currentGroup.orderedChildren.push(child);
3941
+ }
3942
+ }
3943
+ if (currentGroup) groups.push(currentGroup);
3944
+ const results = [];
3945
+ for (let g = 0; g < groups.length; g++) {
3946
+ const group = groups[g];
3947
+ const isLast = g === groups.length - 1;
3948
+ const syntheticP = {};
3949
+ if (group.pPrIdx >= 0 && pPrList[group.pPrIdx]) {
3950
+ syntheticP.pPr = pPrList[group.pPrIdx];
3951
+ }
3952
+ if (group.rIndices.length > 0) {
3953
+ syntheticP.r = group.rIndices.map((i) => rList[i]);
3954
+ }
3955
+ if (group.fldIndices.length > 0) {
3956
+ syntheticP.fld = group.fldIndices.map((i) => fldList[i]);
3957
+ }
3958
+ if (group.brIndices.length > 0) {
3959
+ syntheticP.br = group.brIndices.map((i) => brList[i]);
3960
+ }
3961
+ if (isLast && p.endParaRPr) {
3962
+ syntheticP.endParaRPr = p.endParaRPr;
3963
+ }
3964
+ const paragraph = parseParagraph(
3965
+ syntheticP,
3966
+ colorResolver,
3967
+ rels,
3968
+ fontScheme,
3969
+ lstStyle,
3970
+ group.orderedChildren
3971
+ );
3972
+ if (!isLast && paragraph.runs.length > 0) {
3973
+ const lastRun = paragraph.runs[paragraph.runs.length - 1];
3974
+ if (lastRun.text.endsWith("\n")) {
3975
+ paragraph.runs[paragraph.runs.length - 1] = {
3976
+ ...lastRun,
3977
+ text: lastRun.text.slice(0, -1)
3978
+ };
3979
+ }
3980
+ }
3981
+ results.push(paragraph);
3982
+ }
3983
+ return results;
3984
+ }
3876
3985
  function parseTextBody(txBody, colorResolver, rels, fontScheme, lstStyleOverride, orderedTxBody) {
3877
3986
  if (!txBody) return null;
3878
3987
  const bodyPr = txBody.bodyPr;
@@ -3917,9 +4026,23 @@ function parseTextBody(txBody, colorResolver, rels, fontScheme, lstStyleOverride
3917
4026
  const paragraphs = [];
3918
4027
  const pList = txBody.p ?? [];
3919
4028
  for (let i = 0; i < pList.length; i++) {
3920
- paragraphs.push(
3921
- parseParagraph(pList[i], colorResolver, rels, fontScheme, lstStyle, orderedParagraphs[i])
3922
- );
4029
+ const orderedChildren = orderedParagraphs[i];
4030
+ if (orderedChildren && hasMultipleBulletPPr(pList[i], orderedChildren)) {
4031
+ paragraphs.push(
4032
+ ...splitInterleavedParagraph(
4033
+ pList[i],
4034
+ orderedChildren,
4035
+ colorResolver,
4036
+ rels,
4037
+ fontScheme,
4038
+ lstStyle
4039
+ )
4040
+ );
4041
+ } else {
4042
+ paragraphs.push(
4043
+ parseParagraph(pList[i], colorResolver, rels, fontScheme, lstStyle, orderedChildren)
4044
+ );
4045
+ }
3923
4046
  }
3924
4047
  if (paragraphs.length === 0) return null;
3925
4048
  return { paragraphs, bodyProperties };
@@ -7900,7 +8023,7 @@ function renderTextBody(textBody, transform) {
7900
8023
  const firstParaFontSizePt = getParagraphFontSize(paragraphs[0], defaultFontSize) * fontScale;
7901
8024
  const firstLineBaselineOffsetPt = firstParaFontSizePt * defaultAscenderRatio;
7902
8025
  yStart += firstLineBaselineOffsetPt * PX_PER_PT3;
7903
- const textElement = `<text x="0" y="${yStart}">${tspans.join("")}</text>`;
8026
+ const textElement = `<text x="0" y="${yStart}" xml:space="preserve">${tspans.join("")}</text>`;
7904
8027
  if (isVerticalText(bodyProperties.vert)) {
7905
8028
  return `<g transform="translate(${originalWidth}, 0) rotate(90)">${textElement}</g>`;
7906
8029
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pptx-glimpse",
3
- "version": "0.10.1",
3
+ "version": "0.10.3",
4
4
  "description": "A lightweight JavaScript library for rendering PowerPoint (.pptx) files as SVG or PNG in Node.js. No LibreOffice required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",