previous   A NewspaperAJR Format   next


JDR Binary Format

Jpgfdraw's native file format is a binary format written in the big-endian fashion. Since all 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.5.

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

  1. To read a data stream in (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");
    
    To read:
    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 file format version comes next. This may be 1.0, 1.1, 1.2, 1.3, 1.4 or 1.5. 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)
    
    To read:
    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)
    To read:
    switch (din.readByte())
    {
       case 0:
       // do nothing
       break;
       case 1:
       // read settings (see below)
       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);
    
    To read:
    if (din.readBoolean())
    {
       // read settings (see below)
    }
    JDR1.0-1.2

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

    2. A boolean variable (gridLock) indicating whether or not to lock the grid. To write:
      dout.writeBoolean(gridLock);
      
      To read:
      boolean gridLock = din.readBoolean();
      

    3. A boolean variable (showRulers) indicating whether or not to show the . To write:
      dout.writeBoolean(showRulers);
      
      To read:
      boolean showRulers = din.readBoolean();
      

    4. 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);
      
      To read:
      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

    5. 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);
      
      To read:
      int normalSize = din.readInt();
      

    6. The paper size (see below).

    7. An 8-bit byte representing the unit used for the rulers and grid. This should be one of: 0 ( ), 1 (inches), 2 (centimetres) or 3 ( ). To write:
      dout.writeByte(unitType);
      
      To read:
      byte unitType = din.readByte();
      

    8. Two 32-bit integers representing the major grid divisions and the subdivisions, respectively. To write:
      dout.writeInt(majorDivisions);
      dout.writeInt(subdivisions);
      
      To read:
      int majorDivisions = din.readInt();
      int subdivisions = din.readInt();
      

  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);
    }
    
    To read:
    byte paperSize = din.readByte();
    if (paperSize < 0 || paperSize > 18)
    {
       // insert invalid paper size id code
    }
    else if (paperSize == 18) // user defined paper size
    {
       double paperWidth  = din.readDouble();
       double paperHeight = din.readDouble();
       boolean isPortrait = din.readBoolean();
    }
    
    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);
    }
    
    To read:
    byte paperSize = din.readByte();
    if (paperSize < 0 || paperSize > 72)
    {
       // insert invalid paper size id code
    }
    else if (paperSize == 18) // user defined paper size
    {
       double paperWidth  = din.readDouble();
       double paperHeight = din.readDouble();
    }
    
    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 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 that constitute the picture. Each is then recursively stored. For example, if a picture contains a , a and a , in the file these three objects will be stored as a single group structure containing the three objects. If in Jpgfdraw you explicitly all the objects, then in the file, the outermost implicit group will contain only one which will be this .

    Each 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: G-- , P-- , T-- , I-- . JDR version 1.5 includes the new object type that is identified by X.

    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)
    }

    // 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)

    To read:

    char c = din.readChar();
    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
    {
       // insert invalid object id code
    }

    if (din.readBoolean())
    {
       // 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 within the , there should then follow <n> lots of <object data>, where <object data> is the data for each 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)
      }

      To read:

      int n = din.readInt();
      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 color><fill color><line style>O|C<n><segment data>+
      JDR1.0-1.2
      JDR1.3 onwards
      <line color><fill color><line style>O|C<n><start point><segment data>+
      JDR1.3 onwards
      where <line color> and <fill color> contain the line and fill color 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 color data (see below)
      // save fill color 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)
      }
      To read:
      // read line color data (see below)
      // read fill color data (see below)
      // read line style data (see below)
      char c = din.readChar();
      if (c == 'O')
      {
         // make it an open path
      }
      else if (c == 'C')
      {
         // make it a closed path
      }
      else
      {
         // insert invalid identifier code
      }
      int n = din.readInt();
      for (int i = 0; i < n; i++)
      {
         // read data for segment i (see below)
      }
      JDR1.0-1.2
      JDR1.3 onwards
      JDR v1.3 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 color data (see below)
      // save fill color 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)
      }
      To read:
      // read line color data (see below)
      // read fill color data (see below)
      // read line style data (see below)
      char c = din.readChar();
      if (c == 'O')
      {
         // make it an open path
      }
      else if (c == 'C')
      {
         // make it a closed path
      }
      else
      {
         // insert invalid identifier code
      }
      int n = din.readInt();
      double x = din.readDouble();
      double y = din.readDouble();
      for (int i = 0; i < n; i++)
      {
         // read data for segment i (see below)
      }
      JDR1.3 onwards

      1. Color data is stored as follows: <col-id>[<color-specs>], where <col-id> is a character representing the color 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 Color Types
        Type ID Version
        Transparent T 1.0 onwards
        RGB R 1.0 onwards
        CMYK C 1.0 onwards
        Linear Gradient G 1.0 onwards
        Radial Gradient D 1.3 onwards
        Gray Y 1.4 onwards
        HSB S 1.4 onwards

        To write

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

        To read:

        char c = din.readChar();
        if (c == 'T')
        {
           // set to transparent
        }
        else if (c == 'R')
        {
           // read single RGB color data (see below)
        }
        else if (c == 'C')
        {
           // read single CMKY color data (see below)
        }
        else if (c == 'G')
        {
           // read linear gradient color data (see below)
        }
        else if (c == 'D' /* and JDR version >= 1.3 */)
        {
           // read radial gradient color data (see below)
        }
        else if (c == 'S' /* and JDR version >= 1.4 */)
        {
           // read HSB color data (see below)
        }
        else if (c == 'Y' /* and JDR version >= 1.4 */)
        {
           // read gray data (see below)
        }
        else
        {
           // insert invalid color identifier code
        }

        1. Single RGB color 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);
          
          To read:
          float red   = din.readFloat();
          // check lies in range [0,1]
          float green = din.readFloat();
          // check lies in range [0,1]
          float blue  = din.readFloat();
          // check lies in range [0,1]
          float alpha = din.readFloat();
          // check lies in range [0,1]
          

        2. Single CMYK color 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);
          
          To read:
          float cyan   = din.readFloat();
          // check lies in range [0,1]
          float magenta = din.readFloat();
          // check lies in range [0,1]
          float yellow  = din.readFloat();
          // check lies in range [0,1]
          float black  = din.readFloat();
          // check lies in range [0,1]
          float alpha = din.readFloat();
          // check lies in range [0,1]
          

        3. As from version 1.4, HSB color 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);
          
          To read:
          float hue         = din.readFloat();
          // check lies in range [0,360)
          float saturation  = din.readFloat();
          // check lies in range [0,1]
          float brightness  = din.readFloat();
          // check lies in range [0,1]
          float alpha       = din.readFloat();
          // check lies in range [0,1]
          

        4. As from version 1.4, gray 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 gray value, and <A> represents the alpha (transparency) value. To write:
          dout.writeFloat(gray);
          dout.writeFloat(alpha);
          
          To read:
          float gray   = din.readFloat();
          // check lies in range [0,1]
          float alpha = din.readFloat();
          // check lies in range [0,1]
          

        5. Linear gradient color data is specified as:

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

          where <start-col-id> is the color identifier for the starting color and <start-col-specs> is the color specification, and <end-col-id> is the color identifier for the end color and <end-col-specs> is the color specification. The color identifiers may be any of those listed in Table A.4 except the linear or radial gradient types. The color 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 color RGB */)
          {
             dout.writeChar('R');
             // save RGB single color data (see above)
          }
          else if (/* start color CMYK */)
          {
             dout.writeChar('C');
             // save CMYK single color data (see above)
          }
          else if (/* start color HSB and version >= 1.4 */)
          {
             dout.writeChar('S');
             // save HSB single color data (see above)
          }
          else if (/* start color grey and version >= 1.4 */)
          {
             dout.writeChar('Y');
             // save HSB single gray data (see above)
          }
          else
          {
             // insert invalid color type code
          }

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

          dout.writeInt(direction);

          To read:

          char c = din.readChar();

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

          c = din.readChar();

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

          int direction = din.readInt();
          // check direction is in range [0,7]

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

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

          where <start-col-id> is the color identifier for the starting color and <start-col-specs> is the color specification, and <end-col-id> is the color identifier for the end color and <end-col-specs> is the color specification. The color identifiers may be any of those listed in Table A.4 except the linear or radial gradient types. The color 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 (Center). To write:

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

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

          dout.writeInt(startLocation);

          To read:

          char c = din.readChar();

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

          c = din.readChar();

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

          int startLocation = din.readInt();
          // 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>[<miter-limit>]<winding><start arrow><end arrow>
        JDR1.0
        JDR1.1 and above
        <linewidth><dash><cap><join>[<miter-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);
          
          To read:
          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);
          
          To read:
          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++)
             {
                pattern[i] = din.readFloat();
             }
             float offset = din.readFloat();
          }
          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);
          
          To read:
          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 (miter), 1 (round) or 2 (bevel). To write:
          dout.writeByte(join);
          
          To read:
          byte join = din.readByte();
          // check join is in the range [0,2]
          

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

        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);
          
          To read:
          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);
          }
          
          To read:
          byte arrowType = din.readByte();
          // omitted code to check arrowType is in range [0,7]
          if (arrowType != 0)
          {
             float arrowSize = din.readFloat();
             boolean arrowDouble = din.readBoolean();
             boolean arrowReversed = din.readBoolean();
          }
          
          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);
          
          To read:
          byte markerType = din.readByte();
          // omitted code to check markerType has valid value
          if (markerType != 0)
          {
             // read in marker data
          }
          

          The <marker data> is stored as follows:

          <size><repeat><is reversed><orient data><color 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);
            
            To read:
            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);
            
            To read:
            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);
            
            To read:
            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);
            
            To read:
            boolean autoOrient = din.readBoolean();
            float angle = 0.0f;
            if (!autoOrient) angle = din.readFloat();
            

          • <color data> is the marker color. This has the same form as the line/fill/text color data defined earlier, except a transparent value indicates the color 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);
            
            To read:
            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.


          Table A.5: Marker IDs
          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


          Table A.6: Additional Marker IDs (JDR 1.4)
          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

          JDR1.1-1.3
          JDR1.4
          <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. To write:
          dout.writeByte(markerType);
          
          To read:
          byte markerType = din.readByte();
          // omitted code to check markerType has valid value
          if (markerType != 0)
          {
             // read in marker data
          }
          

          The <marker data> is stored as follows:

          <size> <repeat> <is reversed> <orient data> <color data> <overlay> <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);
             }
          }
          
          To read:
          if (overlay)
          {
             boolean userOffsetFlag = din.readBoolean();
          
             if (userOffsetFlag)
             {
                float userOffset = din.readFloat();
             }
          
             boolean repeatOffsetFlag = din.readBoolean();
          
             if (repeatOffsetFlag)
             {
                float repeatOffset = din.readFloat();
             }
          }
          

          JDR1.4

      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)
        }

        To read:

        char c = din.readChar();

        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]);
          }
          
          To read:
          double[] x = new double[4];
          double[] y = new double[4];
          for (int i = 0; i < 4; i++)
          {
             x[i] = din.readDouble();
             y[i] = din.readDouble();
          }
          
          JDR1.0-1.2
          JDR1.3 onwards
          for (int i = 0; i < 3; i++)
          {
             dout.writeDouble(x[i]);
             dout.writeDouble(y[i]);
          }
          
          To read:
          double[] x = new double[3];
          double[] y = new double[3];
          for (int i = 0; i < 3; i++)
          {
             x[i] = din.readDouble();
             y[i] = din.readDouble();
          }
          
          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]);
          }
          
          To read:
          double[] x = new double[2];
          double[] y = new double[2];
          for (int i = 0; i < 2; i++)
          {
             x[i] = din.readDouble();
             y[i] = din.readDouble();
          }
          
          JDR1.0-1.2
          JDR1.3 onwards
          To write:
          dout.writeDouble(x1);
          dout.writeDouble(y1);
          
          To read:
          x1 = din.readDouble();
          y1 = din.readDouble();
          
          JDR1.3 onwards

    3. data is stored as follows:

      <fam-length><family><shape><series><size><transformation><latex-flag>[<latex-specs>]<text color><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);
        
        To read:
        int n = din.readInt();
        char[] fam = new char[n];
        for (int i = 0; i < n; i++)
        {
           fam[i] = din.readChar();
        }
        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);
        
        to read:
        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);
        
        To read:
        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);
        
        To read:
        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:

        \begin{displaymath}
