Previous: Step-by-Step Examples  Up: Manual Home  Next: AJR Format

# JDR Binary Format

Jpgfdraw's native JDR file format is a binary format written in the big-endian fashion. Since all Java™ binary data files are platform independent, there should be no problems transferring the files between processorsA.1. Integers are stored as 32-bit integers, single precision numbers are stored as 32-bit floats, double precision numbers are stored as 64-bit doubles and characters are stored as 16-bit Unicode characters. (For more details see [2, Chapter 12] or http://java.sun.com/j2se/1.5.0/docs/api/java/io/DataInput.html)

The current JDR file format version is 1.6.

If you use the uk.ac.uea.cmp.nlct.jdr package, you can load and save a JDR file using the JDR.load() and JDR.save() methods, otherwise the JDR file format is as follows:

1. To read a data stream in Java™ (where filename is a string containing the file name):
DataInputStream din =
new DataInputStream(new FileInputStream(filename));

or to write a data stream:
DataOutputStream dout =
new DataOutputStream(new FileOutputStream(filename));


2. At the start of the file, there must be the three characters JDR stored as 16-bit Unicode characters. To write:
dout.writeChars("JDR");

char[] str = new char[3];
for (int i = 0; i < 3; i++) str[i] = din.readChar();
if (!(new String(str)).equals("JDR"))
{
// not a JDR file error code
}


3. The JDR file format version comes next. This may be 1.0, 1.1, 1.2, 1.3, 1.4, 1.5 or 1.6. The file version number is stored as a string not a number. First the length of the string (fileVersion) is stored, then follows the string itself. To write:
dout.writeInt(fileVersion.length())
dout.writeChars(fileVersion)

int n = din.readInt();
char[] version = new char[n];
for (int i = 0; i < n; i++) version[i] = din.readChar();


4. Next is a value indicating whether or not the Jpgfdraw settings are stored.
JDR1.3 onwards
In version 1.3 onwards, this value is a byte, and may take one of three values: 0 (no settings), 1 (all settings) or 2 (paper size only). To omit the settings information:
dout.writeByte((byte)0);

To save all the settings:
dout.writeByte((byte)1);
// code to save the settings (see below)
To save only the paper size:
dout.writeByte((byte)2);
// code to save the paper size (see below)
{
case 0:
// do nothing
break;
case 1:
break;
case 2:
// read paper size (see below)
break;
default
// throw exception
}
JDR1.3 onwards
JDR1.0-1.2
In versions prior to 1.3, this value is a boolean value. To save the settings:
dout.writeBoolean(true);
// code to save the settings (see below)
To omit the settings information:
dout.writeBoolean(false);

{
}
JDR1.0-1.2

5. The settings information is stored as follows:
a
A boolean variable (grid) indicating whether or not to display the grid. To write:
dout.writeBoolean(grid);

boolean grid = din.readBoolean();


b
A boolean variable (gridLock) indicating whether or not to lock the grid. To write:
dout.writeBoolean(gridLock);

boolean gridLock = din.readBoolean();


c
A boolean variable (showRulers) indicating whether or not to show the rulers. To write:
dout.writeBoolean(showRulers);

boolean showRulers = din.readBoolean();


d
A 32-bit integer indicating which tool to select. This must be an integer between 0 and 7 (inclusive). Table A.1 indicates the integer ID for each tool. To write (where tool is an integer):
dout.writeInt(tool);

int tool = din.readInt();
if (tool < 0 || tool > 7)
{
// insert invalid tool id error
}


Table A.1: Tool Identifiers
ID Tool
0 Select
1 Open Line Path
2 Closed Line Path
3 Open Curve Path
4 Closed Curve Path
5 Rectangle
6 Ellipse
7 Text

e
A 32-bit integer indicating the normal font size. (This is used as the default in the font settings dialog box, and as the normal size font for the LaTeX font size conversions.) To write:
dout.writeInt(normalSize);

int normalSize = din.readInt();


f
The paper size (see below).

g
The grid style:

JDR1.0-1.5
1. An 8-bit byte representing the unit used for the rulers and grid. This should be one of: 0 (TeX pt), 1 (inches), 2 (centimetres) or 3 (PostScript points). To write:
dout.writeByte(unitType);

byte unitType = din.readByte();


2. Two 32-bit integers representing the major grid divisions and the subdivisions, respectively. To write:
dout.writeInt(majorDivisions);
dout.writeInt(subdivisions);

int majorDivisions = din.readInt();

JDR1.0-1.5
JDR1.6 onwards
An 8-bit byte representing the grid style ID. This may be:
0
A rectangular grid. This is then followed by:
1. An 8-bit byte representing the unit ID (as above).

2. A 64-bit double representing the major grid division.

3. A 32-bit integer representing the grid subdivision.
1
A radial grid. This is then followed by:
1. An 8-bit byte representing the unit ID (as above).

2. A 64-bit double representing the major grid division.

3. A 32-bit integer representing the grid subdivision.

4. A 32-bit integer representing the number of spokes.
JDR1.6 onwards

6. The paper size is specified as an 8-bit byte. For versions before 1.3, this must be an integer in the range 0 to 18 (inclusive), otherwise it must be in the range 0 to 72 (inclusive). Table A.2 indicates the integer ID for each paper size, and Table A.3 shows additional values for version 1.3. If the paper size has an ID of 18 (user defined), then there must follow the paper width (64-bit double in points), height (64-bit double in points). For versions prior to 1.3, the user defined setting must also be followed by a boolean variable to indicate whether or not the orientation is portrait (true) or landscape (false).
JDR1.0-1.2
To write:
dout.writeByte(paperSize);
if (paperSize == 18) // user defined paper size
{
dout.writeDouble(paperWidth);
dout.writeDouble(paperHeight);
dout.writeBoolean(isPortrait);
}

byte paperSize = din.readByte();
if (paperSize < 0 || paperSize > 18)
{
// insert invalid paper size id code
}
else if (paperSize == 18) // user defined paper size
{
}

JDR1.0-1.2
JDR1.3 onwards
To write:
dout.writeByte(paperSize);
if (paperSize == 18) // user defined paper size
{
dout.writeDouble(paperWidth);
dout.writeDouble(paperHeight);
}

