001 /* 002 * ArrayConverter 003 * 004 * Copyright (c) 2002, 2003 Marco Schmidt. 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.util; 009 010 /** 011 * Helper class with static methods to convert between byte arrays and primitive types. 012 * Useful for serialization. 013 * @author Marco Schmidt 014 * @since 0.9.0 015 */ 016 public class ArrayConverter 017 { 018 private static final int SHORT_SIZE = 2; 019 private static final int INT_SIZE = 4; 020 021 private ArrayConverter() 022 { 023 } 024 025 /** 026 * Makes sure that the arguments define a valid (existing) array interval. 027 * This includes: 028 * <ul> 029 * <li>array is non-null</li> 030 * <li>offset is >= 0 and smaller than array.length</li> 031 * <li>length is > 0</li> 032 * <li>offset + length is <= array.length</li> 033 * </ul> 034 */ 035 private static void checkArray(byte[] array, int offset, int length) throws IllegalArgumentException 036 { 037 if (array == null) 038 { 039 throw new IllegalArgumentException("Array must not be null."); 040 } 041 if (offset < 0) 042 { 043 throw new IllegalArgumentException("Array index must not be negative."); 044 } 045 if (length < 1) 046 { 047 throw new IllegalArgumentException("Length of value must not be smaller than one."); 048 } 049 if (offset >= array.length) 050 { 051 throw new IllegalArgumentException("Offset " + offset + 052 " is invalid, must be smaller than array length " + 053 array.length + "."); 054 } 055 if (offset + length > array.length) 056 { 057 throw new IllegalArgumentException("Value of length " + 058 length + " does not fit at offset " + offset + 059 " into an array of length " + array.length + "."); 060 } 061 } 062 063 /*public static void convertPacked2BitIntensityTo8BitA(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes) 064 { 065 final byte[] DEST_VALUES = {0, 85, (byte)170, (byte)255}; 066 while (numPackedBytes-- > 0) 067 { 068 int srcValue = src[srcOffset++] & 0xff; 069 dest[destOffset++] = DEST_VALUES[(srcValue >> 6) & 3]; 070 dest[destOffset++] = DEST_VALUES[(srcValue >> 4) & 3]; 071 dest[destOffset++] = DEST_VALUES[(srcValue >> 2) & 3]; 072 dest[destOffset++] = DEST_VALUES[srcValue & 3]; 073 } 074 }*/ 075 076 /** 077 * Converts bytes with two four-bit-intensity samples to 8 byte intensity 078 * values, each stored in one byte. 079 * Two-bit values can be 0, 1, 2 or 3. 080 * These values will be scaled to the full [0;255] range so that 0 remains 0, 081 * 1 becomes 85, 2 becomes 170 and 3 becomes 255. 082 * <p> 083 * A little discussion on how to implement this method 084 * was held in the German Java newsgroup 085 * <a href="news:de.comp.lang.java">de.comp.lang.java</a>. 086 * The message I wrote to start the thread has the ID 087 * <code>1ef7du4vfqsd2pskb6jukut6pnhn87htt2@4ax.com</code>. 088 * Read the 089 * <a target="_top" href="http://groups.google.com/groups?as_umsgid=1ef7du4vfqsd2pskb6jukut6pnhn87htt2@4ax.com">thread 090 * at Google Groups</a>. 091 * @param src byte array, each byte stores four two-bit intensity values 092 * @param srcOffset index into src 093 * @param dest byte array, each byte stores an eight-bit intensity values 094 * @param destOffset index into dest 095 * @param numPackedBytes number of bytes in src to be decoded 096 */ 097 public static void convertPacked2BitIntensityTo8Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes) 098 { 099 while (numPackedBytes-- > 0) 100 { 101 int srcValue = src[srcOffset++] & 0xff; 102 dest[destOffset++] = (byte)(((srcValue >> 6) & 3) * 85); 103 dest[destOffset++] = (byte)(((srcValue >> 4) & 3) * 85); 104 dest[destOffset++] = (byte)(((srcValue >> 2) & 3) * 85); 105 dest[destOffset++] = (byte)((srcValue & 3) * 85); 106 } 107 } 108 109 /** 110 * Converts bytes with four two-bit-intensity samples to byte-sized intensity values. 111 * Four-bit values can be from 0 to 15. 112 * These values will be scaled to the full [0;255] range so that 0 remains 0, 113 * 1 becomes 17, 2 becomes 34, ..., and 15 becomes 255. 114 * The most significant four bits in a byte become the left, the least significant 115 * four bits the right pixel. 116 * @param src byte array, each byte stores two four-bit intensity values 117 * @param srcOffset index into src 118 * @param dest byte array, each byte stores an eight-bit intensity values 119 * @param destOffset index into dest 120 * @param numPackedBytes number of bytes in src to be decoded 121 * @since 0.12.0 122 */ 123 public static void convertPacked4BitIntensityTo8Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes) 124 { 125 while (numPackedBytes-- > 0) 126 { 127 int srcValue = src[srcOffset++] & 0xff; 128 dest[destOffset++] = (byte)((srcValue & 0xf0) | ((srcValue & 0xf0) >> 4)); 129 dest[destOffset++] = (byte)((srcValue & 0x0f) | ((srcValue & 0x0f) << 4)); 130 } 131 } 132 133 /** 134 * Copies a number of bit values from one byte array to another. 135 * @param src array from which is copied 136 * @param srcOffset index into the src array of the first byte from which is copied 137 * @param srcBitOffset first bit within src[srcOffset] from which is copied (0 is left-most, 1 is second left-most, 7 is right-most) 138 * @param dest array to which is copied 139 * @param destOffset index into the dest array of the first byte to which is copied 140 * @param destBitOffset first bit within dest[destOffset] to which is copied (0 is left-most, 1 is second left-most, 7 is right-most) 141 * @param numSamples number of bits to be copied 142 */ 143 public static void copyPackedBytes(byte[] src, int srcOffset, int srcBitOffset, byte[] dest, int destOffset, int destBitOffset, int numSamples) 144 { 145 if (numSamples < 0) 146 { 147 throw new IllegalArgumentException("Number of samples to be copied must be 0 or larger."); 148 } 149 if (srcBitOffset == 0 && destBitOffset == 0 && numSamples > 7) 150 { 151 int bytes = numSamples >> 3; 152 System.arraycopy(src, srcOffset, dest, destOffset, bytes); 153 srcOffset += bytes; 154 destOffset += bytes; 155 numSamples &= 7; 156 } 157 int srcMask = 1 << (7 - srcBitOffset); 158 int destMask = 1 << (7 - destBitOffset); 159 while (numSamples-- != 0) 160 { 161 if ((src[srcOffset] & srcMask) == 0) 162 { 163 dest[destOffset] &= (byte)(255 - destMask); 164 } 165 else 166 { 167 dest[destOffset] |= (byte)destMask; 168 } 169 if (srcMask == 1) 170 { 171 srcMask = 128; 172 srcOffset++; 173 } 174 else 175 { 176 srcMask >>= 1; 177 } 178 if (destMask == 1) 179 { 180 destMask = 128; 181 destOffset++; 182 } 183 else 184 { 185 destMask >>= 1; 186 } 187 } 188 } 189 190 public static void decodePacked1Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes) 191 { 192 while (numPackedBytes-- != 0) 193 { 194 int srcValue = src[srcOffset++] & 0xff; 195 dest[destOffset++] = (byte)((srcValue >> 7) & 0x01); 196 dest[destOffset++] = (byte)((srcValue >> 6) & 0x01); 197 dest[destOffset++] = (byte)((srcValue >> 5) & 0x01); 198 dest[destOffset++] = (byte)((srcValue >> 4) & 0x01); 199 dest[destOffset++] = (byte)((srcValue >> 3) & 0x01); 200 dest[destOffset++] = (byte)((srcValue >> 2) & 0x01); 201 dest[destOffset++] = (byte)((srcValue >> 1) & 0x01); 202 dest[destOffset++] = (byte)(srcValue & 0x01); 203 } 204 } 205 206 /** 207 * Decodes bytes with four two-bit samples to single bytes. 208 * The two most significant bits of a source byte become the first value, 209 * the two least significant bits the fourth value. 210 * The method expects <code>numPackedBytes</code> bytes at <code>src[srcOffset]</code> 211 * (these will be read and interpreted) and 212 * <code>numPackedBytes * 4</code> at <code>dest[destOffset]</code> (where the decoded 213 * byte values will be stored. 214 * <p> 215 * @param src byte array, each byte stores four two-bit values 216 * @param srcOffset index into src 217 * @param dest byte array, each byte stores a single decoded value (from 0 to 3) 218 * @param destOffset index into dest 219 * @param numPackedBytes number of bytes in src to be decoded 220 * @since 0.10.0 221 */ 222 public static void decodePacked2Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes) 223 { 224 while (numPackedBytes-- != 0) 225 { 226 int srcValue = src[srcOffset++] & 0xff; 227 dest[destOffset++] = (byte)(srcValue >> 6); 228 dest[destOffset++] = (byte)((srcValue >> 4) & 0x03); 229 dest[destOffset++] = (byte)((srcValue >> 2) & 0x03); 230 dest[destOffset++] = (byte)(srcValue & 0x03); 231 } 232 } 233 234 /** 235 * Decodes bytes with two four-bit samples to single bytes. 236 * The four most significant bits of a source byte become the first value, 237 * the least significant four bits the second value. 238 * The method expects <code>numPackedBytes</code> bytes at <code>src[srcOffset]</code> 239 * (these will be read and interpreted) and 240 * <code>numPackedBytes * 2</code> at <code>dest[destOffset]</code> (where the decoded 241 * byte values will be stored. 242 * <p> 243 * @param src byte array, each byte stores two four-bit values 244 * @param srcOffset index into src 245 * @param dest byte array, each byte stores a single decoded value 246 * @param destOffset index into dest 247 * @param numPackedBytes number of bytes in src to be decoded 248 */ 249 public static void decodePacked4Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes) 250 { 251 while (numPackedBytes-- > 0) 252 { 253 int srcValue = src[srcOffset++] & 0xff; 254 dest[destOffset++] = (byte)(srcValue >> 4); 255 dest[destOffset++] = (byte)(srcValue & 0x0f); 256 } 257 } 258 259 /** 260 * Convert 16 bit RGB samples stored in big endian (BE) byte order 261 * with 5 bits for red and blue and 6 bits for green to 24 262 * bit RGB byte samples. 263 * @since 0.10.0 264 */ 265 public static void decodePackedRGB565BigEndianToRGB24(byte[] src, int srcOffset, 266 byte[] red, int redOffset, 267 byte[] green, int greenOffset, 268 byte[] blue, int blueOffset, 269 int numPixels) 270 { 271 while (numPixels-- != 0) 272 { 273 int pixel = ((src[srcOffset] & 0xff) << 8) | (src[srcOffset + 1] & 0xff); 274 srcOffset += 2; 275 int r = (pixel >> 11) & 0x1f; 276 int g = (pixel >> 5) & 0x3f; 277 int b = pixel & 0x1f; 278 red[redOffset++] = (byte)((r << 3) | ((r >> 2) & 0x07)); 279 green[greenOffset++] = (byte)((g << 2) | ((g >> 4) & 0x03)); 280 blue[blueOffset++] = (byte)((b << 3) | ((b >>2) & 0x07)); 281 } 282 } 283 284 public static void encodePacked2Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numSamples) 285 { 286 int numBytes = numSamples / 4; 287 while (numBytes-- != 0) 288 { 289 int b1 = src[srcOffset++] & 3; 290 int b2 = src[srcOffset++] & 3; 291 int b3 = src[srcOffset++] & 3; 292 int b4 = src[srcOffset++] & 3; 293 dest[destOffset++] = (byte)(b1 << 6 | b2 << 4 | b3 << 2 | b4); 294 } 295 numSamples = numSamples % 4; 296 if (numSamples > 0) 297 { 298 int value = 0; 299 int mask = 6; 300 while (numSamples-- != 0) 301 { 302 value |= ((src[srcOffset++] & 3) << mask); 303 mask -= 2; 304 } 305 dest[destOffset] = (byte)value; 306 } 307 } 308 309 public static void encodePacked4Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numSamples) 310 { 311 int numBytes = numSamples / 2; 312 while (numBytes-- != 0) 313 { 314 int b1 = src[srcOffset++] & 15; 315 int b2 = src[srcOffset++] & 15; 316 dest[destOffset++] = (byte)(b1 << 4 | b2); 317 } 318 if ((numSamples % 2) == 1) 319 { 320 dest[destOffset] = (byte)((src[srcOffset] & 15) << 4); 321 } 322 } 323 324 /** 325 * Convert 24 bit RGB pixels to 16 bit pixels stored in big endian (BE) byte order 326 * with 5 bits for red and blue and 6 bits for green. 327 * @since 0.10.0 328 */ 329 public static void encodeRGB24ToPackedRGB565BigEndian( 330 byte[] red, int redOffset, 331 byte[] green, int greenOffset, 332 byte[] blue, int blueOffset, 333 byte[] dest, int destOffset, 334 int numPixels) 335 { 336 while (numPixels-- != 0) 337 { 338 int r = (red[redOffset++] & 0xff) >> 3; 339 int g = (green[greenOffset++] & 0xff) >> 2; 340 int b = (blue[blueOffset++] & 0xff) >> 3; 341 int pixel = r << 11 | g << 5 | b; 342 dest[destOffset++] = (byte)(pixel >> 8); 343 dest[destOffset++] = (byte)(pixel & 0xff); 344 } 345 } 346 347 /** 348 * Reads four consecutive bytes from the given array at the 349 * given position in big endian order and returns them as 350 * an <code>int</code>. 351 * @param src the array from which bytes are read 352 * @param srcOffset the index into the array from which the bytes are read 353 * @return int value taken from the array 354 */ 355 public static int getIntBE(byte[] src, int srcOffset) 356 { 357 checkArray(src, srcOffset, INT_SIZE); 358 return 359 (src[srcOffset + 3] & 0xff) | 360 ((src[srcOffset + 2] & 0xff) << 8) | 361 ((src[srcOffset + 1] & 0xff) << 16) | 362 ((src[srcOffset] & 0xff) << 24); 363 } 364 365 /** 366 * Reads four consecutive bytes from the given array at the 367 * given position in little endian order and returns them as 368 * an <code>int</code>. 369 * @param src the array from which bytes are read 370 * @param srcOffset the index into the array from which the bytes are read 371 * @return short value taken from the array 372 */ 373 public static int getIntLE(byte[] src, int srcOffset) 374 { 375 checkArray(src, srcOffset, INT_SIZE); 376 return 377 (src[srcOffset] & 0xff) | 378 ((src[srcOffset + 1] & 0xff) << 8) | 379 ((src[srcOffset + 2] & 0xff) << 16) | 380 ((src[srcOffset + 3] & 0xff) << 24); 381 } 382 383 /** 384 * Reads two consecutive bytes from the given array at the 385 * given position in big endian order and returns them as 386 * a <code>short</code>. 387 * @param src the array from which two bytes are read 388 * @param srcOffset the index into the array from which the two bytes are read 389 * @return short value taken from the array 390 */ 391 public static short getShortBE(byte[] src, int srcOffset) 392 { 393 checkArray(src, srcOffset, SHORT_SIZE); 394 return (short) 395 (((src[srcOffset++] & 0xff) << 8) | 396 (src[srcOffset++] & 0xff)); 397 } 398 399 /** 400 * Reads two consecutive bytes from the given array at the 401 * given position in little endian order and returns them as 402 * a <code>short</code>. 403 * @param src the array from which two bytes are read 404 * @param srcOffset the index into the array from which the two bytes are read 405 * @return short value taken from the array 406 */ 407 public static short getShortLE(byte[] src, int srcOffset) 408 { 409 checkArray(src, srcOffset, SHORT_SIZE); 410 return (short) 411 ((src[srcOffset++] & 0xff) | 412 ((src[srcOffset++] & 0xff) << 8)); 413 } 414 415 /** 416 * Writes an int value into four consecutive bytes of a byte array, 417 * in big endian (network) byte order. 418 * @param dest the array to which bytes are written 419 * @param destOffset index of the array to which the first byte is written 420 * @param newValue the int value to be written to the array 421 */ 422 public static void setIntBE(byte[] dest, int destOffset, int newValue) 423 { 424 checkArray(dest, destOffset, INT_SIZE); 425 dest[destOffset] = (byte)((newValue >> 24)& 0xff); 426 dest[destOffset + 1] = (byte)((newValue >> 16)& 0xff); 427 dest[destOffset + 2] = (byte)((newValue >> 8)& 0xff); 428 dest[destOffset + 3] = (byte)(newValue & 0xff); 429 } 430 431 /** 432 * Writes an int value into four consecutive bytes of a byte array, 433 * in little endian (Intel) byte order. 434 * @param dest the array to which bytes are written 435 * @param destOffset index of the array to which the first byte is written 436 * @param newValue the int value to be written to the array 437 */ 438 public static void setIntLE(byte[] dest, int destOffset, int newValue) 439 { 440 checkArray(dest, destOffset, INT_SIZE); 441 dest[destOffset] = (byte)(newValue & 0xff); 442 dest[destOffset + 1] = (byte)((newValue >> 8)& 0xff); 443 dest[destOffset + 2] = (byte)((newValue >> 16)& 0xff); 444 dest[destOffset + 3] = (byte)((newValue >> 24)& 0xff); 445 } 446 447 public static void setShortBE(byte[] dest, int destOffset, short newValue) 448 { 449 checkArray(dest, destOffset, SHORT_SIZE); 450 dest[destOffset] = (byte)((newValue >> 8) & 0xff); 451 dest[destOffset + 1] = (byte)(newValue & 0xff); 452 } 453 454 public static void setShortLE(byte[] dest, int destOffset, short newValue) 455 { 456 checkArray(dest, destOffset, SHORT_SIZE); 457 dest[destOffset + 1] = (byte)((newValue >> 8) & 0xff); 458 dest[destOffset] = (byte)(newValue & 0xff); 459 } 460 461 }