\left(
\begin{array}{lll}
m_0 & m_2 & m_4\\
m_1 & m_3 & m_5\\
0 & 0 & 1
\end{array}\right)
\end{displaymath}

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

      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)
        }

        To read:

        boolean latexFlag = din.readBoolean();
        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);
          
          To read:
          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++)
             {
                fam[i] = din.readChar();
             }
             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);
          
          To read:
          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++)
             {
                str[i] = din.readChar();
             }
             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);
          
          To read:
          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++)
             {
                str[i] = din.readChar();
             }
             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);
          
          To read:
          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++)
             {
                str[i] = din.readChar();
             }
             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 (center) or 2 (right). To write:
          dout.writeByte(halign);
          
          To read:
          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 (center), 2 (base) or 3 (bottom). To write:
          dout.writeByte(valign);
          
          To read:
          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);
          
          To read:
          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++)
             {
                str[i] = din.readChar();
             }
             String ltext = new String(str);
          }
          

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

      9. <text length> is the number of characters contained in the (stored as a 32-bit integer) and <text> are the characters contained in the . <text length> must be strictly positive. To write:
        // String text contains the text
        dout.writeInt(text.length());
        dout.writeChars(text);
        
        To read:
        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++)
        {
           str[i] = din.readChar();
        }
        String text = new String(str);
        

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

      <text color><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 color> to <text>) is as described above for . The remaining information is as described above for .

    5. Bitmap data is 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);
        
        To read:
        int n = din.readInt();
        if (n <= 0)
        {
           // insert code to throw exception
        }
        char[] str = new char[n];
        for (int i = 0; i < n; i++)
        {
           str[i] = din.readChar();
        }
        

      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)
        }

        To read:

        boolean latexFlag = din.readBoolean();
        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);
        
        To read:
        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++)
           {
              str[i] = din.readChar();
           }
           String lfilename = new String(str);
        }
        n = din.readInt();
        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++)
           {
              cmd[i] = din.readChar();
           }
           String imgcmd = new String(cmd);
        }
        

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

  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)
      
      To read:
      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);
      }
      
      To read:
      if (type != 3)
      {
         boolean border = din.readBoolean();
         int n = din.readInt();
         // throw exception if n < 0
         String label = "";
         char[] c;
         if (n > 0)
         {
            c = new char[n];
            for (int i = 0; i < n; i++)
            {
               c[i] = din.readChar();
            }
            label = new String(c);
         }
         n = din.readInt();
         // throw exception if n < 0
         String pages = "";
         if (n > 0)
         {
            c = new char[n];
            for (int i = 0; i < n; i++)
            {
               c[i] = din.readChar();
            }
            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);
      
      To read:
      float top    = din.readFloat();
      float bottom = din.readFloat();
      float left   = din.readFloat();
      float right  = 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);
      }
      
      To read
      if (type == 0 || type == 2)
      {
         byte shape = din.readByte();
      }
      

    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 (center) or 2 (bottom). To write:
      if (type == 0 || type == 2)
      {
         dout.writeByte(valign);
      }
      
      To read
      if (type == 0 || type == 2)
      {
         byte valign = din.readByte();
      }
      

  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);
    }
    
    To read:
    int n = din.readInt();
    String description = "";
    if (n > 0)
    {
       char[] desc = new char[n];
       for (int i = 0; i < n; i++)
       {
          desc[i] = din.readChar();
       }
       description = new String(desc);
    }
    



Footnotes

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

previous   A NewspaperAJR Format   next