byte paperSize = din.readByte();
if (paperSize < 0 || paperSize > 72)
{
// insert invalid paper size id code
}
else if (paperSize == 18) // user defined paper size
{
}

JDR1.3 onwards

Table A.2: Paper Size Identifiers
ID Paper Size ID Paper Size
0 A0 (portrait) 9 A0 (landscape)
1 A1 (portrait) 10 A1 (landscape)
2 A2 (portrait) 11 A2 (landscape)
3 A3 (portrait) 12 A3 (landscape)
4 A4 (portrait) 13 A4 (landscape)
5 A5 (portrait) 14 A5 (landscape)
6 letter (portrait) 15 letter (landscape)
7 legal (portrait) 16 legal (landscape)
8 executive (portrait) 17 executive (landscape)
18 user defined

Table A.3: Additional Paper Size Identifiers (JDR v1.3 onwards)
ID Paper Size ID Paper Size
19 A6 (portrait) 46 A6 (landscape)
20 A7 (portrait) 47 A7 (landscape)
21 A8 (portrait) 48 A8 (landscape)
22 A9 (portrait) 49 A9 (landscape)
23 A10 (portrait) 50 A10 (landscape)
24 B0 (portrait) 51 B0 (landscape)
25 B1 (portrait) 52 B1 (landscape)
26 B2 (portrait) 53 B2 (landscape)
27 B3 (portrait) 54 B3 (landscape)
28 B4 (portrait) 55 B4 (landscape)
29 B5 (portrait) 56 B5 (landscape)
30 B6 (portrait) 57 B6 (landscape)
31 B7 (portrait) 58 B7 (landscape)
32 B8 (portrait) 59 B8 (landscape)
33 B9 (portrait) 60 B9 (landscape)
34 B10 (portrait) 61 B10 (landscape)
35 C0 (portrait) 62 C0 (landscape)
36 C1 (portrait) 63 C1 (landscape)
37 C2 (portrait) 64 C2 (landscape)
38 C3 (portrait) 65 C3 (landscape)
39 C4 (portrait) 66 C4 (landscape)
40 C5 (portrait) 67 C5 (landscape)
41 C6 (portrait) 68 C6 (landscape)
42 C7 (portrait) 69 C7 (landscape)
43 C8 (portrait) 70 C8 (landscape)
44 C9 (portrait) 71 C9 (landscape)
45 C10 (portrait) 72 C10 (landscape)

7. The objects that constitute the picture are now stored. When saving to a file, an outer grouping is implied that is not evident whilst using Jpgfdraw. This means that there should always be a single group structure saved to file which contains all the objects that constitute the picture. Each object is then recursively stored. For example, if a picture contains a path, a group and a text area, in the JDR file these three objects will be stored as a single group structure containing the three objects. If in Jpgfdraw you explicitly group all the objects, then in the JDR file, the outermost implicit group will contain only one object which will be this group.

Each object has the following format:

JDR1.0 & 1.1
<id-char><object-specs><fflag>[<flowframe-specs>]
JDR1.0 & 1.1
JDR1.2 onwards
<id-char><object-specs><fflag>[<flowframe-specs>]<description-specs>
JDR1.2 onwards
where <id-char> is a character determining the object type:
JDR1.0-1.4
JDR1.0-1.4
JDR1.5
JDR1.5
JDR1.5
JDR1.5

The object specifications <object-specs> vary according to the object type and are described below. <fflag> is a boolean variable indicating whether or not this object has flowframe data associated with it. If true, then the flowframe specifications <flowframe-specs> should follow (see below), otherwise <flowframe-specs> should be omitted. Note that JDR version 1.2 and above contains <description-specs>, which was omitted in earlier versions. To write:

if (/* test to see if object is a group */)
{
dout.writeChar('G');
// save group specification (see below)
}
else if (/* test to see if object is a path */)
{
dout.writeChar('P');
// save path specification (see below)
}
else if (/* test to see if object is a text area */)
{
dout.writeChar('T');
// save text area specification (see below)
}
else if (/* test to see if object is a bitmap */)
{
dout.writeChar('I');
// save bitmap specification (see below)
}
else if (/* test if object is text-path and version > 1.4 */)
{
dout.writeChar('X');
// save text-path specification (see below)
}
else if (/* test if object is rotational-pattern and version > 1.5 */)
{
dout.writeChar('R');
// save rotational-pattern specification (see below)
}
else if (/* test if object is scaled-pattern and version > 1.5 */)
{
dout.writeChar('C');
// save scaled-pattern specification (see below)
}
else if (/* test if object is spiral-pattern and version > 1.5 */)
{
dout.writeChar('L');
// save spiral-pattern specification (see below)
}

// boolean fflag indicates object has flow frame data
dout.writeBoolean(fflag);
if (fflag)
{
// save flow frame data (see below)
}

// if version 1.2 or above save description (see below)

if (c == 'G')
{
// read group data (see below)
}
else if (c == 'P')
{
// read path data (see below)
}
else if (c == 'T')
{
// read text area data (see below)
}
else if (c == 'I')
{
// read bitmap data (see below)
}
else if (c == 'X')
{
// read text-path data (see below)
}
else if (c == 'R')
{
// read rotational-pattern data (see below)
}
else if (c == 'C')
{
// read scaled-pattern data (see below)
}
else if (c == 'L')
{
// read spiral-pattern data (see below)
}
else
{
// insert invalid object id code
}

{
// read flow frame data (see below)
}

// if version 1.2 or above read description (see below)

1. Group data, G, is stored as follows:

<n><object data>+

where <n> is an integer indicating the number of objects within the group, there should then follow <n> lots of <object data>, where <object data> is the data for each object within the group, where the object data is as described above. To write:

// int n is the number of objects in the group
dout.writeInt(n);
for (int i = 0; i < n; i++)
{
// save the ith object in the group (see above)
}

for (int i = 0; i < n; i++)
{
// read in the ith object in the group (see above)
}

2. Path data, P, is stored as follows:

