feat(mxl-compile,mxl-decompile): рисунки и палитра картинок

Рисунок поверх сетки — картинка, фигура, надпись — теперь описывается в DSL
и возвращается из макета: два якоря «ячейка + смещение», тип, ссылка на
картинку, надпись, расшифровка, имя, порядок перекрытия.

Оформление рисунка разложено надвое: общее (заливка, шрифт, выравнивание)
берётся из именованного стиля, а линия и её стороны — собственные ключи
рисунка. У ячейки таких свойств не бывает: все 2 135 записей палитры с ними
принадлежат рисункам.

Палитра картинок: ссылка на библиотеку платформы, данные base64, пустая
запись «картинка не задана» (151 в корпусе) и координата пикселя прозрачного
цвета (tx/ty — проверено, это не размеры картинки).

Заодно: висячий пустой колонтитул в ps1-порте (пустой словарь в PowerShell
истинен, порты расходились на 3 макетах из 40) и проверка индекса формата
рисунка в mxl-validate.

Стенды Рисунки, Рисунки2, КартинкаВЯчейке проходят раундтрип байт в байт
в обоих портах; на 35 корпусных макетах с рисунками расхождение сократилось
у всех 35.
This commit is contained in:
Nick Shirokov
2026-08-15 20:07:12 +03:00
parent 9a1353a1d9
commit 9285ed00cd
23 changed files with 1654 additions and 46 deletions
+72 -2
View File
@@ -708,15 +708,85 @@ current-config не объявляет, поэтому вынести объяв
подсказки (`verticalAlignment: Top` + `style:ToolTipTextColor` + `style:ToolTipBackColor`),
105 — он же с заливкой `#FFFAD9`.
## Ресурсы картинок
## Палитра картинок
Идёт последним блоком документа. Внутренний `<index>` 0-based, а ссылки на него — 1-based:
`<pictureIndex>` у рисунка, `picIndex` в записи формата у картинки в ячейке.
```xml
<picture>
<index>0</index>
<picture ref="v8ui:Штрихкод"/> <!-- ссылка на предопределённую картинку -->
<picture ref="v8ui:Штрихкод"/> <!-- ссылка на библиотеку картинок платформы -->
</picture>
<picture>
<index>1</index>
<picture t="false">iVBORw0KGgoAAAANSUhEUgAAAG4AAAA2CAIAAACp5Ds2AAAAAXNSR0IArs4c6QAA
AARnQUlBAACxjwv8YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAA</picture>
</picture>
```
Данные base64 платформа переносит по строкам тем же переводом, что и весь файл (CRLF), —
в отличие от блоба настроек элемента управления, где перенос голый LF.
Атрибуты внутреннего `<picture>` по корпусу ERP (10 130 записей):
| Вид | Сколько | Смысл |
|-----|--------:|-------|
| данные без атрибутов | 9 896 | картинка хранится в макете |
| `<picture/>` | 151 | картинка не задана; ровно по одной такой записи на макет |
| `ref="v8ui:Имя"` | 83 | ссылка на библиотеку картинок платформы |
| `tx`, `ty` при данных | 9 | координата пикселя внутри картинки (проверено: это НЕ её размеры — у `tx=97 ty=83` сама картинка 368×117) |
Атрибут `t` (прозрачность) в корпусе не встречается, но платформа его пишет: `t="false"`
появляется у картинки, вставленной в ячейку.
## Рисунки
Рисунок — объект поверх сетки: картинка, фигура, надпись, диаграмма. Лежит в `<drawing>`
перед палитрами; геометрия задана двумя якорями «ячейка + смещение в точках».
```xml
<drawing>
<drawingType>Picture</drawingType>
<id>3</id>
<zOrder>3</zOrder>
<beginRow>1</beginRow>
<beginColumn>1</beginColumn>
<beginRowOffset>0</beginRowOffset>
<beginColumnOffset>0</beginColumnOffset>
<endRow>3</endRow>
<endColumn>2</endColumn>
<endRowOffset>34</endRowOffset>
<endColumnOffset>115</endColumnOffset>
<formatIndex>4</formatIndex>
<pictureSize>Proportionally</pictureSize>
<pictureIndex>2</pictureIndex>
<detailParameter>Расшифровка</detailParameter>
</drawing>
```
Координаты строк и колонок здесь 0-based, в отличие от `<i>` ячейки. `<id>` и `<zOrder>`
самостоятельны: на корпусе они расходятся у 8 253 рисунков из 11 268, так что выводить их
из порядка следования нельзя. `<pictureSize>Stretch</pictureSize>` — умолчание, пишется всегда.
Имя рисунка хранится отдельно, среди именованных элементов:
```xml
<namedItem xsi:type="NamedItemDrawing">
<name>Логотип</name>
<drawingID>3</drawingID>
</namedItem>
```
Оформление рисунка — обычная запись палитры форматов, но с собственными тегами: `drawingBorder`
(ссылка в палитру линий, вид `SpreadsheetDocumentDrawingLineType`) и
`drawingHaveLeftBorder` / `drawingHaveTopBorder` / `drawingHaveRightBorder` /
`drawingHaveBottomBorder`. У ячейки таких свойств не бывает: все 2 135 записей корпуса с ними
принадлежат рисункам. Остальное в записи — общие свойства (заливка, шрифт, выравнивание).
Тело диаграмм (`Chart`, `GanttChart`) лежит в том же `<drawing>` в отдельном пространстве имён
и здесь не разбирается.
## Типичная структура макета печатной формы
Печатная форма обычно состоит из именованных горизонтальных областей:
+3 -3
View File
@@ -64,8 +64,6 @@
| `picHorizontalAlignment` | перечисление | `Auto`, `Center`, `Left`, `Right` |
| `picVerticalAlignment` | перечисление | `Top`, `Center`, `Bottom` |
| `textPosition` | перечисление | Положение текста относительно картинки: `Auto`, `Top`, `Right`, `Bottom` |
| `drawingBorder` | число | Рамка рисунка |
| `drawingHaveLeftBorder`, `drawingHaveTopBorder`, `drawingHaveRightBorder`, `drawingHaveBottomBorder` | да/нет | Наличие стороны рамки рисунка |
## Чего в стиле нет
@@ -74,4 +72,6 @@
- `fillType` — выводится из того, каким ключом задано содержимое ячейки
(`text` / `param` / `template`);
- `containsValue`, `valueType`, `controlType` — свойства конкретной ячейки, а не общего
оформления: задаются ключами ячейки `valueType` и `controlType`.
оформления: задаются ключами ячейки `valueType` и `controlType`;
- линия рисунка и её стороны — свойства рисунка: задаются его ключами `line` и `sides`
(у ячейки такого свойства нет вовсе).
+51 -1
View File
@@ -91,6 +91,8 @@
| `columnGroups` | нет | — | Группы колонок (см. ниже) |
| `header` / `footer` | нет | — | Верхний и нижний колонтитулы (см. ниже) |
| `printSettings` | нет | — | Параметры печати (см. ниже) |
| `pictures` | нет | — | Палитра картинок: ссылки на библиотеку платформы или данные (см. ниже) |
| `drawings` | нет | — | Рисунки: картинки, фигуры, надписи (см. ниже) |
## Области (`areas[]`)
@@ -384,6 +386,54 @@
Порядок в списке не важен: компилятор пишет группы так же, как платформа, — родитель
раньше вложенных, по возрастанию начала.
## Рисунки и картинки
Рисунок — объект поверх сетки ячеек: картинка, фигура или надпись. Его положение задают два
якоря: ячейка плюс смещение в точках от её левого верхнего угла.
```json
"pictures": {
"знак": { "ref": "v8ui:Стоп48" },
"логотип": { "data": "iVBORw0KGgo...", "transparent": false }
},
"drawings": [
{ "type": "Picture", "picture": "логотип", "name": "Логотип",
"begin": { "row": 1, "col": 1 },
"end": { "row": 3, "col": 2, "dy": 34, "dx": 115 },
"pictureSize": "Proportionally", "detail": "ПараметрРасшифровки" },
{ "type": "Rectangle", "style": "заливка",
"line": { "style": "Dashed", "width": 2 },
"sides": { "left": true, "top": true, "right": false, "bottom": false },
"begin": { "row": 5, "col": 1 }, "end": { "row": 6, "col": 3 } },
{ "type": "Text", "text": { "ru": "Подпись", "en": "Signature" },
"begin": { "row": 8, "col": 1 }, "end": { "row": 8, "col": 3, "dy": 12 } }
]
```
| Поле | Обяз. | По умолч. | Описание |
|------|:-----:|-----------|----------|
| `type` | нет | `Picture` | `Picture`, `Rectangle`, `Ellipse`, `Line`, `Text`, `Chart`, `GanttChart` |
| `begin` / `end` | да | — | Якоря: `row`, `col` (1-based) и смещения `dy`, `dx` в точках |
| `picture` | нет | — | Имя записи из `pictures` |
| `pictureSize` | нет | `Stretch` | Как картинка заполняет прямоугольник: `Stretch`, `AutoSize`, `Proportionally`, `RealSize` |
| `text` | нет | — | Надпись: строка или объект «язык → текст» |
| `name` | нет | — | Имя рисунка, по которому к нему обращаются из кода |
| `detail` | нет | — | Параметр расшифровки |
| `style` | нет | — | Именованный стиль: заливка, шрифт, выравнивание надписи |
| `line` | нет | — | Линия рисунка (она же его рамка) — как `border` у ячейки |
| `sides` | нет | — | Какие стороны рамки видны: `left`, `top`, `right`, `bottom` |
| `id` | нет | номер по порядку | Идентификатор рисунка |
| `zOrder` | нет | номер по порядку | Порядок перекрытия: чем больше, тем выше |
Порядок в списке `drawings` — порядок в документе; кто кого перекрывает, задаёт `zOrder`.
Запись в `pictures` — либо ссылка на библиотеку картинок платформы (`ref`), либо сами данные
в base64 (`data`). Пустая запись `{}` — картинка не задана, такое в макетах встречается.
С данными сочетаются `transparent` (прозрачность включена) и `transparentPixel`
(`{ "x": …, "y": … }` — координата пикселя, чей цвет считается прозрачным).
Одну запись `pictures` могут использовать несколько рисунков — данные в макете не дублируются.
## `rowStyle` — оформление строки
Стиль применяется ко ВСЕЙ ширине строки: позиции без явных ячеек получают тот же стиль. Так в табличных строках получаются сплошные рамки. Он же становится оформлением самой строки — именно так платформа хранит строку, оформленную целиком.
@@ -399,7 +449,7 @@ round-trip** (`/mxl-decompile` → `/mxl-compile`): в JSON оно не попа
XML не возвращается.
- объединения, не привязанные к ячейке (по всей высоте или ширине документа);
- рисунки и картинки, в том числе штрихкоды;
- настройки диаграмм (`Chart`, `GanttChart`) — сам рисунок сохраняется, его содержимое нет;
- область печати.
Пересборка макета из DSL — это полная перегенерация, а не точечная правка XML, поэтому