1#!/usr/bin/env python3
2"""Create a synthetic native baseline page with independent raster coordinate anchors."""
3import argparse
4import base64
5import json
6from pathlib import Path
7import struct
8import xml.etree.ElementTree as ET
9import zlib
10
11from native_fixture import NS
12
13
14def build():
15 def chunk(kind, data):
16 return struct.pack('!I', len(data)) + kind + data + struct.pack('!I', zlib.crc32(kind + data))
17
18 page = ET.Element(f'{{{NS}}}Page', {'name': 'Baseline anchors'})
19 ET.SubElement(page, f'{{{NS}}}QuickStyleDef', {
20 'index': '0', 'name': 'p', 'font': 'Calibri', 'fontSize': '11',
21 'fontColor': 'automatic', 'highlightColor': 'automatic', 'spaceBefore': '0', 'spaceAfter': '0',
22 })
23 ET.SubElement(page, f'{{{NS}}}QuickStyleDef', {
24 'index': '1', 'name': 'h2', 'font': 'Arial', 'fontSize': '11', 'bold': 'false',
25 'fontColor': 'automatic', 'highlightColor': 'automatic', 'spaceBefore': '3', 'spaceAfter': '4',
26 })
27 title = ET.SubElement(page, f'{{{NS}}}Title')
28 oe = ET.SubElement(title, f'{{{NS}}}OE')
29 ET.SubElement(oe, f'{{{NS}}}T').text = 'Baseline anchors'
30 for index, (x, y, width, height) in enumerate([
31 (20.125, 60.25, 11, 13), (440.5, 355.375, 17, 19), (25.75, 650.875, 23, 29),
32 ]):
33 color = bytes(255 if channel == index else 0 for channel in range(3))
34 pixels = (b'\x00' + color * (width * 2)) * (height * 2)
35 png = (b'\x89PNG\r\n\x1a\n' + chunk(b'IHDR', struct.pack('!2I5B', width * 2, height * 2, 8, 2, 0, 0, 0))
36 + chunk(b'IDAT', zlib.compress(pixels)) + chunk(b'IEND', b''))
37 image = ET.SubElement(page, f'{{{NS}}}Image', {'format': 'png'})
38 ET.SubElement(image, f'{{{NS}}}Position', {'x': str(x), 'y': str(y), 'z': str(index)})
39 ET.SubElement(image, f'{{{NS}}}Size', {'width': str(width), 'height': str(height), 'isSetByUser': 'true'})
40 ET.SubElement(image, f'{{{NS}}}Data').text = base64.b64encode(png).decode()
41 for index, (y, width, font, size, paragraphs) in enumerate([
42 (90, 300, 'Arial', 11, ['Arial eleven HAMBURGEFONTS']),
43 (150, 300, 'Arial', 16, ['Arial sixteen HAMBURGEFONTS']),
44 (210, 300, 'Calibri', 11, ['Calibri eleven HAMBURGEFONTS']),
45 (270, 300, 'Calibri', 17, ['Calibri seventeen HAMBURGEFONTS']),
46 (330, 110, 'Arial', 11, ['Wrapped HAMBURGEFONTS abcdefghijklmnopqrstuvwxyz 0123456789']),
47 (420, 300, 'Arial', 11, ['Mixed <span style="font-family:Arial;font-size:16pt">HAMBURGEFONTS</span> small']),
48 (490, 300, 'Arial', 11, ['Spacing first', '', 'Spacing last']),
49 (570, 300, 'Calibri', 11, ['Blank first', '', 'Blank last']),
50 ]):
51 outline = ET.SubElement(page, f'{{{NS}}}Outline')
52 ET.SubElement(outline, f'{{{NS}}}Position', {'x': '120', 'y': str(y), 'z': str(index + 3)})
53 ET.SubElement(outline, f'{{{NS}}}Size', {'width': str(width), 'height': '20', 'isSetByUser': 'true'})
54 children = ET.SubElement(outline, f'{{{NS}}}OEChildren')
55 for text in paragraphs:
56 style = f'font-family:{font};font-size:{size}pt'
57 oe = ET.SubElement(children, f'{{{NS}}}OE', {'style': style})
58 if y == 490:
59 oe.set('quickStyleIndex', '1')
60 ET.SubElement(oe, f'{{{NS}}}T').text = text
61 return {'sections': ['Baselines.one'], 'pages': [{'section': 'Baselines.one', 'xml': ET.tostring(page, encoding='unicode')}]}
62
63
64if __name__ == '__main__':
65 parser = argparse.ArgumentParser(description=__doc__)
66 parser.add_argument('destination', type=Path)
67 args = parser.parse_args()
68 args.destination.mkdir(parents=True, exist_ok=False)
69 (args.destination / 'fixture.json').write_text(json.dumps(build(), indent=2) + '\n')