JDR1.0-1.2
<line colour><fill colour><line style>O|C<n><segment data>+
JDR1.0-1.2
JDR1.3 onwards
<line colour><fill colour><line style>O|C<n><start point><segment data>+
JDR1.3 onwards
where <line colour> and <fill colour> contain the line and fill colour data (see below), <line style> is the line style data (see below). The character O or C indicates whether the path is open or closed, <n> is an integer indicating the number of segments that constitute the path. This should be followed by <n> lots of <segment data> (described below). Version 1.3 has removed the redundancy present in earlier versions.
JDR1.0-1.2
To write:
// save line colour data (see below)
// save fill colour data (see below)
// save line style data (see below)
// boolean closed indicates whether or not the path
// is closed
dout.writeChar(closed ? 'C' : 'O');
// int n is the number of segments in the path
dout.writeInt(n);
for (int i = 0; i < n; i++)
{
// save data for segment i (see below)
}
// read line colour data (see below)
// read fill colour data (see below)
// read line style data (see below)
if (c == 'O')
{
// make it an open path
}
else if (c == 'C')
{
// make it a closed path
}
else
{
// insert invalid identifier code
}
for (int i = 0; i < n; i++)
{
// read data for segment i (see below)
}
JDR1.0-1.2
JDR1.3 onwards
JDR v1.3 onwards requires that the starting point <start point> follows the number of segments (<n>). The starting point is stored as two double precision numbers. To write:
// save line colour data (see below)
// save fill colour data (see below)
// save line style data (see below)
// boolean closed indicates whether or not the path
// is closed
dout.writeChar(closed ? 'C' : 'O');
// int n is the number of segments in the path
dout.writeInt(n);
// double x, y is the starting position of the path
dout.writeDouble(x);
dout.writeDouble(y);
for (int i = 0; i < n; i++)
{
// save data for segment i (see below)
}
// read line colour data (see below)
// read fill colour data (see below)
// read line style data (see below)
if (c == 'O')
{
// make it an open path
}
else if (c == 'C')
{
// make it a closed path
}
else
{
// insert invalid identifier code
}
for (int i = 0; i < n; i++)
{
// read data for segment i (see below)
}
JDR1.3 onwards

1. Colour data is stored as follows: <col-id>[<colour-specs>], where <col-id> is a character representing the colour type. Available types are listed in Table A.4. Note that if <col-id> is T (transparent) <colour-specs> is omitted.

Table A.4: Available Colour Types
Type ID Version
Transparent T 1.0 onwards
RGB R 1.0 onwards
CMYK C 1.0 onwards
Grey Y 1.4 onwards
HSB S 1.4 onwards

To write

if (/* test if transparent */)
{
dout.writeChar('T');
}
else if (/* test if single RGB colour */)
{
dout.writeChar('R');
// save single RGB colour data (see below)
}
else if (/* test if single CMYK colour */)
{
dout.writeChar('C');
// save single CMYK colour data (see below)
}
else if (/* test if linear gradient colour */)
{
dout.writeChar('G');
// save linear gradient colour data (see below)
}
else if (/* test if radial and JDR version >= 1.3 */)
{
dout.writeChar('D');
}
else if (/* test if HSB colour and JDR version >= 1.4 */)
{
dout.writeChar('S');
// save HSB colour data (see below)
}
else if (/* test if grey and JDR version >= 1.4 */)
{
dout.writeChar('Y');
// save grey data (see below)
}

if (c == 'T')
{
// set to transparent
}
else if (c == 'R')
{
// read single RGB colour data (see below)
}
else if (c == 'C')
{
// read single CMKY colour data (see below)
}
else if (c == 'G')
{
}
else if (c == 'D' /* and JDR version >= 1.3 */)
{
}
else if (c == 'S' /* and JDR version >= 1.4 */)
{
// read HSB colour data (see below)
}
else if (c == 'Y' /* and JDR version >= 1.4 */)
{
// read grey data (see below)
}
else
{
// insert invalid colour identifier code
}

1. Single RGB colour data is specified as:

<R><G><B><A>

where each element is a 32-bit single precision floating point number between 0 and 1 (inclusive), and <R> represents the red value, <G> represents the green value, <B> represents the blue value, and <A> represents the alpha (transparency) value. To write:
dout.writeFloat(red);
dout.writeFloat(green);
dout.writeFloat(blue);
dout.writeFloat(alpha);

float red   = din.readFloat();
// check lies in range [0,1]
// check lies in range [0,1]
// check lies in range [0,1]
// check lies in range [0,1]


2. Single CMYK colour data is specified as:

<C><M><Y><K><A>

where each element is a 32-bit floating point value between 0 and 1 (inclusive), and <C> represents the cyan value, <M> represents the magenta value, <Y> represents the yellow value, <K> represents the black value, and <A> represents the alpha (transparency) value. To write:
dout.writeFloat(cyan);
dout.writeFloat(magenta);
dout.writeFloat(yellow);
dout.writeFloat(black);
dout.writeFloat(alpha);

float cyan   = din.readFloat();
// check lies in range [0,1]
// check lies in range [0,1]
// check lies in range [0,1]
// check lies in range [0,1]
// check lies in range [0,1]


3. As from version 1.4, HSB colour data is specified as:

<H><S><B><A>

where each element is a 32-bit single precision floating point number and all except <H> lie in the range 0-1 (inclusive). <H> represents the hue value in the range [0,360), <S> represents the saturation value, <B> represents the brightness value, and <A> represents the alpha (transparency) value. To write:
dout.writeFloat(hue);
dout.writeFloat(saturation);
dout.writeFloat(brightness);
dout.writeFloat(alpha);

float hue         = din.readFloat();
// check lies in range [0,360)
// check lies in range [0,1]
// check lies in range [0,1]
// check lies in range [0,1]


4. As from version 1.4, grey data is specified as:

<G><A>

where each element is a 32-bit single precision floating point number between 0 and 1 (inclusive), and <G> represents the grey value, and <A> represents the alpha (transparency) value. To write:
dout.writeFloat(grey);
dout.writeFloat(alpha);

float grey   = din.readFloat();
// check lies in range [0,1]
// check lies in range [0,1]


5. Linear gradient colour data is specified as:

