September 18, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Steganography 101 using Java

  • September 6, 2005
  • By Richard G. Baldwin
  • Send Email »
  • More Articles »

Run the Program

I encourage you to copy, compile and run the following programs that are provided in this lesson:

  • ImgMod28
  • ImgMod28a

Experiment with the programs, making changes and observing the results of your changes.

(Remember, you will also need to copy the program named ImgMod02a and the interface named ImgIntfc02 from the earlier lessons entitled Processing Image Pixels Using Java, Controlling Contrast and Brightness and Processing Image Pixels using Java, Getting Started.)

Test images

To replicate the output images shown in this lesson, you will need to use the same images as input.  Those images are provided below.  Simply right-click on the images in Figure 8 and Figure 9.  Save the images locally under the files named imgmod10.jpg and imgmod11.jpg.  Then use them as input to the programs named ImgMod28 and ImgMod28a.


Figure 8
 

Figure 9

Test some other images

If you search the Internet, you should be able to find lots of images that you can download and experiment with.  See if you can find an image in which an embedded message is visually detectable.  Just remember, as explained in the lesson entitled Processing Image Pixels Using Java, Controlling Contrast and Brightness, if you download a gif image, it will probably contain a lot less color information than a comparable jpg image.

Try three and four-bit embedding

Try modifying the program to embed the message in the three LSB of the color values of the image.  See if this causes the message to become visually detectable.  If not, try embedding the message in the four LSB of the color values to see if that results in a visually detectable message.  See how far you can push this before the existence of the message in the image becomes visually detectable.

(There is one thing that I can say for sure.  If you embed the message in the eight LSB of every color value for every pixel, the existence of the message in the image will be visually detectable.)

Have fun and learn

Above all, have fun and use these programs to learn as much as you can about this form of steganography using Java as your programming language.

Summary

In this lesson, I showed you how to write Java code to embed a long text message in an image in such a way that there is no visual indication that the image contains a hidden secret message.  I also showed you how to write the code to extract the message from the image and reconstruct it into readable form.

In addition, I explained how the use of image compression can garble a message that has been embedded in an image and provided some information on both lossy and lossless image compression algorithms.

What's Next?

My next lesson on steganography will probably show you how to hide a secret image in another image and how to extract and reconstruct the secret image later.

A topic that is very similar to steganography is the topic of digital watermarking.  Visible watermarks are often used to indicate the ownership of an image to all viewers of the image.  Invisible watermarks are sometimes used to prove ownership of an image during a dispute regarding the rightful use of the image.

Future lessons will explain:

  • How to create visible watermarks in images in the space domain.
  • How to create invisible watermarks in images in the space domain.
  • How to create invisible watermarks in images in the wave-number domain.

These lessons will also discuss the vulnerability (or lack thereof) of the watermarks to destruction in the face of various modifications to the image such as scaling, rotation, cropping, etc.

Complete Program Listings

Complete listings of the programs discussed in this lesson are provided in Listing 10 and Listing 11.  In order to compile and run these programs, you will also need copies of the program named ImgMod02a and the interface named ImgIntfc02 from the earlier lessons entitled Processing Image Pixels Using Java, Controlling Contrast and Brightness and Processing Image Pixels using Java, Getting Started.

A disclaimer

The programs that I am providing and explaining in this series of lessons are not intended to be used for high-volume production work.  Numerous integrated image-processing programs are available for that purpose.  In addition, the Java Advanced Imaging API (JAI) has a number of built-in special effects if you prefer to write your own production image-processing programs using Java.

The programs that I am providing in this series are intended to make it easier for you to develop and experiment with image-processing algorithms and to gain a better understanding of how they work, and why they do what they do.

