/*-------------------------------------------------------------------------- ** File: inkstore.h ** ** Copyright 1993, Slate Corporation, All Rights Reserved. ** ** This document is part of the Jot specification for the storage and ** interchange of electronic ink data. This specification is the joint work ** of representatives of Slate Corporation, Lotus Development Corporation, ** GO, Microsoft, Apple, General Magic, and others. ** ** This document and the accompanying code samples on disk comprise Version ** 1.0 of the Jot specification for the storage and interchange of electronic ** ink data. Permission is granted to incorporate and otherwise use any ** portion of the specification. You may make copies of the specification ** for distribution to others, provided you include the notice "Copyright ** 1993, Slate Corporation. All Rights Reserved" on both the document and ** the disk label. You may not modify this specification without written ** permission from Slate Corporation. ** ** The specification is provided "as is" without warranty of any kind. Slate ** further disclaims all implied warranties of merchantability or of fitness ** for a particular purpose. The entire risk arising out of the use or ** performance of the specification remains with you. ** **-------------------------------------------------------------------------- ** ** This is the main body of definitions for the ink storage specification. ** See reference section 1.0 for revision history. ** **------------------------------------------------------------------------*/ #ifndef INKSTORE_INCLUDED #define INKSTORE_INCLUDED /*************************/ /* REFERENCE SECTION 0.0 */ /*************************/ /*-------------------------------------------------------------------------- ** "Rationale for the ink specification" ** ** This document defines a storage and interchange format for embedded ink ** data. The format is device- and platform-independent. The goal is to ** provide application programs on the same and different platforms and ** operating systems a way to store and exchange ink data. Thus a PenPoint ** user might scribble a note and send the untranslated ink as part of an ** e-mail message to a colleague's pen computer running Windows for Pen ** Computing using Magic Mail. ** ** This specification is for a publicly-defined, external format for ** electronic ink data interchange, and neither assumes nor dictates the ** nature of how the application deals with ink data internally. The format ** is not intended to be the "internal" ink format of an application, though ** there is no reason why it could not serve such a purpose. ** ** The scope and goals of this format design are limited to the represent- ** ation of electronic ink data embedded in some other electronic document, ** not to the larger document itself (such as an e-mail or enhanced word- ** processing data file). ** ** The approach taken is to capture the complete user input for the ** electronic ink, including not just X/Y coordinates, but also a large set ** of current drawing attributes such as nib type and ink color. This ** differs from other possible approaches, such as those based on certain ** recognition models for handwritten text, which require decomposing the ** handwritten ink data first into a set of pre-defined approximation curves ** or sub-strokes, and then storing a list of encodings of these sub-strokes. ** In other words, Jot preserves all information about the original input as ** opposed attempting any sort of abstract characterization of the input. ** ** The storage format has a number of properties: ** ** * Simple. Typical operations on the ink data are easy. If you only wish ** to read stroke coordinates and bounding information from the data, ** complex information that might be present will not hinder the process. ** Likewise, it is easy to write out just simple information. The ** complex information is all optional. ** ** * Compact. The storage format is intended to be as compact as possible ** without sacrificing simplicity or fidelity. Optional information such ** as time stamps or color specifications occupy space only when they are ** present. Specifications that apply to many strokes (such as line width ** or color) are represented just once. ** ** * Compression. The stroke information that describes the ink can ** optionally be represented in a compressed format. Compression ** techniques include both compression and reduction of the ink data. ** ** * Inclusive. The format is capable of storing every property of ink ** conceivable as of today. ** ** * Expandable and Compatible. The format is expandable, so as developers ** discover new information that should be recorded in an ink storage ** format, these new features can be added without changing the behavior of ** existing application programs working with an older version of the ** format. In general, new features can generally be ignored by ** applications reading older versions of the format. Likewise, new ** application programs can handle previous versions of the format without ** special work. ** ** The format is not designed to easily support lots of in-memory ** manipulation of the ink data, such as deleting strokes, changing line ** widths, and so on. A format supporting these types of manipulations would ** be at odds with the above goals. All the information needed to perform ** these manipulations is present in this data format, so an application ** might augment this format to facilitate manipulation of the ink data. ** ** Applications are likely to use some other format internally for real-time ** ink manipulation. Many operating environments provide some internal means ** for storing and manipulating ink data, the details of which may be hidden ** to some extent from the application designer. Many such real-time data ** structures store fewer types of and/or less information (such as not ** preserving information about the tablet point data rate) than are covered ** in this definition. ** **------------------------------------------------------------------------*/ /*************************/ /* REFERENCE SECTION 1.0 */ /*************************/ /*------------------------------------------------------------------------- ** Jot Ink Specification ** --------------------- ** ** Revision History: ** ** March 16, 1992 - First public draft. ** July 13, 1992 - Major rewrite to put data into a series of records. ** July 19, 1992 - Inclusion of ink-compacting definitions. ** July 30, 1992 - Change of target rect to offset. ** December 28, 1992 - Changes incorporated from August 1992 review meeting. ** February 12, 1993 - Incremental fixes due to coding experience. ** March 13, 1993 - Revised definition of a "group". ** April 12, 1993 - Release of version 0.99 of the specification. Moved ** reference sections 28 and 29 to a separate file called ** sample.h ** May 01, 1993 - Release of version 1.00 of the specification. ** Changed INK_OFFSET_RECORD units from twips to pen ** units for consistency and ease of implementation. ** Fixed a typo in reference section 26.0 in the diagram. ** The text accompanying the diagram was correct. ** Fixed a typo in reference section 27.0. The old text ** "delta-X == 0 or 1" was replaced with the correct text ** "delta-X == 2". The accompanying diagram was correct. ** Removed all sizeof() constructs and replaced with ** appropriate #defines to reduce compiler dependencies. ** Tagged all struct definitions with tag_ prefix. ** Added comments and reordered some existing comments. ** May 17, 1993 - Added a few more _SIZE #defines, clarified reserved ** values. ** ** ** GENERAL NOTES ** ------------- ** ** ** Record Structure ** ---------------- ** ** If not otherwise specified, all words are stored in Intel order: low-order ** word first, then high-order word, and inside of a word, low-order byte, ** then high-order byte. For example, a 32 bit quantity 0x12345678 would be ** written to the file as 0x78 0x56 0x34 0x12. The notable exception is the ** storage of point data in "standard compression" format. Sign bits are ** used to indicate item types, so the bytes are stored high-order to low- ** order (exactly opposite). See the sample code and reference section 23.0 ** for more information on the compressed format. Uncompressed data is ** written in Intel order. ** ** All structures are packed for the purposes of writing to a stream. ** ** Signed integer values are two's-complement. Rectangles are stored ** x,y,w,h. ** ** These definitions are intended to insulate the sample ink compaction and ** storage code from any possible variation in item alignment or structure ** packing across architectures. The only possible area of portability ** concern lies in the use of unions in colors (see 11.0) and pen tips (see ** 14.0). ** ** Any use of units of mass to denote units of force ("grams of force"), or ** similar common misuses of physical units, are noted here with an apology ** to any purists, and should be interpreted in the common way by assuming ** one standard gravity. ** ** Record Sequence ** --------------- ** ** In this document, one piece of ink data is called an ink bundle. ** Typically this might correspond to the strokes that make up the ink from ** the time when the pen touches down until the user finishes writing ** (usually determined by a timeout or the pen leaving proximity). Thus an ** ink bundle usually contains many ink strokes, and the strokes do not have ** to describe a continuous line of ink. ** ** As stated in reference section 5.0, all data conforming to this ** specification appears as a stream of ink bundles each of which must begin ** with an INK_BUNDLE_RECORD and end with an INK_END_RECORD. There may be ** more than one INK_BUNDLE_RECORD/INK_END_RECORD pair in a given stream. ** A record stream might look something like this: ** ** INK_BUNDLE_RECORD required // for bundle number one ** INK_SCALE_RECORD optional // sets the scale for rendering ** INK_OFFSET_RECORD optional // sets the offset for rendering ** INK_COLOR_RECORD optional // sets the color for rendering ** INK_START_TIME_RECORD optional // sets the relative start time ** INK_PENTIP_RECORD optional // sets the pentip for rendering ** INK_GROUP_RECORD optional // tags the following PENDATA ** INK_PENDATA_RECORD recommended // actual points ** INK_GROUP_RECORD optional // tags the following PENDATA ** INK_PENDATA_RECORD recommended // actual points ** INK_PENDATA_RECORD recommended // more points in same group ** INK_SCALE_RESET_RECORD optional // resets to default scaling/offset ** INK_PENDATA_RECORD recommended // actual points ** INK_END_TIME_RECORD optional // relative time inking ended ** INK_END_RECORD required // end of bundle number one ** ** It is perfectly reasonable to write out only the following (though doing ** so will cause the ink to be rendered in a completely default manner -- ** black hairline width at 1:1 scaling with offset 0): ** ** INK_BUNDLE_RECORD ** INK_PENDATA_RECORD ** INK_END_RECORD ** ** ** Specification Revisions ** ----------------------- ** ** Future enhancements to this specification may modify certain record types. ** It is guaranteed that any record modified in a subsequent revision of the ** specification will be a strict superset of that record's definition in any ** previous revision of the specification. That is, modified record types ** will only be lengthened, not shortened. If a particular record type must ** be extended such that it would not be a superset of the original, a new ** record type would be added to cover that particular extension. ** ** This extension strategy has two important ramifications: ** ** 1) A reading application should *ALWAYS* use the size of a record as ** recorded in the record structure itself (i.e., the recordLength field ** of the INK_RECORD_HEADERx structure) rather than the sizeof() or any ** other size determined at compile time to determine how may bytes to ** read as the data structures are parsed. This is due to the fact that ** a record may grow in a future revision of the standard. The only ** exception to this rule is the INK_BUNDLE_RECORD which contains a ** version number that will be modified with each change to that record. ** If an INK_BUNDLE_RECORD is encountered and its version matches the ** version used at compile time, the size of the record should exactly ** match the #define of inkRecordBundleSize. ** ** 2) Any particular record may be read into a target data structure up to ** the size of the target data structure and the rest may be ignored. ** This is due to the 'strict superset' rule which means that any ** extension of any record type must leave the meaning, content, and size ** of any existing fields as is. So, for example, if an INK_SCALE_RECORD ** was modified by adding 2 bytes, the reading application can safely read ** the data into the INK_SCALE_RECORD known at compile time and throw ** away the extra two bytes: the header, x, and y will be in the same ** place and will have the same meaning. ** ** ** Files of Ink ** ------------ ** ** It is a recommended practice on DOS and UNIX style file systems to use the ** extension ".JOT" for files consisting solely of ink recorded according to ** this specification. The specification is designed such that ink data can ** be embedded inside any file format and if such a file contains more than ** strictly ink data, it should not use the .JOT extension. ** **------------------------------------------------------------------------*/ /*************************/ /* REFERENCE SECTION 2.0 */ /*************************/ /*------------------------------------------------------------------------- ** Definitions used in this header. ** ** These definitions must be defined appropriately to the target environment ** and compiler. ** ** For example, on some compilers for environments using segmented addressing ** and 64K segments sizes, the correct definition of FAR would be "_huge", ** rather than "_far", because the objects pointed to may be larger than 64K. ** ** In particular, check the definitions of FAR, U32, and S32 for ** compatibility with your compiler, environment, and memory model. ** **------------------------------------------------------------------------*/ #ifndef FAR #define FAR #endif /* useful constants */ #define flag0 (0x0001) #define flag1 (0x0002) #define flag2 (0x0004) #define flag3 (0x0008) #define flag4 (0x0010) #define flag5 (0x0020) #define flag6 (0x0040) #define flag7 (0x0080) #define flag8 (0x0100) #define flag9 (0x0200) #define flag10 (0x0400) #define flag11 (0x0800) #define flag12 (0x1000) #define flag13 (0x2000) #define flag14 (0x4000) #define flag15 (0x8000) #define flag16 (0x00010000L) #define flag17 (0x00020000L) #define flag18 (0x00040000L) #define flag19 (0x00080000L) #define flag20 (0x00100000L) #define flag21 (0x00200000L) #define flag22 (0x00400000L) #define flag23 (0x00800000L) #define flag24 (0x01000000L) #define flag25 (0x02000000L) #define flag26 (0x04000000L) #define flag27 (0x08000000L) #define flag28 (0x10000000L) #define flag29 (0x20000000L) #define flag30 (0x40000000L) #define flag31 (0x80000000L) #define TRUE 1 #define FALSE 0 /* void pointers */ typedef void FAR *P_UNKNOWN; typedef P_UNKNOWN FAR *PP_UNKNOWN; #define pNull ((P_UNKNOWN)0) /* Unsigned integers */ typedef unsigned char U8, FAR *P_U8; #define U8_SIZE 1 typedef unsigned short U16, FAR *P_U16; #define U16_SIZE 2 typedef unsigned long U32, FAR *P_U32; #define U32_SIZE 4 /* Signed integers */ typedef char S8, FAR *P_S8; #define S8_SIZE 1 typedef short S16, FAR *P_S16; #define S16_SIZE 2 typedef long S32, FAR *P_S32; #define S32_SIZE 4 /* typedef signed char S8, FAR *P_S8; #define S8_SIZE 1 typedef signed short S16, FAR *P_S16; #define S16_SIZE 2 typedef signed long S32, FAR *P_S32; #define S32_SIZE 4 */ /* geometry structures */ typedef struct tag_XY32 { S32 x; S32 y; } XY32, FAR *P_XY32; #define XY32_SIZE (S32_SIZE+S32_SIZE) typedef struct tag_XY16 { S16 x; S16 y; } XY16, FAR *P_XY16; /*------------------------------------------------------------------------- ** Note: ** Angles from vertical can exceed +-90 degrees: in this case, the "back" end ** of the stylus is nearer the tablet surface than the "front" end. **-------------------------------------------------------------------------*/ /*------------------------------------------------------------------------- ** Note: ** Standard compaction will normally store angles in nibbles, or single ** bytes, rather than in four-byte records. **-------------------------------------------------------------------------*/ typedef struct tag_ANGLE16 { S16 theta; /* "X" angle of the stylus, degrees from vertical, */ /* increasing in the positive "X" direction. */ S16 phi; /* "Y" angle of the stylus. */ } ANGLE16, FAR *P_ANGLE16; #define ANGLE16_SIZE (S16_SIZE+S16_SIZE) typedef struct tag_SIZE32 { S32 w; S32 h; } SIZE32, FAR *P_SIZE32; #define SIZE32_SIZE (S32_SIZE+S32_SIZE) typedef struct tag_SIZE16 { S16 w; S16 h; } SIZE16, FAR *P_SIZE16; #define SIZE16_SIZE (S16_SIZE+S16_SIZE) /*------------------------------------------------------------------------- ** Note: ** A rect where xmin==xmax and ymin==ymax has a size of zero: ** size.w and size.h are both zero. **-------------------------------------------------------------------------*/ typedef struct tag_RECT32 { XY32 origin; SIZE32 size; } RECT32, FAR *P_RECT32; #define RECT32_SIZE (XY32_SIZE+SIZE32_SIZE) typedef U32 FIXED_FRACTION; /* fixed point value, unity = 0x00010000 */ #define FIXED_FRACTION_SIZE U32_SIZE #define INK_UNITY_SCALE ((U32) 0x00010000L) /*************************/ /* REFERENCE SECTION 3.0 */ /*************************/ /*------------------------------------------------------------------------- ** A block of ink data is called an ink bundle. Each ink bundle consists of ** a series of n records. Each record has a common header that indicates the ** record type and the record length. An ink bundle always starts with an ** INK_BUNDLE_RECORD and always ends with an INK_END_RECORD. ** ** Any records of unknown type can be skipped by simply reading the length of ** the record. ** ** Note: ** Within an ink bundle, time increases. This implies a drawing order of ** back-to-front. Between adjacent sequential bundles, the implicit drawing ** is also back-to-front. ** ** A number of record types are defined. The most common is the ** inkRecordPenData which contains the actual pen data. Other records are ** mostly attributes of the pen data and are optional. They will, in ** general, only be present when a given attribute changes to something ** different than the default value for that attribute. ** ** In order to have the most compact format and also allow large records, ** several different record headers are defined, each with a different ** length. ** ** The top two bits of the record type indicate what kind of record length ** follows: ** ** The record length can be: ** ** - non-existent (the entire record consists of just the recordType) ** - An 8 bit length (one byte) for records up to 255 bytes ** - A 16 bit length (two bytes) for records up to 64k ** - A 32 bit length (four bytes) for really big records ** **------------------------------------------------------------------------*/ #define inkRecordNoLength 0 /* no length, just recordType */ #define inkRecordLength8 flag14 /* 8 bit length */ #define inkRecordLength16 flag15 /* 16 bit length */ #define inkRecordLength32 (flag15 | flag14) /* 32 bit length */ /* useful defines for isolating or clearing the length type bits */ #define inkRecordLengthMask (flag15 | flag14) /* mask for length bits */ #define inkRecordLengthClearMask (~inkRecordLengthMask) /* some useful macros for declaring the various types of record types */ #define MakeRec0(recType) (recType | inkRecordNoLength) /* no rec length */ #define MakeRec8(recType) (recType | inkRecordLength8) /* 8 bit length */ #define MakeRec16(recType) (recType | inkRecordLength16) /* 16 bit length */ #define MakeRec32(recType) (recType | inkRecordLength32) /* 32 bit length */ typedef U16 INK_RECORD_TYPE, FAR *P_INK_RECORD_TYPE; #define INK_RECORD_TYPE_SIZE U16_SIZE #define inkRecordHeaderLength(record_type) \ ( (((record_type) & inkRecordLength32) == inkRecordNoLength) ?\ INK_RECORD_TYPE_SIZE \ : (((record_type) & inkRecordLength32) == inkRecordLength8) ?\ INK_RECORD_TYPE_SIZE+U8_SIZE \ : (((record_type) & inkRecordLength32) == inkRecordLength16) ?\ INK_RECORD_TYPE_SIZE+U16_SIZE \ : INK_RECORD_TYPE_SIZE+U32_SIZE \ ) /*------------------------------------------------------------------------- ** Note: most compilers will not generate code for the above macro but will ** determine the proper value at compile time. **-------------------------------------------------------------------------*/ /*************************/ /* REFERENCE SECTION 4.0 */ /*************************/ /*------------------------------------------------------------------------- ** These are all the currently defined record types. The macro MakeRecX() ** encodes the right bits in with the record Id to define its recordLength. ** ** For simplicity, recType values may not be repeated for different ** INK_RECORD_TYPEs. Use of a record type defined as MakeRec32(63) thus ** forbids the use of a record type defined as MakeRec16(63), MakeRec8(63), ** or MakeRec0(63). ** ** Record type 63 is reserved explicitly for possible future extension beyond ** 63 record types. ** **------------------------------------------------------------------------*/ #define inkRecordEnd MakeRec0( 0) /* end of bundle */ #define inkRecordBundle MakeRec8( 1) #define inkRecordPenData MakeRec32( 2) #define inkRecordScale MakeRec8( 3) #define inkRecordScaleReset MakeRec0( 4) #define inkRecordColor MakeRec8( 5) #define inkRecordTip MakeRec8( 6) #define inkRecordGroup MakeRec8( 7) #define inkRecordOffset MakeRec8( 8) #define inkRecordStartTime MakeRec8( 9) #define inkRecordEndTime MakeRec8( 10) #define inkRecordPointsPerSecond MakeRec8( 11) #define inkRecordUnitsPerZ MakeRec8( 12) #define inkRecordUnitsPerForce MakeRec8( 13) /* Record types 14 .. 61 are reserved for future definition. */ #define inkRecordApp MakeRec32(62) /* application-specific records*/ #define inkRecordExt MakeRec32(63) /* reserved for extension */ /*------------------------------------------------------------------------- ** Every record starts with a header that contains the recordType and the ** recordLength. The recordType indicates the type of data here. The ** recordLength indicates the total length of all the data for the record ** (including the size of the header). **-------------------------------------------------------------------------*/ /* no recordLength */ typedef struct tag_INK_RECORD_HEADER0 { INK_RECORD_TYPE recordType; } INK_RECORD_HEADER0, FAR *P_INK_RECORD_HEADER0; /* 8 bit recordLength */ typedef struct tag_INK_RECORD_HEADER8 { INK_RECORD_TYPE recordType; U8 recordLength; } INK_RECORD_HEADER8, FAR *P_INK_RECORD_HEADER8; /* 16 bit recordLength */ typedef struct tag_INK_RECORD_HEADER16 { INK_RECORD_TYPE recordType; U16 recordLength; } INK_RECORD_HEADER16, FAR *P_INK_RECORD_HEADER16; /* 32 bit recordLength */ typedef struct tag_INK_RECORD_HEADER32 { INK_RECORD_TYPE recordType; U32 recordLength; } INK_RECORD_HEADER32, FAR *P_INK_RECORD_HEADER32; /*************************/ /* REFERENCE SECTION 5.0 */ /*************************/ /*------------------------------------------------------------------------- ** A bundle of ink consists of an INK_BUNDLE_RECORD, a series of records, ** terminated with an INK_END_RECORD. ** ** An INK_BUNDLE_RECORD, along with a matching INK_END_RECORD, are the ** mandatory records in the format. The ink data must start with an ** INK_BUNDLE_RECORD. ** ** It is suggested that anyone reading this format do a number of validity ** checks on the first record in any ink data. The first record should meet ** the following minimum requirements: ** ** 1) header.recordType == INK_RECORD_BUNDLE ** 2) header.recordLength >= inkRecordBundleSize (See general notes in ** reference section 1.0 for important information about record sizes.) ** 3) compactionType is an expected and supported value ** 4) penUnitsPerX and penUnitsPerY seem reasonable and expected: ** greater than, say, 1000 units per meter (25.4/inch), less than, say, ** 400,000 (~10,000 units per inch) ** **------------------------------------------------------------------------*/ typedef struct tag_INK_END_RECORD { INK_RECORD_HEADER0 header; /* value is inkRecordEnd */ } INK_END_RECORD, FAR *P_INK_END_RECORD; #define inkRecordEndSize (inkRecordHeaderLength(inkRecordEnd)) /*************************/ /* REFERENCE SECTION 6.0 */ /*************************/ /*------------------------------------------------------------------------- ** The terms compression and compaction are used somewhat interchangeably ** in this specification but they actually have slightly different meanings ** and are both supported to a certain extent by Jot. ** ** Compression refers to a technique of encoding data such that the resuling ** data, while smaller, is still whole. That is, compression under Jot is ** loss-less. Compaction refers to a process where certain pieces of less ** important data are actually omitted from the stream and are possibly ** reconstructed by the reader of the data. ** ** Using Jot, a writing application may choose to compress only, compact only ** or use some combination. The standard compression mechanism defined here ** and implemented in the sample code supports both notions. ** **------------------------------------------------------------------------*/ typedef U8 INK_COMPACTION_TYPE, FAR *P_INK_COMPACTION_TYPE; #define INK_COMPACTION_TYPE_SIZE U8_SIZE #define inkNoCompression (0) #define inkStdCompression (1) /*------------------------------------------------------------------------- ** Other compression schemes may be adopted in future revisions of this ** specification. **-------------------------------------------------------------------------*/ /*************************/ /* REFERENCE SECTION 7.0 */ /*************************/ /*------------------------------------------------------------------------- ** The INK_BUNDLE_FLAGS contain some flags that apply to an entire bundle. ** If you wanted to store several pieces of ink that had different ** INK_BUNDLE_FLAGS, you would do it by storing several different bundles. ** ** Advisory flags: ** ** inkPointsRemoved ** Indicates whether all original points are still present or whether ** some points were removed to save space. For applications that are ** only interested in the visual aspects of ink, many points can be ** removed that do not affect the appearance (i.e. duplicate points, ** collinear points, points which deviate less than some screen ** resolution, etc..). Some other types of applications must know that ** points are present at some consistent sampling rate (i.e. some forms ** of handwriting translation). This flag indicates whether all ** original points are still there. ** ** Note: ** The purpose of "inkPointsRemoved" is to indicate that the timing ** information cannot be accurately derived by counting points: ** replacing individual points with an "elided point" item does not ** constitute removing points. ("Elided" means omitted or skipped). ** ** inkProxDataRemoved ** Indicates that the original points between strokes (proximity) were ** removed to save space. An out-of-prox point should be stored between ** strokes to delimit them. Some applications depend on knowing the ** time between strokes or at the ends of strokes for certain ** functions. ** ** Note: ** "Proximity" is defined as the stylus being close enough to the tablet ** for the tablet to report the stylus position, although perhaps at ** lower accuracy and perhaps at a lower number of points per second. A ** recommended practice is to include "out of proximity" points in the ** recorded ink data when they are used as part of determining the ** amount of time a stylus was out of contact with the tablet, or for ** triggering the completion of an action such as a "gesture". ** ** inkStrokeLimitsPresent ** Indicates that INK_BUTTONS items are also present, and that they ** indicate what the storing app decided the stroke start/end points ** were. (Note: the reading application may otherwise use a different ** algorithm for using tip force values to delimit strokes.) ** ** Note: ** If inkStrokeLimitsPresent is set, then inkButtonDataPresent must also ** be set. ** ** Data flags: ** ** inkAngleDataPresent indicates angle data is present. ** inkForceDataPresent indicates force data is present. ** inkProxDataPresent indicates points are present when pen is lifted ** up (i.e. the force drops below some threshold). ** inkRotationDataPresent indicates pen rotation data is present. ** inkHeightDataPresent indicates pen height data is present. ** inkButtonDataPresent indicates "button state" information is present. ** inkPreMultiplyScale indicates that scaling should be applied before ** the offset value is added ("pre-multiply") ** rather than after ("post-multiply") ** ** Note: ** A previous draft version included a provision for compacting data to an ** approximation based on Bezier curves. Initial results did not show ** promise in terms of efficiency and performance. ** ** "inkBezierRepresentation" would have indicated that the X/Y ordinates ** reflected a Bezier approximation to the original tablet data. This would ** have meant that the ordinate data represented aggregates of anchor points ** and control points for each piece wise approximation, and therefore could ** not be used directly to render the data. The definition of these anchor ** and control points, and the example code for the approximation and ** regeneration of the "true" coordinates could not be worked out at this ** time. ** ** Some standard values for pen units per meter follow: ** ** 1000 points per inch digitizer == 39370 pen units per meter ** 500 points per inch digitizer == 19685 pen units per meter ** 200 points per inch digitizer == 7874 pen units per meter ** 254 points per inch (1/10 mm) == 10000 pen units per meter ** ** 1000 pen units per meter is a reasonable minimum; 400,000 is a reasonable ** maximum value. ** ** The specific format for each of these types of data is described in the ** INK_PENDATA_RECORD documentation (reference section 8.0). ** ** Note: ** The order in which these flags are defined has nothing to do with the ** order in which the data appears in the INK_POINT structure when reading ** or writing point data. For more information, see reference section 21.0. ** **------------------------------------------------------------------------*/ typedef U16 INK_BUNDLE_FLAGS, FAR *P_INK_BUNDLE_FLAGS; #define INK_BUNDLE_FLAGS_SIZE U16_SIZE #define inkPointsRemoved (flag0) #define inkProxDataRemoved (flag1) #define inkAngleDataPresent (flag2) #define inkForceDataPresent (flag3) #define inkRotationDataPresent (flag4) #define inkHeightDataPresent (flag5) #define inkButtonDataPresent (flag6) #define inkStrokeLimitsPresent (flag7) #define inkPreMultiplyScale (flag8) /*------------------------------------------------------------------------- ** Reserved: flag9, flag10, flag11, flag12, flag13, flag14, flag15. ** More flags beyond flag15 can be added in a new record type ** in a later revision to this specification. **-------------------------------------------------------------------------*/ typedef struct tag_INK_BUNDLE_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordBundle */ U8 version; /* Value for release 1.0 is 1 */ INK_COMPACTION_TYPE compactionType; INK_BUNDLE_FLAGS flags; /* flags for the whole bundle */ U32 penUnitsPerX; /* pen units per meter (x dir) */ U32 penUnitsPerY; /* pen units per meter (y dir) */ } INK_BUNDLE_RECORD, FAR *P_INK_BUNDLE_RECORD; #define inkPointDefaultVersion (1) #define inkPointDefaultCompactionType (inkStdCompression) #define inkPointDefaultBundleFlags (0) #define inkPointDefaultPenUnitsPerX (1000) #define inkPointDefaultPenUnitsPerY (1000) #define inkRecordBundleSize \ (inkRecordHeaderLength(inkRecordBundle) + U8_SIZE + \ INK_COMPACTION_TYPE_SIZE + INK_BUNDLE_FLAGS_SIZE + \ U32_SIZE + U32_SIZE) /*************************/ /* REFERENCE SECTION 8.0 */ /*************************/ /*------------------------------------------------------------------------- ** A penData record contains the actual pen data for one or more pen strokes. ** The bounds applies to all the strokes contained within this record. ** Multiple strokes are typically grouped into one record to increase the ** efficiency of the compression algorithm, though strokes may be stored ** individually, if desired. ** ** The bounds is the pure mathematical bounds of the raw pen points and does ** not take into account any rendering information such as the pen tip or the ** line width. All points in the INK_PENDATA have been normalized relative ** to the lower bounds in the INK_PENDATA header. ** ** Some applications will prefer to know the bounds of individual strokes. ** This can be accomplished in two ways. ** ** 1) The bounds for a given stroke can be computed when reading the file ** by decompressing an INK_PENDATA_RECORD into its strokes and then ** traversing the points in each stroke to build the bounds for each ** stroke. ** ** 2) An application can decide to store only one stroke per ** INK_PENDATA_RECORD (and thus the bounds of the PENDATA_RECORD is ** already the bounds of one stroke). The sacrifice here is in ** compression efficiency and the need to still support reading files ** written by other applications that might group multiple strokes ** into a single INK_PENDATA_RECORD. ** ** Note: ** In practice, our experience is that unpacking the data in order to compute ** the bounds for each stroke to check for strokes that intrude into a given ** region is not an excessive burden. The checks that would have been done ** on the bounds of each stroke can be done on the builds for each penData ** group, and not all strokes must be checked individually. ** ** The format of the pen data is determined by the settings for ** compactionType and flags in the INK_BUNDLE_RECORD structure, and ** is described later in this file. Two formats are currently defined: ** an uncompacted format and a delta-encoded compacted format, both with ** optional components present or absent depending on the state of the flags ** in the INK_BUNDLE_RECORD. ** **------------------------------------------------------------------------*/ typedef struct tag_INK_PENDATA_RECORD { INK_RECORD_HEADER32 header; /* value is inkRecordPenData */ RECT32 bounds; U8 inkData[1]; /* ink data goes here: definitions */ /* follow later in this file. */ } INK_PENDATA_RECORD, FAR *P_INK_PENDATA_RECORD; #define inkRecordPenDataSize(data_length) \ (inkRecordHeaderLength(inkRecordPenData) + RECT32_SIZE + (data_length)) /*************************/ /* REFERENCE SECTION 9.0 */ /*************************/ /*------------------------------------------------------------------------- ** Ink scale is recorded in two fixed point values. A unity scale (scale ** of one) is represented as 0x00010000, a scale of 0.5 as 0x00008000. ** ** Note: ** All ink is located relative to the lower-left (0,0) corner of a logical ** page or window. Scale and offset operations are cumulative, much in the ** same way as in PostScript. One begins with a normalized graphics state ** and sequentially applies the scale and offset operations to that matrix. ** The INK_SCALE_RESET record returns the graphics state to its default state ** (i.e., the transformation matrix is set to an identity matrix and the ** offset is reset to the default of 0). By default, scaling is applied ** after adding in any offset specified in an INK_OFFSET_RECORD. If the ink ** bundle has the inkPreMultiplyScale bit set, for all ink in that bundle ** scaling is applied before adding in any offset. ** ** As used in this format, ink scale and offset values are set by the storing ** application, to be applied by the rendering application. If the storing ** application collected the ink at scales of (2.0,2.0), the storing ** application should insert an INK_SCALE_RECORD with a scale of (0.5,0.5) ** for the rendering application to multiply all ink X and Y coordinates by. ** ** It is the responsibility of the storing application to deal with any ** effects from round-off or truncation error due to the limits of precision ** in the FIXED_FRACTION values used in INK_SCALE_RECORDs. ** ** An ink scale record indicates a scale change that stays in effect until ** another ink scale record is encountered. Ink scale values compound: if ** the current scale is (2.0,2.0) and an INK_SCALE_RECORD is encountered with ** scale of (2.0,3.0), the scale to be applied to ink then becomes(4.0,6.0). ** In absence of any ink scale record, the default ink scale is unity. In ** general, a typical usage pattern for an application that supports drawing ** ink while zoomed at scale is to record a number of strokes at a given ** scale, reset the scale with an INK_SCALE_RESET_RECORD (which resets both ** the scale and the offset to the default values), then switch to another ** scale, then record a number more strokes, and so on. ** ** Note: ** The extension scaling and offset to the Z ordinate value is not defined in ** this version of the specification. The extension to Z scaling and offset ** in a "standard" record type (i.e. not an application-specific record) may ** be addressed in the future. ** **------------------------------------------------------------------------*/ typedef struct tag_INK_SCALE { FIXED_FRACTION x; /* scale in the x direction */ FIXED_FRACTION y; /* scale in the y direction */ } INK_SCALE, FAR *P_INK_SCALE; #define INK_SCALE_SIZE (FIXED_FRACTION_SIZE+FIXED_FRACTION_SIZE) #define inkPointDefaultScale (INK_UNITY_SCALE) /* Unity. */ typedef struct tag_INK_SCALE_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordScale */ INK_SCALE scale; } INK_SCALE_RECORD, FAR *P_INK_SCALE_RECORD; #define inkRecordScaleSize \ (inkRecordHeaderLength(inkRecordScale) + \ FIXED_FRACTION_SIZE + FIXED_FRACTION_SIZE) /**************************/ /* REFERENCE SECTION 10.0 */ /**************************/ /*------------------------------------------------------------------------- ** The offset position is used to relocate ink data, after scaling. For ** example, in a forms application, ink in a sketch field is drawn relative ** to a given sketch field in the form. The location of this original field ** is important to know so we know how the ink in this bundle relates to its ** original field. If we wanted to move this ink to another field (i.e. ** cut/paste or move), we would need to know the location of the original ** field so we could render the ink in the new field in a manner consistent ** with how it was drawn relative to its original field (i.e. a similar ** baseline for a hand-written signature). ** ** This record is optional. If it exists, it will then apply to all ** following pen data in the file. If it is not present it is assumed that ** no information of this type is relevant. For example, while field ink ** would have an offset position, markup ink over an entire form would not ** have a offset position (or would have an offset position of (0,0) and a ** scale of (1,1)) because it is relative to the entire form coordinate ** system, not relative to some piece in the form. ** ** Note: ** This approach allows a reader to "blindly" apply the scale and offset ** values specified to ink data, and puts the burden for computing ** compounding of multiple zoom levels, etc., on the writing application. ** **------------------------------------------------------------------------*/ typedef struct tag_INK_OFFSET_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordOffset */ XY32 positionOffset; /* values are in pen units */ } INK_OFFSET_RECORD, FAR *P_INK_OFFSET_RECORD; #define inkRecordOffsetSize \ (inkRecordHeaderLength(inkRecordOffset) + XY32_SIZE) #define inkPointDefaultOffset ((S32) 0) /* No offset. */ typedef struct tag_INK_SCALE_RESET_RECORD { INK_RECORD_HEADER0 header; /* value is inkRecordScaleReset */ } INK_SCALE_RESET_RECORD, FAR *P_INK_SCALE_RESET_RECORD; #define inkRecordScaleResetSize (inkRecordHeaderLength(inkRecordScaleReset)) /**************************/ /* REFERENCE SECTION 11.0 */ /**************************/ /*------------------------------------------------------------------------- ** Ink color is represented as an rgb value, plus opacity. ** ** The default color is black (r,g,b,o) = (0,0,0,255). A color change ** present in the file remains in effect until another color change. ** Typically, the color will stay the same for many ink strokes and thus ** a color record will only be used occasionally when the color changes. ** ** "Opacity" is rather vaguely understood, especially in color environments. ** In this context, opacity means the degree to which the display underneath ** the ink shows through. An opacity value of 255 means that nothing under ** the ink shows through; 0 means that everything shows through (the ink ** is transparent). It is up to the reading application to define the ** implementation of opacity on the reading platform. ** ** The color/opacity value of (255,255,255,0), or "transparent white" is ** defined as an "erase" color. In inking applications that support a true ** "erase" function, such as the ability to erase annotation ink on an ** "original" document (perhaps a FAX image) the "erase" color restores the ** background image where painted. The "background image" is defined by the ** rendering application. ** ** Applications which do not support a true "erase" function may interpret ** this as some other drawing function, such as drawing the "background" ** color. ** **------------------------------------------------------------------------*/ typedef union { U32 all; struct { U8 red, green, blue, opacity; /* opaqueness: see defines below */ } rgb; } INK_COLOR, FAR *P_INK_COLOR; #define INK_COLOR_SIZE (U32_SIZE) typedef struct tag_INK_COLOR_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordColor */ INK_COLOR color; } INK_COLOR_RECORD, FAR *P_INK_COLOR_RECORD; #define inkRecordColorSize \ (inkRecordHeaderLength(inkRecordColor) + U32_SIZE) /*------------------------------------------------------------------------- ** Standardized opacity values: ** A recommended practice is that an opacity value of 128 (midway between ** 0 and 255) be used for "highlighter" colors. A recommended practice is ** that grey values as defined below be used for "standard grey" ** highlighters. **-------------------------------------------------------------------------*/ #define inkOpacityTransparent 0x00 #define inkOpacityHighlight 0x80 #define inkOpacityOpaque 0xFF /* Standard solid colors: */ #define inkColorErase {0xFF,0xFF,0xFF,0x00} #define inkColorWhite {0xFF,0xFF,0xFF,0xFF} #define inkColorLtGrey {0x80,0x80,0x80,0xFF} #define inkColorDkGrey {0x40,0x40,0x40,0xFF} #define inkColorBlack {0x00,0x00,0x00,0xFF} /* Standard highlighter (transparent) colors: */ #define inkColorLtGreyHighlight {0x80,0x80,0x80,0x80} #define inkColorDkGreyHighlight {0x40,0x40,0x40,0x80} #define inkDefaultColor ((INK_COLOR) inkColorBlack) /**************************/ /* REFERENCE SECTION 12.0 */ /**************************/ /*------------------------------------------------------------------------- ** Time is measured in milliseconds. ** ** Note: ** Because of the difficulty synchronizing clocks on different machines ** at the time granularity of digitizing tablets, and because the "editing" ** of ink at a later time makes the definition of the absolute time for each ** ink point ambiguous, the base for the time is arbitrary. All times in ** strokes are just relative to each other with no absolute time ** relationship. ** ** These records, when encountered in the file, apply to the next stroke data ** in the file (so this record comes before the penData that it applies to). ** End time records are not required. The interpretation of an end time ** which is in conflict with the end time inferred from the assumed data rate ** of points and the number of points (including elided points) is not ** defined. ** ** Start time is the time for the first point in the following penData record ** and end time is the time of the last point in the following penData ** record, because if you are recording tip force, the exact definition of ** pen up and pen down may be fuzzy and/or application dependent. ** **------------------------------------------------------------------------*/ typedef U32 INK_TIME, FAR *P_INK_TIME; /* milliseconds */ #define INK_TIME_SIZE U32_SIZE #define inkDefaultTime ((INK_TIME) 0) typedef struct tag_INK_START_TIME_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordStartTime */ INK_TIME startTime; } INK_START_TIME_RECORD, FAR *P_INK_START_TIME_RECORD; #define inkRecordStartTimeSize \ (inkRecordHeaderLength(inkRecordStartTime) + INK_TIME_SIZE) typedef struct tag_INK_END_TIME_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordEndTime */ INK_TIME endTime; } INK_END_TIME_RECORD, FAR *P_INK_END_TIME_RECORD; #define inkRecordEndTimeSize \ (inkRecordHeaderLength(inkRecordEndTime) + INK_TIME_SIZE) /**************************/ /* REFERENCE SECTION 13.0 */ /**************************/ /*------------------------------------------------------------------------- ** INK_PENDATA_RECORDs can be grouped. If they are grouped, each ** INK_PENDATA_RECORD can be assigned a group number. All ** INK_PENDATA_RECORDs with the same group number belong to the same group. ** ** The exact interpretation of grouping is up the applications involved. ** Writing applications may group ink data, but not all reading applications ** that read the data may interpret grouping in the same way. ** ** For example, grouping could be used in the traditional fashion as in ** drawing programs so the user moves or copies an entire group of ** INK_PENDATA_RECORDs together. A group could also be used to signify a ** series of INK_PENDATA_RECORDs entered by the user all within some criteria ** (i.e. all during one proximity session or all within some time frame). ** ** Group numbers are simply signed 16 bit values and can be anything. They ** do not need to be contiguous (i.e. they do not need to be 0,1,2). They ** can be 12,49,-12345 if that is useful. ** ** This record can also be used as a simple marker for starting a new group ** when the groupId is not really used: Group numbers of 0,0,0,0 ... are ** thus permitted. ** ** INK_GROUPs are nestable. Group 0 is reserved as the end-of-group marker ** for disjoint groups. If no end-of-group marker is encountered before the ** end of the file or the end of all ink data (as indicated by an ** INK_END_RECORD), all current (and possibly nested) groups are terminated ** as if end-of-groups markers for them had been encountered. ** **------------------------------------------------------------------------*/ typedef S32 INK_GROUP, FAR *P_INK_GROUP; #define INK_GROUP_SIZE S32_SIZE typedef struct tag_INK_GROUP_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordGroup */ INK_GROUP groupId; /* application-specific interpretation */ } INK_GROUP_RECORD, FAR *P_INK_GROUP_RECORD; #define inkDefaultGroup ((INK_GROUP) 0) #define inkRecordGroupSize \ (inkRecordHeaderLength(inkRecordGroup) + INK_GROUP_SIZE) /**************************/ /* REFERENCE SECTION 14.0 */ /**************************/ /*------------------------------------------------------------------------- ** Some applications may support the idea of rendering ink as if it were ** drawn by a certain shaped pen tip. The most common pen tips would be ** round or rectangular. The exact details of how to render a given pen ** tip will be application specific, but this record states what pen tip ** parameters were used by the storing app. ** ** Pen tips determine, in part, how ink is rendered. For pen tip types ** defined in future versions of this format which require additional ** parameters (such as the X and Y rectangle for a simulated nib pen, or ** brush dimensions for a simulated brush), additional data is included ** at the end of the structure. ** ** The writing application should be aware that the reading application will ** only do "the best possible" job of rendering and that fully compliant ** reading applications may not be able to render certain nib types and/or ** colors. Both reading and writing applications should pay particular ** attention to the following notes regarding defaults and ink drawn at a ** width of zero. ** ** A pen tip which is drawing ink in zero width renders at the minimum ** visible width the reading application will support. ** ** A recommended practice is that ink which should not render (should this ** be called for) be drawn with a color value of (0,0,0, 0), i.e., black, ** completely transparent. ** ** Pen tip size should scale when an INK_SCALE_RECORD is encountered. The ** writing application should write a new INK_PENTIP_RECORD after an ** INK_SCALE_RECORD if the writing application does not want the pen tip ** size to scale along with the ink. If the pen tip scales to zero width, ** it should be rendered by the reading application according to the comment ** above. ** ** The default pen tip if no pentip record exists is INK_PENTIP_ROUND, with a ** width of one twip. The dimensions of a round nib specify diameter, not ** radius: the X/Y coordinate is the center of this diameter. Similarly, for ** for rectangular nibs, the X/Y coordinate is the center of the rectangle. ** ** Note: ** This specification does not specify information for an algorithmic ** variation in nib width, ink color, or other "brush" effects as a function ** of tip force, speed or any other factor. An example would be for an ** application to draw wider ink as the user presses down harder with the ** stylus. Applications wishing to implement such features may do so using ** application-specific record types for this revision of the specification. ** **------------------------------------------------------------------------*/ typedef S16 INK_PENTIP, FAR *P_INK_PENTIP; #define INK_PENTIP_SIZE S16_SIZE #define INK_PENTIP_ROUND (0) /* Diameter in twips */ #define INK_PENTIP_RECTANGLE (1) /* Dimensions in twips */ #define INK_PENTIP_SLANT_RECTANGLE (2) #define INK_PENTIP_ROUND_FLAT_END (3) /* ... more to be filled in here if needed */ #define inkDefaultPentip INK_PENTIP_ROUND #define inkDefaultPentipData ((U16) 1) typedef struct tag_INK_PENTIP_SLANT { SIZE16 rectangle_size; /* INK_PENTIP_SLANTRECTANGLE */ U16 angle; /* Whole degrees from vertical, counter-clockwise */ } INK_PENTIP_SLANT, FAR *P_INK_PENTIP_SLANT; typedef union { U16 round_width; /* INK_PENTIP_ROUND */ SIZE16 rectangle_size; /* INK_PENTIP_RECTANGLE */ INK_PENTIP_SLANT slant; /* INK_PENTIP_SLANT_RECTANGLE */ U16 round_flat_width; /* INK_PENTIP_ROUND_FLAT_END */ } INK_PENTIP_DATA, FAR *P_INK_PENTIP_DATA; /* Size of the union is determined by INK_PENTIP_SLANT */ #define INK_PENTIP_DATA_SIZE (SIZE16_SIZE+U16_SIZE) typedef struct tag_INK_PENTIP_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordTip */ INK_PENTIP tip; INK_PENTIP_DATA tip_data; } INK_PENTIP_RECORD, FAR *P_INK_PENTIP_RECORD; #define inkRecordTipSize \ (inkRecordHeaderLength(inkRecordTip) + INK_PENTIP_SIZE + \ SIZE16_SIZE + U16_SIZE) /**************************/ /* REFERENCE SECTION 15.0 */ /**************************/ /*------------------------------------------------------------------------- ** For some applications, it will be important to know the sampling rate of ** the pen digitizer. ** ** This record would likely be present once in a bundle and would typically ** be after the INK_BUNDLE_RECORD, but before the first pen data. ** ** Note: ** Writing applications are not required to report the "true" sampling rate ** of the digitizer, nor are rendering applications required to play back the ** ink at the specified rate. It is likely that most types of rendering ** applications will render ink as rapidly as possible to construct a display ** in minimum time, and that some types of animation applications will ** intentionally set an arbitrary sampling rate to vary the display rate. ** ** Note: ** For hardware which supports a highly variable sampling rate, the writing ** application can simulate a very high sampling rate (say, 1000 points/ ** second), and use skip records for "elided" points to achieve an exact time ** value (at 1-millisecond resolution) for each point. ** ** A default value for sampling rate has been arbitrarily defined below. ** **------------------------------------------------------------------------*/ typedef struct tag_INK_POINTS_PER_SECOND_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordPointsPerSecond */ U16 pointsPerSecond; } INK_POINTS_PER_SECOND_RECORD, FAR *P_INK_POINTS_PER_SECOND_RECORD; #define inkPointDefaultPointsPerSecond (100) #define inkRecordPointsPerSecondSize \ (inkRecordHeaderLength(inkRecordPointsPerSecond) + U16_SIZE) /**************************/ /* REFERENCE SECTION 16.0 */ /**************************/ /*------------------------------------------------------------------------- ** Units for Z height of stylus above the tablet. ** ** This record would only be present once in a bundle and would typically be ** after the INK_BUNDLE_RECORD, but before the first pen data. ** **------------------------------------------------------------------------*/ typedef struct tag_INK_UNITS_PER_Z_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordUnitsPerZ */ U32 unitsPerZ; /* pen units per meter (Z height) */ } INK_UNITS_PER_Z_RECORD, FAR *P_INK_UNITS_PER_Z_RECORD; #define inkPointDefaultUnitsPerZ (10000) /* 0.1 mm units */ #define inkRecordUnitsPerZSize \ (inkRecordHeaderLength(inkRecordUnitsPerZ) + U32_SIZE) /**************************/ /* REFERENCE SECTION 17.0 */ /**************************/ /*------------------------------------------------------------------------- ** Units for stylus tip force. ** ** This record would only be present once in a bundle and would typically be ** after the INK_BUNDLE_RECORD, but before the first pen data. ** ** Note: ** This specification assumes some level of accuracy and linearity for tip ** force data, if such data is present. However, since tip force sensors in ** current digitizer tablet and stylus designs may well vary in accuracy and ** linearity from one unit to the next even for hardware of the same design ** and model, and since algorithms for using tip force to determine stroke ** start and end are likely to differ, a recommended practice for writing ** applications that use the tip force value to determine the "touch" points ** in a stroke is to mark those points using the touch bit in the INK_BUTTONS ** structure. ** ** It is also recommended that vendors supporting tip force sensing in their ** hardware linearize their transducers to the greatest extent possible. ** ** Because of the likelihood that tip force transducers may not be accurately ** linearized, negative tip force values, while perhaps somewhat absurd ** are possible and are permitted in this specification. ** **------------------------------------------------------------------------*/ typedef struct tag_INK_UNITS_PER_FORCE_RECORD { INK_RECORD_HEADER8 header; /* value is inkRecordUnitsPerForce */ U32 unitsPerForce; /* tip-force units per k-gram of force*/ } INK_UNITS_PER_FORCE_RECORD, FAR *P_INK_UNITS_PER_FORCE_RECORD; #define inkPointDefaultUnitsPerForce (1000) /* grams of force */ #define inkRecordUnitsPerForceSize \ (inkRecordHeaderLength(inkRecordUnitsPerForce) + U32_SIZE) /**************************/ /* REFERENCE SECTION 18.0 */ /**************************/ /*------------------------------------------------------------------------- ** The INK_APP_RECORD record is a universal record to be used by individual ** applications to put data into the file that is not supported by an ** additional publicly defined record type. The basic idea is that an ** application puts its own unique application signature into the appData ** bytes in the INK_APP_RECORD. This identifies the data as originating with ** a particular application. Then, an application defines a set of ** subRecordTypes that they wish to use. Then, using these subRecordTypes ** they can put a wide variety of information into the file. By examining ** the appData signature and comparing it to theirs, an application can ** decide whether it knows how to interpret the various subRecordtypes. ** **------------------------------------------------------------------------*/ typedef struct tag_INK_APP_RECORD { INK_RECORD_HEADER32 header; /* value is inkRecordApp */ U8 appSignature[8];/* reserved for possible unique */ /* application signature */ U16 subRecordType; /* data here appropriate to the subRecordType and appData signature */ } INK_APP_RECORD, FAR *P_INK_APP_RECORD; #define inkRecordAppSize(data_length) \ (inkRecordHeaderLength(inkRecordApp) + 8 + U16_SIZE + (data_length)) /**************************/ /* REFERENCE SECTION 19.0 */ /**************************/ /*------------------------------------------------------------------------- ** Definition of the inkData components of an INK_PENDATA_RECORD: ** ** Uncompacted point format: ** ------------------------- ** ** This structure immediately follows the rest of the INK_PENDATA_RECORD. ** The structure has several optional components, present or not present as ** indicated by the INK_BUNDLE_FLAGS in the INK_BUNDLE_RECORD. The format is ** a sequence of "point values", each containing all the scalar data for each ** sampled tablet point. ** ** In the uncompacted format, there is a single structure that contains all ** of the state information for each point from the tablet. Components not ** present (as indicated by the INK_BUNDLE_FLAGS) are just that: not present, ** do not exist, do not occupy space. ** ** Compacted point format: ** ----------------------- ** ** In the compacted format, "State values", such as the stylus state of ** touch/no-touch/out-of-prox or the on/off state of the barrel switches, are ** stored in a compacted "INK_BUTTONS" item (represented using reserved ** encodings in the INK_POINT coordinate values) interjected when their state ** changes. The initial state is assumed to be "not touching", "out of ** proximity", all barrel switches "off". It is possible to have both tip ** force data, and explicit starts and ends of strokes: the starts and ends ** of the strokes are then points that were considered to be such by the ** original application storing the data. The INK_BUTTONS record reflects ** the state of the next X/Y point following. ** **------------------------------------------------------------------------*/ /**************************/ /* REFERENCE SECTION 20.0 */ /**************************/ /*------------------------------------------------------------------------- ** "INK_BUTTONS" items may most often be used only to indicate stylus touch ** and out-of-prox state, and perhaps a single barrel button. The format is ** optimized for this case. The format extends to a total of 28 stylus/puck ** buttons. ** **------------------------------------------------------------------------*/ /*------------------------------------------------------------------------- ** The lowest-order bit (flag0) is "0" when the stylus is out of ** proximity, "1" when it is in proximity. ** Second lowest-order bit (flag1) is "1" to indicate the next inkPoints are ** when the stylus is touching (the start of a stroke: tip-switch "on"), ** "0" to indicate that the stylus is not touching (end of a stroke). ** Third bit (flag2) indicates state of first (or only) barrel switch, ** etc. ** 31'st bit (flag30) is normally "0", "1" is indicates there are more ** than 29 barrel/puck buttons with state, and the rest are in the next ** four-byte word. **-------------------------------------------------------------------------*/ typedef U32 INK_BUTTONS, FAR * P_INK_BUTTONS; /*------------------------------------------------------------------------- ** These definitions hold the maximum and minimum values that ** can be used with the S15 and S31 representations described in ** this document: **-------------------------------------------------------------------------*/ #define MAX_S31 ((S32) 0x3FFFFFFF) #define MIN_S31 ((S32) 0xC0000000) #define MAX_S15 ((S16) 0x3FFF) #define MIN_S15 ((S16) 0xC000) #define MAX_S7 ((S16) 0x003F) #define MIN_S7 ((S16) 0xFFC0) #define MAX_S3 ((S16) 0x0003) #define MIN_S3 ((S16) 0xFFFC) /* SignExtend4/8/16/32: Sign-extend an S3, S7, S15, S31 to an S32: */ #define SignExtend4(value) ((S32) \ (((value)&0x00000004l)== 0 ? ((value)&0x00000007l) \ : (((value)&0x00000007l) | 0xFFFFFFF8l))) #define SignExtend8(value) ((S32) \ (((value)&0x00000040l)== 0 ? ((value)&0x0000007Fl) \ : (((value)&0x0000007Fl) | 0xFFFFFF80l))) #define SignExtend16(value) ((S32) \ (((value)&0x00004000l)== 0 ? ((value)&0x00007FFFl) \ : (((value)&0x00007FFFl) | 0xFFFF8000l))) #define SignExtend32(value) ((S32) \ (((value)&0x40000000l)== 0 ? ((value)&0x7FFFFFFFl) \ : (((value)&0x7FFFFFFFl) | 0x80000000l))) /**************************/ /* REFERENCE SECTION 21.0 */ /**************************/ /*------------------------------------------------------------------------- ** INK_POINT data. The INK_POINT structure varies in size depending on ** flags set in the bundle header. The XY32 position is always present, but ** the force, rho, height, angle, and buttons members are only present when ** indicated by the corresponding flag in the bundle header. When optional ** data is present, it is present in the order defined by this structure; ** that is, position, force, height, rho, angle, and finally buttons. ** ** The INK_POINT structure has the following elements: ** ** position - required and always present ** Positions are measured with (0,0) at the lower-left, X increasing to ** the right, Y increasing upwards. Values are actually S31, not S32. ** The high bit in X and Y must be zero. ** force - optional, present if inkForceDataPresent is asserted ** Units are in pen force units, zero is no contact. ** height - optional, present if inkHeightDataPresent is asserted ** Units are in pen unitsPerZ as specified by inkPointDefaultUnitsPerZ or ** by an INK_UNITS_PER_Z_RECORD, whichever is appropriate. Units increase ** as the stylus is taken away from the tablet. Zero means "just in ** contact". Negative values could possibly result from spring action if ** the stylus is pressed hard, or if the tablet is not perfectly accurate. ** rho - optional, present if inkRotationDataPresent is asserted ** Angles are measured in degrees from some nominal orientation of ** "stylus button on top" (somewhat arbitrary). Angles increase with ** clockwise rotation as seen from the rear end of the stylus. ** angle - optional, present if inkAngleDataPresent is asserted ** Angles are measured in pen angle units from the vertical. Theta ** increases in the positive-X direction, phi in the positive-Y. ** buttons - optional, present if inkButtonDataPresent is asserted ** ** When the INK_BUNDLE_RECORD member compactionType is inkStdCompression, ** all data in this structure is compressed according to the methods ** described in reference section 23.0. For more details on how to interpret ** the compressed data stream, see the sample code. The bundle flags which ** indicate whether a particular piece of data is present are used regardless ** of whether the data is compressed or not. Note that when data is written ** in compressed format, it is NOT written in Intel order but rather most ** significant byte first. In compressed form, some of the eight bit delta ** values are reserved for button data and elided (skipped) point counts. ** This has two important ramifications. 1) When expecting a point, ** compacted button data or elided point data may be encountered instead, and ** 2) when the inkButtonDataPresent flag is asserted in the bundle header, ** button data will appear in the place of a point and not in addition to a ** point. If inkButtonDataPresent is not asserted, the reader need not check ** the point data for the special case of button data; however, the point ** data must still be checked to see if it is a count of elided points rather ** than an actual point. ** **------------------------------------------------------------------------*/ typedef struct tag_INK_POINT { XY32 position; /* required x/y point data */ S16 force; /* optional force data */ S16 height; /* optional z height data */ S16 rho; /* optional rotational data */ ANGLE16 angle; /* optional theta and phi data */ INK_BUTTONS buttons; /* optional proximity, contact, button data */ } INK_POINT, FAR *P_INK_POINT; /**************************/ /* REFERENCE SECTION 22.0 */ /**************************/ /*------------------------------------------------------------------------- ** The following default values are assumed before the start of any ** INK_BUNDLE: ** **------------------------------------------------------------------------*/ #define inkPointDefaultXYPosition ((S32) 0) #define inkPointDefaultForce ((S16) 0) #define inkPointDefaultHeight ((S16) 0) #define inkPointDefaultRho ((S16) 0) #define inkPointDefaultAngle ((S16) 0) #define inkPointDefaultButtons ((U32) 0) /**************************/ /* REFERENCE SECTION 23.0 */ /**************************/ /*------------------------------------------------------------------------- ** Compacted point format: ** --------------------- ** ** A recommended practice is always to use the compacted point format, not ** the uncompacted point format. Sample code for reading and writing the ** compacted format is included in an appendix. ** ** This structure also immediately follows the rest of the ** INK_PENDATA_RECORD. ** ** The uncompacted values above are stored in sequential bytes in a more ** compact, delta-oriented format. Deltas are all signed values, a value to ** add to the previous value. The first point in an INK_PENDATA_RECORD is ** always relative to the defined default values for each component of the ** point. ** ** The storing application, as an alternative to eliminating points, can ** specify a "skip" record for elided points. The skipRecord indicates that ** a number of points were skipped, and the reading application is free to ** insert values for the elided points (interpolating where appropriate). ** The intent is to allow for accurate time information to be maintained ** between time stamps for synchronization with recorded voice, press-hold ** gesture recognition, etc. ** ** Compacted data is written most significant byte first so that reading ** applications can read the first byte and determine (from the top two bits) ** how large the encoded delta is. ** ** Note: ** "Reserved encodings" are those encodings that, if real points, would fit ** into the next smaller delta size. 16 bit deltas and 8 bit deltas have ** reserved encodings. The reserved encodings for 16 bit deltas are all 16 ** bit delta pairs where both X and Y are within the inclusive range MIN_S7 ** and MAX_S7. Similarly, the reserved encoding for 8 bit deltas are all 8 ** bit delta pairs where both X and Y are within the inclusive range MIN_S3 ** and MAX_S3. In revision 1.0 of Jot, three of the reserved encodings for 8 ** bit deltas are used for special cases: skip counts (reference section ** 27.0) and button changes (reference section 26.0). ** ** x/y position: ** ------------ ** ** 32-bit absolute X/Y: ** ** Two 32 bit long words: Data is actually two S31s: ** ** |0|0| (30 low-order bits of X) | ** ... Sign bit is taken from first bit of next word. ** ---------------------------------------------------------------- ** |X| (sign bit of X plus 31 bits of Y) | ** ---------------------------------------------------------------- ** ** 16-bit short delta X/Y: ** ** Short words: two 16 bit words: Deltas are actually two S15s: ** Values that would fit into an 8-bit byte delta are reserved. ** ** |0|1| (14 low-order bits of delta-X) | ** ... Sign bit is taken from first bit of next word. ** -------------------------------------------------- ** |X| (sign bit of X plus 15 bits of delta Y | ** -------------------------------------------------- ** ** 8-bit byte delta X/Y: ** ** Bytes: two bytes: Deltas are actually two S7s: ** Values that would fit into a 4-bit nibble delta are reserved. ** ** |1|0| (6 low-order bits of delta-X) | ** ... Sign bit is taken from first bit of next word. ** ------------------------------------------ ** |X| (7 bits of delta-Y) | ** ------------------------------------------ ** ** 4-bit nibble delta X/Y: ** ** Nibbles: one byte: Deltas are actually S3: ** ** |1|1| (S3 delta-X) | (S3 delta-Y) | ** ----------------------------------- ** **------------------------------------------------------------------------*/ /**************************/ /* REFERENCE SECTION 24.0 */ /**************************/ /*------------------------------------------------------------------------- ** Tip force: ** ---------- ** ** 16-bit absolute force: ** ** Short word: one word: Value is actually S15: ** Values that would fit into an 8-bit byte delta are reserved. ** ** |0| (15 bits of force) | ** --------------------------------------------- ** ** 8-bit byte delta force: ** ** Byte: one byte: Deltas are actually S7: ** ** |1| (S7 delta-force) | ** -------------------------- ** ** ** Height: ** ------ ** ** (Same encoding as tip force) ** ** Rho: ** --- ** ** (Same encoding as tip force) ** ** ** Stylus theta-phi: ** ---------------- ** ** 16-bit absolute theta-phi: ** ** Short words: two words: Data is actually S15: ** ** |0|0| (14 low-order bits of theta) | ** ------------------------------------------- ** ... Sign bit is taken from first bit of next word. ** |X| (15 bits of phi) | ** ------------------------------------------- ** **------------------------------------------------------------------------*/ /**************************/ /* REFERENCE SECTION 25.0 */ /**************************/ /*------------------------------------------------------------------------- ** 8-bit byte delta theta-phi ** ** Bytes: two bytes: Deltas are actually S7: ** Values that would fit into a 4-bit nibble delta are reserved. ** ** |0|1| (6 low-order bits of delta-theta)| ** -------------------------------------------- ** ... Sign bit is taken from first bit of next word. ** |X| (7 bits of delta-phi) | ** -------------------------------------------- ** ** 4-bit nibble delta theta-phi ** ** Nibbles: one byte: Deltas are actually S3: ** ** |1|0|(S3 delta-theta)|(S3 delta-phi)| ** ------------------------------------- ** ** Note: ** Leading bit values of |1|1| are reserved ** **------------------------------------------------------------------------*/ /**************************/ /* REFERENCE SECTION 26.0 */ /**************************/ /*------------------------------------------------------------------------- ** Since the X/Y data is always present, we use some of the reserved delta ** encodings to encode button states and elided (skipped) points. We use the ** 8-bit delta encodings that are unused: the values that can fit into the ** smaller 4-bit delta encodings. ** ** Button/tip records: ** ------------------ ** ** It is assumed that the state of barrel buttons and the touching sensor on ** the stylus change infrequently. A compacted button/tip record is only ** included when the state changes in one of the switches. The button state ** value applies to the X/Y point immediately following the button state ** record. ** ** ** (Taken from 8-bit byte delta X/Y: two bytes total) ** ** |1|0| 0|0|0|0|0|0/1| 0|X|.|.|.|.|X|X| ** --------------------------------------- ** (delta-X) (delta-Y) ** ** An eight-bit delta with delta-X == 0 or 1, and delta-Y in the range ** (-4..3) indicates a button state encoding. ** ** It is likely to be the case that many hardware platforms have only one ** barrel button. ** ** The three delta-Y bits indicate the "touch", "out-of-prox", and "first ** barrel button" state as follows: ** ** low-order delta-Y bit: 1 --> in proximity, 0 --> out of prox ** next delta-Y bit: 1 --> touching tablet, 0 --> not touching ** high-order (sign) delta-Y bit: 1 --> first button closed, 0 --> open ** ** ** The lowest order bit of the delta-X bits is used to indicate that ** additional bytes follow: "1" indicates that the next byte is used for the ** next 7 barrel buttons with state. The high order bit of each sequential ** byte in the series is "1" if an additional byte must be fetched, "0" ** otherwise. In these additional bytes, the additional buttons are ** associated in order starting with the low-order bit. ** **------------------------------------------------------------------------*/ /**************************/ /* REFERENCE SECTION 27.0 */ /**************************/ /*------------------------------------------------------------------------- ** Skipped-point records: ** --------------------- ** ** (Taken from 8-bit byte delta X/Y: two bytes total) ** ** ** |1|0| 0|0|0|0|1|0| 0|X|.|.|.|.|X|X| ** ------------------------------------- ** (delta-X) (delta-Y) ** ** An eight-bit delta with delta-X == 2, and delta-Y in the range ** (-4..3) indicates a count of elided points. The delta-Y values in the ** range (-4..-1) are used to represent skip counts of (4..7). If the ** delta-Y value is zero "0", the next two bytes are fetched to get a U16 ** skip count value. ** ** The elided points are points removed between the point immediately prior ** to the skipped-point record and the point immediately afterward. This ** implies that at least one point must follow every skip record (though ** the point may not appear next in the stream if there are intervening ** button state transitions). Reading applications that are interested in ** recovering elided points will typically interpolate. Skip counts of zero ** are meaningless and not permitted. ** ** Reserved: ** -------- ** ** The remaining encodings from the 8-bit byte delta X/Y are reserved: ** ** delta-X of -4, -3, -2, -1, 3 AND ((delta-Y >= -4) & ((delta-Y <= 3)) ** **------------------------------------------------------------------------*/ #endif /* end of INKSTORE_INCLUDED */