<start-col-id><start-col-specs><end-col-id><end-col-specs><direction>

where <start-col-id> is the colour identifier for the starting colour and <start-col-specs> is the colour specification, and <end-col-id> is the colour identifier for the end colour and <end-col-specs> is the colour specification. The colour identifiers may be any of those listed in Table A.4 except the linear or radial gradient types. The colour specifications are as described above. The gradient direction, <direction>, is a 32-bit integer and may only take one of the following values: 0 (North), 1 (North East), 2 (East), 3 (South East), 4 (South), 5 (South West), 6 (West) and 7 (North West). To write:

if (/* start colour RGB */)
{
dout.writeChar('R');
// save RGB single colour data (see above)
}
else if (/* start colour CMYK */)
{
dout.writeChar('C');
// save CMYK single colour data (see above)
}
else if (/* start colour HSB and version >= 1.4 */)
{
dout.writeChar('S');
// save HSB single colour data (see above)
}
else if (/* start colour grey and version >= 1.4 */)
{
dout.writeChar('Y');
// save HSB single grey data (see above)
}
else
{
// insert invalid colour type code
}

if (/* end colour RGB */)
{
dout.writeChar('R');
// save RGB single colour data (see above)
}
else if (/* end colour CMYK */)
{
dout.writeChar('C');
// save CMYK single colour data (see above)
}
else if (/* end colour HSB and version >= 1.4 */)
{
dout.writeChar('S');
// save HSB single colour data (see above)
}
else if (/* end colour grey and version >= 1.4 */)
{
dout.writeChar('Y');
// save HSB single grey data (see above)
}
else
{
// insert invalid colour type code
}

dout.writeInt(direction);

if (c == 'R')
{
// read RGB single colour data (see above)
}
else if (c == 'C')
{
// read CMYK single colour data (see above)
}
else if (c == 'S')
{
// read HSB single colour data (see above)
}
else if (c == 'Y')
{
// read grey data (see above)
}
else
{
// insert invalid start colour identifier code
}

if (c == 'R')
{
// read RGB single colour data (see above)
}
else if (c == 'C')
{
// read CMYK single colour data (see above)
}
else if (c == 'S')
{
// read HSB single colour data (see above)
}
else if (c == 'Y')
{
// read grey data (see above)
}
else
{
// insert invalid end colour identifier code
}

// check direction is in range [0,7]

6. Radial gradient colour data is not available for versions prior to JDR v1.3. The radial colour data is specified as:

<start-col-id><start-col-specs><end-col-id><end-col-specs><start location>

where <start-col-id> is the colour identifier for the starting colour and <start-col-specs> is the colour specification, and <end-col-id> is the colour identifier for the end colour and <end-col-specs> is the colour specification. The colour identifiers may be any of those listed in Table A.4 except the linear or radial gradient types. The colour specifications are as described above. The starting location, <start location>, is a 32-bit integer and may only take one of the following values: 0 (North), 1 (North East), 2 (East), 3 (South East), 4 (South), 5 (South West), 6 (West), 7 (North West) and 8 (Centre). To write:

if (/* start colour RGB */)
{
dout.writeChar('R');
// save RGB single colour data (see above)
}
else if (/* start colour CMYK */)
{
dout.writeChar('C');
// save CMYK single colour data (see above)
}
else if (/* start colour HSB and version >= 1.4 */)
{
dout.writeChar('S');
// save HSB single colour data (see above)
}
else if (/* start colour grey and version >= 1.4 */)
{
dout.writeChar('Y');
// save HSB single grey data (see above)
}
else
{
// insert invalid colour type code
}

if (/* end colour RGB */)
{
dout.writeChar('R');
// save RGB single colour data (see above)
}
else if (/* end colour CMYK */)
{
dout.writeChar('C');
// save CMYK single colour data (see above)
}
else if (/* end colour HSB and version >= 1.4 */)
{
dout.writeChar('S');
// save HSB single colour data (see above)
}
else if (/* end colour grey and version >= 1.4 */)
{
dout.writeChar('Y');
// save HSB single grey data (see above)
}
else
{
// insert invalid colour type code
}

dout.writeInt(startLocation);

if (c == 'R')
{
// read RGB single colour data (see above)
}
else if (c == 'C')
{
// read CMYK single colour data (see above)
}
else if (c == 'S')
{
// read HSB single colour data (see above)
}
else if (c == 'Y')
{
// read grey data (see above)
}
else
{
// insert invalid start colour identifier code
}

if (c == 'R')
{
// read RGB single colour data (see above)
}
else if (c == 'C')
{
// read CMYK single colour data (see above)
}
else if (c == 'S')
{
// read HSB single colour data (see above)
}
else if (c == 'Y')
{
// read grey data (see above)
}
else
{
// insert invalid end colour identifier code
}

// check startLocation is in range [0,8]

2. The line style data has changed from file version 1.0 to 1.1 to take into account the inclusion of mid point markers, and is stored as follows:
JDR1.0
<linewidth><dash><cap><join>[<mitre-limit>]<winding><start arrow><end arrow>
JDR1.0
JDR1.1 and above
<linewidth><dash><cap><join>[<mitre-limit>]<winding><start arrow><mid marker><end arrow>
JDR1.1 and above
where:
1. <linewidth> the line width (in points) stored as a 32-bit floating point number. To write:
dout.writeFloat(linewidth);

float linewidth = din.readFloat();
// check linewidth isn't negative


2. <dash> is the dash pattern. This is stored as:

<n>[<pattern>+<offset>]

where <n> is 0 if there is no dash pattern (i.e. a solid line) or the number of patterns. There should be an even number of patterns, the odd numbered patterns represent the dash length, the even number of patterns represent the dash gap. The patterns should be stored as a 32-bit floating point number (in points). Lastly, the offset should be a 32-bit float (in points). Note that if <n> is 0, there should be no <pattern> or <offset>. To write:
dout.writeInt(n);
for (int i = 0; i < n; i++)
{
dout.writeFloat(pattern[i]);
}
if (n > 0) dout.writeFloat(offset);

