How to: Read a Journal File
The Microsoft Windows Journal Note Reader component provides programmatic read access to files in the Journal format. Journal files have the .jnt file extension. This simple component takes a stream containing a .jnt file and returns a stream containing the file’s content in XML format. The XML returned by the component conforms to the Journal Note Reader schema. This schema is documented in Journal Reader Schema Reference.
Example
The following example reads a .jnt file and adds each page in the file to an InkCanvas. This example assumes that there is a TabControl called pagePanel
.
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.IO
Imports System.Windows.Ink
Imports System.Xml
...
Private Sub LoadInk()
' Load a Journal file.
Dim openJnt As New Microsoft.Win32.OpenFileDialog()
openJnt.Multiselect = False
openJnt.Filter = "Journal Files(*.jnt) | *.jnt"
openJnt.ShowDialog()
If openJnt.FileName = "" Then
Return
End If
Me.Title = openJnt.FileName
'Read in the journal file and load its XML.
Dim jntFile As Stream = openJnt.OpenFile()
Dim jntXml As Stream = _
Microsoft.Ink.JournalReader.ReadFromStream(jntFile)
' Get the xml from the JournalReader.
Dim jntDoc As New XmlDocument()
jntDoc.Load(jntXml)
'Get all JournalPage nodes in the xml.
nsmgr = New XmlNamespaceManager(jntDoc.NameTable)
nsmgr.AddNamespace("jnt", _
"urn:schemas-microsoft-com:tabletpc:journalreader")
Dim pages As XmlNodeList = _
jntDoc.DocumentElement.SelectNodes(".//jnt:JournalPage", nsmgr)
Dim pageCounter As Integer
For pageCounter = 0 To pages.Count - 1
Dim page As XmlNode = pages(pageCounter)
' Create an InkCanvas to hold the ink.
Dim pageCanvas As New InkCanvas()
' Create a tab item for each page and name
' it according to its page number.
Dim tabPage As New TabItem()
tabPage.Header = "Page " & (pageCounter + 1)
' Add the InkCanvas to the TabItem.
tabPage.Content = pageCanvas
' Find all the InkWord and Drawings nodes and add the
' ink to the InkCanvas.
Dim inkWords As XmlNodeList = _
page.SelectNodes(".//jnt:InkWord | .//jnt:Drawing", nsmgr)
AddInkToCanvas(pageCanvas, inkWords)
' Add the TabItem representing the current Journal
' page to the TabControl.
pagePanel.Items.Add(tabPage)
Next pageCounter
'Close the streams.
jntXml.Close()
jntFile.Close()
End Sub 'LoadInk
Private Sub AddInkToCanvas(ByVal pageCanvas As InkCanvas, _
ByVal xmlNodes As XmlNodeList)
Const cmPerInch As Double = 2.54
' The value to multiply to get
' device independant pixels.
Const WPFRatio As Double = 96.0 / 2540.0
Dim node As XmlNode
For Each node In xmlNodes
Dim scalarMatrix As New Matrix()
' Look for a ScalarTransform element and create a matrix
' if it is found. The GetValue method is defined below.
' ScalarTransform's matrix is in the following format:
' Mat1 Mat4 Mat7
' Mat2 Mat5 Mat8
' Mat3 Mat6 Mat9
Dim scalarTransform As XmlNode = _
node.SelectSingleNode("./jnt:ScalarTransform", nsmgr)
If Not (scalarTransform Is Nothing) Then
scalarMatrix.M11 = GetMatrixValue(scalarTransform, "Mat1")
scalarMatrix.M12 = GetMatrixValue(scalarTransform, "Mat4")
scalarMatrix.M21 = GetMatrixValue(scalarTransform, "Mat2")
scalarMatrix.M22 = GetMatrixValue(scalarTransform, "Mat5")
' Multiply OffsetX and OffsetY by WPFRatio
' to find the WPF coordinates.
scalarMatrix.OffsetX = _
GetMatrixValue(scalarTransform, "Mat3") * WPFRatio
scalarMatrix.OffsetY = _
GetMatrixValue(scalarTransform, "Mat6") * WPFRatio
End If
' Find the InkObject node.
Dim inkObject As XmlNode = _
node.SelectSingleNode("./jnt:InkObject", nsmgr)
If Not (inkObject Is Nothing) Then
' Load the base64 ISF into a MemoryStream and
' create a StrokeCollection.
Dim base64ISF As String = inkObject.InnerText
Dim isfData As _
New MemoryStream(Convert.FromBase64String(base64ISF))
Dim strokes As New StrokeCollection(isfData)
' Journal saves the ink in English Metric Units
' so convert the ink to inches.
Dim scalar As New ScaleTransform(cmPerInch, cmPerInch)
strokes.Transform(scalar.Value, False)
If Not scalarMatrix.IsIdentity Then
' Apply the accompying ScalarMatrix to the strokes.
strokes.Transform(scalarMatrix, False)
End If
'Add the ink to the page.
pageCanvas.Strokes.Add(strokes)
End If
Next node
End Sub 'AddInkToCanvas
' Converts the value of ScalarTransform's
' attribute to a double.
Private Function GetMatrixValue(ByVal node As XmlNode, _
ByVal valueName As String) As Double
Dim nodeValue As String = _
node.Attributes.GetNamedItem(valueName).Value
Return Convert.ToDouble(nodeValue)
End Function 'GetValue
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.IO;
using System.Windows.Ink;
using System.Xml;
...
private void LoadInk()
{
// Load a Journal file.
Microsoft.Win32.OpenFileDialog openJnt = new Microsoft.Win32.OpenFileDialog();
openJnt.Multiselect = false;
openJnt.Filter = "Journal Files(*.jnt) | *.jnt";
openJnt.ShowDialog();
if (openJnt.FileName == "")
{
return;
}
this.Title = openJnt.FileName;
//Read in the journal file and load its XML.
Stream jntFile = openJnt.OpenFile();
Stream jntXml = Microsoft.Ink.JournalReader.ReadFromStream(jntFile);
// Get the xml from the JournalReader.
XmlDocument jntDoc = new XmlDocument();
jntDoc.Load(jntXml);
//Get all JournalPage nodes in the xml.
nsmgr = new XmlNamespaceManager(jntDoc.NameTable);
nsmgr.AddNamespace("jnt", "urn:schemas-microsoft-com:tabletpc:journalreader");
XmlNodeList pages = jntDoc.DocumentElement.SelectNodes(".//jnt:JournalPage", nsmgr);
for (int pageCounter = 0; pageCounter < pages.Count; pageCounter++)
{
XmlNode page = pages[pageCounter];
// Create an InkCanvas to hold the ink.
InkCanvas pageCanvas = new InkCanvas();
// Create a tab item for each page and name
// it according to its page number.
TabItem tabPage = new TabItem();
tabPage.Header = "Page " + (pageCounter + 1);
// Add the InkCanvas to the TabItem.
tabPage.Content = pageCanvas;
// Find all the InkWord and Drawings nodes and add the
// ink to the InkCanvas.
XmlNodeList inkWords =
page.SelectNodes(".//jnt:InkWord | .//jnt:Drawing", nsmgr);
AddInkToCanvas(pageCanvas, inkWords);
// Add the TabItem representing the current Journal
// page to the TabControl.
pagePanel.Items.Add(tabPage);
}
//Close the streams.
jntXml.Close();
jntFile.Close();
}
private void AddInkToCanvas(InkCanvas pageCanvas, XmlNodeList xmlNodes)
{
const double cmPerInch = 2.54;
// The value to multiply to get
// device independant pixels.
const double WPFRatio = 96d / 2540d;
foreach (XmlNode node in xmlNodes)
{
Matrix scalarMatrix = new Matrix();
// Look for a ScalarTransform element and create a matrix
// if it is found. The GetValue method is defined below.
// ScalarTransform's matrix is in the following format:
// Mat1 Mat4 Mat7
// Mat2 Mat5 Mat8
// Mat3 Mat6 Mat9
XmlNode scalarTransform =
node.SelectSingleNode("./jnt:ScalarTransform", nsmgr);
if (scalarTransform != null)
{
scalarMatrix.M11 = GetValue(scalarTransform, "Mat1");
scalarMatrix.M12 = GetValue(scalarTransform, "Mat4");
scalarMatrix.M21 = GetValue(scalarTransform, "Mat2");
scalarMatrix.M22 = GetValue(scalarTransform, "Mat5");
// Multiply OffsetX and OffsetY by WPFRatio
// to find the WPF coordinates.
scalarMatrix.OffsetX = GetValue(scalarTransform, "Mat3") * WPFRatio;
scalarMatrix.OffsetY = GetValue(scalarTransform, "Mat6") * WPFRatio;
}
// Find the InkObject node.
XmlNode inkObject = node.SelectSingleNode("./jnt:InkObject", nsmgr);
if (inkObject != null)
{
// Load the base64 ISF into a MemoryStream and
// create a StrokeCollection.
string base64ISF = inkObject.InnerText;
MemoryStream isfData =
new MemoryStream(Convert.FromBase64String(base64ISF));
StrokeCollection strokes = new StrokeCollection(isfData);
// Journal saves the ink in English Metric Units
// so convert the ink to inches.
ScaleTransform scalar =
new ScaleTransform(cmPerInch, cmPerInch);
strokes.Transform(scalar.Value, false);
if (!scalarMatrix.IsIdentity)
{
// Apply the accompying ScalarMatrix to the strokes.
strokes.Transform(scalarMatrix, false);
}
//Add the ink to the page.
pageCanvas.Strokes.Add(strokes);
}
}
}
// Converts the value of ScalarTransform's
// attribute to a double.
private double GetValue(XmlNode node, string valueName)
{
string nodeValue = node.Attributes.GetNamedItem(valueName).Value;
return Convert.ToDouble(nodeValue);
}
Compiling the Code
To compile the code, add a reference to the Microsoft.Ink.JournalReader.dll assembly.