Hacking the INK formatof HP databases.

Steve Korson (skorson@asic.sc.ti.com)
Thu, 15 May 1997 11:28:46 -0500 (CDT)

All,

This is for people interested in hacking/developing stuff for the
ogo.

I am posting this to let people who may be interested know what I
have found about the INK formats in the HP databases (specifically
the *.GDB files, but I would bet it works for all of them.) I have
not completed my investigation, but want to share what I have with
others to perhaps speed up the process.

The INK format in the HP databases seems to be identical to that of
the JOTTER.000 INK file from GEOS.

Specifically, the format for GEOS INK is included at the end of this
msg. (Note, this file can be found at the GEOWORKS site in their
documentation section)

I have been able to hack at a USER DEF 17 field in GDB files, which
is where the ink data is stored for that type of database.

I have figured out (I think) that the first two bytes forms an long int
number of XY pairs (points.)

*** What I haven't yet figured out is what must be included after the
last point of data. The INK data is bit aligned, not byte, so at the
end of the database, there is extra data. I tried to make a 'picture'
by packing some data back into the GDB. I just set the last few bits and
the very last byte to '0', yet I couldn't read the GDB when restored
back to the omnigo. I also tried to set the last few bits to the
1000000 end string. Still didn't work.

I have checked various simple INK pictures, yet still can't figure out
how to end them. I have had no problem parsing them, if I just ignore
the last data after I have calculated all the necessary points.
If someone has time to hack at this, I wouldn't complain about any help.
[grin]

Regards,
Steve
"My opinions are my own, not necessarily those of my employer."

========================================================================================
Here is an example:

========================================================================================
Record Type: 17 Status: 2 Length: 20 Number: 0
Type: USER DEF 17

Hex content:
08 00 b0 00 36 00 1f c9 a1 00 82 0e 90

Binary Stream: (+'s indicated valid info segments.)

+00001000 00000000 +10110000 0000000 001+10110 00000000 000111+
| # Int: XY paris | X= 1 | Y= 7 |
| 8 pairs | pair1 |
| | (1,7) |

11 + 11+00 +100.1. 101+00 +00 +1 000.000+00 +100.0.001+0 0+00 +01 +11 +0 1+00 +10000
|X-1|Y-1|Xnc|Y-6 |Xnc|Ync| End |Xnc| Y + 2 |Xnc|Ync|X+1|Y-1|X+1|Ync| End**
| pair2 | pair3 | pair4 | | pair5 | pair6 | pair7 | pair8 |
| (0,6) | (0,0) | (0,0) | | (0,2) | (0,2) | (1,1) | (2,1) |

*nc = No Change
** Even though the end has the start of the 1000000 termination pattern,
not every database I have looked at has it. Some have other 1's strewn about,
even though the correct number of pairs have alredy been defined.

Picture of what is drawn:

012
0|*
1|***
2|*
3|*
4|*
5|*
6|*
7| *
8|

========================================================================================

Ink Format
==========
Ink on the Clipboard is stored as a DBGroupAndItem. CIFI_vmChain
(which is the same as CRA_data) contains the DBGroupAndItem for the
ink item. (Thus you can do
myPtr = DBLock(cra->CRA_file,
DBGroupFromDBGroupAndItem(cra->CRA_data),
DBItemFromDBGroupAndItem(cra->CRA_data));
to get a pointer to the ink data.)

The item of ink is stored in compressed format. For which the format is:
XYSize (dword) - size of the area clipped by user
PointBlockHeader (word) - number of points in the ink
compacted data (as bits)

//You might want to consider using InkDecompress() to convert the ink to
//an easier to use format. (more on this later)

Here's the format of the compacted data:

When compacting:
Output X delta first, then Y delta. The first X and Y values
you output must be an absolute 15-bit position.

if (delta == 0)
Output (00)
else if (delta == 1)
Output (01)
else if (delta == -1)
Output (11)
else if (delta >= -8 && delta < -1) /* Output 3-bit negative delta */
Output (1001000 | (ABS(delta) - 1))
else if (delta <= 8 && delta > 1) /* Output 3-bit positive delta */
Output (1000000 | (delta - 1))
else /* Output 15-bit absolute position) */
Output (1011 0000 0000 0000 000 | delta);

At the end of each segment, output (1000000) (note, this is 7 bits,
not 8).

When uncompacting:

If you encounter: it means:

00 a delta of zero
01 a delta of 1
11 a delta of -1

100 0 000 Terminate the current segment

100 0 xxx the xxx bits are a positive
(delta - 1). e.g.:
100 0001 = 2
100 0010 = 3
100 0011 = 4
100 0100 = 5
100 0101 = 6
100 0110 = 7
100 0111 = 8

100 1 000 reserved for future use

100 1 xxx the xxx bits are a negative
(delta - 1). e.g.:
100 1001 = -2
100 1010 = -3
100 1011 = -4
100 1100 = -5
100 1101 = -6
100 1110 = -7
100 1111 = -8

101 0 xxxxxx the x bits are a reserved
keyword - not currently used

101 1 xxxx xxxx xxxx xxx the x bits are an absolute
position, not a delta

You will always encounter a 1011 token (an absolute position) before
encountering any deltas.

Here is an example of the compressed ink data for the number '4'.
And to ellucidate, here is a picture of what the 4 looks like (note
the two coordinates are given to help orient you).

*--(3,0)
(0,1)--* *
*****
*
*

First line drawn is the "side-ways L" part. it goes down from 0,1 and
cuts right to 4,2.
Second line is the main vertical. it starts at 3,0 and goes down to
3,4.

Thus the data in the clipboard is:
XYSize = 6,6 (6x6 is just an arbitrary number)
numPoints = 5 (there are 5 coordinate points)
data = 101 1 0000 0000 0000 000 (initial X)
101 1 0000 0000 0000 001 (initial Y)
00 (X no delta)
01 (Y delta 1)
100 0011 (X delta 4)
00 (Y no delta)
100 0000 (end of first segment)

101 1 0000 0000 0000 011 (initial X)
101 1 0000 0000 0000 000 (initial Y)
00 (X no delta)
100 0011 (Y delta 4)
100 0000 (end of second segment)

*******InkDecompress doesn't seem to work. I'll check into it.*******

As stated earlier, another option for you is to use InkDecompress on
the clipboard data to convert it to more easily managed data. That
data is stored as from-to InkPoint structures. InkPoint is basically
unsigned x,y coordinates with the addition that the high bit of the x
coordinate is set to signify the end of a stroke
(IXC_TERMINATE_STROKE). So for the above example, InkDecompress would
produce:

numPoint = 5
(0,1)
(0,2)
(0x84,2) ; (4,2) + end of stroke
(3,0)
(0x83,4)

========================================================================================