int n = din.readInt();
if (n < 0)
{
// insert invalid pattern length code
}
else if (n > 0)
{
float[] pattern = new float[n];
for (int i = 0; i < n; i++)
{
}
}
else
{
// solid line
}


3. <cap> is the cap style, this is an 8-bit byte. It may only have one of the following values: 0 (butt), 1 (round) or 2 (square). To write:
dout.writeByte(cap);

byte cap = din.readByte();
// check cap is in the range [0,2]


4. <join> is the join style, this is an 8-bit byte. It may only have one of the following values: 0 (mitre), 1 (round) or 2 (bevel). To write:
dout.writeByte(join);

byte join = din.readByte();
// check join is in the range [0,2]


5. <mitre-limit> is the mitre-limit, this is a 32-bit float, and should only be stored if the join style is a mitre. To write:
if (join == 0)
{
dout.writeFloat(mitreLimit);
}

if (join == 0)
{
}


6. <winding> is the winding rule, this is an 8-bit byte. It may only have one of the following values: 0 (Even-Odd) or 1 (Non Zero). To write:
dout.writeByte(windingRule);

byte windingRule = din.readByte();
// check it's either 0 or 1


7. <start arrow> and <end arrow> are the starting and ending arrow styles. The <mid marker> is the style for the mid-point markers. Each marker type (start/mid/end) has the same format, but the file format varies as follows:
JDR1.0
<id>[<size><is double><is reversed>]

where <id> is an 8-bit byte identifying the arrow type. This may be one of: 0 (none), 1 (pointed), 2 (triangle), 3 (circle), 4 (diamond), 5 (square), 6 (bar) or 7 (single). <size> is 32-bit float representing the arrow size. (Some arrows only have a fixed size, but a size must still be present.) <is double> is a boolean value indicating whether the arrow head is a double arrow (<true>) or a single arrow (<false>). <is reversed> is a boolean value indicating whether the arrow head has been reversed. The values <size><is double><is reversed> are omitted if <id> equals 0 (no arrow head). To write:
dout.writeByte(arrowType);
if (arrowType != 0)
{
dout.writeFloat(arrowSize);
dout.writeBoolean(arrowDouble);
dout.writeBoolean(arrowReversed);
}

byte arrowType = din.readByte();
// omitted code to check arrowType is in range [0,7]
if (arrowType != 0)
{
}

JDR1.0
JDR1.1-1.3
<id>[<marker data>]

where <id> is an 8-bit byte identifying the marker type. If <id> is 0, then <marker data> should be omitted, otherwise it should be present. Valid <id> values are listed in Table A.5. To write:
dout.writeByte(markerType);

byte markerType = din.readByte();
// omitted code to check markerType has valid value
if (markerType != 0)
{
}


The <marker data> is stored as follows:

<size><repeat><is reversed><orient data><colour data><overlay><composite data>

where:

• <size> is a 32-bit float representing the marker size (some markers will ignore this attribute, but it must still be present in the file.) To write:
dout.writeFloat(markerSize);

float markerSize = din.readFloat();


• <repeat> is an 8-bit byte identifying the repeat factor (a value of 1 indicates a single marker, a value of 2 indicates a double marker, a value of 3 indicates a triple marker.) To write:
dout.writeByte(markerRepeat);

byte markerRepeat = din.readByte();
// check lies in range [1-3]


• <is reversed> is a boolean value indicating whether or not the marker has been reversed. To write:
dout.writeBoolean(markerReversed);

boolean markerReversed = din.readBoolean();


• <orient data> is the marker orientation data. This has the form <auto-orient>[<angle>] where <auto-orient> is a boolean value indicating whether the marker should be oriented along the path. If <auto-orient> is true, <angle> should be omitted, otherwise <angle> should be a float representing the orientation angle (in Radians). To write:
dout.writeBoolean(autoOrient);
if (!autoOrient) dout.writeFloat(angle);

boolean autoOrient = din.readBoolean();
float angle = 0.0f;


• <colour data> is the marker colour. This has the same form as the line/fill/text colour data defined earlier, except a transparent value indicates the colour should be derived from the path to which the marker is attached, and there is no provision for gradient paint markers.

• <overlay> is a boolean value indicating whether to overlay composite markers. To write:
dout.writeBoolean(overlay);

boolean overlay = din.readBoolean();


• <composite data> is the data for composite markers. This has the same format as the <marker data>. If the <composite data> has a marker id of 0, then the marker is not a composite marker. Although the format allows for nested composite markers, Jpgfdraw's marker settings dialog boxes do not allow for it.

 0 No marker 11 Box Filled 1 Pointed 12 Box Open 2 Triangle 13 Cross 3 Circle 14 Plus 4 Diamond 15 Star 5 Square bracket 16 Triangle Up Filled 6 Bar 17 Triangle Up Open 7 Single 18 Triangle Down Filled 8 Round bracket 19 Triangle Down Open 9 Dot Filled 20 Rhombus Filled 10 Dot Open 21 Rhombus Open

JDR1.1-1.3
JDR1.4 onwards

 22 Pentagon Filled 41 Half Cusp Down 60 Open Semicircle 23 Pentagon Open 42 Alt Single 61 Filled Semicircle 24 Hexagon Filled 43 Alt Single Open 62 Open 5 Pointed star 25 Hexagon Open 44 Triangle Open 63 Filled 5 Pointed star 26 Octagon Filled 45 Circle Open 64 Asterisk 27 Octagon Open 46 Diamond Open 65 Scissors Down Filled 28 Pointed 60 47 Brace 66 Scissors Up Filled 29 Pointed 45 48 Rectangle Cap 67 Scissors Down Open 30 Hooks 49 Chevron Cap 68 Scissors Up Open 31 Hook up 50 Fast Cap 69 Heart Right Filled 32 Hook Down 51 Round Cap 70 Heart Right Open 33 Half Pointed Up 52 Triangle Cap 71 Heart Filled 34 Half Pointed Down 53 Inverted Triangle Cap 72 Heart Open 35 Half Pointed 60 Up 54 Inverted Chevron Cap 73 Snowflake 36 Half Pointed 60 Down 55 Inverted Fast Cap 74 Star Chevron Open 37 Half Pointed 45 Up 56 Alt Bar 75 Star Chevron Filled 38 Half Pointed 45 Down 57 Alt Round 76 Star 6 Filled 39 Cusp 58 Alt Square 77 Star 6 Open 40 Half Cusp Up 59 Alt Brace 78 Equilateral Filled 79 Equilateral Open

 80 Ball Cap 85 Forward Triple Leaf Cap 81 Leaf Cap 86 Back Triple Leaf Cap 82 Double Leaf Cap 87 Forward Double Leaf Cap 83 Triple Leaf Cap 88 Back Double Leaf Cap 84 Club Cap 89 Cutout Bulge Cap

