1param([Parameter(Mandatory=$true)][string]$Root, [Parameter(Mandatory=$true)][string]$CloneHost)
2# Pressure ink as OneNote 2010 keeps it: WPF writes strokes with NormalPressure (and one with
3# tilt) as ISF, and OneNote takes each through UpdatePageContent into a section of its own.
4Set-StrictMode -Version Latest
5$ErrorActionPreference = 'Stop'
6& "$PSScriptRoot\cold-current.ps1" -Root $Root -CloneHost $CloneHost
7Add-Type -AssemblyName PresentationCore, WindowsBase
8$P = [System.Windows.Input.StylusPointProperties]
9$U = [System.Windows.Input.StylusPointPropertyUnit]
10
11function Info($property, $min, $max, $unit, $resolution) {
12 if ($null -eq $min) { return New-Object System.Windows.Input.StylusPointPropertyInfo($property) }
13 New-Object System.Windows.Input.StylusPointPropertyInfo($property, $min, $max, $unit, $resolution)
14}
15
16# A stroke through `points` of [x, y, pressure 0..1, extra values...] in WPF units (1/96 inch).
17function Stroke($points, $width, $height, [switch]$Ignore, [switch]$Rectangle, $infos) {
18 if (-not $infos) { $infos = @((Info $P::X), (Info $P::Y), (Info $P::NormalPressure)) }
19 $description = New-Object System.Windows.Input.StylusPointDescription(,[System.Windows.Input.StylusPointPropertyInfo[]]$infos)
20 $pressure = $infos[2]
21 $collection = New-Object System.Windows.Input.StylusPointCollection(,$description)
22 foreach ($p in $points) {
23 $extra = [int[]]@($p | Select-Object -Skip 3)
24 $collection.Add((New-Object System.Windows.Input.StylusPoint($p[0], $p[1], [single]0.5, $description, $extra)))
25 $point = $collection[$collection.Count - 1]
26 $point.SetPropertyValue([System.Windows.Input.StylusPointProperties]::NormalPressure,
27 [int][Math]::Round($pressure.Minimum + $p[2] * ($pressure.Maximum - $pressure.Minimum)))
28 $collection[$collection.Count - 1] = $point
29 }
30 $stroke = New-Object System.Windows.Ink.Stroke -ArgumentList (,$collection)
31 $stroke.DrawingAttributes.Width = $width
32 $stroke.DrawingAttributes.Height = $height
33 $stroke.DrawingAttributes.IgnorePressure = [bool]$Ignore
34 $stroke.DrawingAttributes.FitToCurve = $false
35 if ($Rectangle) { $stroke.DrawingAttributes.StylusTip = [System.Windows.Ink.StylusTip]::Rectangle }
36 $stroke
37}
38
39function Isf($strokes) {
40 $collection = New-Object System.Windows.Ink.StrokeCollection
41 foreach ($stroke in $strokes) { $collection.Add([System.Windows.Ink.Stroke]$stroke) }
42 $stream = New-Object IO.MemoryStream
43 $collection.Save($stream, $true)
44 [Convert]::ToBase64String($stream.ToArray())
45}
46
47function Line($x, $y, $pressure, $count, $step) {
48 $points = @()
49 for ($i = 0; $i -lt $count; $i++) { $points += ,@(($x + $i * $step), $y, $pressure) }
50 ,$points
51}
52
53# "Levels": one drawing of nine 24-point strokes at pressures 0 to 1 in eighths, and one of
54# the same levels on a pen reporting 0..255.
55$levels = @(); $coarse = @()
56$narrow = @((Info $P::X), (Info $P::Y), (Info $P::NormalPressure 0 255 $U::None 1))
57for ($i = 0; $i -le 8; $i++) {
58 $levels += Stroke (Line 0 ($i * 48) ($i / 8) 5 20) 32 32
59 $coarse += Stroke (Line 0 ($i * 48) ($i / 8) 5 20) 32 32 -infos $narrow
60}
61# "Strokes": a rising ramp, a wave, a pen ignoring the pressure it recorded, a stroke with
62# tilt, and a rectangular tip, each a drawing of its own.
63$ramp = @(); $wave = @(); $flat = @(); $tilt = @(); $block = @()
64for ($i = 0; $i -le 40; $i++) {
65 $ramp += ,@(($i * 8), 0, ($i / 40))
66 $wave += ,@(($i * 8), (20 * [Math]::Sin($i / 4)), (0.5 + 0.5 * [Math]::Sin($i / 5)))
67 $flat += ,@(($i * 8), 0, ($i / 40))
68 $tilt += ,@(($i * 8), 0, (0.2 + $i / 60), (-4500 + $i * 200), 3000)
69}
70for ($i = 0; $i -le 10; $i++) { $block += ,@(($i * 20), 0, ($i / 10)) }
71$tilted = @((Info $P::X), (Info $P::Y), (Info $P::NormalPressure),
72 (Info $P::XTiltOrientation -9000 9000 $U::Degrees 100), (Info $P::YTiltOrientation -9000 9000 $U::Degrees 100))
73$pages = [ordered]@{
74 'Levels' = @(@(36, 90, (Isf $levels)), @(252, 90, (Isf $coarse)))
75 'Strokes' = @(
76 @(36, 90, (Isf @(Stroke $ramp 8 8))),
77 @(36, 150, (Isf @(Stroke $wave 4 4))),
78 @(36, 220, (Isf @(Stroke $flat 8 8 -Ignore))),
79 @(36, 270, (Isf @(Stroke $tilt 8 8 -infos $tilted))),
80 @(36, 320, (Isf @(Stroke $block 4 24 -Rectangle))))
81}
82
83$namespace = 'http://schemas.microsoft.com/office/onenote/2010/onenote'
84$app = New-Object -ComObject OneNote.Application
85$notebookId = ''
86try {
87 $app.OpenHierarchy((Join-Path $Root 'notebook'), '', [ref]$notebookId, 0)
88 $sectionId = ''
89 $app.OpenHierarchy('Pressure.one', $notebookId, [ref]$sectionId, 3)
90 foreach ($name in $pages.Keys) {
91 $pageId = ''
92 $app.CreateNewPage($sectionId, [ref]$pageId, 0)
93 $drawings = ($pages[$name] | ForEach-Object {
94 "<one:InkDrawing><one:Position x=`"$($_[0])`" y=`"$($_[1])`"/><one:Data>$($_[2])</one:Data></one:InkDrawing>"
95 }) -join ''
96 $xml = "<?xml version=`"1.0`"?><one:Page xmlns:one=`"$namespace`" ID=`"$pageId`"><one:Title><one:OE><one:T><![CDATA[$name]]></one:T></one:OE></one:Title>$drawings</one:Page>"
97 [IO.File]::WriteAllText((Join-Path $Root "author-$name.xml"), $xml, [Text.Encoding]::UTF8)
98 $app.UpdatePageContent($xml, [DateTime]::MinValue, 1, $false)
99 }
100 $app.SyncHierarchy($notebookId)
101 $app.CloseNotebook($notebookId, $false)
102 $notebookId = ''
103} finally {
104 if ($notebookId) { $app.CloseNotebook($notebookId, $false) }
105 [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app)
106 [GC]::Collect()
107 [GC]::WaitForPendingFinalizers()
108}