/*File ImgMod28.java.java
Copyright 2005, R.G.Baldwin
This program is designed to be driven by the
program named ImgMod02a.java.
This program illustrates one form of 
steganography by:
1. Burying a text message in an image.
2. Displaying the original message.
3. Extracting and displaying the extracted 
message for comparison with the original.
4. Displaying the modified image alongside the
original image for a visual comparison of the
two.
Enter the following on the command line to run
this program:
java ImgMod02a ImgMod28 ImageFileName
In an attempt to make it more difficult for an
evesdropper to determine that a message is 
embedded in the image, the message is not 
embedded at the beginning of the image.  Rather
the image is embedded at a predetermined pixel
location somewhere internal to the image.
In a further attempt to make it difficult for an
evesdropper to determine that a message is
embedded in the image, message values are not
embedded into adjacent pixels.  Rather, a space
consisting of 0, 1, 2, or 3 pixels is allowed 
between modified pixels.  Furthermore, the space
that is allowed between any two modified pixels
is probably random because it is based on
the value of two bits from the previous message
character.  While this probably makes the 
existence of the hidden message harder to detect,
it also makes the overall process more vulnerable
to problems resulting from data errors.  Once a
data error causes the reconstruction process to
lose synchronization, it is probably not possible
to recover.  Therefore, this feature may, or may
not be advantageous depending on the liklihood of
transmission errors with the image.  However, it
is relatively easy to disable this feature.  (See
the program named ImgMod28a for a version of the 
program in which this feature has been disabled.)
The program supports a message character set
consisting of 64 characters beginning with the
space character in the ASCII table.  This set
includes the space character, the numeric 
characters, the upper-case characters, and most
of the punctuation and special characters.  By
using this format, each modified pixel can carry
one message character.
The program uses an underscore character to
indicate the end of the message.  Therefore, the
underscore character cannot be used within the
body of the message so the effective number of
available characters is reduced from 64 to 63.
This program produces the following output when
run with an image file named imgmod10.jpg.  Note
that line breaks were manually inserted to force
this material to fit into this narrow publication
format.
Processing program: ImgMod28
Image file: imgmod10.jpg
Width = 324
Height = 330
Original message:
Four score and seven years ago our fathers brough
t forth on this continent a new nation, conceived
 in liberty and dedicated to the proposition that
 all men are created equal.
Msg Length = 175
Insertion point = 5000
Reconstructed message:
FOUR SCORE AND SEVEN YEARS AGO OUR FATHERS BROUGH
T FORTH ON THIS CONTINENT A NEW NATION, CONCEIVED
 IN LIBERTY AND DEDICATED TO THE PROPOSITION THAT
 ALL MEN ARE CREATED EQUAL._
Although the message used to test the program
was fairly short, an image of this size could 
hide a message with a length in excess of 33,000
characters, assuming one character for every
three pixels.  If the pixel-skipping feature is
disabled, an image of this size could hide a 
message with a length in excess of 106,000
characters.  As you can see, the message-hiding
capacity of this approach is substantial.
Tested using J2SE 5.0 and WinXP
************************************************/
class ImgMod28 implements ImgIntfc02{
  //This method must be defined to implement
  // the interface named ImgIntfc02.
  public int[][][] processImg(
                             int[][][] threeDPix,
                             int imgRows,
                             int imgCols){
    //Make a working copy of the 3D array to
    // avoid making permanent changes to the
    // image data.
    int[][][] temp3D =
                    new int[imgRows][imgCols][4];
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        temp3D[row][col][0] =
                          threeDPix[row][col][0];
        temp3D[row][col][1] =
                          threeDPix[row][col][1];
        temp3D[row][col][2] =
                          threeDPix[row][col][2];
        temp3D[row][col][3] =
                          threeDPix[row][col][3];
      }//end inner loop
    }//end outer loop
    System.out.println("Width = " + imgCols);
    System.out.println("Height = " + imgRows);
    
    //Define the raw message
    String msg =
     "Four score and seven years ago our fathers"
     + " brought forth on this continent a new"
     + " nation, conceived in liberty and"
     + " dedicated to the proposition that all"
     + " men are created equal.";
     System.out.println(
                    "Original message:n" + msg);
     //Note:  The text for this message was taken
     // from
     // http://www.law.ou.edu/hist/getty.html
     
     //Terminate the message with an underscore.
     msg = msg + "_";
      
    //Convert the message to 64-char six-bit
    // data format. This includes the space,
    // the numbers, the upper-case characters,
    // and most of the punctuation characters
    // and other special characters.
    //Begin by converting to all upper-case
    // characters.
    msg = msg.toUpperCase();
    //Create an object to receive the modified
    // version of the message.
    StringBuffer sixBitMsg = new StringBuffer();
    //Subtract a value of 32 causing all of the
    // modified character values to fall between
    // 0 and 63.  This bias value of 32 will be
    // added back later when the message is
    // reconstructed.
    char temp;
    for(int cnt = 0;cnt < msg.length();cnt++){
      temp = (char)(msg.charAt(cnt) - 32);
      sixBitMsg.append(temp);
    }//end for loop
    //Replace the original Unicode message with
    // the 6-bit message.  This is the message
    // that will be hidden in the image.
    msg = new String(sixBitMsg);
    //The overall process is to break each six-
    // bit character into three pairs of bits,and
    // to substitute those three pairs of bits
    // for the two lsb of the red, green, and
    // blue color values in selected pixels in
    // the image.
    //Extract each pair of bits from each six-bit
    // char and store the two bits in the two lsb
    // of a byte in an array of bytes.  This will
    // make it easier to access the pairs of bits
    // later for use in modifying the pixel
    // values.
    //Begin by converting the message into an
    // array of bytes.  This process preserves
    // only the 8 lsb of each character.
    byte[] msgBytes = msg.getBytes();
    System.out.println(
              "Msg Length = " + msgBytes.length);
    //Create an array to store the bytes
    // containing the pairs of bits.
    byte[] twoBitBytes = 
                   new byte[3 * msgBytes.length];
    
    //Shift and mask the bytes in the array
    // containing the message bytes to get and
    // save the pairs of bits.
    int twoBitByteCnt = 0;
    for(byte element:msgBytes){
      twoBitBytes[twoBitByteCnt++] 
                        = (byte)(element & 0x03);
      twoBitBytes[twoBitByteCnt++] 
                 = (byte)((element >> 2) & 0x03);
      twoBitBytes[twoBitByteCnt++] 
                 = (byte)((element >> 4) & 0x03);
    }//end for-each
    
    //Begin embedding the pairs of message bits
    // at a predetermined non-zero pixel location
    // in the image. Two bits from a single 6-bit
    // message character are embedded into the
    // lsb of the red, green, and blue pixel
    // values.  After a pixel has been modified,
    // use the value of the two bits that were
    // embedded into the blue pixel to determine
    // the number of pixels to skip before
    // modifying another pixel.  The number of
    // pixels to be skipped will be either 0, 1,
    // 2, or 3.  This prevents adjacent pixels
    // from being modified about three-fourths of
    // the time.
    //Specify the predefined insertion point
    int insertionPoint = 5000;
    System.out.println(
          "Insertion point = " + insertionPoint);
    //Initialize the number of pixels to skip.
    int skipValue = 0;
    //Use a nested loop to operate on each pixel
    // and to embed message bits into the red,
    // green, and blue values of selected pixels.
    twoBitByteCnt = 0;//Re-use this variable
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        //Embed 6-bit message characters
        // beginning at a predefined pixel
        // location in the image and skipping
        // pixels on the basis of the value of
        // two bits in the message character.
        if((row * col > insertionPoint) 
          && (twoBitByteCnt < twoBitBytes.length)
          && skipValue-- == 0){
          //Replace the two lsb of the red,
          // green, and blue pixel values with
          // two bits from the six-bit message
          // character.
          temp3D[row][col][1] = 
                (temp3D[row][col][1] & 0xFC)
                  | twoBitBytes[twoBitByteCnt++];
          temp3D[row][col][2] = 
                (temp3D[row][col][2] & 0xFC)
                  | twoBitBytes[twoBitByteCnt++];
          temp3D[row][col][3] = 
                (temp3D[row][col][3] & 0xFC)
                  | twoBitBytes[twoBitByteCnt++];
          //Determine number of pixels to skip
          // before modifying another pixel.
          skipValue = 
                  twoBitBytes[twoBitByteCnt - 1];
        }//end if
      }//end for loop on col
    }//end for loop on row
    
    //Up to this point, the program demonstrates
    // how to modify an image to include a hidden
    // message.
    //The remainder of the program demonstrates
    // how to extract that message from the
    // image.  Note that this code requires
    // prior knowledge of the insertion point
    // value.
    //Create an array object large enough to
    // contain one byte for every two-bit byte
    // that can be extracted from every pixel
    // between the insertion point and the end of
    // the message.
    byte[] extractedTwoBitBytes = 
                     new byte[(imgRows * imgCols 
                          - insertionPoint) * 3];
    twoBitByteCnt = 0;
    skipValue = 0;
    //Process every pixel.
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        if((row * col > insertionPoint) 
                          && (skipValue-- == 0)){
          //Extract and save the message
          // characters two bits at a time.
          extractedTwoBitBytes[twoBitByteCnt++]
            = (byte)(temp3D[row][col][1] & 0x03);
          extractedTwoBitBytes[twoBitByteCnt++] 
            = (byte)(temp3D[row][col][2] & 0x03);
          extractedTwoBitBytes[twoBitByteCnt++] 
            = (byte)(temp3D[row][col][3] & 0x03);
          //Determine number of pixels to skip
          // before extracting data for another
          // pixeProcessing program: ImgMod28
Image file: imgmod11.jpg
Width = 480
Height = 120
Raw message:
Four score and seven years ago our fathers brough
t forth on this continent a new nation, conceived
 in liberty and dedicated to the proposition that
 all men are created equal.
Msg Length = 175
Insertion point = 5000
Extracted message:
FOUR SCORE AND SEVEN YEARS AGO OUR FATHERS BROUGH
T FORTH ON THIS CONTINENT A NEW NATION, CONCEIVED
 IN LIBERTY AND DEDICATED TO THE PROPOSITION THAT
 ALL MEN ARE CREATED EQUAL._
          skipValue = extractedTwoBitBytes[
                              twoBitByteCnt - 1];
        }//end if
      }//end for loop on col
    }//end for loop on row
        
    //Reconstruct and display the 64-char version
    // of the message
    StringBuffer extractedMsg = 
                              new StringBuffer();
    byte[] sixBitBytes = 
         new byte[extractedTwoBitBytes.length/3];
    twoBitByteCnt = 0;
    for(byte element:sixBitBytes){
      //Shift and or the pairs of bits into the
      // 6-bit format.
      element = (byte)(extractedTwoBitBytes[
                               twoBitByteCnt++]);
      element = 
          (byte)(element | (extractedTwoBitBytes[
                         twoBitByteCnt++] << 2));
      element = 
          (byte)(element | (extractedTwoBitBytes[
                         twoBitByteCnt++] << 4));
      extractedMsg.append((char)(element + 32));
      //Stop processing when terminating
      // underscore character is encountered.
      if((char)(element + 32) == '_')break;
    }//end for-each
    
    System.out.println("Extracted message:n"
                                 + extractedMsg);
    //Return the modified image for display.
    return temp3D;
  }//end processImg
  //-------------------------------------------//
}//end class ImgMod28
Listing 10