<id> [<marker data> ]

where <id> is an 8-bit byte identifying the marker type. If <id> is 0, then <marker data> should be omitted, otherwise it should be present. Valid <id> values are listed in Table A.5 and Table A.6. Additional markers listed in Table A.7 are also available for version 1.6 onwards.

To write:

dout.writeByte(markerType);

byte markerType = din.readByte();
// omitted code to check markerType has valid value
if (markerType != 0)
{
}


The <marker data> is stored as follows:

<size> <repeat> <is reversed> <orient data> <colour data> <overlay> [<user offset flag> [<user offset>] <repeat offset flag> [<repeat offset>]] <composite data>

where: <user offset flag> [<user offset>] <repeat offset flag> [<repeat offset>] are only specified if <overlay> is false. <user offset> and <repeat offset> are only specified if <user offset flag> or <repeat offset flag> are true, respectively. The remaining values are as for JDR versions 1.1-1.3 described above.

• <user offset flag> is a boolean value indicating whether the marker offset is specified by the user (true) or determined automatically (false).

• <user offset> is a 32-bit float indicating the marker offset from the vertex.

• <repeat offset flag> is a number indicating whether the repeat offset (i.e. gap between repeat markers) is specified by the user (true) or determined automatically (false).

• <repeat offset> is a 32-bit float indicating the gap between repeat markers.
To write:
if (overlay)
{
dout.writeBoolean(userOffsetFlag);

if (userOffsetFlag)
{
dout.writeFloat(userOffset);
}

dout.writeBoolean(repeatOffsetFlag);

if (repeatOffsetFlag)
{
dout.writeFloat(repeatOffset);
}
}

if (overlay)
{

if (userOffsetFlag)
{
}

if (repeatOffsetFlag)
{
}
}


JDR1.4 onwards

3. Segments are stored as follows:

<id><specs>

where <id> is a character representing the segment type. This can be one of: B (cubic Bézier), L (line) or M (move). To write:

if (/* test if Bézier */)
{
dout.writeChar('B');
// save Bézier data (see below)
}
else if (/* test if line */)
{
dout.writeChar('L');
//save line data (see below)
}
else
{
dout.writeChar('M');
// save move to data (see below)
}

if (c == 'B')
{
// read Bézier data (see below)
}
else if (c == 'L')
{
// read line data (see below)
}
else if (c == 'M')
{
// read move to data (see below)
}
else
{
// insert invalid segment identifier code
}

1. Bézier segments are stored as follows:
JDR1.0-1.2
<c0x><c0y><c1x><c1y><c2x><c2y><c3x><c3y>
JDR1.0-1.2
JDR1.3 onwards
<c1x><c1y><c2x><c2y><c3x><c3y>
JDR1.3 onwards
where <c0x> and <c0y> are the x and y co-ordinates of the starting point, <c1x> and <c1y> are the x and y co-ordinates of the first curvature control point, <c2x> and <c2y> are the x and y co-ordinates of the second curvature control point, and <c3x> and <c3y> are the x and y co-ordinates of the end point. All values are stored as 64-bit doubles. To write:
JDR1.0-1.2
for (int i = 0; i < 4; i++)
{
dout.writeDouble(x[i]);
dout.writeDouble(y[i]);
}

double[] x = new double[4];
double[] y = new double[4];
for (int i = 0; i < 4; i++)
{
}

JDR1.0-1.2
JDR1.3 onwards
for (int i = 0; i < 3; i++)
{
dout.writeDouble(x[i]);
dout.writeDouble(y[i]);
}

double[] x = new double[3];
double[] y = new double[3];
for (int i = 0; i < 3; i++)
{
}

JDR1.3 onwards

2. Line and move to (gap) segments are stored as follows:
JDR1.0-1.2
<x0><y0><x1><y1>
JDR1.0-1.2
JDR1.3 onwards
<x1><y1>
JDR1.3 onwards
where <x0> and <y0> are the x and y co-ordinates of the starting point and <x1> and <y1> are the x and y co-ordinates of the end point.
JDR1.0-1.2
To write:
for (int i = 0; i < 2; i++)
{
dout.writeDouble(x[i]);
dout.writeDouble(y[i]);
}

double[] x = new double[2];
double[] y = new double[2];
for (int i = 0; i < 2; i++)
{
}

JDR1.0-1.2
JDR1.3 onwards
To write:
dout.writeDouble(x1);
dout.writeDouble(y1);

x1 = din.readDouble();

JDR1.3 onwards

3. Text area data is stored as follows:

<fam-length><family><shape><series><size><transformation><latex-flag>[<latex-specs>]<text colour><text-length><text>

where:
1. <fam-length> is a 32-bit integer that is the length of the font family name, and <family> is the font family name. To write:
// String family contains the name of the font family
dout.writeInt(family.length());
dout.writeChars(family);

int n = din.readInt();
char[] fam = new char[n];
for (int i = 0; i < n; i++)
{
}
String family = new String(fam);


2. <shape> is an 8-bit byte representing the font shape. This can have one of two values: 0 (upright) or 1 (italic). To write:
dout.writeByte(shape);

byte shape = din.readByte();
// check shape is either 0 or 1


3. <series> is an 8-bit byte representing the font series. This can have one of two values: 0 (medium) or 1 (bold). To write:
dout.writeByte(series);

byte series = din.readByte();
// check series is either 0 or 1


4. <size> is the font size stored as a 32-bit integer. To write:
dout.writeInt(size);

int size = din.readInt();
// check size is not negative


