v0.27.0
The last minor release before the 1.0 release candidate. Numbers gains pictures, shapes, text boxes, charts, the
print setup and a table's exact position on the canvas. The public surface has its final naming pass, and the
renames under Changed break source: each is a compile error at the line to change, mapped in
Migrating to 1.0. ReadOptions.cellLimit now holds for every reader, the codecs read and
write faster with the same bytes, and the documentation is English throughout, with a getting-started guide, a
cookbook whose recipes CI builds and runs, and llms.txt.
Added
-
Pictures, shapes and text boxes in Numbers (spec Appendix B.83).
sheet.imagesandsheet.shapesare read
from a Numbers sheet's canvas — theTSD.ImageArchivewith its bytes underData/, theTSWP.ShapeInfoArchive
with its text, fill and outline — and written back as canvas objects: a picture becomes a data record and an
image archive, a shape or a text box a rectangle path with a text storage of its own, every reference into the
stylesheet declared the way Numbers declares it. Numbers places objects at a point, so an anchor reads back as
.absolute; a cell anchor is written by summing the first table's rows and columns. Only the rectangle and the
text box are drawn as measured — any other geometry is written as a rectangle and named (degraded), as is a
text alignment. The reader's report for what stays out (a chart, a movie, a group, a picture that is not PNG /
JPEG / GIF) is unchanged. ODS furigana was measured and stays reported: LibreOffice Calc discardstext:ruby
in a cell (spec Appendix B.70). -
The print setup in Numbers (spec Appendix B.84). The sheet archive's own words are read and written:
orientation, scale, margins, the first page number and the odd header / footer in Numbers' three zones (&L,
&C,&R).&Pbecomes Numbers' page number — drawn in the centre of the footer, and said so when it was
asked for elsewhere; other codes are dropped and named; even / first-page variants are dropped. The paper
size, fit-to-pages, the print area, title rows and page breaks stay reported, now each by name. A Numbers
document reads back with the footer Numbers prints (&C&P) and its scale (72 %). -
Where a table stands on a Numbers canvas (spec Appendix B.85).
Table.position(aCanvasPointin points)
is read exactly and written back;sheet.addTable(named:at:)places one. A table with a non-defaultanchor
goes on the default 98 × 20 pt grid, and one with neither goes below the previous table as before. -
The paper and the title rows in Numbers (spec Appendix B.86). The paper size goes onto the document (one per
document; a sheet asking for another is said so) and comes back; title rows / columns from row 1 / column 1
become the first table's header rows / columns repeated on every printed page. The print area and page breaks
have no place and stay reported. -
Ten shape geometries in Numbers (spec Appendix B.87): rectangle, rounded rectangle, ellipse, diamond,
triangle, the four arrows and a line are drawn as bezier paths and recognised on the way back. Other presets
are still rectangles, named with the list of what is drawn. -
Charts in Numbers (spec Appendix B.88).
sheet.chartsis read from a Numbers canvas — the kind, title and
legend, and each series' values, categories and name reference followed back through the chart mediator's
formulas to the table cells — and written: a column, bar, line or pie chart becomes a chart drawable over the
template's style preset, with its cached grid, its mediator and its registration with the calculation engine.
Numbers opens the written chart, saves it again and exports it to Excel with the chart intact (judged).Chart
gainsframe(aCanvasRectin points); the XLSX and ODS writers place a chart that
only has a frame over the cells it covers. A chart whose data is not linked to a table stays reported.
Changed
The last look at the public surface before 1.0 (spec Appendix B.89). Each change is a rename or a narrowing that the
compiler points at; no alias is kept.
SheetImage.Anchor.absolute(x:y:width:height:)→SheetImage.Anchor.absolute(CanvasRect)— one rectangle type
for a position on the canvas, the oneChart.framealready uses.addSparkline(_:data:at:)→addSparkline(_:dataRange:at:), now with aCellReftwin beside the A1 string, and
SparklineGroup.Sparkline(dataRange:location:)→SparklineGroup.Sparkline(dataRange:at:)— one label per role.addTable(named:anchor:)→addTable(named:at:)— the same label as the canvas-point form, told apart by type.IconSet.Icon.set→IconSet.Icon.setName, the wordIconSet.nameuses for the same kind of value.PhoneticText.Run.startandend→PhoneticText.Run.range, aRange<Int>of UTF-16 code units made with
Run(_:over:). The reader clamps a file whoseebcomes before itssbinstead of trapping on it.DataBar.isGradient→DataBar.gradient, the attribute's own word, likepercentandreverse.Alignment.wrapText→Alignment.wrapsTextandAlignment.shrinkToFit→Alignment.shrinksToFit— the two
imperative Bools 0.24.0's pass missed, spelled the way itsfitToPage→fitsToPagealready is. A test now scans the
whole public surface for the naming rules, so the next one is caught when it is written.- No longer public, because each answered a codec's question rather than a caller's:
CommentThread.mirrorPrefix,
Chart.anchorOrFrameCells,Chart.Kind.drawable(askisDrawable),Shape.Geometry.presets(askisPreset)
andDataBar.usesExtension. - A shape made with
Shape(_:)and appended by hand covers cell A1 as a span instead of borrowing a picture's
.originalsize, so the XLSX and Numbers writers draw it at the same size. - The warning for preserved parts a conversion cannot carry names what they hold, from the inventory
(…; what they hold: pivot 2, slicer 1); the ODS writer's no longer guesses "charts, drawings, VBA…". Cell.inittakesthread:like every other extra;CanvasPointandCanvasRectareCodable;
PreservationSummaryisHashable; assigningTheme.colorsnormalises toAARRGGBB, as the initialiser does.
Fixed
ReadOptions.cellLimitstops XLSX, Numbers and delimited-text reads too (spec Appendix B.90). It was documented
as the cell budget for untrusted input in every format, but only the ODS reader counted. One budget covers the
workbook, sheets parsed side by side included; a sheet that reaches it keeps the cells read so far and says so
with adegradedwarning. With no limit set, nothing is counted.
Performance
- XLSX reads and writes a quarter to a third faster (spec Appendix B.91). Measured on a million cells, the old
and the new build run alternately five times each at the same time: write 1.54 → 1.09 s and 254 → 214 MB peak,
read 2.61 → 1.85 s at 216 MB, row-by-row read 1.85 → 1.35 s at 13 MB, row-by-row write 1.84 → 1.51 s at 11 MB,
open-edit-save 3.87 → 2.59 s and 255 → 211 MB. A cell with the default style is written without hashing its style
and read without copying one, a number is trimmed only when its ends are not plain ASCII, a read cell is stored
once, a dense sheet's rows are written straight from its extent, dated cells share one style per format, and the
writers' style caches are bounded. The bytes written are unchanged. - ODS, CSV and Numbers too (spec Appendix B.91), measured the same way: write ODS 3.39 → 2.25 s, row-by-row
write ODS 3.52 → 2.50 s, read ODS 3.59 → 3.16 s, read CSV 1.76 → 1.32 s, row-by-row read CSV 1.31 → 0.87 s, write
CSV 0.88 → 0.65 s, write Numbers 3.90 → 2.20 s, row-by-row write Numbers 3.57 → 3.07 s, each at the peak memory it
had. The ODS writer works out a cell's style facts once per style, delimited text tests its rules on bytes with one
locale, and the Numbers writer encodes an integer without long division and its style keys once per style. - Fewer copies in the model's own cells (spec Appendix B.91): a cell a reader or an append creates is made without
comparing the default style with itself, and delimited text reserves its table for the fields it parsed. Building
the model 0.57 → 0.47 s at 203 MB; read CSV 1.27 → 1.12 s and 238 → 165 MB peak; the XLSX, ODS and Numbers readers
5–7% faster at the same peak.
Full changelog: 0.26.0...0.27.0