/*File ImgMod28a.java.java
Copyright 2005, R.G.Baldwin
This program is an update of the program named
ImgMod28.  The purpose of this program is to 
determine the extent to which randomly modifying
the two least-significant bits of every pixel in
an image degrades the visual quality of the
image.
This program is designed to be driven by the
program named ImgMod02a.java.
This program illustrates steganography for very
long messages by:
1. Burying a long text message in an image by 
modifying every pixel in the image to contain 
one character from the message.
2. Displaying selected characters from throughout
the original message.
3. Extracting the message from the image and 
displaying the same set of selected characters 
for comparison of the extracted message with the
original message.
2. Displaying the modified image alongside the
original image for a visual comparison of the
two.
Enter the following on the command line to run
this program:
java ImgMod02a ImgMod28a ImageFileName
The program supports a message character set
consisting of 64 characters beginning with the
space character in the ASCII table.  This set
includes the space character, the numeric 
characters, the upper-case characters, and most
of the punctuation and special characters.  By
using this format, each modified pixel can carry
one message character.  (Note however that the
random message used to test this program does
not contain all of the allowed characters.)
The program uses an underscore character to
indicate the end of the message.  Therefore, the
underscore character cannot be used within the
body of the message so the effective number of
available characters is reduced from 64 to 63.
This program produced the following output when
run with an image file named imgmod10.jpg.  Note
that line breaks were manually inserted to force
this material to fit into this narrow publication
format.  Note also that because the message that
is embedded in the image is generated using a
random number generator, the output will be 
different each time the program is run.
Processing program: ImgMod28a
Image file: imgmod10.jpg
Width = 324
Height = 330
Characters from original message:
%1" 9:)<8;>';4$:!?,,*"'+4:6$-'?!2: (3$8 :729$&;%&
'(-724
Msg Length = 106920
Insertion point = 0
Characters from reconstructed message:
%1" 9:)<8;>';4$:!?,,*"'+4:6$-'?!2: (3$8 :729$&;%&
'(-724
As you can see, for this image, it was possible
to embed a message containing 106,920 characters
in the image.  As you will also see if you run
this program using the same image, there was no
discernable deterioration in the visual quality
of the image.
Tested using J2SE 5.0 and WinXP
************************************************/
import java.util.*;
class ImgMod28a implements ImgIntfc02{
  //This method must be defined to implement
  // the interface named ImgIntfc02.
  public int[][][] processImg(
                             int[][][] threeDPix,
                             int imgRows,
                             int imgCols){
    //Make a working copy of the 3D array to
    // avoid making permanent changes to the
    // image data.
    int[][][] temp3D =
                    new int[imgRows][imgCols][4];
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        temp3D[row][col][0] =
                          threeDPix[row][col][0];
        temp3D[row][col][1] =
                          threeDPix[row][col][1];
        temp3D[row][col][2] =
                          threeDPix[row][col][2];
        temp3D[row][col][3] =
                          threeDPix[row][col][3];
      }//end inner loop
    }//end outer loop
    System.out.println("Width = " + imgCols);
    System.out.println("Height = " + imgRows);
    //For this version of the program, define a
    // raw message consisting of an array of
    // random bytes equal in size to the number
    // of pixels in the image.
    byte[] rawMsg = new byte[imgCols * imgRows];
    Random randomGenerator = 
                new Random(new Date().getTime());
    randomGenerator.nextBytes(rawMsg);
    
    //Force all of the bytes to represent
    // printable characters within the range of
    // character values from 33 to 63.
    for(int cnt = 0;cnt < rawMsg.length;cnt++){
      //Eliminate characters above 63
      rawMsg[cnt] = (byte)(rawMsg[cnt] & 0x003F);
      //Eliminate control codes. Preserve space
      // and above.
      if(rawMsg[cnt] <= 31) rawMsg[cnt] += 32;
    }//end for loop
    //Replace the last character with an
    // underscore to terminate the message.
    rawMsg[rawMsg.length - 1] = '_';
    //Convert bytes to a message String
    String msg = new String(rawMsg);
    System.out.println(
            "Characters from original message:");
    //Select and print every (6*imgCols + 1)
    // character from the message
    for(int cnt = 0;cnt < msg.length();cnt++){
      if(cnt%(6*imgCols + 1) == 0){
        System.out.print(msg.charAt(cnt));
      }//end if
    }//end for loop
    System.out.println();//blank line
    //Make the memory occupied by the byte array
    // eligible for garbage collection.
    rawMsg = null;
    //Convert the message to 64-char six-bit
    // data format. This includes the space,
    // the numbers, the upper-case characters,
    // and most of the punctuation characters
    // and other special characters.  Note
    // however that many of these characters were
    // not included in the set of random bytes
    // that constitute the message.
    //Begin by converting to all upper-case
    // characters.
    msg = msg.toUpperCase();
    //Create an object to receive the modified
    // version of the message.
    StringBuffer sixBitMsg = new StringBuffer();
    //Subtract a value of 32 causing all of the
    // modified character values to fall between
    // 0 and 63.  This bias value of 32 will be
    // added back later when the message is
    // reconstructed.
    char temp;
    for(int cnt = 0;cnt < msg.length();cnt++){
      temp = (char)(msg.charAt(cnt) - 32);
      sixBitMsg.append(temp);
    }//end for loop
    //Replace the original Unicode message with
    // the 6-bit message.  This is the message
    // that will be hidden in the image.
    msg = new String(sixBitMsg);
    //The overall process is to break each six-
    // bit character into three pairs of bits,and
    // to substitute those three pairs of bits
    // for the two lsb of the red, green, and
    // blue color values in selected pixels in
    // the image.
    //Extract each pair of bits from each six-bit
    // char and store the two bits in the two lsb
    // of a byte in an array of bytes.  This will
    // make it easier to access the pairs of bits
    // later for use in modifying the pixel
    // values.
    //Begin by converting the message into an
    // array of bytes.  This process preserves
    // only the 8 lsb of each character.
    byte[] msgBytes = msg.getBytes();
    System.out.println(
              "Msg Length = " + msgBytes.length);
    //Create an array to store the bytes
    // containing the pairs of bits.
    byte[] twoBitBytes = 
                   new byte[3 * msgBytes.length];
    
    //Shift and mask the bytes in the array
    // containing the message bytes to get and
    // save the pairs of bits.
    int twoBitByteCnt = 0;
    for(byte element:msgBytes){
      twoBitBytes[twoBitByteCnt++] 
                        = (byte)(element & 0x03);
      twoBitBytes[twoBitByteCnt++] 
                 = (byte)((element >> 2) & 0x03);
      twoBitBytes[twoBitByteCnt++] 
                 = (byte)((element >> 4) & 0x03);
    }//end for loop
    
    //Begin embedding the pairs of message bits
    // at a predetermined pixel location
    // in the image. Two bits from a single 6-bit
    // message character are embedded into the
    // lsb of the red, green, and blue pixel
    // values.  DISABLE THE PIXEL-SKIPPING
    // FEATURE IN THIS VERSION OF THE PROGRAM.
    // EMBED ONE CHARACTER INTO EVERY PIXEL
    // STARTING WITH THE FIRST PIXEL.
    //Specify the predefined insertion point.
    //SET IT TO 0 FOR THIS VERSION OF THE
    // PROGRAM.
    int insertionPoint = 0;
    System.out.println(
          "Insertion point = " + insertionPoint);
    //Use a nested loop to operate on each pixel
    // and to embed message bits into the red,
    // green, and blue values of every pixel.
    twoBitByteCnt = 0;//Re-use this variable
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        //Embed 6-bit message characters
        // into every pixel location.
        if((row * col > insertionPoint) && 
           (twoBitByteCnt < twoBitBytes.length)){
          //Replace the two lsb of the red,
          // green, and blue pixel values with
          // two bits from the six-bit message
          // character.
          temp3D[row][col][1] = 
                (temp3D[row][col][1] & 0xFC)
                  | twoBitBytes[twoBitByteCnt++];
          temp3D[row][col][2] = 
                (temp3D[row][col][2] & 0xFC)
                  | twoBitBytes[twoBitByteCnt++];
          temp3D[row][col][3] = 
                (temp3D[row][col][3] & 0xFC)
                  | twoBitBytes[twoBitByteCnt++];
        }//end if
      }//end for loop on col
    }//end for loop on row
    
    //Up to this point, the program demonstrates
    // how to modify an image to include a hidden
    // message.
    //The remainder of the program demonstrates
    // how to extract that message from the
    // image.  Note that this code requires
    // prior knowledge of the insertion point
    // value.
    //Create an array object large enough to
    // contain one byte for every two-bit byte
    // that can be extracted from every pixel
    // between the insertion point and the end of
    // the message.
    byte[] extractedTwoBitBytes = 
                     new byte[(imgRows * imgCols 
                          - insertionPoint) * 3];
    twoBitByteCnt = 0;
    for(int row = 0;row < imgRows;row++){
      for(int col = 0;col < imgCols;col++){
        if(row * col > insertionPoint){
          //Extract and save the message
          // characters two bits at a time.
          extractedTwoBitBytes[twoBitByteCnt++]
            = (byte)(temp3D[row][col][1] & 0x03);
          extractedTwoBitBytes[twoBitByteCnt++] 
            = (byte)(temp3D[row][col][2] & 0x03);
          extractedTwoBitBytes[twoBitByteCnt++] 
            = (byte)(temp3D[row][col][3] & 0x03);
        }//end if
      }//end for loop on col
    }//end for loop on row
        
    //Reconstruct and display the 64-char version
    // of the message
    StringBuffer extractedMsg = 
                              new StringBuffer();
    byte[] sixBitBytes = 
         new byte[extractedTwoBitBytes.length/3];
    twoBitByteCnt = 0;
    for(byte element:sixBitBytes){
      //Shift and or the pairs of bits into the
      // 6-bit format.
      element = (byte)(extractedTwoBitBytes[
                               twoBitByteCnt++]);
      element = 
          (byte)(element | (extractedTwoBitBytes[
                         twoBitByteCnt++] << 2));
      element = 
          (byte)(element | (extractedTwoBitBytes[
                         twoBitByteCnt++] << 4));
      extractedMsg.append(
                           (char)(element + 32));
      //Stop processing when terminating
      // underscore character is encountered.
      if((char)(element + 32) == '_')break;
    }//end for-each
    
    //Select and print every (6*imgCols + 1)
    // character from the extracted message
    System.out.println(
       "Characters from reconstructed message:");
    for(int cnt = 0;cnt < extractedMsg.length()
                                         ;cnt++){
      if(cnt%(6*imgCols + 1) == 0){
        System.out.print(
                       extractedMsg.charAt(cnt));
      }//end if
    }//end for loop
    System.out.println();//blank line
    //Return the modified image for display.
    return temp3D;
  }//end processImg
  //-------------------------------------------//
}//end class ImgMod28a
Listing 11


Copyright 2005, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP).  His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments.  (TI is still a world leader in DSP.)  In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel