Custom Rendering of Tablet PC Ink
Summary: Learn about ink transformations three transformations you can apply to ink using the Tablet PC. You should be familiar with the Tablet PC, in general, but you do not need to be familiar with transformations. (8 printed pages)
What is a Transformation, Anyway?
The Renderer Object
Types of Transformations
View Transformations on the Renderer Object
Object Transformations on the Renderer Object
Transformations on Stroke and Strokes Objects
One of the confusing topics of the Tablet PC is ink transformations. This article will clarify what transformations are, describe the three different types of transformations related to ink and define the difference between each of them.
The Tablet PC has two coordinate systems (actually, there are at least two; but we are only concerned with two at the moment): device coordinates, which are typically referred to as pixel coordinates, and ink coordinates. A coordinate system is a planar space that locates two-dimensional objects by using two reference axes that are perpendicular to each other, referred to as the x and y axis. So, if you wanted to locate the square in the following diagram, you could say that it is located 100 units along the y axis and 50 units along the x axis from the origin (0,0).
Figure 1. Coordinate system
Why are there two different coordinate systems? For a very simple reason: ink coordinates are much denser than device coordinates. On average, for every one device coordinate, there are 10 corresponding ink coordinates. To explain transformations, we first need to understand how these two coordinate systems interact.
Remember transparencies in school? Perhaps that was before your time, but a transparency was a sheet of transparent film with opaque ink on it. A device called an overhead projector was used to display a transparency by illuminating it from below and projecting it onto a screen. The interesting aspect of transparencies is that one can combine transparencies by placing one on top of the other:
Figure 2. Combining transparencies
Now that you have placed one of the transparencies on top of the other, you get a combined output of 'Hello World'. What would happen if we moved one of the transparencies so that the two were not exactly on top of each other?
Figure 3. Transformation example
The combined output is now different, right? 'Hello' and 'World' no longer appear on the same line. You have just done your first transformation (a translation transformation to be exact). The first transparency represents device coordinates, the second transparency represents ink coordinates, and the alignment or mapping between the two represents a transformation. The combined output represents what you see on your Tablet PC's screen: Microsoft® Windows® manages output from the two coordinate spaces and combines them to produce an image on the screen that a user can see.
You might be asking yourself what happens when you move the second transparency so far over that it is no longer on top of the first one? How does Windows combine the display? The answer is that from the user's perspective, it doesn't. The first transparency — device coordinates — defines the area that the user sees on the screen. The second transparency — ink coordinates — is combined with the first to produce an output, if you move it too far over, by transforming it, you will not be able to see any of its contents.
The Tablet PC exposes the mapping between these two coordinate systems via the Renderer object. The Renderer object exposes methods that allow developers to map between the two coordinate systems and to transform the mapping between them, thus changing how ink is displayed. Both the InkCollector and InkOverlay objects have an associated Renderer object that affects the display of the ink on the window the objects are collecting on.
So far we have only looked at a single transformation, the translation transformation, which is used to move the ink coordinate system along the x and / or y axis relative to the device coordinate system. There are also scale, rotation, shear and reflection transformations that affect the mapping of these two coordinate systems.
These various transformations can be applied using one or more types of transformations:
- Object transformation. This type of transformation changes the mapping between the two coordinate systems, thus changing how ink is rendered, but does not scale the apparent width of the ink and pen width during a scale transformation. The underlying ink stroke is not modified, only the appearance of that ink stroke.
- View transformation. This type of transformation is identical to object transformations, except that the apparent width of the ink and pen are scaled during a scale transformation. Also, an object transformation is applied before a view transformation is. The underlying ink stroke is not modified, only the appearance of that ink stroke.
- Stroke transformation. This type of transformation is different than the previous two because it does not affect the mapping between the two coordinate systems; it only changes the underlying stroke's properties to simulate such a transformation.
I realize these concepts are initially a bit confusing. To clear this up, let's look at a demonstration of a scale transformation being applied using these three types of transformations. To do so, we will be applying each transformation to the following ink strokes:
Figure 4. Ink strokes sample
View transformations are exposed on the Renderer object, so to change the scale of the view transformation; you would execute the following code:
Changing the Scale of the View Transformation in C++
// Headers for Tablet PC Automation interfaces #include <atlbase.h> #include <msInkaut.h> #include <msInkaut_i.c> // Create an InkOverlay object. CComPtr<IInkOverlay> spIInkOverlay; HRESULT hr = spIInkOverlay.CoCreateInstance(CLSID_InkOverlay); // Enable ink input in the m_hWnd window hr = spIInkOverlay->put_hWnd((long)m_hWnd); hr = spIInkOverlay->put_Enabled(VARIANT_TRUE); // Get a pointer to the associated Renderer CComPtr<IInkRenderer> spIInkRenderer; hr = spIInkOverlay->get_Renderer(&spIInkRenderer); // get the current view transform CComPtr<IInkTransform> spIInkTransform; spIInkRenderer->GetViewTransform(spIInkTransform); // adjust the scale spIInkTransform->ScaleTransform(1.25, 1.25); // set the transformation spIInkRenderer->SetViewTransform(spIInkTransform);
Changing the Scale of the View Transformation in C#
using System; using Microsoft.Ink using System.Drawing.Drawing2D; // Create an InkOverlay object. InkOverlay inkOverlay = new InkOverlay(); // Enable ink input in the current form inkOverlay.Handle = this.Handle; inkOverlay.Enabled = true; // get the current view transform Matrix matrix = new Matrix(); inkOverlay.Renderer.GetViewTransform(ref matrix); // adjust the scale matrix.Scale(1.25F, 1.25F); // set the transformation inkOverlay.Renderer.SetViewTransform(matrix);
The result of this code is as follows:
Figure 5. Ink strokes sample with adjusted scale
Ink coordinates have now been scaled 125% along both the x and y axis, and the apparent width of the strokes have also been scaled. The dashed blue lines represents the extent of the ink coordinate system (as it relates to device coordinates, represented by the solid black lines) The net effect is that the ink strokes appear bigger, even though the measurement of the bounding rectangle of the ink strokes (in ink coordinates) has not changed. A view transformation might be used to implement zooming and panning in a document's "print preview" mode.
Object transformations are also exposed on the Renderer object, so to change the scale of the object transformation; you would execute the following code:
Changing the Scale of the Object Transformation in C++
// get the current object transform CComPtr<IInkTransform> spIInkTransform; spIInkRenderer->GetObjectTransform(spIInkTransform); // adjust the scale spIInkTransform->ScaleTransform(1.25, 1.25); // set the transformation spIInkRenderer->SetObjectTransform(spIInkTransform);
Changing the Scale of the Object Transformation in C#
// get the current object transform Matrix matrix = new Matrix(); inkOverlay.Renderer.GetObjectTransform(ref matrix); // adjust the scale matrix.Scale(1.25F, 1.25F); // set the transformation inkOverlay.Renderer.SetObjectTransform(matrix);
The result of this code is as follows:
Figure 6. Changing the ink strokes sample scale without changing the apparent width of the strokes
Once again, ink coordinates have been scaled 125% along both the x and y axis, but with this object transformation the apparent width of the strokes has not been scaled. This is the only difference between a view and object transformation. The dashed blue lines again represent the new ink coordinate space as it relates to the corresponding device coordinate space (solid black lines). An object transformation makes sense in a zooming or panning scenario where the ink being transformed represents a path or distance, such as annotations to an architectural drawing or a route drawn on a map.
The last transformation is a stroke type transformation. Calling this a stroke transformation is actually a bit misleading, because transformations refer to changes int the mappings between two coordinate systems, and we are not changing that. More accurately, the stroke is being modified using transformation semantics:
Changing the Size of Strokes Using a Scale Transformation in C++
// Get a pointer to the ink object interface. CComPtr<IInkDisp> spIInkDisp; hr = spIInkOverlay->get_Ink(&spIInkDisp); // Get a pointer the strokes in the ink object CComPtr<IInkStrokes> spIInkStrokes; hr = spIInkDisp->get_Strokes(&spIInkStrokes); // create a new InkTransform object CComPtr<IInkTransform> spIInkTransform; hr = spIInkTransform.CoCreateInstance(CLSID_InkTransform); // set the scale hr = spIInkTransform->ScaleTransform(1.25, 1.25); // apply the transform hr = spIInkStrokes->Transform(spIInkTransform, VARIANT_TRUE);
Changing the Size of Strokes Using a Scale Transformation in C#
// get the current view transform Matrix matrix = new Matrix(); // adjust the scale matrix.Scale(1.25F, 1.25F); // set the transformation inkOverlay. Ink.Strokes.Transform(matrix, true);
The result of this code is as follows:
Figure 7. Ink strokes sample stroke size increased
You will notice that in this case, the mapping between ink and device coordinates have not been altered (the blue dashed lines are directly on top of the black solid lines), but the size of the ink bounding rectangle — in ink coordinates — has. This is the difference between using view and object transformations and applying a transform to a stroke or collection of strokes. Since stroke transformations permanently modify the ink data, they are useful for moving and scaling strokes within a document during editing.
Transformations are a powerful feature of the Tablet PC that allows developers to change the appearance of objects on the screen. The Tablet PC exposes three types of transformations: view, object and stroke transformations.