Documentation of 'edu.rit.image.PJGImage' Java class
PJGImage
edu.rit.image

Class PJGImage

  • Direct Known Subclasses:
    BaseColorImage, PJGGrayImage


    public abstract class PJGImage
    extends java.lang.Object
    Class PJGImage is the abstract base class for an image that is read from or written to a file in Parallel Java Graphics (PJG) format. PJG image files are designed to be generated by parallel programs.

    Compared to PNG files, PJG files use a compression algorithm that yields somewhat larger file sizes but has a much smaller running time. In one test of a set of 24-bit color images, the PJG file sizes were 2-17% of the raw data sizes, whereas the PNG file sizes were 2-11% of the raw data sizes. The PJG file sizes were 30-50% larger than the corresponding PNG file sizes. However, the time to write the PJG files was only 1/10th to 1/20th the time to write the PNG files. This small running time to write a PJG file can substantially reduce a parallel program's sequential fraction, with a corresponding increase in the program's scalability.

    In addition, sections of an image can be written to a PJG image file in arbitrary order. Sections of an image can also be scattered across multiple files. This lets the processes of a cluster parallel program generate portions of an image independently, without needing to gather the whole image into one process.

    The PJG program can be used to display an image stored in one PJG file or scattered among multiple PJG files; to save the displayed image in a single PJG file; and to save the image in a PNG file or PostScript file.

    Usage

    To create a PJGImage object, instantiate one of the subclasses of class PJGImage, depending on the type of image. The image's pixel data is stored in an external matrix, as described in the documentation for each subclass. The available subclasses are:

    • PJGColorImage -- 24-bit color image, best when the image has a small number of discrete colors
    • PJGHueImage -- 24-bit hue image, best when the image has a continuous range of hues
    • PJGGrayImage -- 8-bit grayscale image
    Subclasses for other types of images will be added in later releases.

    To get and set the image's pixel data, use methods in the subclass. You only need to allocate storage in the pixel data matrix for the portions of the image you are actually accessing; the complete matrix need not be allocated. Class Arrays has static methods for allocating portions of a matrix.

    To write a PJGImage object to a PJG image file, call the prepareToWrite() method, specifying the output stream to write. The prepareToWrite() method returns an instance of class PJGImage.Writer. Call the methods of the PJG image writer object to write the pixel data, or sections of the pixel data, to the output stream. When finished, close the PJG image writer.

    To read a PJGImage object from a PJG image file, call the prepareToRead() method, specifying the input stream to read. The prepareToRead() method returns an instance of class PJGImage.Reader. Call the methods of the PJG image reader object to read the pixel data, or sections of the pixel data, from the input stream. When finished, close the PJG image reader.

    The previous paragraph assumes you already have a PJGImage object which is an instance of the correct subclass to hold the pixel data that will be read from the PJG image file. To both create an instance of the correct PJGImage subclass and read a PJG image file into that instance, call the static readFromStream() method. To create an instance of the correct PJGImage subclass to hold the contents of a PJG image file without actually reading in the pixel data, call the static createFromStream() method.

    To get a BufferedImage object that uses the same underlying pixel data matrix as the PJGImage object, call the getBufferedImage() method. You can then do all the following with the BufferedImage: display it on the screen, draw into it using a graphics context, copy another BufferedImage into it, read it from or write it to a file using package javax.imageio (which typically supports PNG, JPG, and GIF formats). The rows and columns of the underlying matrix need not all be allocated when accessing the BufferedImage. If you get a pixel from the BufferedImage in an unallocated row or column, a pixel value of 0 (black) is returned. If you set a pixel in the BufferedImage in an unallocated row or column, the pixel value is discarded.

    Note: Class PJGImage is not multiple thread safe.

    PJG Image File Format

    A PJG image file consists of a sequence of segments. Each segment consists of the following:

    • Segment type. Stored as a one-byte integer. Legal values:
      0 = Header segment
      1 = Image type segment
      2 = Height segment
      3 = Width segment
      4 = Creation time segment
      5 = Comment segment
      6 = Run length encoded 24-bit color pixel data segment
      7 = Huffman delta encoded 8-bit grayscale pixel data segment
      8 = Huffman delta encoded 24-bit hue pixel data segment

    • Segment contents. Depends on the type of segment, as described below.

    Header segment (segment type 0). The first segment in the file must be a header segment. There must be exactly one header segment in the file. The segment contents are:

    • One byte with the value 0x50.

    • One byte with the value 0x4A.

    • One byte with the value 0x47.

    • PJG file format version number. Stored as a four-byte integer, most significant byte first. Currently the PJG file format version number is 1.
    Thus, the first eight bytes of a PJG image file must be 0x00, 0x50, 0x4A, 0x47, 0x00, 0x00, 0x00, 0x01.

    Image type segment (segment type 1). The image type segment must come after the header segment and before any pixel data segments. There must be exactly one image type segment in the file. The segment contents are:

    • Image type. Stored as a one-byte integer. Legal values:
      0 = 24-bit color image
      1 = 8-bit grayscale image
      2 = 24-bit hue image

    Height segment (segment type 2). The height segment must come after the header segment and before any pixel data segments. There must be exactly one height segment in the file. The segment contents are:

    • Image height in pixels. Stored as a four-byte integer, most significant byte first. The image height must be > 0.

    Width segment (segment type 3). The width segment must come after the header segment and before any pixel data segments. There must be exactly one width segment in the file. The segment contents are:

    • Image width in pixels. Stored as a four-byte integer, most significant byte first. The image width must be > 0.

    Creation time segment (segment type 4). The creation time segment must come after the header segment and before any pixel data segments. There must be at most one creation time segment in the file. The segment contents are:

    • File creation time in milliseconds since midnight 01-Jan-1970 UTC. Stored as an eight-byte integer, most significant byte first. (This is the return value of the System.currentTimeMillis() method.)

    Comment segment (segment type 5). A comment segment must come after the header segment and before any pixel data segments. There may be zero or more comment segments in the file. The segment contents are:

    • Comment text, a string stored in the same format as the java.io.DataInput and java.io.DataOutput interfaces use. This consists of the number of bytes in the encoded string, stored as a two-byte integer, most significant byte first, followed by the encoded string itself. The string is encoded using a modified UTF-8 encoding.

    Run length encoded 24-bit color pixel data segment (segment type 6). A run length encoded 24-bit color pixel data segment may appear only in a file with image type = 0 (24-bit color image). A run length encoded 24-bit color pixel data segment may appear anywhere in the file after the header, image type, height, width, creation time, and comment segments. There may be zero or more run length encoded 24-bit color pixel data segments in the file.

    The pixel data segment contains pixel data for one block of the image. The block encompasses certain rows and certain columns of the image (not necessarily all the rows and columns). Blocks may appear in any order in the file. The file need not contain pixel data for all the rows and columns in the image.

    There is an implicit dictionary that associates consecutive indexes 0, 1, 2, . . . with pixel data values. The dictionary is not stored in the file; rather, the contents of the dictionary are built up as the pixel data segments are written or read. The dictionary persists between pixel data segments and is used for all the pixel data segments in the file.

    The first four fields of the pixel data segment are:

    • The block's upper left pixel's row index, in the range 0 .. image height - 1. Stored as a four-byte integer, most significant byte first.

    • The block's upper left pixel's column index, in the range 0 .. image width - 1. Stored as a four-byte integer, most significant byte first.

    • Number of rows in the block. Stored as a four-byte integer, most significant byte first. The number of rows must be > 0. The block's row index plus the number of rows must be <= the image height.

    • Number of columns in the block. Stored as a four-byte integer, most significant byte first. The number of columns must be > 0. The block's column index plus the number of columns must be <= the image width.
    The pixel data for the block is encoded as a sequence of runs. Each run consists of one or more consecutive pixels with identical values. The runs are found by scanning the pixel rows from lowest to highest row index. Within each row, the runs are found by scanning the pixels from lowest to highest column index. A run ends at the end of a row, or when a different pixel value is encountered.

    Each run is encoded as follows. Let n be one less than the number of pixels in the run. Let p be the 24-bit pixel value (8-bit red component, 8-bit green component, 8-bit blue component) of the pixels in the run. Let x be the index associated with pixel value p in the dictionary. First encode the run length:

    • If n <= 127, store one byte: 0nnnnnnn.

    • If 128 <= n <= 32767, store two bytes: 1nnnnnn nnnnnnn.

    • Otherwise, break the run into two or more runs each with n <= 32767 and encode each run separately.
    Then encode the pixel value:
    • If p is in the dictionary and x <= 127, store one byte: 0xxxxxxx.

    • If p is in the dictionary and 128 <= x <= 16383, store two bytes: 10xxxxxx xxxxxxxx.

    • If p is in the dictionary and 16384 <= x <= 2097151, store three bytes: 110xxxxx xxxxxxxx xxxxxxxx.

    • Otherwise, store four bytes: 11100000 pppppppp pppppppp pppppppp. Also, if the dictionary has fewer than 2097152 entries, add p to the dictionary, associating p with the next higher unused index x. That is, the first p added to the dictionary is associated with index 0, the second p added to the dictionary is associated with index 1, and so on.

    Huffman delta encoded 8-bit grayscale pixel data segment (segment type 7). A Huffman delta encoded 8-bit grayscale pixel data segment may appear only in a file with image type = 1 (8-bit grayscale image). A Huffman delta encoded 8-bit grayscale pixel data segment may appear anywhere in the file after the header, image type, height, width, creation time, and comment segments. There may be zero or more Huffman delta encoded 8-bit grayscale pixel data segments in the file.

    The pixel data segment contains pixel data for one block of the image. The block encompasses certain rows and certain columns of the image (not necessarily all the rows and columns). Blocks may appear in any order in the file. The file need not contain pixel data for all the rows and columns in the image.

    The first four fields of the pixel data segment are:

    • The block's upper left pixel's row index, in the range 0 .. image height - 1. Stored as a four-byte integer, most significant byte first.

    • The block's upper left pixel's column index, in the range 0 .. image width - 1. Stored as a four-byte integer, most significant byte first.

    • Number of rows in the block. Stored as a four-byte integer, most significant byte first. The number of rows must be > 0. The block's row index plus the number of rows must be <= the image height.

    • Number of columns in the block. Stored as a four-byte integer, most significant byte first. The number of columns must be > 0. The block's column index plus the number of columns must be <= the image width.
    Each pixel value is an integer from 0 (black) through 255 (white) inclusive.

    Certain pixel data in each row of the block is encoded in the form of deltas rather than the pixel values themselves. The delta in column i is equal to the pixel value in column i minus the pixel value in column i-1, except the delta in the block's first column is equal to the pixel value in the block's first column.

    The pixel data for the block is encoded by scanning the pixel rows from lowest to highest row index. Within each row, the pixels are scanned from lowest to highest column index. Each column is encoded using a modified Huffman encoding as follows:

    • If the delta is 0, encode 1 bit: 0.
       
    • If the delta is in the range -2 through -1 inclusive, encode 4 bits: 10dd, where dd is the delta as a signed two's complement number.
       
    • If the delta is in the range +1 through +2 inclusive, encode 4 bits: 10dd, where dd is (delta - 1) as a signed two's complement number.
       
    • If the delta is in the range -10 through -3 inclusive, encode 7 bits: 110dddd, where dddd is (delta + 2) as a signed two's complement number.
       
    • If the delta is in the range +3 through +10 inclusive, encode 7 bits: 110dddd, where dddd is (delta - 3) as a signed two's complement number.
       
    • If the delta is in the range -42 through -11 inclusive, encode 10 bits: 1110dddddd, where dddddd is (delta + 10) as a signed two's complement number.
       
    • If the delta is in the range +11 through +42 inclusive, encode 10 bits: 1110dddddd, where dddddd is (delta - 11) as a signed two's complement number.
       
    • Otherwise, encode 12 bits: 1111pppppppp, where pppppppp is the pixel value (not the delta).
    The above encoding process yields a bit string. Each group of 8 bits is packed into a byte, from most significant bit to least significant bit. Any unused least significant bits in the last byte are set to zero. The resulting sequence of bytes forms the remainder of the pixel data segment.

    Huffman delta encoded 24-bit hue pixel data segment (segment type 8). A Huffman delta encoded 24-bit hue pixel data segment may appear only in a file with image type = 2 (24-bit hue image). A Huffman delta encoded 24-bit hue pixel data segment may appear anywhere in the file after the header, image type, height, width, creation time, and comment segments. There may be zero or more Huffman delta encoded 24-bit hue pixel data segments in the file.

    The pixel data segment contains pixel data for one block of the image. The block encompasses certain rows and certain columns of the image (not necessarily all the rows and columns). Blocks may appear in any order in the file. The file need not contain pixel data for all the rows and columns in the image.

    The first four fields of the pixel data segment are:

    • The block's upper left pixel's row index, in the range 0 .. image height - 1. Stored as a four-byte integer, most significant byte first.

    • The block's upper left pixel's column index, in the range 0 .. image width - 1. Stored as a four-byte integer, most significant byte first.

    • Number of rows in the block. Stored as a four-byte integer, most significant byte first. The number of rows must be > 0. The block's row index plus the number of rows must be <= the image height.

    • Number of columns in the block. Stored as a four-byte integer, most significant byte first. The number of columns must be > 0. The block's column index plus the number of columns must be <= the image width.
    Each 24-bit pixel value consists of an 8-bit red component, an 8-bit green component, and an 8-bit blue component. Each component is an integer from 0 through 255 inclusive.

    First, the red components of all the pixels are treated as an 8-bit grayscale image and are encoded using Huffman delta encoding as described above, yielding a bit string.

    Second, the green components of all the pixels are treated as an 8-bit grayscale image and are encoded using Huffman delta encoding as described above, yielding a bit string.

    Third, the blue components of all the pixels are treated as an 8-bit grayscale image and are encoded using Huffman delta encoding as described above, yielding a bit string.

    Finally, the above three bit strings are concatenated yielding a longer bit string. Each group of 8 bits is packed into a byte, from most significant bit to least significant bit. Any unused least significant bits in the last byte are set to zero. The resulting sequence of bytes forms the remainder of the pixel data segment.

    • Nested Class Summary

      Nested Classes 
      Modifier and Type Class and Description
      class  PJGImage.Reader
      Class PJGImage.Reader is the abstract base class for an object with which to read a PJGImage from an input stream.
      class  PJGImage.Writer
      Class PJGImage.Writer is the abstract base class for an object with which to write a PJGImage to an output stream.
    • Method Summary

      All Methods Static Methods Instance Methods Abstract Methods Concrete Methods 
      Modifier and Type Method and Description
      void addComment(java.lang.String theComment)
      Add the given comment to this image.
      void clearComments()
      Remove all of the comments in this image.
      static PJGImage createFromStream(java.io.InputStream theStream)
      Create an instance of class PJGImage based on the given input stream.
      abstract java.awt.image.BufferedImage getBufferedImage()
      Obtain a BufferedImage whose pixel data comes from this image's underlying matrix.
      java.lang.Iterable<java.lang.String> getComments()
      Returns an iterable collection of the comments in this image.
      java.lang.Long getCreationTime()
      Returns this image's creation time.
      abstract Displayable getDisplayable()
      Obtain a Displayable object with which to display this image in a Swing UI.
      int getHeight()
      Returns this image's height.
      int getWidth()
      Returns this image's width.
      abstract PJGImage.Reader prepareToRead(java.io.InputStream theStream)
      Prepare to read this image from the given input stream.
      abstract PJGImage.Writer prepareToWrite(java.io.OutputStream theStream)
      Prepare to write this image to the given output stream.
      static PJGImage readFromStream(java.io.InputStream theStream)
      Create an instance of class PJGImage and read the image's pixel data from the given input stream.
      void setCreationTime(java.lang.Long time)
      Set this image's creation time.
      • Methods inherited from class java.lang.Object

        equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Method Detail

      • getHeight

        public int getHeight()
        Returns this image's height.
        Returns:
        Image height in pixels.
      • getWidth

        public int getWidth()
        Returns this image's width.
        Returns:
        Image width in pixels.
      • getCreationTime

        public java.lang.Long getCreationTime()
        Returns this image's creation time.
        Returns:
        Creation time in milliseconds since midnight 01-Jan-1970 UTC, or null if creation time is not set.
      • setCreationTime

        public void setCreationTime(java.lang.Long time)
        Set this image's creation time.
        Parameters:
        time - Creation time in milliseconds since midnight 01-Jan-1970 UTC. If null, the creation time is not set.
      • getComments

        public java.lang.Iterable<java.lang.String> getComments()
        Returns an iterable collection of the comments in this image. The returned collection is unmodifiable.
        Returns:
        Comment strings.
      • clearComments

        public void clearComments()
        Remove all of the comments in this image.
      • addComment

        public void addComment(java.lang.String theComment)
        Add the given comment to this image.
        Parameters:
        theComment - Comment string.
        Throws:
        java.lang.NullPointerException - (unchecked exception) Thrown if theComment is null.
      • prepareToWrite

        public abstract PJGImage.Writer prepareToWrite(java.io.OutputStream theStream)
                                                throws java.io.IOException
        Prepare to write this image to the given output stream. Certain header information is written to the output stream at this time. To write this image's pixel data, call methods on the returned PJG image writer, then close the PJG image writer.

        For improved performance, specify an output stream with buffering, such as an instance of class java.io.BufferedOutputStream.

        Parameters:
        theStream - Output stream.
        Returns:
        PJG image writer object with which to write this image.
        Throws:
        java.lang.NullPointerException - (unchecked exception) Thrown if theStream is null.
        java.io.IOException - Thrown if an I/O error occurred.
      • prepareToRead

        public abstract PJGImage.Reader prepareToRead(java.io.InputStream theStream)
                                               throws java.io.IOException
        Prepare to read this image from the given input stream. Certain header information is read from the input stream at this time. To read this image's pixel data, call methods on the returned PJG image reader, then close the PJG image reader.

        For improved performance, specify an input stream with buffering, such as an instance of class java.io.BufferedInputStream.

        Parameters:
        theStream - Input stream.
        Returns:
        PJG image reader object with which to read this image.
        Throws:
        java.lang.NullPointerException - (unchecked exception) Thrown if theStream is null.
        java.io.IOException - Thrown if an I/O error occurred.
      • createFromStream

        public static PJGImage createFromStream(java.io.InputStream theStream)
                                         throws java.io.IOException
        Create an instance of class PJGImage based on the given input stream. An instance of the correct subclass of class PJGImage is created, depending on the contents of the input stream. The image's header information is read from the input stream, then the input stream is reset to its position when createFromStream() was called. The input stream is not closed.

        The createFromStream() method calls the mark() and reset() methods on the input stream. If the input stream does not support these methods, an IOException is thrown.

        For improved performance, specify an input stream with buffering, such as an instance of class java.io.BufferedInputStream. (BufferedInputStream supports mark() and reset().)

        Parameters:
        theStream - Input stream.
        Returns:
        PJG image object.
        Throws:
        java.lang.NullPointerException - (unchecked exception) Thrown if theStream is null.
        java.io.IOException - Thrown if an I/O error occurred.
      • readFromStream

        public static PJGImage readFromStream(java.io.InputStream theStream)
                                       throws java.io.IOException
        Create an instance of class PJGImage and read the image's pixel data from the given input stream. An instance of the correct subclass of class PJGImage is created, depending on the contents of the input stream. The image's pixel data is read from the input stream, then the input stream is closed.

        The readFromStream() method calls the mark() and reset() methods on the input stream. If the input stream does not support these methods, an IOException is thrown.

        For improved performance, specify an input stream with buffering, such as an instance of class java.io.BufferedInputStream. (BufferedInputStream supports mark() and reset().)

        Parameters:
        theStream - Input stream.
        Returns:
        PJG image object containing image read from theStream.
        Throws:
        java.lang.NullPointerException - (unchecked exception) Thrown if theStream is null.
        java.io.IOException - Thrown if an I/O error occurred.
      • getBufferedImage

        public abstract java.awt.image.BufferedImage getBufferedImage()
        Obtain a BufferedImage whose pixel data comes from this image's underlying matrix.
        Returns:
        BufferedImage.
      • getDisplayable

        public abstract Displayable getDisplayable()
        Obtain a Displayable object with which to display this image in a Swing UI.
        Returns:
        Displayable object.

DMelt 3.0 © DataMelt by jWork.ORG

You see the box below because you did not login.