#7687·univer

[Bug][Slides] Negative connector extent from FPresentation.save() is rejected by PPTX export

Author: zsq1234Created Sep 16, 2026Updated Sep 16, 2026
Labelsbug 🐛scope:slide

Before you submit this issue

  • This is reproducible with an official Slides snapshot and the official Node exchange exporter.
  • I searched the public Issues and PRs for OOXML extent, negative Slide width/height, connector transform, and PPTX connector export, but found no matching report.

Affected packages and versions

  • @univerjs-pro/slides: 1.0.0-rc.0
  • @univerjs-pro/slides-ui: 1.0.0-rc.0
  • @univerjs-pro/exchange-node: 1.0.0-rc.0
  • @univerjs/core: 1.0.0-rc.0
  • Node.js: 22.22.1

Reproduction snapshot

A sanitized full ISlideData snapshot is available here:

https://gist.github.com/zsq1234/ed2c3962127fb42a34b2e29e0bbac44f

The DSH RPC wrapper and session identifiers were removed; only the presentation snapshot is included. The top-level presentation ID was replaced with negative-connector-extent-repro.

The failing element in that snapshot is:

json
{
  "slideId": "GX5wTC",
  "slideName": "月度趋势",
  "element": {
    "id": "VpGNav",
    "type": "connector",
    "transform": {
      "left": 365.45454545454544,
      "top": 387.39857666666666,
      "width": 68.36363636363637,
      "height": -43.125713333333294,
      "rotation": 0,
      "flipX": false,
      "flipY": false
    },
    "connectorData": {
      "stroke": {
        "lineStrokeType": 2,
        "color": "#2563EB",
        "width": 3
      },
      "shapeType": "line"
    }
  }
}

This is an upward-sloping connector. Its signed height appears to represent the direction from one endpoint to the other.

Steps to reproduce

  1. Load the attached snapshot as a Slide presentation.
  2. Obtain the snapshot through the official Facade API:
typescript
const presentation = univerAPI.getActivePresentation();
const snapshot = presentation.save();
  1. Export that official snapshot with the official Node exporter:
typescript
await exportToFile(snapshot, outputPath, {
  type: UniverInstanceType.UNIVER_SLIDE,
  format: ExchangeFormat.PPTX,
});

Actual behavior

The export fails with:

validation error: slide page GX5wTC element VpGNav transform height must produce an OOXML extent between 0 and 2147483647 EMU, got -43.125713333333294 pt (-547697 EMU)

FPresentation.save() preserves the signed connector height, while @univerjs-pro/exchange-node rejects it as an unsigned OOXML extent.

Expected behavior

A snapshot returned by the official FPresentation.save() API should be accepted by the official exchange-node PPTX exporter.

For a connector with a negative height, the exporter or an earlier canonicalization boundary could preserve the same bounds and direction by converting it to an OOXML-compatible transform, for example:

typescript
top = top + height;
height = Math.abs(height);
flipY = !flipY;

The equivalent normalization applies to a negative width using left and flipX.

Additional context

This looks like a contract mismatch between the Slides connector model and the PPTX exporter rather than an arbitrary invalid consumer snapshot: signed width/height are useful for encoding connector endpoint direction, but OOXML a:ext values must be non-negative.

Could the connector serializer canonicalize signed transforms before validating/writing OOXML extents, or should the Slides model/save path guarantee canonical positive extents?