5. <transformation> is the transformation. The origin is taken to be the leftmost point along the baseline of the text. The transformation is stored as:

<m0><m1><m2><m3><m4><m5>

where each element is stored as a 64-bit double precision number. The transformation matrix used is given by:

To write:
for (int i = 0; i < 6; i++)
{
dout.writeDouble(matrix[i]);
}

double[] matrix = new double[6];
for (int i = 0; i < 6; i++)
{
}


6. <latex-flag> is a boolean variable indicating whether or not the <latex-specs> are present. To write:

dout.writeBoolean(latexFlag)
if (latexFlag)
{
// save LaTeX specs (see below)
}

if (latexFlag)
{
// read LaTeX specs (see below)
}

7. <latex-specs> contains the LaTeX information, and has the format:

<lfam-length>[<lfamily>]<lseries-length>[<lseries>]<lshape-length>[<lshape>]<lsize-length>[<lsize>]<halign><valign><ltext-length>[<ltext>]

where:
1. <lfam-length> is an integer indicating the number of characters in <lfamily> where <lfamily> is a string containing the LaTeX family declaration (e.g. \rmfamily). If <lfam-length> is zero, <lfamily> is omitted. (<lfam-length> must not be negative.) To write:
// String lfamily contains the LaTeX family declaration
dout.writeInt(lfamily.length());
dout.writeChars(lfamily);

int n = din.readInt();
if (n < 0)
{
// insert code to throw error if n is negative
}
else if (n > 0)
{
char[] fam = new char[n];
for (int i = 0; i < n; i++)
{
}
String lfamily = new String(fam);
}


2. <lseries-length> is an integer indicating the number of characters in <lseries> where <lseries> is a string containing the LaTeX series declaration (e.g. \bfseries). If <lseries-length> is zero, <lseries> is omitted. (<lseries-length> must not be negative.) To write:
// String lseries contains the LaTeX series declaration
dout.writeInt(lseries.length());
dout.writeChars(lseries);

int n = din.readInt();
if (n < 0)
{
// insert code to throw error if n is negative
}
else if (n > 0)
{
char[] str = new char[n];
for (int i = 0; i < n; i++)
{
}
String lseries = new String(str);
}


3. <lshape-length> is an integer indicating the number of characters in <lshape> where <lshape> is a string containing the LaTeX shape declaration (e.g. \itshape). If <lshape-length> is zero, <lshape> is omitted. (<lshape-length> must not be negative.) To write:
// String lshape contains the LaTeX shape declaration
dout.writeInt(lshape.length());
dout.writeChars(lshape);

int n = din.readInt();
if (n < 0)
{
// insert code to throw error if n is negative
}
else if (n > 0)
{
char[] str = new char[n];
for (int i = 0; i < n; i++)
{
}
String lshape = new String(str);
}


4. <lsize-length> is an integer indicating the number of characters in <lsize> where <lsize> is a string containing the LaTeX size declaration (e.g. \large). If <lsize-length> is zero, <lsize> is omitted. (<lsize-length> must not be negative.) To write:
// String lsize contains the LaTeX size declaration
dout.writeInt(lsize.length());
dout.writeChars(lsize);

int n = din.readInt();
if (n < 0)
{
// insert code to throw error if n is negative
}
else if (n > 0)
{
char[] str = new char[n];
for (int i = 0; i < n; i++)
{
}
String lsize = new String(str);
}


5. <halign> is an 8-bit byte indicating the horizontal alignment of the \pgfbox command. It may only take one of the following values: 0 (left), 1 (centre) or 2 (right). To write:
dout.writeByte(halign);

byte halign = din.readByte();
if (halign < 0 || halign > 2)
{
// insert code to throw invalid halign exception
}


6. <valign> is an 8-bit byte indicating the vertical alignment of the \pgfbox command. It may only take one of the following values: 0 (top), 1 (centre), 2 (base) or 3 (bottom). To write:
dout.writeByte(valign);

byte valign = din.readByte();
if (valign < 0 || valign > 3)
{
// insert code to throw invalid valign exception
}


7. <ltext-length> is an integer indicating the number of characters in <ltext> where <ltext> is a string containing the LaTeX alternative to <text>. If <ltext-length> is zero, <ltext> is omitted. (<ltext-length> must not be negative.) To write:
// String ltext contains the alternative LaTeX text
dout.writeInt(ltext.length());
dout.writeChars(ltext);

int n = din.readInt();
if (n < 0)
{
// insert code to throw error if n is negative
}
else if (n > 0)
{
char[] str = new char[n];
for (int i = 0; i < n; i++)
{
}
String ltext = new String(str);
}


8. <text colour> is the text colour. This has the same format as the path line and fill colours described above.

9. <text length> is the number of characters contained in the text area (stored as a 32-bit integer) and <text> are the characters contained in the text area. <text length> must be strictly positive. To write:
// String text contains the text
dout.writeInt(text.length());
dout.writeChars(text);

int n = din.readInt();
if (n <= 0)
{
// insert code to throw invalid length exception
}
char[] str = new char[n];
for (int i = 0; i < n; i++)
{
}
String text = new String(str);


4. Text-paths are not available for versions below 1.5. For newer versions, the specifications are stored as follows:

<text colour><fam-length><family><shape><series><size><transformation><latex-flag>[<latex-specs>]<text-length><text>O|C<n><start point><segment data>+

where the text information (<text colour> to <text>) is as described above for text areas. The remaining information is as described above for paths.

5. Rotational patterns are not available for versions below 1.6. For newer versions, the specifications are stored as follows:

<shape-specs><anchor-x><anchor-y><angle><replicas><mode><show>

where:
1. <shape-specs> are the underlying object's specifications as described above. (Bitmap and text specifications not permitted.)

2. <anchor-x> is a 64-bit double representing the x-coordinate of the anchor point.

3. <anchor-y> is a 64-bit double representing the y-coordinate of the anchor point.

4. <angle> is a 64-bit double representing the angle of rotation.

5. <replicas> is a 32-bit integer representing the number of replicas.

6. <mode> is a boolean variable, true if single-path mode.

7. <show> is a boolean variable, true if the underlying path is visible.

