com.aowagie.text.pdf.codec.BmpImage Maven / Gradle / Ivy
/*
* Copyright 2003-2008 by Paulo Soares.
*
* The contents of this file are subject to the Mozilla Public License Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the License.
*
* The Original Code is 'iText, a free JAVA-PDF library'.
*
* The Initial Developer of the Original Code is Bruno Lowagie. Portions created by
* the Initial Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie.
* All Rights Reserved.
* Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer
* are Copyright (C) 2000, 2001, 2002 by Paulo Soares. All Rights Reserved.
*
* Contributor(s): all the names of the contributors are added in the source code
* where applicable.
*
* Alternatively, the contents of this file may be used under the terms of the
* LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), in which case the
* provisions of LGPL are applicable instead of those above. If you wish to
* allow use of your version of this file only under the terms of the LGPL
* License and not to allow others to use your version of this file under
* the MPL, indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by the LGPL.
* If you do not delete the provisions above, a recipient may use your version
* of this file under either the MPL or the GNU LIBRARY GENERAL PUBLIC LICENSE.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the MPL as stated above or under the terms of the GNU
* Library General Public License as published by the Free Software Foundation;
* either version 2 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Library general Public License for more
* details.
*
* If you didn't download this code from the following link, you should check if
* you aren't using an obsolete version:
* http://www.lowagie.com/iText/
*
* This code was originally released in 2001 by SUN (see class
* com.sun.media.imageioimpl.plugins.bmp.BMPImageReader.java)
* using the BSD license in a specific wording. In a mail dating from
* January 23, 2008, Brian Burkhalter (@sun.com) gave us permission
* to use the code under the following version of the BSD license:
*
* Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
* NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
* USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
* ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
* INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for
* use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
package com.aowagie.text.pdf.codec;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.LinkedHashMap;
import com.aowagie.text.BadElementException;
import com.aowagie.text.ExceptionConverter;
import com.aowagie.text.Image;
import com.aowagie.text.ImgRaw;
import com.aowagie.text.pdf.PdfArray;
import com.aowagie.text.pdf.PdfDictionary;
import com.aowagie.text.pdf.PdfName;
import com.aowagie.text.pdf.PdfNumber;
import com.aowagie.text.pdf.PdfString;
/** Reads a BMP image. All types of BMP can be read.
*
* It is based in the JAI codec.
*
* @author Paulo Soares ([email protected])
*/
public class BmpImage {
// BMP variables
private InputStream inputStream;
private long bitmapFileSize;
private long bitmapOffset;
private long compression;
private long imageSize;
private byte palette[];
private int imageType;
private int numBands;
private boolean isBottomUp;
private int bitsPerPixel;
private int redMask, greenMask, blueMask, alphaMask;
private final HashMap properties = new LinkedHashMap();
private long xPelsPerMeter;
private long yPelsPerMeter;
// BMP Image types
private static final int VERSION_2_1_BIT = 0;
private static final int VERSION_2_4_BIT = 1;
private static final int VERSION_2_8_BIT = 2;
private static final int VERSION_2_24_BIT = 3;
private static final int VERSION_3_1_BIT = 4;
private static final int VERSION_3_4_BIT = 5;
private static final int VERSION_3_8_BIT = 6;
private static final int VERSION_3_24_BIT = 7;
private static final int VERSION_3_NT_16_BIT = 8;
private static final int VERSION_3_NT_32_BIT = 9;
private static final int VERSION_4_1_BIT = 10;
private static final int VERSION_4_4_BIT = 11;
private static final int VERSION_4_8_BIT = 12;
private static final int VERSION_4_16_BIT = 13;
private static final int VERSION_4_24_BIT = 14;
private static final int VERSION_4_32_BIT = 15;
// Color space types
private static final int LCS_CALIBRATED_RGB = 0;
private static final int LCS_sRGB = 1;
private static final int LCS_CMYK = 2;
// Compression Types
private static final int BI_RGB = 0;
private static final int BI_RLE8 = 1;
private static final int BI_RLE4 = 2;
private static final int BI_BITFIELDS = 3;
private int width;
private int height;
private BmpImage(final InputStream is, final boolean noHeader, final int size) throws IOException {
this.bitmapFileSize = size;
this.bitmapOffset = 0;
process(is, noHeader);
}
/** Reads a BMP from an url.
* @param url the url
* @throws IOException on error
* @return the image
*/
public static Image getImage(final URL url) throws IOException {
InputStream is = null;
try {
is = url.openStream();
final Image img = getImage(is);
img.setUrl(url);
return img;
}
finally {
if (is != null) {
is.close();
}
}
}
/** Reads a BMP from a stream. The stream is not closed.
* @param is the stream
* @throws IOException on error
* @return the image
*/
private static Image getImage(final InputStream is) throws IOException {
return getImage(is, false, 0);
}
/** Reads a BMP from a stream. The stream is not closed.
* The BMP may not have a header and be considered as a plain DIB.
* @param is the stream
* @param noHeader true to process a plain DIB
* @param size the size of the DIB. Not used for a BMP
* @throws IOException on error
* @return the image
*/
public static Image getImage(final InputStream is, final boolean noHeader, final int size) throws IOException {
final BmpImage bmp = new BmpImage(is, noHeader, size);
try {
final Image img = bmp.getImage();
img.setDpi((int)(bmp.xPelsPerMeter * 0.0254d + 0.5d), (int)(bmp.yPelsPerMeter * 0.0254d + 0.5d));
img.setOriginalType(Image.ORIGINAL_BMP);
return img;
}
catch (final BadElementException be) {
throw new ExceptionConverter(be);
}
}
/** Reads a BMP from a byte array.
* @param data the byte array
* @throws IOException on error
* @return the image
*/
public static Image getImage(final byte data[]) throws IOException {
final ByteArrayInputStream is = new ByteArrayInputStream(data);
final Image img = getImage(is);
img.setOriginalData(data);
return img;
}
private void process(final InputStream stream, final boolean noHeader) throws IOException {
if (noHeader || stream instanceof BufferedInputStream) {
this.inputStream = stream;
} else {
this.inputStream = new BufferedInputStream(stream);
}
if (!noHeader) {
// Start File Header
if (!(readUnsignedByte(this.inputStream) == 'B' &&
readUnsignedByte(this.inputStream) == 'M')) {
throw new
RuntimeException("Invalid magic value for BMP file.");
}
// Read file size
this.bitmapFileSize = readDWord(this.inputStream);
// Read the two reserved fields
readWord(this.inputStream);
readWord(this.inputStream);
// Offset to the bitmap from the beginning
this.bitmapOffset = readDWord(this.inputStream);
// End File Header
}
// Start BitmapCoreHeader
final long size = readDWord(this.inputStream);
if (size == 12) {
this.width = readWord(this.inputStream);
this.height = readWord(this.inputStream);
} else {
this.width = readLong(this.inputStream);
this.height = readLong(this.inputStream);
}
final int planes = readWord(this.inputStream);
this.bitsPerPixel = readWord(this.inputStream);
this.properties.put("color_planes", Integer.valueOf(planes));
this.properties.put("bits_per_pixel", Integer.valueOf(this.bitsPerPixel));
// As BMP always has 3 rgb bands, except for Version 5,
// which is bgra
this.numBands = 3;
if (this.bitmapOffset == 0) {
this.bitmapOffset = size;
}
if (size == 12) {
// Windows 2.x and OS/2 1.x
this.properties.put("bmp_version", "BMP v. 2.x");
// Classify the image type
if (this.bitsPerPixel == 1) {
this.imageType = VERSION_2_1_BIT;
} else if (this.bitsPerPixel == 4) {
this.imageType = VERSION_2_4_BIT;
} else if (this.bitsPerPixel == 8) {
this.imageType = VERSION_2_8_BIT;
} else if (this.bitsPerPixel == 24) {
this.imageType = VERSION_2_24_BIT;
}
// Read in the palette
final int numberOfEntries = (int)((this.bitmapOffset-14-size) / 3);
int sizeOfPalette = numberOfEntries*3;
if (this.bitmapOffset == size) {
switch (this.imageType) {
case VERSION_2_1_BIT:
sizeOfPalette = 2 * 3;
break;
case VERSION_2_4_BIT:
sizeOfPalette = 16 * 3;
break;
case VERSION_2_8_BIT:
sizeOfPalette = 256 * 3;
break;
case VERSION_2_24_BIT:
sizeOfPalette = 0;
break;
}
this.bitmapOffset = size + sizeOfPalette;
}
readPalette(sizeOfPalette);
} else {
this.compression = readDWord(this.inputStream);
this.imageSize = readDWord(this.inputStream);
this.xPelsPerMeter = readLong(this.inputStream);
this.yPelsPerMeter = readLong(this.inputStream);
final long colorsUsed = readDWord(this.inputStream);
final long colorsImportant = readDWord(this.inputStream);
switch((int)this.compression) {
case BI_RGB:
this.properties.put("compression", "BI_RGB");
break;
case BI_RLE8:
this.properties.put("compression", "BI_RLE8");
break;
case BI_RLE4:
this.properties.put("compression", "BI_RLE4");
break;
case BI_BITFIELDS:
this.properties.put("compression", "BI_BITFIELDS");
break;
}
this.properties.put("x_pixels_per_meter", Long.valueOf(this.xPelsPerMeter));
this.properties.put("y_pixels_per_meter", Long.valueOf(this.yPelsPerMeter));
this.properties.put("colors_used", Long.valueOf(colorsUsed));
this.properties.put("colors_important", Long.valueOf(colorsImportant));
if (size == 40) {
// Windows 3.x and Windows NT
switch((int)this.compression) {
case BI_RGB: // No compression
case BI_RLE8: // 8-bit RLE compression
case BI_RLE4: // 4-bit RLE compression
if (this.bitsPerPixel == 1) {
this.imageType = VERSION_3_1_BIT;
} else if (this.bitsPerPixel == 4) {
this.imageType = VERSION_3_4_BIT;
} else if (this.bitsPerPixel == 8) {
this.imageType = VERSION_3_8_BIT;
} else if (this.bitsPerPixel == 24) {
this.imageType = VERSION_3_24_BIT;
} else if (this.bitsPerPixel == 16) {
this.imageType = VERSION_3_NT_16_BIT;
this.redMask = 0x7C00;
this.greenMask = 0x3E0;
this.blueMask = 0x1F;
this.properties.put("red_mask", Integer.valueOf(this.redMask));
this.properties.put("green_mask", Integer.valueOf(this.greenMask));
this.properties.put("blue_mask", Integer.valueOf(this.blueMask));
} else if (this.bitsPerPixel == 32) {
this.imageType = VERSION_3_NT_32_BIT;
this.redMask = 0x00FF0000;
this.greenMask = 0x0000FF00;
this.blueMask = 0x000000FF;
this.properties.put("red_mask", Integer.valueOf(this.redMask));
this.properties.put("green_mask", Integer.valueOf(this.greenMask));
this.properties.put("blue_mask", Integer.valueOf(this.blueMask));
}
// Read in the palette
final int numberOfEntries = (int)((this.bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries*4;
if (this.bitmapOffset == size) {
switch (this.imageType) {
case VERSION_3_1_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 2 : colorsUsed) * 4;
break;
case VERSION_3_4_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 16 : colorsUsed) * 4;
break;
case VERSION_3_8_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 256 : colorsUsed) * 4;
break;
default:
sizeOfPalette = 0;
break;
}
this.bitmapOffset = size + sizeOfPalette;
}
readPalette(sizeOfPalette);
this.properties.put("bmp_version", "BMP v. 3.x");
break;
case BI_BITFIELDS:
if (this.bitsPerPixel == 16) {
this.imageType = VERSION_3_NT_16_BIT;
} else if (this.bitsPerPixel == 32) {
this.imageType = VERSION_3_NT_32_BIT;
}
// BitsField encoding
this.redMask = (int)readDWord(this.inputStream);
this.greenMask = (int)readDWord(this.inputStream);
this.blueMask = (int)readDWord(this.inputStream);
this.properties.put("red_mask", Integer.valueOf(this.redMask));
this.properties.put("green_mask", Integer.valueOf(this.greenMask));
this.properties.put("blue_mask", Integer.valueOf(this.blueMask));
if (colorsUsed != 0) {
// there is a palette
sizeOfPalette = (int)colorsUsed*4;
readPalette(sizeOfPalette);
}
this.properties.put("bmp_version", "BMP v. 3.x NT");
break;
default:
throw new
RuntimeException("Invalid compression specified in BMP file.");
}
} else if (size == 108) {
// Windows 4.x BMP
this.properties.put("bmp_version", "BMP v. 4.x");
// rgb masks, valid only if comp is BI_BITFIELDS
this.redMask = (int)readDWord(this.inputStream);
this.greenMask = (int)readDWord(this.inputStream);
this.blueMask = (int)readDWord(this.inputStream);
// Only supported for 32bpp BI_RGB argb
this.alphaMask = (int)readDWord(this.inputStream);
final long csType = readDWord(this.inputStream);
final int redX = readLong(this.inputStream);
final int redY = readLong(this.inputStream);
final int redZ = readLong(this.inputStream);
final int greenX = readLong(this.inputStream);
final int greenY = readLong(this.inputStream);
final int greenZ = readLong(this.inputStream);
final int blueX = readLong(this.inputStream);
final int blueY = readLong(this.inputStream);
final int blueZ = readLong(this.inputStream);
final long gammaRed = readDWord(this.inputStream);
final long gammaGreen = readDWord(this.inputStream);
final long gammaBlue = readDWord(this.inputStream);
if (this.bitsPerPixel == 1) {
this.imageType = VERSION_4_1_BIT;
} else if (this.bitsPerPixel == 4) {
this.imageType = VERSION_4_4_BIT;
} else if (this.bitsPerPixel == 8) {
this.imageType = VERSION_4_8_BIT;
} else if (this.bitsPerPixel == 16) {
this.imageType = VERSION_4_16_BIT;
if ((int)this.compression == BI_RGB) {
this.redMask = 0x7C00;
this.greenMask = 0x3E0;
this.blueMask = 0x1F;
}
} else if (this.bitsPerPixel == 24) {
this.imageType = VERSION_4_24_BIT;
} else if (this.bitsPerPixel == 32) {
this.imageType = VERSION_4_32_BIT;
if ((int)this.compression == BI_RGB) {
this.redMask = 0x00FF0000;
this.greenMask = 0x0000FF00;
this.blueMask = 0x000000FF;
}
}
this.properties.put("red_mask", Integer.valueOf(this.redMask));
this.properties.put("green_mask", Integer.valueOf(this.greenMask));
this.properties.put("blue_mask", Integer.valueOf(this.blueMask));
this.properties.put("alpha_mask", Integer.valueOf(this.alphaMask));
// Read in the palette
final int numberOfEntries = (int)((this.bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries*4;
if (this.bitmapOffset == size) {
switch (this.imageType) {
case VERSION_4_1_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 2 : colorsUsed) * 4;
break;
case VERSION_4_4_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 16 : colorsUsed) * 4;
break;
case VERSION_4_8_BIT:
sizeOfPalette = (int)(colorsUsed == 0 ? 256 : colorsUsed) * 4;
break;
default:
sizeOfPalette = 0;
break;
}
this.bitmapOffset = size + sizeOfPalette;
}
readPalette(sizeOfPalette);
switch((int)csType) {
case LCS_CALIBRATED_RGB:
// All the new fields are valid only for this case
this.properties.put("color_space", "LCS_CALIBRATED_RGB");
this.properties.put("redX", Integer.valueOf(redX));
this.properties.put("redY", Integer.valueOf(redY));
this.properties.put("redZ", Integer.valueOf(redZ));
this.properties.put("greenX", Integer.valueOf(greenX));
this.properties.put("greenY", Integer.valueOf(greenY));
this.properties.put("greenZ", Integer.valueOf(greenZ));
this.properties.put("blueX", Integer.valueOf(blueX));
this.properties.put("blueY", Integer.valueOf(blueY));
this.properties.put("blueZ", Integer.valueOf(blueZ));
this.properties.put("gamma_red", Long.valueOf(gammaRed));
this.properties.put("gamma_green", Long.valueOf(gammaGreen));
this.properties.put("gamma_blue", Long.valueOf(gammaBlue));
// break;
throw new
RuntimeException("Not implemented yet.");
case LCS_sRGB:
// Default Windows color space
this.properties.put("color_space", "LCS_sRGB");
break;
case LCS_CMYK:
this.properties.put("color_space", "LCS_CMYK");
// break;
throw new
RuntimeException("Not implemented yet.");
}
} else {
this.properties.put("bmp_version", "BMP v. 5.x");
throw new
RuntimeException("BMP version 5 not implemented yet.");
}
}
if (this.height > 0) {
// bottom up image
this.isBottomUp = true;
} else {
// top down image
this.isBottomUp = false;
this.height = Math.abs(this.height);
}
// When number of bitsPerPixel is <= 8, we use IndexColorModel.
if (this.bitsPerPixel == 1 || this.bitsPerPixel == 4 || this.bitsPerPixel == 8) {
this.numBands = 1;
// Create IndexColorModel from the palette.
byte r[], g[], b[];
int sizep;
if (this.imageType == VERSION_2_1_BIT ||
this.imageType == VERSION_2_4_BIT ||
this.imageType == VERSION_2_8_BIT) {
sizep = this.palette.length/3;
if (sizep > 256) {
sizep = 256;
}
int off;
r = new byte[sizep];
g = new byte[sizep];
b = new byte[sizep];
for (int i=0; i 256) {
sizep = 256;
}
int off;
r = new byte[sizep];
g = new byte[sizep];
b = new byte[sizep];
for (int i=0; i>>= 1;
}
return mask;
}
private int findShift(int mask) {
int k = 0;
for (; k < 32; ++k) {
if ((mask & 1) == 1) {
break;
}
mask >>>= 1;
}
return k;
}
private Image read1632Bit(final boolean is32) throws IOException, BadElementException {
final int red_mask = findMask(this.redMask);
final int red_shift = findShift(this.redMask);
final int red_factor = red_mask + 1;
final int green_mask = findMask(this.greenMask);
final int green_shift = findShift(this.greenMask);
final int green_factor = green_mask + 1;
final int blue_mask = findMask(this.blueMask);
final int blue_shift = findShift(this.blueMask);
final int blue_factor = blue_mask + 1;
final byte bdata[] = new byte[this.width * this.height * 3];
// Padding bytes at the end of each scanline
int padding = 0;
if (!is32) {
// width * bitsPerPixel should be divisible by 32
final int bitsPerScanline = this.width * 16;
if ( bitsPerScanline%32 != 0) {
padding = (bitsPerScanline/32 + 1)*32 - bitsPerScanline;
padding = (int)Math.ceil(padding/8.0);
}
}
int imSize = (int)this.imageSize;
if (imSize == 0) {
imSize = (int)(this.bitmapFileSize - this.bitmapOffset);
}
int l=0;
int v;
if (this.isBottomUp) {
for (int i=this.height - 1; i >= 0; --i) {
l = this.width * 3 * i;
for (int j=0; j>> red_shift & red_mask) * 256 / red_factor);
bdata[l++] = (byte)((v >>> green_shift & green_mask) * 256 / green_factor);
bdata[l++] = (byte)((v >>> blue_shift & blue_mask) * 256 / blue_factor);
}
for (int m=0; m>> red_shift & red_mask) * 256 / red_factor);
bdata[l++] = (byte)((v >>> green_shift & green_mask) * 256 / green_factor);
bdata[l++] = (byte)((v >>> blue_shift & blue_mask) * 256 / blue_factor);
}
for (int m=0; m= 0; i--) {
index = i * this.width;
lineEnd = l + this.width;
while(l != lineEnd) {
val[l++] = inverted[index++];
}
}
}
final int stride = (this.width + 1) / 2;
final byte bdata[] = new byte[stride * this.height];
int ptr = 0;
int sh = 0;
for (int h = 0; h < this.height; ++h) {
for (int w = 0; w < this.width; ++w) {
if ((w & 1) == 0) {
bdata[sh + w / 2] = (byte)(val[ptr++] << 4);
} else {
bdata[sh + w / 2] |= (byte)(val[ptr++] & 0x0f);
}
}
sh += stride;
}
return indexedModel(bdata, 4, 4);
}
private byte[] decodeRLE(final boolean is8, final byte values[]) {
final byte val[] = new byte[this.width * this.height];
try {
int ptr = 0;
int x = 0;
int q = 0;
for (int y = 0; y < this.height && ptr < values.length;) {
int count = values[ptr++] & 0xff;
if (count != 0) {
// encoded mode
final int bt = values[ptr++] & 0xff;
if (is8) {
for (int i = count; i != 0; --i) {
val[q++] = (byte)bt;
}
}
else {
for (int i = 0; i < count; ++i) {
val[q++] = (byte)((i & 1) == 1 ? bt & 0x0f : bt >>> 4 & 0x0f);
}
}
x += count;
}
else {
// escape mode
count = values[ptr++] & 0xff;
if (count == 1) {
break;
}
switch (count) {
case 0:
x = 0;
++y;
q = y * this.width;
break;
case 2:
// delta mode
x += values[ptr++] & 0xff;
y += values[ptr++] & 0xff;
q = y * this.width + x;
break;
default:
// absolute mode
if (is8) {
for (int i = count; i != 0; --i) {
val[q++] = (byte)(values[ptr++] & 0xff);
}
}
else {
int bt = 0;
for (int i = 0; i < count; ++i) {
if ((i & 1) == 0) {
bt = values[ptr++] & 0xff;
}
val[q++] = (byte)((i & 1) == 1 ? bt & 0x0f : bt >>> 4 & 0x0f);
}
}
x += count;
// read pad byte
if (is8) {
if ((count & 1) == 1) {
++ptr;
}
}
else {
if ((count & 3) == 1 || (count & 3) == 2) {
++ptr;
}
}
break;
}
}
}
}
catch (final RuntimeException e) {
//empty on purpose
}
return val;
}
// Windows defined data type reading methods - everything is little endian
// Unsigned 8 bits
private int readUnsignedByte(final InputStream stream) throws IOException {
return stream.read() & 0xff;
}
// Unsigned 2 bytes
private int readUnsignedShort(final InputStream stream) throws IOException {
final int b1 = readUnsignedByte(stream);
final int b2 = readUnsignedByte(stream);
return (b2 << 8 | b1) & 0xffff;
}
// Signed 16 bits
private int readShort(final InputStream stream) throws IOException {
final int b1 = readUnsignedByte(stream);
final int b2 = readUnsignedByte(stream);
return b2 << 8 | b1;
}
// Unsigned 16 bits
private int readWord(final InputStream stream) throws IOException {
return readUnsignedShort(stream);
}
// Unsigned 4 bytes
private long readUnsignedInt(final InputStream stream) throws IOException {
final int b1 = readUnsignedByte(stream);
final int b2 = readUnsignedByte(stream);
final int b3 = readUnsignedByte(stream);
final int b4 = readUnsignedByte(stream);
final long l = b4 << 24 | b3 << 16 | b2 << 8 | b1;
return l & 0xffffffff;
}
// Signed 4 bytes
private int readInt(final InputStream stream) throws IOException {
final int b1 = readUnsignedByte(stream);
final int b2 = readUnsignedByte(stream);
final int b3 = readUnsignedByte(stream);
final int b4 = readUnsignedByte(stream);
return b4 << 24 | b3 << 16 | b2 << 8 | b1;
}
// Unsigned 4 bytes
private long readDWord(final InputStream stream) throws IOException {
return readUnsignedInt(stream);
}
// 32 bit signed value
private int readLong(final InputStream stream) throws IOException {
return readInt(stream);
}
}