![]() |
|||
![]() ![]() |
![]() |
|
![]() |
Little-Endian data To read Little-Endian data, you first read the necessary number of bytes into an array. Then you use the << bit shift operator and the | operator to put the parts of the Little-Endian number back together in the right order. public static int readLittleEndianInt(InputStream is) throws IOException { int result; byte[] buffer = new byte[4]; int check = is.read(buffer); if (check != 4) throw new IOException("Unexpected End of Stream"); result = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0]; return result; } Longs are just the same except you have to use an 8-byte buffer and put eight pieces back together. To write Little-Endian data, you create a buffer for the bytes in an int. The bytes are extracted from the int by a simple cast. Recall that casting an int to a byte truncates the int to its least significant byte. Before the cast is done, the right shift operator >> moves the needed byte into position in the least significant byte. public static void writeLittleEndianInt(int i, OutputStream os) throws IOException { int result; byte[] buffer = new byte[4]; buffer[0] = (byte) i; buffer[1] = (byte) (i >> 8); buffer[2] = (byte) (i >> 16); buffer[3] = (byte) (i >> 24); os.write(buffer); } Unsigned integers java.io.DataInputStream has methods to read unsigned bytes and unsigned shorts, but nothing to read an unsigned int. To do that, you must read four bytes and use them to construct the lower four bytes of a long. The upper four bytes of the long will be zero. For example: public static long readUnsignedInt(InputStream is) throws IOException { byte[] buffer = new byte[4]; int check = is.read(buffer); if (check != 4) throw new IOException("Unexpected End of Stream"); long result = 0L; // move the bytes into position result = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; // zero out the upper four bytes result &= 0xFFFFFFFF; return result; } Its necessary to combine the result with 0xFFFFFFFF using a bitwise and to make sure that none of the bytes were sign extended into negative numbers when left-shifted. Image manipulation with bit shift operators Bit shift operators are fairly obscure. One of the few areas of Java where theyre useful is working with images and image filters. Java images are built with a 32-bit color model. Each color has four channels: alpha, red, green, and blue. The alpha channel represents transparency. The other three channels are the primary colors for an additive color system. Each of the four channels has a value from 0 to 255 (in other words, one unsigned byte). For the color channels, the higher the value, the brighter the color. For the alpha channel, the higher the value, the more opaque the image is.
Figure 2-9 shows a color that is 50 percent gray. The alpha channel is 255 (11111111), which is fully opaque, while each of the red, green, and blue channels is set to 127. This means the color is equal to the integer 111111011111110111111101111111. The integer value has little meaning here, though; its the individual bytes that matter.
When the red channel, green channel, and blue channel have the same value, the resulting image varies from black (all three 00000000) to white (all three 11111111). It passes through various shades of gray in between. By varying the colors disproportionately, you can produce the different colors of the visible spectrum. For example, pure blue is 11111111000000-001111111100000000. So how do you create these colors? Its simple, really. Just initialize ints to the values you want for each of the four channels, shift them into place, and combine them with the bitwise OR operator, |. For example, to create a pure blue, do the following: int alpha = 255 << 24; int red = 0 << 16; int blue = 255 << 8; int green = 0; int pureblue = alpha | red | green | blue; If you prefer, you can combine these on one line. For example, to create the 50 percent gray of Figure 2-9, use this command: int halfgray = (255 << 24) | (127 << 16) | (127 << 8) | 127; SummaryIn this chapter you learn how a computer stores numbers. You learn what a place-value number system is, and about the binary and hexadecimal place-value number systems computers use. You learn how the primitive Java data types like int and float are laid out in memory and how this affects operations with those types. You also learn how Java stores characters and the different character sets used for this purpose, particularly ASCII, ISO Latin-1, Unicode, and UTF8. You learn when and for what purposes these different but related character sets are used and how to convert from one to another. Finally, you learn how to use the bit-level operators to operate on numbers at a very low level. The bitwise operators combine values in memory, while the bitshift operators move the bits in data back and forth.
|
![]() |
|