6. Scaled patterns are not available for versions below 1.6. For newer versions, the specifications are stored as follows:

where <shape-specs>, <anchor-x>, <anchor-y>, <replicas>, <mode> and <show> are as above. Additionally:
1. <adjust-x> is a 64-bit double representing the x-coordinate of the adjust control point.

2. <adjust-y> is a 64-bit double representing the y-coordinate of the adjust control point.

3. <scale-x> is a 64-bit double representing the x-scale factor.

4. <scale-y> is a 64-bit double representing the y-scale factor.

7. Spiral patterns are not available for versions below 1.6. For newer versions, the specifications are stored as follows:

1. <angle> is a 64-bit double representing the spiral angle parameter.

2. <distance> is a 64-bit double representing the spiral distance parameter.

8. Bitmap data are stored as follows:

<filename-length><filename><latex-flag>[<latex-bitmap-specs>]<transformation>

where:
1. <filename-length> is an integer indicating the number of characters in the file name, and <filename> is the file name. Note that <filename-length> must be strictly positive. To write:
// String filename contains the file name
dout.writeInt(filename.length());
dout.writeChars(filename);

int n = din.readInt();
if (n <= 0)
{
// insert code to throw exception
}
char[] str = new char[n];
for (int i = 0; i < n; i++)
{
}


2. <latex-flag> is a boolean variable indicating whether or not the <latex-bitmap-specs> is present. To write:

dout.writeBooleanlatexFlag;
if (latexFlag)
{
// save LaTeX bitmap information (see below)
}

if (latexFlag)
{
// read LaTeX bitmap information (see below)
}

3. <latex-bitmaps-specs> has the following format:

<lfilename-length>[<lfilename>]<imgcmd-length>[<imgcmd>]

where <lfilename-length> is an integer indicating the number of characters in <lfilename>, and <lfilename> is the LaTeX link to the bitmap file. If <lfilename-length> is zero, <lfilename> is omitted. <imgcmd-length> is an integer indicating the number of characters in <imgcmd>, where <imgcmd> is a string containing the LaTeX command name to include the bitmap (e.g. \pgfimage.) If <imgcmd-length> is zero, <imgcmd> is omitted. To write
// String lfilename contains the LaTeX link to the bitmap
dout.writeInt(lfilename.length());
dout.writeChars(lfilename);
// String imgcmd contains the LaTeX image command
dout.writeInt(imgcmd.length());
dout.writeChars(imgcmd);

int n = din.readInt();
if (n < 0)
{
// insert code to throw invalid length exception
}
else if (n > 0)
{
char[] str = new char[n];
for (int i = 0; i < n; i++)
{
}
String lfilename = new String(str);
}
if (n < 0)
{
// insert code to throw invalid length exception
}
else if (n > 0)
{
char[] cmd = new char[n];
for (int i = 0; i < n; i++)
{
}
String imgcmd = new String(cmd);
}


4. <transformation> is the transformation matrix, and has the same format as the text area transformation matrix (see above.) The origin is the bottom left corner of the bitmap.

8. Flow frame data is stored as follows:
1. The frame type is stored as an 8-bit byte. This may only take one of the following values: 0 (static), 1 (flow), 2 (dynamic) and 3 (typeblock). There should only be one typeblock and this should belong to the outermost implicit group. To write:
dout.writeByte(type)

byte type = din.readByte();
// check valid value


2. If <type> is not equal to 3 (i.e. is not the typeblock), the following information should also be saved: a boolean value (border) indicating whether or not the frame should have a border, the identification label (label) stored as an integer (the number of characters in label) followed by that many characters, and the page list (pages) should likewise be stored as an integer (the number of characters in pages) followed by that many characters. To write:
if (type != 3)
{
dout.writeBoolean(border);
dout.writeInt(label.length());
dout.writeChars(label);
dout.writeInt(pages.length());
dout.writeChars(pages);
}

if (type != 3)
{
// throw exception if n < 0
String label = "";
char[] c;
if (n > 0)
{
c = new char[n];
for (int i = 0; i < n; i++)
{
}
label = new String(c);
}
// throw exception if n < 0
String pages = "";
if (n > 0)
{
c = new char[n];
for (int i = 0; i < n; i++)
{
}
pages = new String(c);
}
}


3. Store margin information as a 32-bit single precision floating point number, in the following order: top, bottom, left, right. To write:
dout.writeFloat(top);
dout.writeFloat(bottom);
dout.writeFloat(left);
dout.writeFloat(right);

float top    = din.readFloat();


4. JDR v1.2 and above contains extra information if the frame type is either 0 (static frame) or 2 (dynamic frame) which relates to the paragraph shape. This is a byte that can be 0 (standard shape), 1 (use \parshape) or 2 (use \shapepar). To write:
if (type == 0 || type == 2)
{
dout.writeByte(shape);
}

if (type == 0 || type == 2)
{
}


5. JDR v1.3 onwards contains additional information if the frame type is either 0 (static frame) or 2 (dynamic frame) which relates to the vertical alignment of material in the frame. This is a byte that can be 0 (top), 1 (centre) or 2 (bottom). To write:
if (type == 0 || type == 2)
{
dout.writeByte(valign);
}

if (type == 0 || type == 2)
{
}


9. JDR v1.2 and above also optionally contains the object's description. This is saved in the form:

<desc-length>[<description>]

where <desc-length> is an integer indicating the length of the description string. This may be zero, in which case <description> is omitted, otherwise <description> is a sequence of <desc-length> characters that make up the description. To write:
// description is a String
int n = description.length();
dout.writeInt(n);
if (n > 0)
{
dout.writeChars(description);
}

int n = din.readInt();
String description = "";
if (n > 0)
{
char[] desc = new char[n];
for (int i = 0; i < n; i++)
{
}
description = new String(desc);
}


#### Footnotes

... processorsA.1
although some fonts may not be available, and links to bitmaps may be unresolved

Previous: Step-by-Step Examples  Up: Manual Home  Next: AJR Format
© 2012 Dickimaw Books. "Dickimaw", "Dickimaw Books" and the Dickimaw parrot logo are trademarks. The logo was derived from a painting by Magdalene Pritchett.