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
+5 -1
View File
@@ -66,7 +66,10 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-compile.ps1" -J
columnGroups: [{ cols, name, collapsed, titleLocation }],
header: { left, center, right, font, verticalAlignment, show, startPage }, footer: { … },
printSettings: { pageOrientation, topMargin, …, fitToPage, firstPageNumber },
columnSets: { name: { columns, columnWidths, columnStyles } }
columnSets: { name: { columns, columnWidths, columnStyles } },
pictures: { name: { ref } | { data, transparent, transparentPixel } | {} },
drawings: [{ type, begin: { row, col, dy, dx }, end: { … }, picture, pictureSize,
text, name, detail, style, line, sides, id, zOrder }]
}
```
@@ -87,6 +90,7 @@ powershell.exe -NoProfile -File "${CLAUDE_SKILL_DIR}/scripts/mxl-compile.ps1" -J
- `rowGroups`/`columnGroups` — группы строк и колонок (сворачиваются кнопкой на полях): плоский список диапазонов, вложенность выражена вхождением одного в другой
- `header`/`footer` — колонтитулы: три слота (`left`/`center`/`right`), общий шрифт и вертикальное выравнивание; текст может нести поля `[&НомерСтраницы]`, `[&Дата]`
- `note` — всплывающая подсказка у ячейки: строка, объект языков или `{ text, style, autoSize, box }`
- `drawings` — рисунки поверх сетки (картинка, фигура, надпись): положение задают два якоря «ячейка + смещение в точках», картинка берётся по имени из `pictures`
- `valueType` делает ячейку полем ввода (`"Number(15,3,nonneg)"`, `"String(10)"`, `"CatalogRef.Валюты"`, составной через ` + `); текста в такой ячейке быть не может, значение задаётся ключом `value`
Двухуровневая шапка массивами:
@@ -91,6 +91,8 @@
| `columnGroups` | нет | — | Группы колонок (см. ниже) |
| `header` / `footer` | нет | — | Верхний и нижний колонтитулы (см. ниже) |
| `printSettings` | нет | — | Параметры печати (см. ниже) |
| `pictures` | нет | — | Палитра картинок: ссылки на библиотеку платформы или данные (см. ниже) |
| `drawings` | нет | — | Рисунки: картинки, фигуры, надписи (см. ниже) |
## Области (`areas[]`)
@@ -376,6 +378,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` — оформление строки
Стиль применяется ко ВСЕЙ ширине строки: позиции без явных ячеек получают тот же стиль. Так в табличных строках получаются сплошные рамки. Он же становится оформлением самой строки — именно так платформа хранит строку, оформленную целиком.
@@ -391,7 +441,7 @@ round-trip** (`/mxl-decompile` → `/mxl-compile`): в JSON оно не попа
XML не возвращается.
- объединения, не привязанные к ячейке (по всей высоте или ширине документа);
- рисунки и картинки, в том числе штрихкоды;
- настройки диаграмм (`Chart`, `GanttChart`) — сам рисунок сохраняется, его содержимое нет;
- область печати.
Пересборка макета из DSL — это полная перегенерация, а не точечная правка XML, поэтому
@@ -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` (см. `dsl-spec.md`).
оформления: задаются ключами ячейки `valueType` и `controlType`;
- линия рисунка и её стороны — свойства рисунка: задаются его ключами `line` и `sides`
(у ячейки такого свойства нет вовсе) (см. `dsl-spec.md`).
@@ -1,4 +1,4 @@
# mxl-compile v1.47 — Compile 1C spreadsheet from JSON
# mxl-compile v1.48 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -287,11 +287,15 @@ if (-not $hasDefault) {
$script:lineRegistry = @()
function Get-LineKey {
# Вид линии входит в ключ: одинаковые по стилю линии рамки ячейки и рисунка — РАЗНЫЕ записи,
# у них разный xsi:type.
param($ln)
return "$($ln.Style)|$($ln.Width)|$($ln.Gap)"
return "$($ln.Style)|$($ln.Width)|$($ln.Gap)|$($ln.Kind)"
}
function Register-Line {
# Запись палитры линий типизирована: у рамки ячейки xsi:type Cell, у линии рисунка Drawing.
# Вид выводится из свойства, которое на линию ссылается, — отдельного ключа в DSL не нужно.
param($ln)
$key = Get-LineKey $ln
for ($i = 0; $i -lt $script:lineRegistry.Count; $i++) {
@@ -589,7 +593,11 @@ function Resolve-Style {
continue
}
switch ($kinds[$tag]) {
'line' { $props[$tag] = Register-Line (ConvertTo-LineValue $val $where) }
'line' {
$lnVal = ConvertTo-LineValue $val $where
$lnVal['Kind'] = if ($tag -ceq 'drawingBorder') { 'Drawing' } else { 'Cell' }
$props[$tag] = Register-Line $lnVal
}
'bool' { $props[$tag] = if ($val -eq $true -or "$val" -eq 'true') { 'true' } else { 'false' } }
'int' { $props[$tag] = [int]$val }
'enum' {
@@ -1023,15 +1031,15 @@ function Get-FormatMlTags {
# line — ссылка в палитру <line>; color — #RRGGBB / style: / web: / win:
# ml — многоязычная строка; enum — замкнутый список (см. Get-FormatEnumValues)
# containsValue / valueType / controlType сюда НЕ входят: это свойства конкретной ячейки,
# а стиль — сущность общая, один на многие ячейки.
# а стиль — сущность общая, один на многие ячейки. По той же причине здесь нет линии рисунка
# (drawingBorder, drawingHave*Border): на корпусе все 2 135 записей с ними принадлежат только
# рисункам, у ячейки такого свойства не бывает — они задаются ключами самого рисунка.
function Get-FormatTagKind {
return @{
'autoIndent' = 'int'; 'autoMarkIncomplete' = 'bool'; 'autoWidthCalculation' = 'bool'
'backColor' = 'color'; 'border' = 'line'; 'borderColor' = 'color'
'bottomBorder' = 'line'; 'bySelectedColumns' = 'bool'; 'columnSizeChange' = 'enum'
'detailsUse' = 'enum'; 'drawingBorder' = 'int'
'drawingHaveBottomBorder' = 'bool'; 'drawingHaveLeftBorder' = 'bool'
'drawingHaveRightBorder' = 'bool'; 'drawingHaveTopBorder' = 'bool'
'detailsUse' = 'enum'
'editFormat' = 'ml'; 'fillType' = 'enum'; 'font' = 'int'; 'format' = 'ml'
'height' = 'int'; 'hidden' = 'bool'; 'horizontalAlignment' = 'enum'
'hyperLink' = 'bool'; 'indent' = 'int'; 'leftBorder' = 'line'
@@ -1582,6 +1590,100 @@ function Emit-PrintSettings {
X "`t</printSettings>"
}
# Палитра картинок. Ресурс хранится двумя способами: ссылкой на библиотеку платформы
# (ref="v8ui:Имя") либо данными base64 прямо в макете (9 905 из 9 988 картинок корпуса).
# На неё ссылаются и рисунки (pictureIndex), и ячейки (picIndex в стиле) — индекс 1-based.
$pictureNames = @{} # имя из DSL → 1-based индекс
$pictureEntries = @()
if ($def.pictures) {
foreach ($pr in $def.pictures.PSObject.Properties) {
# Пустая запись — законная картинка «не задана»: в корпусе таких 151, ровно по одной
# на макет. Ошибкой считаем только запись с непонятным содержимым.
$entry = @{ Ref = ''; Data = ''; Transparent = ''; PixelX = ''; PixelY = '' }
if ($pr.Value.ref) { $entry.Ref = "$($pr.Value.ref)" }
if ($null -ne $pr.Value.data) { $entry.Data = "$($pr.Value.data)" }
if ($null -ne $pr.Value.transparent) {
$entry.Transparent = if ($pr.Value.transparent -eq $true -or "$($pr.Value.transparent)" -eq 'true') { 'true' } else { 'false' }
}
if ($null -ne $pr.Value.transparentPixel) {
$entry.PixelX = "$([int]$pr.Value.transparentPixel.x)"
$entry.PixelY = "$([int]$pr.Value.transparentPixel.y)"
}
if (-not $entry.Ref -and -not $entry.Data -and
($entry.Transparent -or $entry.PixelX)) {
[Console]::Error.WriteLine("pictures[$($pr.Name)]: 'transparent' and 'transparentPixel' require 'data'")
exit 1
}
$pictureEntries += $entry
$pictureNames[$pr.Name] = $pictureEntries.Count
}
}
# Рисунки: своя геометрия из двух якорей, тип, ссылка на картинку, текст, расшифровка.
# id и zOrder — данные, а не позиция: на корпусе они расходятся у 8 253 рисунков из 11 268.
$drawingTypes = @('Picture', 'Rectangle', 'Ellipse', 'Line', 'Text', 'Chart', 'GanttChart')
$drawings = @()
$drawingIdx = 0
foreach ($dr in $def.drawings) {
$drawingIdx++
$where = "drawings[$drawingIdx]"
$type = if ($dr.type) { "$($dr.type)" } else { 'Picture' }
$canonType = @($drawingTypes | Where-Object { $_ -eq $type })[0]
if (-not $canonType) {
[Console]::Error.WriteLine("${where}: unknown drawing 'type' `"$type`". Allowed: $($drawingTypes -join ', ')")
exit 1
}
$picIdx = 0
if ($dr.picture) {
if (-not $pictureNames.ContainsKey("$($dr.picture)")) {
[Console]::Error.WriteLine("${where}: unknown 'picture' `"$($dr.picture)`" — not declared in pictures")
exit 1
}
$picIdx = $pictureNames["$($dr.picture)"]
}
# Оформление рисунка: общее — из именованного стиля, чисто рисуночное (линия и её стороны)
# — своими ключами, поверх стиля. Тот же приём, что у ячейки с fillType и значением.
$props = @{}
if ($dr.style) { $props = Resolve-Style -styleName "$($dr.style)" -fillType "" }
if ($null -ne $dr.line) {
$lnVal = ConvertTo-LineValue $dr.line $where
$lnVal['Kind'] = 'Drawing'
$props['drawingBorder'] = Register-Line $lnVal
}
foreach ($side in @('left', 'top', 'right', 'bottom')) {
$v = $dr.sides.$side
if ($null -ne $v) {
$tag = 'drawingHave' + $side.Substring(0,1).ToUpperInvariant() + $side.Substring(1) + 'Border'
$props[$tag] = if ($v -eq $true -or "$v" -eq 'true') { 'true' } else { 'false' }
}
}
$fmtIdx = 0
if ($props.Count -gt 0) { $fmtIdx = Register-Format $props }
function Get-Anchor {
param($node, [string]$rowKey, [string]$colKey)
return @{
Row = if ($node -and $null -ne $node.row) { [int]$node.row - 1 } else { 0 }
Col = if ($node -and $null -ne $node.col) { [int]$node.col - 1 } else { 0 }
Dy = if ($node -and $null -ne $node.dy) { [int]$node.dy } else { 0 }
Dx = if ($node -and $null -ne $node.dx) { [int]$node.dx } else { 0 }
}
}
$drawings += @{
Type = $canonType
Id = if ($null -ne $dr.id) { [int]$dr.id } else { $drawingIdx }
ZOrder = if ($null -ne $dr.zOrder) { [int]$dr.zOrder } else { $drawingIdx }
FormatIdx = $fmtIdx
Detail = $dr.detail
Text = $dr.text
Begin = Get-Anchor $dr.begin
End = Get-Anchor $dr.end
PictureSize = if ($dr.pictureSize) { "$($dr.pictureSize)" } else { 'Stretch' }
PictureIdx = $picIdx
Name = $dr.name
}
}
# Формат по умолчанию — последняя запись палитры (см. выше).
$defaultFormatIndex = Register-Format @{ width = $defaultWidth }
@@ -2173,6 +2275,47 @@ if ($def.namedAreas) {
}
}
# 7d-bis2. Рисунки идут сразу после строк, до колонтитулов. Порядок тегов снят с корпуса:
# у всех 11 268 рисунков он один и тот же.
foreach ($dr in $drawings) {
X "`t<drawing>"
X "`t`t<drawingType>$($dr.Type)</drawingType>"
X "`t`t<id>$($dr.Id)</id>"
X "`t`t<formatIndex>$($dr.FormatIdx)</formatIndex>"
if ($dr.Detail) { X "`t`t<detailParameter>$($dr.Detail)</detailParameter>" }
if ($null -ne $dr.Text) {
$pairs = @()
if ($dr.Text -is [System.Management.Automation.PSCustomObject]) {
foreach ($pr in $dr.Text.PSObject.Properties) { $pairs += @{ Lang = $pr.Name; Text = "$($pr.Value)" } }
} else {
foreach ($l in $textLanguages) { $pairs += @{ Lang = $l; Text = "$($dr.Text)" } }
}
X "`t`t<text>"
foreach ($pr in $pairs) {
X "`t`t`t<v8:item>"
X "`t`t`t`t<v8:lang>$($pr.Lang)</v8:lang>"
X "`t`t`t`t<v8:content>$(Esc-XmlText $pr.Text)</v8:content>"
X "`t`t`t</v8:item>"
}
X "`t`t</text>"
}
X "`t`t<beginRow>$($dr.Begin.Row)</beginRow>"
X "`t`t<beginRowOffset>$($dr.Begin.Dy)</beginRowOffset>"
X "`t`t<endRow>$($dr.End.Row)</endRow>"
X "`t`t<endRowOffset>$($dr.End.Dy)</endRowOffset>"
X "`t`t<beginColumn>$($dr.Begin.Col)</beginColumn>"
X "`t`t<beginColumnOffset>$($dr.Begin.Dx)</beginColumnOffset>"
X "`t`t<endColumn>$($dr.End.Col)</endColumn>"
X "`t`t<endColumnOffset>$($dr.End.Dx)</endColumnOffset>"
# autoSize у рисунка на корпусе всегда false (11 268 из 11 268), «АвтоРазмер» из
# диалога уходит в pictureSize.
X "`t`t<autoSize>false</autoSize>"
X "`t`t<pictureSize>$($dr.PictureSize)</pictureSize>"
X "`t`t<zOrder>$($dr.ZOrder)</zOrder>"
if ($dr.PictureIdx -gt 0) { X "`t`t<pictureIndex>$($dr.PictureIdx)</pictureIndex>" }
X "`t</drawing>"
}
# 7d-ter. Колонтитулы: шесть слотов идут после строк и перед скалярными свойствами документа.
foreach ($slot in $script:headerSlots) {
if ($def.header) { Emit-HeaderSlot "$($slot)Header" $def.header.$slot $headerFmt }
@@ -2294,9 +2437,15 @@ $colGroups = Get-Groups 'columnGroups' 'cols'
# 7e. Scalar metadata
X "`t<templateMode>true</templateMode>"
X "`t<defaultFormatIndex>$defaultFormatIndex</defaultFormatIndex>"
X "`t<height>$totalRowCount</height>"
# Рисунок расширяет документ, не создавая строк: на стендах высота равна нижней границе
# самого нижнего рисунка, при том что строк записана всего одна.
$docHeight = $totalRowCount
foreach ($dr in $drawings) {
if (($dr.End.Row + 1) -gt $docHeight) { $docHeight = $dr.End.Row + 1 }
}
X "`t<height>$docHeight</height>"
if ($rowGroups.Count -gt 0) { X "`t<vgLevels>$(Get-GroupLevels $rowGroups)</vgLevels>" }
X "`t<vgRows>$totalRowCount</vgRows>"
X "`t<vgRows>$docHeight</vgRows>"
Emit-Groups 'vg' $rowGroups
Emit-Groups 'hg' $colGroups
@@ -2324,8 +2473,20 @@ function Get-OrdinalKey {
param([string]$name)
return (($name.ToLowerInvariant().ToCharArray() | ForEach-Object { '{0:X4}' -f [int]$_ }) -join '')
}
# Имя рисунка — namedItem другого типа, но список общий: на корпусе оба вида отсортированы
# вместе по имени во всех 266 макетах с именованными рисунками.
foreach ($dr in $drawings) {
if ($dr.Name) { $namedItems += @{ Name = "$($dr.Name)"; DrawingId = $dr.Id } }
}
$sortedNamedItems = @($namedItems | Sort-Object -Property @{ Expression = { Get-OrdinalKey $_.Name } })
foreach ($ni in $sortedNamedItems) {
if ($ni.DrawingId) {
X "`t<namedItem xsi:type=`"NamedItemDrawing`">"
X "`t`t<name>$($ni.Name)</name>"
X "`t`t<drawingID>$($ni.DrawingId)</drawingID>"
X "`t</namedItem>"
continue
}
# Тип области выводится из указанных осей, как в ТабличныйДокумент.Область():
# нет колонок → полоса строк, нет строк → полоса колонок, обе → прямоугольник.
$hasRows = $ni.BeginRow -ge 0
@@ -2347,7 +2508,8 @@ foreach ($ni in $sortedNamedItems) {
# 7h. Line palette
foreach ($ln in $script:lineRegistry) {
X "`t<line width=`"$($ln.Width)`" gap=`"$($ln.Gap)`">"
X "`t`t<v8ui:style xsi:type=`"v8ui:SpreadsheetDocumentCellLineType`">$($ln.Style)</v8ui:style>"
$lineKind = if ($ln.Kind -ceq 'Drawing') { 'SpreadsheetDocumentDrawingLineType' } else { 'SpreadsheetDocumentCellLineType' }
X "`t`t<v8ui:style xsi:type=`"v8ui:$lineKind`">$($ln.Style)</v8ui:style>"
X "`t</line>"
}
@@ -2404,7 +2566,31 @@ foreach ($key in $formatRegistry.Keys) {
X "`t</format>"
}
# 7k. Close document
# 7k. Палитра картинок — последний блок документа. Индекс здесь 0-based, а ссылки
# на него (pictureIndex рисунка, picIndex стиля) 1-based.
$picIdx = 0
foreach ($pic in $pictureEntries) {
X "`t<picture>"
X "`t`t<index>$picIdx</index>"
if ($pic.Ref) {
X "`t`t<picture ref=`"$(Esc-Xml $pic.Ref)`"/>"
} elseif (-not $pic.Data) {
X "`t`t<picture/>"
} else {
$attr = if ($pic.Transparent) { " t=`"$($pic.Transparent)`"" } else { '' }
if ($pic.PixelX) { $attr += " tx=`"$($pic.PixelX)`" ty=`"$($pic.PixelY)`"" }
# Данные платформа переносит по строкам тем же переводом, что и весь файл, —
# в отличие от блоба настроек элемента управления, где перенос голый LF.
$parts = @("$($pic.Data)" -split "`r?`n")
$parts[0] = "`t`t<picture$attr>$($parts[0])"
$parts[-1] = "$($parts[-1])</picture>"
foreach ($line in $parts) { X $line }
}
X "`t</picture>"
$picIdx++
}
# 7l. Close document
X '</document>'
# --- 8. Write output ---
+179 -14
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# mxl-compile v1.47 — Compile 1C spreadsheet from JSON
# mxl-compile v1.48 — Compile 1C spreadsheet from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import hashlib
@@ -355,14 +355,14 @@ def format_tag_kind():
line — ссылка в палитру <line>; color — #RRGGBB / style: / web: / win:
ml — многоязычная строка; enum — замкнутый список (см. format_enum_values).
containsValue / valueType / controlType сюда НЕ входят: это свойства конкретной ячейки,
а стиль — сущность общая, один на многие ячейки."""
а стиль — сущность общая, один на многие ячейки. По той же причине здесь нет линии рисунка
(drawingBorder, drawingHave*Border): на корпусе все 2 135 записей с ними принадлежат только
рисункам, у ячейки такого свойства не бывает — они задаются ключами самого рисунка."""
return {
'autoIndent': 'int', 'autoMarkIncomplete': 'bool', 'autoWidthCalculation': 'bool',
'backColor': 'color', 'border': 'line', 'borderColor': 'color',
'bottomBorder': 'line', 'bySelectedColumns': 'bool', 'columnSizeChange': 'enum',
'detailsUse': 'enum', 'drawingBorder': 'int',
'drawingHaveBottomBorder': 'bool', 'drawingHaveLeftBorder': 'bool',
'drawingHaveRightBorder': 'bool', 'drawingHaveTopBorder': 'bool',
'detailsUse': 'enum',
'editFormat': 'ml', 'fillType': 'enum', 'font': 'int', 'format': 'ml',
'height': 'int', 'hidden': 'bool', 'horizontalAlignment': 'enum',
'hyperLink': 'bool', 'indent': 'int', 'leftBorder': 'line',
@@ -382,8 +382,8 @@ def format_enum_values():
'detailsUse': ['Cell', 'Row', 'WithoutProcessing'],
'fillType': ['Parameter', 'Template', 'Text'],
'horizontalAlignment': ['Auto', 'Center', 'Justify', 'Left', 'Right'],
'pattern': ['Pattern7', 'Pattern10', 'Pattern12', 'Pattern13', 'Pattern14',
'Pattern16', 'Solid', 'WithoutPattern'],
# Узоры платформа нумерует подряд, без семантических имён: «Узор 1» … «Узор 17».
'pattern': ['WithoutPattern', 'Solid', 'Pattern1', 'Pattern2', 'Pattern3', 'Pattern4', 'Pattern5', 'Pattern6', 'Pattern7', 'Pattern8', 'Pattern9', 'Pattern10', 'Pattern11', 'Pattern12', 'Pattern13', 'Pattern14', 'Pattern15', 'Pattern16', 'Pattern17'],
'picHorizontalAlignment': ['Auto', 'Center', 'Left', 'Right'],
'picVerticalAlignment': ['Bottom', 'Center', 'Top'],
'pictureSizeMode': ['AutoSize', 'Proportionally', 'RealSize'],
@@ -872,9 +872,12 @@ def main():
line_registry = []
def register_line(ln):
key = (ln['Style'], str(ln['Width']), ln['Gap'])
# Запись палитры линий типизирована: у рамки ячейки xsi:type Cell, у линии рисунка
# Drawing. Вид входит в ключ, иначе одинаковые по стилю линии двух видов слились бы.
key = (ln['Style'], str(ln['Width']), ln['Gap'], ln.get('Kind', 'Cell'))
for i, existing in enumerate(line_registry):
if (existing['Style'], str(existing['Width']), existing['Gap']) == key:
if (existing['Style'], str(existing['Width']), existing['Gap'],
existing.get('Kind', 'Cell')) == key:
return i
line_registry.append(ln)
return len(line_registry) - 1
@@ -1122,7 +1125,9 @@ def main():
continue
kind = kinds[tag]
if kind == 'line':
props[tag] = register_line(to_line_value(val, where))
ln_val = to_line_value(val, where)
ln_val['Kind'] = 'Drawing' if tag == 'drawingBorder' else 'Cell'
props[tag] = register_line(ln_val)
elif kind == 'bool':
props[tag] = 'true' if (val is True or str(val) == 'true') else 'false'
elif kind == 'int':
@@ -1542,6 +1547,87 @@ def main():
lines.extend(emitted)
lines.append('\t</printSettings>')
# Палитра картинок. Ресурс хранится двумя способами: ссылкой на библиотеку платформы
# (ref="v8ui:Имя") либо данными base64 прямо в макете (9 905 из 9 988 картинок корпуса).
# На неё ссылаются и рисунки (pictureIndex), и ячейки (picIndex в стиле) — индекс 1-based.
picture_names = {}
picture_entries = []
for pic_name, pic_def in (defn.get('pictures') or {}).items():
# Пустая запись — законная картинка «не задана»: в корпусе таких 151, ровно по одной
# на макет. Ошибкой считаем только запись с непонятным содержимым.
entry = {'Ref': '', 'Data': '', 'Transparent': '', 'PixelX': '', 'PixelY': ''}
if pic_def.get('ref'):
entry['Ref'] = str(pic_def['ref'])
if pic_def.get('data') is not None:
entry['Data'] = str(pic_def['data'])
if pic_def.get('transparent') is not None:
entry['Transparent'] = 'true' if (pic_def['transparent'] is True
or str(pic_def['transparent']).lower() == 'true') else 'false'
if pic_def.get('transparentPixel') is not None:
entry['PixelX'] = str(int(pic_def['transparentPixel'].get('x', 0)))
entry['PixelY'] = str(int(pic_def['transparentPixel'].get('y', 0)))
if not entry['Ref'] and not entry['Data'] and (entry['Transparent'] or entry['PixelX']):
print(f"pictures[{pic_name}]: 'transparent' and 'transparentPixel' require 'data'", file=sys.stderr)
sys.exit(1)
picture_entries.append(entry)
picture_names[pic_name] = len(picture_entries)
# Рисунки: своя геометрия из двух якорей, тип, ссылка на картинку, текст, расшифровка.
# id и zOrder — данные, а не позиция: на корпусе они расходятся у 8 253 рисунков из 11 268.
DRAWING_TYPES = ('Picture', 'Rectangle', 'Ellipse', 'Line', 'Text', 'Chart', 'GanttChart')
def drawing_anchor(node):
node = node or {}
return {
'Row': int(node['row']) - 1 if node.get('row') is not None else 0,
'Col': int(node['col']) - 1 if node.get('col') is not None else 0,
'Dy': int(node['dy']) if node.get('dy') is not None else 0,
'Dx': int(node['dx']) if node.get('dx') is not None else 0,
}
drawings = []
for idx, dr in enumerate(defn.get('drawings') or [], start=1):
where = f'drawings[{idx}]'
dtype = str(dr.get('type') or 'Picture')
canon_type = next((t for t in DRAWING_TYPES if t.lower() == dtype.lower()), None)
if canon_type is None:
print(f'{where}: unknown drawing \'type\' "{dtype}". Allowed: {", ".join(DRAWING_TYPES)}',
file=sys.stderr)
sys.exit(1)
pic_idx = 0
if dr.get('picture'):
if str(dr['picture']) not in picture_names:
print(f'{where}: unknown \'picture\' "{dr["picture"]}" — not declared in pictures',
file=sys.stderr)
sys.exit(1)
pic_idx = picture_names[str(dr['picture'])]
# Оформление рисунка: общее — из именованного стиля, чисто рисуночное (линия и её
# стороны) — своими ключами, поверх стиля. Тот же приём, что у ячейки с fillType.
props = resolve_style(str(dr['style']), '') if dr.get('style') else {}
if dr.get('line') is not None:
ln_val = to_line_value(dr['line'], where)
ln_val['Kind'] = 'Drawing'
props['drawingBorder'] = register_line(ln_val)
for side in ('left', 'top', 'right', 'bottom'):
v = (dr.get('sides') or {}).get(side)
if v is not None:
tag = 'drawingHave' + side.capitalize() + 'Border'
props[tag] = 'true' if (v is True or str(v).lower() == 'true') else 'false'
fmt_idx = register_format(props) if props else 0
drawings.append({
'Type': canon_type,
'Id': int(dr['id']) if dr.get('id') is not None else idx,
'ZOrder': int(dr['zOrder']) if dr.get('zOrder') is not None else idx,
'FormatIdx': fmt_idx,
'Detail': dr.get('detail'),
'Text': dr.get('text'),
'Begin': drawing_anchor(dr.get('begin')),
'End': drawing_anchor(dr.get('end')),
'PictureSize': str(dr.get('pictureSize') or 'Stretch'),
'PictureIdx': pic_idx,
'Name': dr.get('name'),
})
# Формат по умолчанию — последняя запись палитры (см. выше).
default_format_index = register_format({'width': default_width})
@@ -2065,6 +2151,45 @@ def main():
'ColumnSet': na_set,
})
# 7d-bis2. Рисунки идут сразу после строк, до колонтитулов. Порядок тегов снят с корпуса:
# у всех 11 268 рисунков он один и тот же.
for dr in drawings:
lines.append('\t<drawing>')
lines.append(f'\t\t<drawingType>{dr["Type"]}</drawingType>')
lines.append(f'\t\t<id>{dr["Id"]}</id>')
lines.append(f'\t\t<formatIndex>{dr["FormatIdx"]}</formatIndex>')
if dr['Detail']:
lines.append(f'\t\t<detailParameter>{dr["Detail"]}</detailParameter>')
if dr['Text'] is not None:
value = dr['Text']
if isinstance(value, dict):
pairs = [(str(k), str(v)) for k, v in value.items()]
else:
pairs = [(lang, str(value)) for lang in text_languages]
lines.append('\t\t<text>')
for lang, content in pairs:
lines.append('\t\t\t<v8:item>')
lines.append(f'\t\t\t\t<v8:lang>{lang}</v8:lang>')
lines.append(f'\t\t\t\t<v8:content>{esc_xml_text(content)}</v8:content>')
lines.append('\t\t\t</v8:item>')
lines.append('\t\t</text>')
lines.append(f'\t\t<beginRow>{dr["Begin"]["Row"]}</beginRow>')
lines.append(f'\t\t<beginRowOffset>{dr["Begin"]["Dy"]}</beginRowOffset>')
lines.append(f'\t\t<endRow>{dr["End"]["Row"]}</endRow>')
lines.append(f'\t\t<endRowOffset>{dr["End"]["Dy"]}</endRowOffset>')
lines.append(f'\t\t<beginColumn>{dr["Begin"]["Col"]}</beginColumn>')
lines.append(f'\t\t<beginColumnOffset>{dr["Begin"]["Dx"]}</beginColumnOffset>')
lines.append(f'\t\t<endColumn>{dr["End"]["Col"]}</endColumn>')
lines.append(f'\t\t<endColumnOffset>{dr["End"]["Dx"]}</endColumnOffset>')
# autoSize у рисунка на корпусе всегда false (11 268 из 11 268), «АвтоРазмер» из
# диалога уходит в pictureSize.
lines.append('\t\t<autoSize>false</autoSize>')
lines.append(f'\t\t<pictureSize>{dr["PictureSize"]}</pictureSize>')
lines.append(f'\t\t<zOrder>{dr["ZOrder"]}</zOrder>')
if dr['PictureIdx'] > 0:
lines.append(f'\t\t<pictureIndex>{dr["PictureIdx"]}</pictureIndex>')
lines.append('\t</drawing>')
# 7d-ter. Колонтитулы: шесть слотов идут после строк и перед скалярными свойствами документа.
for slot in ('left', 'center', 'right'):
if defn.get('header'):
@@ -2176,10 +2301,15 @@ def main():
# 7e. Scalar metadata
lines.append(f'\t<templateMode>true</templateMode>')
lines.append(f'\t<defaultFormatIndex>{default_format_index}</defaultFormatIndex>')
lines.append(f'\t<height>{total_row_count}</height>')
# Рисунок расширяет документ, не создавая строк: на стендах высота равна нижней границе
# самого нижнего рисунка, при том что строк записана всего одна.
doc_height = total_row_count
for dr in drawings:
doc_height = max(doc_height, dr['End']['Row'] + 1)
lines.append(f'\t<height>{doc_height}</height>')
if row_groups:
lines.append(f'\t<vgLevels>{group_levels(row_groups)}</vgLevels>')
lines.append(f'\t<vgRows>{total_row_count}</vgRows>')
lines.append(f'\t<vgRows>{doc_height}</vgRows>')
emit_groups(lines, 'vg', row_groups)
emit_groups(lines, 'hg', col_groups)
@@ -2200,7 +2330,19 @@ def main():
# с несколькими элементами иного порядка нет ни разу. Сортировка регистронезависимая и
# ординальная (в ps1 поэтому нельзя Sort-Object — он сортирует по текущей культуре).
# NB: имён с «ё» в выборке не встретилось, этот случай не проверен.
# Имя рисунка — namedItem другого типа, но список общий: на корпусе оба вида отсортированы
# вместе по имени во всех 266 макетах с именованными рисунками.
for dr in drawings:
if dr['Name']:
named_items.append({'Name': str(dr['Name']), 'DrawingId': dr['Id']})
for ni in sorted(named_items, key=lambda x: str(x['Name']).lower()):
if ni.get('DrawingId'):
lines.append('\t<namedItem xsi:type="NamedItemDrawing">')
lines.append(f'\t\t<name>{ni["Name"]}</name>')
lines.append(f'\t\t<drawingID>{ni["DrawingId"]}</drawingID>')
lines.append('\t</namedItem>')
continue
# Тип области выводится из указанных осей, как в ТабличныйДокумент.Область():
# нет колонок → полоса строк, нет строк → полоса колонок, обе → прямоугольник.
has_rows = int(ni['BeginRow']) >= 0
@@ -2222,7 +2364,9 @@ def main():
# 7h. Line palette
for ln in line_registry:
lines.append(f'\t<line width="{ln["Width"]}" gap="{ln["Gap"]}">')
lines.append(f'\t\t<v8ui:style xsi:type="v8ui:SpreadsheetDocumentCellLineType">{ln["Style"]}</v8ui:style>')
line_kind = ('SpreadsheetDocumentDrawingLineType' if ln.get('Kind') == 'Drawing'
else 'SpreadsheetDocumentCellLineType')
lines.append(f'\t\t<v8ui:style xsi:type="v8ui:{line_kind}">{ln["Style"]}</v8ui:style>')
lines.append('\t</line>')
# 7i. Font palette
@@ -2275,7 +2419,28 @@ def main():
lines.append('\t</format>')
# 7k. Close document
# 7k. Палитра картинок — последний блок документа. Индекс здесь 0-based, а ссылки
# на него (pictureIndex рисунка, picIndex стиля) 1-based.
for pic_i, pic in enumerate(picture_entries):
lines.append('\t<picture>')
lines.append(f'\t\t<index>{pic_i}</index>')
if pic['Ref']:
lines.append(f'\t\t<picture ref="{esc_xml(pic["Ref"])}"/>')
elif not pic['Data']:
lines.append('\t\t<picture/>')
else:
attr = f' t="{pic["Transparent"]}"' if pic['Transparent'] else ''
if pic['PixelX']:
attr += f' tx="{pic["PixelX"]}" ty="{pic["PixelY"]}"'
# Данные платформа переносит по строкам тем же переводом, что и весь файл, —
# в отличие от блоба настроек элемента управления, где перенос голый LF.
parts = str(pic['Data']).replace('\r\n', '\n').split('\n')
parts[0] = f'\t\t<picture{attr}>{parts[0]}'
parts[-1] = f'{parts[-1]}</picture>'
lines.extend(parts)
lines.append('\t</picture>')
# 7l. Close document
lines.append('</document>')
# --- 8. Write output ---
@@ -1,4 +1,4 @@
# mxl-decompile v1.26 — Decompile 1C spreadsheet to JSON
# mxl-decompile v1.27 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -41,7 +41,7 @@ function Get-FormatTagKind {
'autoIndent' = 'int'; 'autoMarkIncomplete' = 'bool'; 'autoWidthCalculation' = 'bool'
'backColor' = 'color'; 'border' = 'line'; 'borderColor' = 'color'
'bottomBorder' = 'line'; 'bySelectedColumns' = 'bool'; 'columnSizeChange' = 'enum'
'detailsUse' = 'enum'; 'drawingBorder' = 'int'
'detailsUse' = 'enum'; 'drawingBorder' = 'line'
'drawingHaveBottomBorder' = 'bool'; 'drawingHaveLeftBorder' = 'bool'
'drawingHaveRightBorder' = 'bool'; 'drawingHaveTopBorder' = 'bool'
'editFormat' = 'ml'; 'fillType' = 'enum'; 'font' = 'int'; 'format' = 'ml'
@@ -265,6 +265,98 @@ function Get-Format {
return $rawFormats[$idx - 1]
}
# --- 4-bis. Палитра картинок и рисунки ---
# Картинка хранится ссылкой на библиотеку либо данными base64; ссылки на палитру (у рисунка
# pictureIndex, у ячейки picIndex) — 1-based, сам <index> — 0-based.
$picturesOut = [ordered]@{}
$pictureKey = @{}
$picI = 0
foreach ($picNode in $root.SelectNodes("d:picture", $ns)) {
$inner = $picNode.SelectSingleNode("d:picture", $ns)
if (-not $inner) { continue }
$picI++
$name = "pic$picI"
$entry = [ordered]@{}
if ($inner.GetAttribute('ref')) {
$entry["ref"] = $inner.GetAttribute('ref')
} elseif (($inner.InnerText).Trim()) {
# System.Xml переводы строк в тексте не нормализует, а lxml нормализует: без этой
# замены порты дали бы разный JSON на одном и том же файле.
$entry["data"] = ($inner.InnerText -replace "`r`n", "`n").Trim()
if ($inner.HasAttribute('t')) { $entry["transparent"] = ($inner.GetAttribute('t') -ceq 'true') }
# Пиксель прозрачного цвета: координата внутри самой картинки (проверено —
# это не её размеры). В корпусе встречается без атрибута t.
if ($inner.HasAttribute('tx')) {
$entry["transparentPixel"] = [ordered]@{
x = [int]$inner.GetAttribute('tx')
y = [int]$inner.GetAttribute('ty')
}
}
}
$picturesOut[$name] = $entry
$pictureKey[$picI] = $name
}
$drawingNames = @{}
foreach ($niNode in $root.SelectNodes("d:namedItem", $ns)) {
if ($niNode.GetAttribute("type", "http://www.w3.org/2001/XMLSchema-instance") -cne 'NamedItemDrawing') { continue }
$idN = $niNode.SelectSingleNode("d:drawingID", $ns)
$nmN = $niNode.SelectSingleNode("d:name", $ns)
$drawingNames[$(if ($idN) { $idN.InnerText } else { '' })] = $(if ($nmN) { $nmN.InnerText } else { '' })
}
$drawingsOut = @()
$drI = 0
foreach ($dr in $root.SelectNodes("d:drawing", $ns)) {
$drI++
$item = [ordered]@{}
$tN = $dr.SelectSingleNode("d:drawingType", $ns)
$item["type"] = if ($tN) { $tN.InnerText } else { 'Picture' }
$idN = $dr.SelectSingleNode("d:id", $ns)
$did = if ($idN) { $idN.InnerText } else { "$drI" }
if ($did -cne "$drI") { $item["id"] = [int]$did }
$zN = $dr.SelectSingleNode("d:zOrder", $ns)
$zorder = if ($zN) { $zN.InnerText } else { "$drI" }
if ($zorder -cne "$drI") { $item["zOrder"] = [int]$zorder }
if ($drawingNames.ContainsKey($did)) { $item["name"] = $drawingNames[$did] }
$piN = $dr.SelectSingleNode("d:pictureIndex", $ns)
if ($piN -and $pictureKey.ContainsKey([int]$piN.InnerText)) {
$item["picture"] = $pictureKey[[int]$piN.InnerText]
}
$dpN = $dr.SelectSingleNode("d:detailParameter", $ns)
if ($dpN -and $dpN.InnerText) { $item["detail"] = $dpN.InnerText }
$tEl = $dr.SelectSingleNode("d:text", $ns)
if ($tEl) {
$byLang = [ordered]@{}
foreach ($it in $tEl.SelectNodes("v8:item", $ns)) {
$l = $it.SelectSingleNode("v8:lang", $ns)
$cnt = $it.SelectSingleNode("v8:content", $ns)
$byLang[$(if ($l) { $l.InnerText } else { '' })] = $(if ($cnt) { $cnt.InnerText } else { '' })
}
$item["text"] = $byLang
}
# Оформление разбирается позже: линию нужно развернуть в описание, а помощник для
# этого появляется вместе с палитрой стилей.
$fN = $dr.SelectSingleNode("d:formatIndex", $ns)
foreach ($pair in @(@('begin', 'beginRowOffset', 'beginColumnOffset'), @('end', 'endRowOffset', 'endColumnOffset'))) {
$prefix = $pair[0]
$rN = $dr.SelectSingleNode("d:$($prefix)Row", $ns)
$cN = $dr.SelectSingleNode("d:$($prefix)Column", $ns)
$dyN = $dr.SelectSingleNode("d:$($pair[1])", $ns)
$dxN = $dr.SelectSingleNode("d:$($pair[2])", $ns)
$item[$prefix] = [ordered]@{
row = $(if ($rN) { [int]$rN.InnerText } else { 0 }) + 1
col = $(if ($cN) { [int]$cN.InnerText } else { 0 }) + 1
dy = $(if ($dyN) { [int]$dyN.InnerText } else { 0 })
dx = $(if ($dxN) { [int]$dxN.InnerText } else { 0 })
}
}
$psN = $dr.SelectSingleNode("d:pictureSize", $ns)
if ($psN -and $psN.InnerText -cne 'Stretch') { $item["pictureSize"] = $psN.InnerText }
$item["_fmt"] = if ($fN) { [int]$fN.InnerText } else { 0 }
$drawingsOut += , $item
}
# --- 4a. Колонтитулы и параметры печати ---
# Слот колонтитула устроен как ячейка: ссылка на формат плюс текст. Признак вывода и стартовую
# страницу читаем только у записи, где есть <height>: палитра дедуплицирована, и колонтитул без
@@ -640,7 +732,11 @@ function Get-DslText {
# общий на многие ячейки, а они индивидуальны. Компилятор таких ключей не знает, так что
# в DSL они были чистым шумом.
$nonStyleTags = @('width', 'height', 'fillType', 'font',
'containsValue', 'valueType', 'controlType')
'containsValue', 'valueType', 'controlType',
# Линия рисунка и её стороны — свойства рисунка, а не общего оформления:
# на корпусе все 2 135 записей с ними принадлежат только рисункам.
'drawingBorder', 'drawingHaveLeftBorder', 'drawingHaveTopBorder',
'drawingHaveRightBorder', 'drawingHaveBottomBorder')
$borderTags = @('border', 'leftBorder', 'topBorder', 'rightBorder', 'bottomBorder')
function ConvertTo-DslLine {
@@ -793,6 +889,20 @@ foreach ($r in ($rowData.Keys | Sort-Object { [int]$_ } | ForEach-Object { $rowD
}
}
# Формат рисунка — ещё один владелец записи палитры, наравне с ячейкой, строкой, колонкой
# и примечанием: без этого оформление рисунка теряло имя и вырезалось как неиспользуемое.
foreach ($item in $drawingsOut) {
$fi = [int]$item['_fmt']
if ($fi -le 0) { continue }
$dfmt = Get-Format $fi
if (-not $dfmt) { continue }
if ((Get-StyleProps $dfmt).Count -gt 0 -or $dfmt.FontIdx -ge 0) {
$dkey = Get-StyleKey $dfmt
if (-not $styleKeys.Contains($dkey)) { $styleKeys[$dkey] = $dfmt }
$formatToStyleKey[$fi] = $dkey
}
}
# Оформление строки без её собственных свойств: скрытие уезжает инлайном к height,
# поэтому в именованный стиль попадать не должно.
function Get-RowStyleFmt {
@@ -1519,6 +1629,15 @@ foreach ($cs in $columnSets) {
if ($name) { $usedStyles[$name] = $true }
}
}
# Рисунок — пятый владелец формата. Имя ему присваивается позже, при сборке результата,
# поэтому здесь считаем его из ссылки на палитру: иначе стиль рисунка вырежется как
# неиспользуемый, а ссылка на него останется висячей.
foreach ($item in $drawingsOut) {
$fi = [int]$item['_fmt']
if ($fi -le 0) { continue }
$dname = Get-StyleName $fi
if ($dname -cne 'default') { $usedStyles[$dname] = $true }
}
$toRemove = @($styleDefs.Keys | Where-Object { -not $usedStyles.ContainsKey($_) })
foreach ($s in $toRemove) { $styleDefs.Remove($s)
}
@@ -1553,10 +1672,44 @@ if ($colGroups.Count -gt 0) { $result["columnGroups"] = [array]$colGroups }
# становится известен только после разбора строк.
$headerPart = Read-HeaderPart 'Header'
$footerPart = Read-HeaderPart 'Footer'
if ($headerPart) { $result["header"] = $headerPart }
if ($footerPart) { $result["footer"] = $footerPart }
# Пустой словарь в PowerShell истинен, поэтому проверяем именно наполнение: макет со ссылкой
# на общую запись палитры, но без своих настроек колонтитула, иначе получал в DSL пустой ключ.
if ($headerPart -and $headerPart.Count -gt 0) { $result["header"] = $headerPart }
if ($footerPart -and $footerPart.Count -gt 0) { $result["footer"] = $footerPart }
if ($printSettings) { $result["printSettings"] = $printSettings }
# Оформление рисунка: линия и её стороны — его собственные ключи, общее — именованный стиль.
# Порядок ключей задаём здесь же, чтобы он не зависел от того, что разбиралось раньше.
$drawingsOrdered = @()
foreach ($item in $drawingsOut) {
$fmtIdx = [int]$item['_fmt']
$item.Remove('_fmt')
if ($item.Contains("text")) { $item["text"] = Get-DslText $item["text"] }
$lineVal = $null
$sides = [ordered]@{}
if ($fmtIdx -gt 0) {
$dfmt = Get-Format $fmtIdx
$props = if ($dfmt) { $dfmt.Props } else { @{} }
if ($props.Contains('drawingBorder')) { $lineVal = ConvertTo-DslLine ([int]$props['drawingBorder']) }
foreach ($side in @('Left', 'Top', 'Right', 'Bottom')) {
$tag = "drawingHave${side}Border"
if ($props.Contains($tag)) { $sides[$side.ToLowerInvariant()] = ($props[$tag] -ceq 'true') }
}
$dname = Get-StyleName $fmtIdx
if ($dname -cne 'default') { $item["style"] = $dname }
}
if ($null -ne $lineVal) { $item["line"] = $lineVal }
if ($sides.Count -gt 0) { $item["sides"] = $sides }
$outItem = [ordered]@{}
foreach ($key in @('type', 'id', 'zOrder', 'name', 'picture', 'detail', 'text',
'style', 'line', 'sides', 'begin', 'end', 'pictureSize')) {
if ($item.Contains($key)) { $outItem[$key] = $item[$key] }
}
$drawingsOrdered += , $outItem
}
if ($picturesOut.Count -gt 0) { $result["pictures"] = $picturesOut }
if ($drawingsOrdered.Count -gt 0) { $result["drawings"] = [array]$drawingsOrdered }
$result["areas"] = [array]$dslAreas
# Именованные области, не выразимые блоком, — координатами. Тип не пишем: он выводится
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# mxl-decompile v1.26 — Decompile 1C spreadsheet to JSON
# mxl-decompile v1.27 — Decompile 1C spreadsheet to JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -79,7 +79,7 @@ def format_tag_kind():
'autoIndent': 'int', 'autoMarkIncomplete': 'bool', 'autoWidthCalculation': 'bool',
'backColor': 'color', 'border': 'line', 'borderColor': 'color',
'bottomBorder': 'line', 'bySelectedColumns': 'bool', 'columnSizeChange': 'enum',
'detailsUse': 'enum', 'drawingBorder': 'int',
'detailsUse': 'enum', 'drawingBorder': 'line',
'drawingHaveBottomBorder': 'bool', 'drawingHaveLeftBorder': 'bool',
'drawingHaveRightBorder': 'bool', 'drawingHaveTopBorder': 'bool',
'editFormat': 'ml', 'fillType': 'enum', 'font': 'int', 'format': 'ml',
@@ -431,6 +431,77 @@ def main():
return None
return raw_formats[idx - 1]
# --- 4-bis. Палитра картинок и рисунки ---
# Картинка хранится ссылкой на библиотеку либо данными base64; ссылки на палитру (у рисунка
# pictureIndex, у ячейки picIndex) — 1-based, сам <index> — 0-based.
pictures_out = OrderedDict()
picture_key = {}
for pic_i, pic_node in enumerate(findall(root, "d:picture"), start=1):
inner = find(pic_node, "d:picture")
if inner is None:
continue
name = f'pic{pic_i}'
entry = OrderedDict()
if inner.get("ref"):
entry["ref"] = inner.get("ref")
elif (inner.text or "").strip():
entry["data"] = (inner.text or "").strip()
if inner.get("t") is not None:
entry["transparent"] = inner.get("t") == "true"
# Пиксель прозрачного цвета: координата внутри самой картинки (проверено —
# это не её размеры). В корпусе встречается без атрибута t.
if inner.get("tx") is not None:
entry["transparentPixel"] = OrderedDict([("x", int(inner.get("tx"))),
("y", int(inner.get("ty") or 0))])
pictures_out[name] = entry
picture_key[pic_i] = name
drawing_names = {}
for ni_node in findall(root, "d:namedItem"):
if (ni_node.get(f'{{{XSI_NS}}}type') or '') == 'NamedItemDrawing':
drawing_names[text_of(find(ni_node, "d:drawingID")) or ''] = text_of(find(ni_node, "d:name")) or ''
drawings_out = []
for dr_i, dr in enumerate(findall(root, "d:drawing"), start=1):
item = OrderedDict()
item["type"] = text_of(find(dr, "d:drawingType")) or "Picture"
did = text_of(find(dr, "d:id")) or str(dr_i)
if did != str(dr_i):
item["id"] = int(did)
zorder = text_of(find(dr, "d:zOrder")) or str(dr_i)
if zorder != str(dr_i):
item["zOrder"] = int(zorder)
if did in drawing_names:
item["name"] = drawing_names[did]
pic_ref = text_of(find(dr, "d:pictureIndex"))
if pic_ref and int(pic_ref) in picture_key:
item["picture"] = picture_key[int(pic_ref)]
detail = text_of(find(dr, "d:detailParameter"))
if detail:
item["detail"] = detail
t_el = find(dr, "d:text")
if t_el is not None:
by_lang = OrderedDict()
for it in findall(t_el, "v8:item"):
by_lang[text_of(find(it, "v8:lang")) or ''] = text_of(find(it, "v8:content")) or ''
item["text"] = by_lang
# Оформление разбирается позже: линию нужно развернуть в описание, а помощник для
# этого появляется вместе с палитрой стилей.
fmt_idx = int_of(find(dr, "d:formatIndex"))
def anchor(prefix, off_row, off_col):
return OrderedDict([("row", int_of(find(dr, f'd:{prefix}Row')) + 1),
("col", int_of(find(dr, f'd:{prefix}Column')) + 1),
("dy", int_of(find(dr, f'd:{off_row}'))),
("dx", int_of(find(dr, f'd:{off_col}')))])
item["begin"] = anchor("begin", "beginRowOffset", "beginColumnOffset")
item["end"] = anchor("end", "endRowOffset", "endColumnOffset")
psize = text_of(find(dr, "d:pictureSize"))
if psize and psize != "Stretch":
item["pictureSize"] = psize
item["_fmt"] = fmt_idx
drawings_out.append(item)
# --- 4a. Колонтитулы и параметры печати ---
# Слот колонтитула устроен как ячейка: ссылка на формат плюс текст. Признак вывода и стартовую
# страницу читаем только у записи, где есть <height>: палитра дедуплицирована, и колонтитул без
@@ -790,7 +861,11 @@ def main():
# общий на многие ячейки, а они индивидуальны. Компилятор таких ключей не знает, так что
# в DSL они были чистым шумом.
NON_STYLE_TAGS = ("width", "height", "fillType", "font",
"containsValue", "valueType", "controlType")
"containsValue", "valueType", "controlType",
# Линия рисунка и её стороны — свойства рисунка, а не общего оформления:
# на корпусе все 2 135 записей с ними принадлежат только рисункам.
"drawingBorder", "drawingHaveLeftBorder", "drawingHaveTopBorder",
"drawingHaveRightBorder", "drawingHaveBottomBorder")
BORDER_TAGS = ("border", "leftBorder", "topBorder", "rightBorder", "bottomBorder")
def line_to_dsl(idx):
@@ -934,6 +1009,19 @@ def main():
style_keys[nkey] = nfmt
format_to_style_key[cell["Note"]["FormatIdx"]] = nkey
# Формат рисунка — ещё один владелец записи палитры, наравне с ячейкой, строкой, колонкой
# и примечанием: без этого оформление рисунка теряло имя и вырезалось как неиспользуемое.
for _item in drawings_out:
_fi = _item.get("_fmt") or 0
if not _fi:
continue
_fmt = get_format(_fi)
if _fmt and (style_props(_fmt) or _fmt["FontIdx"] >= 0):
_key = get_style_key(_fmt)
if _key not in style_keys:
style_keys[_key] = _fmt
format_to_style_key[_fi] = _key
def row_style_fmt(fmt):
"""Оформление строки без её собственных свойств: скрытие уезжает инлайном к height,
поэтому в именованный стиль попадать не должно."""
@@ -1509,6 +1597,15 @@ def main():
for name in column_styles_of(cs).values():
if name:
used_styles.add(name)
# Рисунок — пятый владелец формата. Имя ему присваивается позже, при сборке результата,
# поэтому здесь считаем его из ссылки на палитру: иначе стиль рисунка вырежется как
# неиспользуемый, а ссылка на него останется висячей.
for _item in drawings_out:
_fi = _item.get("_fmt") or 0
if _fi:
_name = get_style_name(_fi)
if _name != "default":
used_styles.add(_name)
to_remove = [s for s in style_defs if s not in used_styles]
for s in to_remove:
del style_defs[s]
@@ -1552,6 +1649,43 @@ def main():
if print_settings:
result["printSettings"] = print_settings
# Оформление рисунка: линия и её стороны — его собственные ключи, общее — именованный стиль.
# Порядок ключей задаём здесь же, чтобы он не зависел от того, что разбиралось раньше.
ordered = []
for item in drawings_out:
fmt_idx = item.pop("_fmt", 0)
if "text" in item:
item["text"] = get_dsl_text(item["text"])
line_val = None
sides = OrderedDict()
if fmt_idx:
fmt = get_format(fmt_idx)
props = fmt["Props"] if fmt else {}
if "drawingBorder" in props:
line_val = line_to_dsl(int(props["drawingBorder"]))
for side in ("Left", "Top", "Right", "Bottom"):
tag = f'drawingHave{side}Border'
if tag in props:
sides[side.lower()] = props[tag] == "true"
name = get_style_name(fmt_idx)
if name != "default":
item["style"] = name
if line_val is not None:
item["line"] = line_val
if sides:
item["sides"] = sides
out_item = OrderedDict()
for key in ("type", "id", "zOrder", "name", "picture", "detail", "text",
"style", "line", "sides", "begin", "end", "pictureSize"):
if key in item:
out_item[key] = item[key]
ordered.append(out_item)
drawings_out = ordered
if pictures_out:
result["pictures"] = pictures_out
if drawings_out:
result["drawings"] = drawings_out
result["areas"] = dsl_areas
# Именованные области, не выразимые блоком, — координатами. Тип не пишем: он выводится
@@ -1,4 +1,4 @@
# mxl-validate v1.6 — Validate 1C spreadsheet
# mxl-validate v1.7 — Validate 1C spreadsheet
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Alias('Path')]
@@ -408,6 +408,16 @@ foreach ($drawing in $root.SelectNodes("d:drawing", $nsMgr)) {
Report-Error "Drawing id=${drawId}: pictureIndex=$picIdx > picture count ($pictureCount)"
}
}
# Оформление рисунка — такая же запись палитры форматов, как у ячейки, и висячая
# ссылка на неё так же валит загрузку макета.
$fmtIdxNode = $drawing.SelectSingleNode("d:formatIndex", $nsMgr)
if ($fmtIdxNode) {
$fmtIdx = [int]$fmtIdxNode.InnerText
if ($fmtIdx -gt $formatCount) {
$drawId = $drawing.SelectSingleNode("d:id", $nsMgr).InnerText
Report-Error "Drawing id=${drawId}: formatIndex=$fmtIdx > format palette size ($formatCount)"
}
}
}
# --- Check 13: value cells (input fields) ---
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# mxl-validate v1.6 — Validate 1C spreadsheet document Template.xml
# mxl-validate v1.7 — Validate 1C spreadsheet document Template.xml
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
"""Validates spreadsheet Template.xml: height, palette refs, column/row indices, areas, merges."""
import sys, os, argparse
@@ -405,6 +405,16 @@ def main():
draw_id = draw_id_node.text if draw_id_node is not None else '?'
r.error(f'Drawing id={draw_id}: pictureIndex={pic_idx} > picture count ({picture_count})')
# Оформление рисунка — такая же запись палитры форматов, как у ячейки, и висячая
# ссылка на неё так же валит загрузку макета.
fmt_idx_node = drawing.find(f'{{{NS_D}}}formatIndex')
if fmt_idx_node is not None and fmt_idx_node.text:
fmt_idx = int(fmt_idx_node.text)
if fmt_idx > format_count:
draw_id_node = drawing.find(f'{{{NS_D}}}id')
draw_id = draw_id_node.text if draw_id_node is not None else '?'
r.error(f'Drawing id={draw_id}: formatIndex={fmt_idx} > format palette size ({format_count})')
# --- Check 13: value cells (input fields) ---
# Свойства containsValue/valueType/controlType принадлежат ЯЧЕЙКЕ: на корпусе ERP
# (370 197 ссылок) на такие записи палитры ссылаются только <f>, ни строка, ни колонка,
+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, поэтому
@@ -0,0 +1,34 @@
{
"name": "Рисунки: типы, картинки, линия, стороны, расшифровка",
"input": {
"columns": 4,
"styles": {
"заливка": { "backColor": "web:LightYellow" }
},
"pictures": {
"стоп": { "ref": "v8ui:Стоп48" },
"точка": { "data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/q842iQAAAABJRU5ErkJggg==", "transparent": false }
},
"areas": [{ "rows": [["Бланк"]] }],
"drawings": [
{ "type": "Picture", "picture": "стоп", "name": "Знак",
"begin": { "row": 1, "col": 1, "dy": 0, "dx": 0 },
"end": { "row": 2, "col": 2, "dy": 20, "dx": 40 },
"pictureSize": "Proportionally" },
{ "type": "Picture", "picture": "точка", "detail": "ПараметрРасшифровки",
"begin": { "row": 3, "col": 1 },
"end": { "row": 3, "col": 2, "dy": 34, "dx": 115 } },
{ "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": "Ellipse", "line": "Solid",
"begin": { "row": 8, "col": 1 }, "end": { "row": 9, "col": 2 } },
{ "type": "Line", "zOrder": 9,
"begin": { "row": 11, "col": 1 }, "end": { "row": 11, "col": 4 } },
{ "type": "Text", "id": 42, "text": { "ru": "Подпись", "en": "Signature" },
"begin": { "row": 13, "col": 1 }, "end": { "row": 13, "col": 3, "dy": 12 } }
]
},
"params": { "outputPath": "Template.xml" }
}
@@ -0,0 +1,10 @@
{
"name": "Ошибка: прозрачность задана у картинки без данных",
"input": {
"columns": 2,
"pictures": { "пусто": { "transparent": true } },
"areas": [{ "rows": [["Бланк"]] }]
},
"params": { "outputPath": "Template.xml" },
"expectError": "pictures[пусто]: 'transparent' and 'transparentPixel' require 'data'"
}
@@ -0,0 +1,13 @@
{
"name": "Ошибка: рисунок ссылается на необъявленную картинку",
"input": {
"columns": 2,
"areas": [{ "rows": [["Бланк"]] }],
"drawings": [
{ "type": "Picture", "picture": "нет-такой",
"begin": { "row": 1, "col": 1 }, "end": { "row": 2, "col": 2 } }
]
},
"params": { "outputPath": "Template.xml" },
"expectError": "drawings[1]: unknown 'picture' \"нет-такой\" — not declared in pictures"
}
@@ -0,0 +1,284 @@
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://v8.1c.ru/8.2/data/spreadsheet" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<languageSettings>
<currentLanguage>ru</currentLanguage>
<defaultLanguage>ru</defaultLanguage>
<languageInfo>
<id>ru</id>
<code>Русский</code>
<description>Русский</description>
</languageInfo>
<languageInfo>
<id>en</id>
<code>Английский</code>
<description>Английский</description>
</languageInfo>
</languageSettings>
<columns>
<size>5</size>
</columns>
<rowsItem>
<index>0</index>
<row>
<empty>true</empty>
</row>
</rowsItem>
<drawing>
<drawingType>Picture</drawingType>
<id>1</id>
<formatIndex>0</formatIndex>
<detailParameter>ПараметрРасшифровки</detailParameter>
<beginRow>1</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>3</endRow>
<endRowOffset>34</endRowOffset>
<beginColumn>1</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>115</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>1</zOrder>
<pictureIndex>1</pictureIndex>
</drawing>
<drawing>
<drawingType>Picture</drawingType>
<id>2</id>
<formatIndex>1</formatIndex>
<beginRow>6</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>8</endRow>
<endRowOffset>34</endRowOffset>
<beginColumn>1</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>115</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>RealSize</pictureSize>
<zOrder>2</zOrder>
<pictureIndex>1</pictureIndex>
</drawing>
<drawing>
<drawingType>Picture</drawingType>
<id>3</id>
<formatIndex>2</formatIndex>
<beginRow>12</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>14</endRow>
<endRowOffset>34</endRowOffset>
<beginColumn>1</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>115</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Proportionally</pictureSize>
<zOrder>3</zOrder>
<pictureIndex>1</pictureIndex>
</drawing>
<drawing>
<drawingType>Picture</drawingType>
<id>4</id>
<formatIndex>3</formatIndex>
<beginRow>18</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>20</endRow>
<endRowOffset>34</endRowOffset>
<beginColumn>1</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>115</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Tile</pictureSize>
<zOrder>4</zOrder>
<pictureIndex>1</pictureIndex>
</drawing>
<drawing>
<drawingType>Picture</drawingType>
<id>5</id>
<formatIndex>0</formatIndex>
<beginRow>23</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>25</endRow>
<endRowOffset>34</endRowOffset>
<beginColumn>1</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>115</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>AutoSize</pictureSize>
<zOrder>5</zOrder>
<pictureIndex>1</pictureIndex>
</drawing>
<drawing>
<drawingType>Picture</drawingType>
<id>6</id>
<formatIndex>0</formatIndex>
<beginRow>28</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>30</endRow>
<endRowOffset>34</endRowOffset>
<beginColumn>1</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>115</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>ByFontSize</pictureSize>
<zOrder>6</zOrder>
<pictureIndex>1</pictureIndex>
</drawing>
<drawing>
<drawingType>Picture</drawingType>
<id>7</id>
<formatIndex>1</formatIndex>
<beginRow>1</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>2</endRow>
<endRowOffset>31</endRowOffset>
<beginColumn>3</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>3</endColumn>
<endColumnOffset>60</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>7</zOrder>
<pictureIndex>2</pictureIndex>
</drawing>
<drawing>
<drawingType>Line</drawingType>
<id>8</id>
<formatIndex>4</formatIndex>
<beginRow>7</beginRow>
<beginRowOffset>19</beginRowOffset>
<endRow>4</endRow>
<endRowOffset>24</endRowOffset>
<beginColumn>2</beginColumn>
<beginColumnOffset>106</beginColumnOffset>
<endColumn>4</endColumn>
<endColumnOffset>103</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>8</zOrder>
</drawing>
<drawing>
<drawingType>Rectangle</drawingType>
<id>9</id>
<formatIndex>5</formatIndex>
<beginRow>8</beginRow>
<beginRowOffset>36</beginRowOffset>
<endRow>12</endRow>
<endRowOffset>10</endRowOffset>
<beginColumn>2</beginColumn>
<beginColumnOffset>108</beginColumnOffset>
<endColumn>4</endColumn>
<endColumnOffset>125</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>9</zOrder>
</drawing>
<drawing>
<drawingType>Ellipse</drawingType>
<id>10</id>
<formatIndex>6</formatIndex>
<beginRow>14</beginRow>
<beginRowOffset>22</beginRowOffset>
<endRow>17</endRow>
<endRowOffset>12</endRowOffset>
<beginColumn>2</beginColumn>
<beginColumnOffset>134</beginColumnOffset>
<endColumn>4</endColumn>
<endColumnOffset>139</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>10</zOrder>
</drawing>
<drawing>
<drawingType>Text</drawingType>
<id>11</id>
<formatIndex>7</formatIndex>
<text>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Текст</v8:content>
</v8:item>
</text>
<beginRow>19</beginRow>
<beginRowOffset>38</beginRowOffset>
<endRow>23</endRow>
<endRowOffset>17</endRowOffset>
<beginColumn>2</beginColumn>
<beginColumnOffset>101</beginColumnOffset>
<endColumn>4</endColumn>
<endColumnOffset>146</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>11</zOrder>
</drawing>
<templateMode>true</templateMode>
<defaultFormatIndex>8</defaultFormatIndex>
<height>31</height>
<vgRows>31</vgRows>
<namedItem xsi:type="NamedItemDrawing">
<name>Звездочка</name>
<drawingID>7</drawingID>
</namedItem>
<line width="1" gap="false">
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentDrawingLineType">None</v8ui:style>
</line>
<line width="1" gap="false">
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentDrawingLineType">Dashed</v8ui:style>
</line>
<line width="1" gap="false">
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentDrawingLineType">DashDottedDotted</v8ui:style>
</line>
<line width="1" gap="false">
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentDrawingLineType">DashDotted</v8ui:style>
</line>
<format>
<drawingBorder>0</drawingBorder>
</format>
<format>
<backColor xmlns:d3p1="http://v8.1c.ru/8.1/data/ui/colors/web">d3p1:HoneyDew</backColor>
</format>
<format>
<patternColor>style:SpecialTextColor</patternColor>
<pattern>Pattern4</pattern>
</format>
<format>
<verticalAlignment>Top</verticalAlignment>
<backColor>style:FieldBackColor</backColor>
</format>
<format>
<drawingBorder>1</drawingBorder>
<verticalAlignment>Top</verticalAlignment>
<backColor>style:FieldBackColor</backColor>
</format>
<format>
<drawingBorder>2</drawingBorder>
<verticalAlignment>Top</verticalAlignment>
<backColor>style:FieldBackColor</backColor>
</format>
<format>
<drawingBorder>3</drawingBorder>
<verticalAlignment>Top</verticalAlignment>
<backColor>style:FieldBackColor</backColor>
</format>
<format>
<width>72</width>
</format>
<picture>
<index>0</index>
<picture ref="v8ui:Стоп48"/>
</picture>
<picture>
<index>1</index>
<picture t="false">iVBORw0KGgoAAAANSUhEUgAAABkAAAAeCAYAAADZ7LXbAAAAAXNSR0IArs4c6QAA
AARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAAE9SURBVEhL7ZOh
coQwEIb7tBExmBjEGUwNBhGDiUH0DWIQmJgYREwM5gwCcwZT83cLuWlhrhOCqOJT
uwszX3Y3ecM/cEmSuCRJXJIkTkmszJFLG7I4JyQ9JGNgTFJ0jFOddCVJyi5kcaKS
XmZgPIdyc6gAj7ZA0T5CBsyuhqDustqFypaoZPjIwZfxCNRP0aChhzWcrUS2fOe4
6XEt7jg8Lt9rNGWJxk/wWkFpj8k3KMsGuvfhr9ek74RGs3bGqbNQi5Akme8W1hnI
jIGLGp2zcPefXf1FVPI5GqhCLKfPnm/jMWAIezcVXQzqShQKZlpre6ISffseDQmq
X4/PVKhMiAm7iOi/9zZUtsTHNXkYt701rubgu4WMNEa6Ey9JXzzRCDq1aEIWw56R
eChaPMsURcc41UkqlySJS5IA8AW5c2KJOTY6eAAAAABJRU5ErkJggg==</picture>
</picture>
</document>
@@ -0,0 +1,20 @@
{
"name": "Картинки: пустая запись и пиксель прозрачного цвета",
"input": {
"columns": 2,
"pictures": {
"пусто": {},
"точка": {
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/q842iQAAAABJRU5ErkJggg==",
"transparent": true,
"transparentPixel": { "x": 3, "y": 5 }
}
},
"areas": [{ "rows": [["Бланк"]] }],
"drawings": [
{ "type": "Picture", "picture": "точка",
"begin": { "row": 1, "col": 1 }, "end": { "row": 2, "col": 2 } }
]
},
"params": { "outputPath": "Template.xml" }
}
@@ -0,0 +1,13 @@
{
"name": "Раундтрип макета ПЛАТФОРМЫ байт в байт: Рисунки2",
"setup": "fixture:platform-roundtrip",
"preRun": [
{ "script": "mxl-decompile/scripts/mxl-decompile",
"args": { "-TemplatePath": "Рисунки2.xml", "-OutputPath": "back.json" },
"cwd": "{workDir}" }
],
"params": { "outputPath": "out.xml" },
"noSnapshot": "эталон — файл платформы, сверяется expect.filesEqual",
"expect": { "filesEqual": { "actual": "out.xml", "expected": "Рисунки2.xml" } },
"inputFrom": "back.json"
}
@@ -0,0 +1,176 @@
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://v8.1c.ru/8.2/data/spreadsheet" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<languageSettings>
<currentLanguage>ru</currentLanguage>
<defaultLanguage>ru</defaultLanguage>
<languageInfo>
<id>ru</id>
<code>Русский</code>
<description>Русский</description>
</languageInfo>
</languageSettings>
<columns>
<size>4</size>
</columns>
<rowsItem>
<index>0</index>
<row>
<c>
<c>
<f>0</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Бланк</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<drawing>
<drawingType>Picture</drawingType>
<id>1</id>
<formatIndex>0</formatIndex>
<beginRow>0</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>1</endRow>
<endRowOffset>20</endRowOffset>
<beginColumn>0</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>40</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Proportionally</pictureSize>
<zOrder>1</zOrder>
<pictureIndex>1</pictureIndex>
</drawing>
<drawing>
<drawingType>Picture</drawingType>
<id>2</id>
<formatIndex>0</formatIndex>
<detailParameter>ПараметрРасшифровки</detailParameter>
<beginRow>2</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>2</endRow>
<endRowOffset>34</endRowOffset>
<beginColumn>0</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>115</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>2</zOrder>
<pictureIndex>2</pictureIndex>
</drawing>
<drawing>
<drawingType>Rectangle</drawingType>
<id>3</id>
<formatIndex>1</formatIndex>
<beginRow>4</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>5</endRow>
<endRowOffset>0</endRowOffset>
<beginColumn>0</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>2</endColumn>
<endColumnOffset>0</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>3</zOrder>
</drawing>
<drawing>
<drawingType>Ellipse</drawingType>
<id>4</id>
<formatIndex>2</formatIndex>
<beginRow>7</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>8</endRow>
<endRowOffset>0</endRowOffset>
<beginColumn>0</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>0</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>4</zOrder>
</drawing>
<drawing>
<drawingType>Line</drawingType>
<id>5</id>
<formatIndex>0</formatIndex>
<beginRow>10</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>10</endRow>
<endRowOffset>0</endRowOffset>
<beginColumn>0</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>3</endColumn>
<endColumnOffset>0</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>9</zOrder>
</drawing>
<drawing>
<drawingType>Text</drawingType>
<id>42</id>
<formatIndex>0</formatIndex>
<text>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Подпись</v8:content>
</v8:item>
<v8:item>
<v8:lang>en</v8:lang>
<v8:content>Signature</v8:content>
</v8:item>
</text>
<beginRow>12</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>12</endRow>
<endRowOffset>12</endRowOffset>
<beginColumn>0</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>2</endColumn>
<endColumnOffset>0</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>6</zOrder>
</drawing>
<templateMode>true</templateMode>
<defaultFormatIndex>3</defaultFormatIndex>
<height>13</height>
<vgRows>13</vgRows>
<namedItem xsi:type="NamedItemDrawing">
<name>Знак</name>
<drawingID>1</drawingID>
</namedItem>
<line width="2" gap="false">
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentDrawingLineType">Dashed</v8ui:style>
</line>
<line width="1" gap="false">
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentDrawingLineType">Solid</v8ui:style>
</line>
<format>
<drawingBorder>0</drawingBorder>
<drawingHaveLeftBorder>true</drawingHaveLeftBorder>
<drawingHaveTopBorder>true</drawingHaveTopBorder>
<drawingHaveRightBorder>false</drawingHaveRightBorder>
<drawingHaveBottomBorder>false</drawingHaveBottomBorder>
<backColor xmlns:d3p1="http://v8.1c.ru/8.1/data/ui/colors/web">d3p1:LightYellow</backColor>
</format>
<format>
<drawingBorder>1</drawingBorder>
</format>
<format>
<width>10</width>
</format>
<picture>
<index>0</index>
<picture ref="v8ui:Стоп48"/>
</picture>
<picture>
<index>1</index>
<picture t="false">iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/q842iQAAAABJRU5ErkJggg==</picture>
</picture>
</document>
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://v8.1c.ru/8.2/data/spreadsheet" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<languageSettings>
<currentLanguage>ru</currentLanguage>
<defaultLanguage>ru</defaultLanguage>
<languageInfo>
<id>ru</id>
<code>Русский</code>
<description>Русский</description>
</languageInfo>
</languageSettings>
<columns>
<size>2</size>
</columns>
<rowsItem>
<index>0</index>
<row>
<c>
<c>
<f>0</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Бланк</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<drawing>
<drawingType>Picture</drawingType>
<id>1</id>
<formatIndex>0</formatIndex>
<beginRow>0</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>1</endRow>
<endRowOffset>0</endRowOffset>
<beginColumn>0</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>0</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>1</zOrder>
<pictureIndex>2</pictureIndex>
</drawing>
<templateMode>true</templateMode>
<defaultFormatIndex>1</defaultFormatIndex>
<height>2</height>
<vgRows>2</vgRows>
<format>
<width>10</width>
</format>
<picture>
<index>0</index>
<picture/>
</picture>
<picture>
<index>1</index>
<picture t="true" tx="3" ty="5">iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4nGP4z8DwHwAFAAH/q842iQAAAABJRU5ErkJggg==</picture>
</picture>
</document>
@@ -0,0 +1,30 @@
{
"name": "Roundtrip — рисунки и палитра картинок",
"preRun": [
{ "script": "mxl-compile/scripts/mxl-compile",
"input": {
"columns": 4,
"styles": { "заливка": { "backColor": "web:LightYellow" } },
"pictures": {
"стоп": { "ref": "v8ui:Стоп48" },
"пусто": {}
},
"areas": [{ "rows": [["Бланк"]] }],
"drawings": [
{ "type": "Picture", "picture": "стоп", "name": "Знак",
"begin": { "row": 1, "col": 1 }, "end": { "row": 2, "col": 2, "dy": 20, "dx": 40 },
"pictureSize": "Proportionally" },
{ "type": "Rectangle", "style": "заливка", "line": { "style": "Dashed", "width": 2 },
"sides": { "left": true, "top": true, "right": false, "bottom": false },
"begin": { "row": 4, "col": 1 }, "end": { "row": 5, "col": 3 } },
{ "type": "Text", "id": 42, "text": { "ru": "Подпись", "en": "Signature" },
"begin": { "row": 7, "col": 1 }, "end": { "row": 7, "col": 3, "dy": 12 } }
]
},
"args": { "-JsonPath": "{inputFile}", "-OutputPath": "Template.xml" },
"cwd": "{workDir}" }
],
"params": { "templatePath": "Template.xml" },
"args_extra": ["-OutputPath", "{workDir}/back.json"],
"expect": { "files": ["back.json"], "stdoutContains": "[OK] Decompiled:" }
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://v8.1c.ru/8.2/data/spreadsheet" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<languageSettings>
<currentLanguage>ru</currentLanguage>
<defaultLanguage>ru</defaultLanguage>
<languageInfo>
<id>ru</id>
<code>Русский</code>
<description>Русский</description>
</languageInfo>
</languageSettings>
<columns>
<size>4</size>
</columns>
<rowsItem>
<index>0</index>
<row>
<c>
<c>
<f>0</f>
<tl>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Бланк</v8:content>
</v8:item>
</tl>
</c>
</c>
</row>
</rowsItem>
<drawing>
<drawingType>Picture</drawingType>
<id>1</id>
<formatIndex>0</formatIndex>
<beginRow>0</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>1</endRow>
<endRowOffset>20</endRowOffset>
<beginColumn>0</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>1</endColumn>
<endColumnOffset>40</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Proportionally</pictureSize>
<zOrder>1</zOrder>
<pictureIndex>1</pictureIndex>
</drawing>
<drawing>
<drawingType>Rectangle</drawingType>
<id>2</id>
<formatIndex>1</formatIndex>
<beginRow>3</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>4</endRow>
<endRowOffset>0</endRowOffset>
<beginColumn>0</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>2</endColumn>
<endColumnOffset>0</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>2</zOrder>
</drawing>
<drawing>
<drawingType>Text</drawingType>
<id>42</id>
<formatIndex>0</formatIndex>
<text>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Подпись</v8:content>
</v8:item>
<v8:item>
<v8:lang>en</v8:lang>
<v8:content>Signature</v8:content>
</v8:item>
</text>
<beginRow>6</beginRow>
<beginRowOffset>0</beginRowOffset>
<endRow>6</endRow>
<endRowOffset>12</endRowOffset>
<beginColumn>0</beginColumn>
<beginColumnOffset>0</beginColumnOffset>
<endColumn>2</endColumn>
<endColumnOffset>0</endColumnOffset>
<autoSize>false</autoSize>
<pictureSize>Stretch</pictureSize>
<zOrder>3</zOrder>
</drawing>
<templateMode>true</templateMode>
<defaultFormatIndex>2</defaultFormatIndex>
<height>7</height>
<vgRows>7</vgRows>
<namedItem xsi:type="NamedItemDrawing">
<name>Знак</name>
<drawingID>1</drawingID>
</namedItem>
<line width="2" gap="false">
<v8ui:style xsi:type="v8ui:SpreadsheetDocumentDrawingLineType">Dashed</v8ui:style>
</line>
<format>
<drawingBorder>0</drawingBorder>
<drawingHaveLeftBorder>true</drawingHaveLeftBorder>
<drawingHaveTopBorder>true</drawingHaveTopBorder>
<drawingHaveRightBorder>false</drawingHaveRightBorder>
<drawingHaveBottomBorder>false</drawingHaveBottomBorder>
<backColor xmlns:d3p1="http://v8.1c.ru/8.1/data/ui/colors/web">d3p1:LightYellow</backColor>
</format>
<format>
<width>10</width>
</format>
<picture>
<index>0</index>
<picture ref="v8ui:Стоп48"/>
</picture>
<picture>
<index>1</index>
<picture/>
</picture>
</document>
@@ -0,0 +1,13 @@
{
"columns": 4,
"defaultWidth": 10,
"fonts": {},
"styles": { "bg": { "backColor": "web:LightYellow" } },
"pictures": { "pic1": { "ref": "v8ui:Стоп48" }, "pic2": {} },
"drawings": [
{ "type": "Picture", "name": "Знак", "picture": "pic1", "begin": { "row": 1, "col": 1, "dy": 0, "dx": 0 }, "end": { "row": 2, "col": 2, "dy": 20, "dx": 40 }, "pictureSize": "Proportionally" },
{ "type": "Rectangle", "style": "bg", "line": { "style": "Dashed", "width": 2 }, "sides": { "left": true, "top": true, "right": false, "bottom": false }, "begin": { "row": 4, "col": 1, "dy": 0, "dx": 0 }, "end": { "row": 5, "col": 3, "dy": 0, "dx": 0 } },
{ "type": "Text", "id": 42, "text": { "ru": "Подпись", "en": "Signature" }, "begin": { "row": 7, "col": 1, "dy": 0, "dx": 0 }, "end": { "row": 7, "col": 3, "dy": 12, "dx": 0 } }
],
"areas": [{ "rows": [["Бланк"]] }]
}