Categories:
Audio (13)
Biotech (29)
Bytecode (36)
Database (77)
Framework (7)
Game (7)
General (507)
Graphics (53)
I/O (35)
IDE (2)
JAR Tools (102)
JavaBeans (21)
JDBC (121)
JDK (426)
JSP (20)
Logging (108)
Mail (58)
Messaging (8)
Network (84)
PDF (97)
Report (7)
Scripting (84)
Security (32)
Server (121)
Servlet (26)
SOAP (24)
Testing (54)
Web (15)
XML (322)
Collections:
Other Resources:
JDK 17 java.desktop.jmod - Desktop Module
JDK 17 java.desktop.jmod is the JMOD file for JDK 17 Desktop module.
JDK 17 Desktop module compiled class files are stored in \fyicenter\jdk-17.0.5\jmods\java.desktop.jmod.
JDK 17 Desktop module compiled class files are also linked and stored in the \fyicenter\jdk-17.0.5\lib\modules JImage file.
JDK 17 Desktop module source code files are stored in \fyicenter\jdk-17.0.5\lib\src.zip\java.desktop.
You can click and view the content of each source code file in the list below.
✍: FYIcenter
⏎ com/sun/imageio/plugins/bmp/BMPImageReader.java
/*
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package com.sun.imageio.plugins.bmp;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.ComponentSampleModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferInt;
import java.awt.image.DataBufferUShort;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.MultiPixelPackedSampleModel;
import java.awt.image.PixelInterleavedSampleModel;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.event.IIOReadProgressListener;
import javax.imageio.event.IIOReadUpdateListener;
import javax.imageio.event.IIOReadWarningListener;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import com.sun.imageio.plugins.common.I18N;
import com.sun.imageio.plugins.common.ImageUtil;
import com.sun.imageio.plugins.common.ReaderUtil;
/** This class is the Java Image IO plugin reader for BMP images.
* It may subsample the image, clip the image, select sub-bands,
* and shift the decoded image origin if the proper decoding parameter
* are set in the provided {@code ImageReadParam}.
*
* This class supports Microsoft Windows Bitmap Version 3-5,
* as well as OS/2 Bitmap Version 2.x (for single-image BMP file).
* It also supports undocumented DIB header of type BITMAPV2INFOHEADER
* & BITMAPV3INFOHEADER.
*/
public class BMPImageReader extends ImageReader implements BMPConstants {
// 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;
// All VERSION_3_EXT_* are for BITMAPV2INFOHEADER & BITMAPV3INFOHEADER
private static final int VERSION_3_EXT_1_BIT = 10;
private static final int VERSION_3_EXT_4_BIT = 11;
private static final int VERSION_3_EXT_8_BIT = 12;
private static final int VERSION_3_EXT_16_BIT = 13;
private static final int VERSION_3_EXT_24_BIT = 14;
private static final int VERSION_3_EXT_32_BIT = 15;
private static final int VERSION_4_1_BIT = 16;
private static final int VERSION_4_4_BIT = 17;
private static final int VERSION_4_8_BIT = 18;
private static final int VERSION_4_16_BIT = 19;
private static final int VERSION_4_24_BIT = 20;
private static final int VERSION_4_32_BIT = 21;
private static final int VERSION_3_XP_EMBEDDED = 22;
private static final int VERSION_3_EXT_EMBEDDED = 23;
private static final int VERSION_4_XP_EMBEDDED = 24;
private static final int VERSION_5_XP_EMBEDDED = 25;
// BMP variables
private long bitmapFileSize;
private long bitmapOffset;
private long bitmapStart;
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 SampleModel sampleModel, originalSampleModel;
private ColorModel colorModel, originalColorModel;
/** The input stream where reads from */
private ImageInputStream iis = null;
/** Indicates whether the header is read. */
private boolean gotHeader = false;
/** The original image width. */
private int width;
/** The original image height. */
private int height;
/** The destination region. */
private Rectangle destinationRegion;
/** The source region. */
private Rectangle sourceRegion;
/** The metadata from the stream. */
private BMPMetadata metadata;
/** The destination image. */
private BufferedImage bi;
/** Indicates whether subsampled, subregion is required, and offset is
* defined
*/
private boolean noTransform = true;
/** Indicates whether subband is selected. */
private boolean seleBand = false;
/** The scaling factors. */
private int scaleX, scaleY;
/** source and destination bands. */
private int[] sourceBands, destBands;
/** Constructs {@code BMPImageReader} from the provided
* {@code ImageReaderSpi}.
*/
public BMPImageReader(ImageReaderSpi originator) {
super(originator);
}
@Override
public void setInput(Object input,
boolean seekForwardOnly,
boolean ignoreMetadata) {
super.setInput(input, seekForwardOnly, ignoreMetadata);
iis = (ImageInputStream) input; // Always works
if(iis != null)
iis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
resetHeaderInfo();
}
@Override
public int getNumImages(boolean allowSearch) throws IOException {
if (iis == null) {
throw new IllegalStateException(I18N.getString("GetNumImages0"));
}
if (seekForwardOnly && allowSearch) {
throw new IllegalStateException(I18N.getString("GetNumImages1"));
}
return 1;
}
@Override
public int getWidth(int imageIndex) throws IOException {
checkIndex(imageIndex);
try {
readHeader();
} catch (IllegalArgumentException e) {
throw new IIOException(I18N.getString("BMPImageReader6"), e);
}
return width;
}
@Override
public int getHeight(int imageIndex) throws IOException {
checkIndex(imageIndex);
try {
readHeader();
} catch (IllegalArgumentException e) {
throw new IIOException(I18N.getString("BMPImageReader6"), e);
}
return height;
}
private void checkIndex(int imageIndex) {
if (imageIndex != 0) {
throw new IndexOutOfBoundsException(I18N.getString("BMPImageReader0"));
}
}
private void readColorPalette(int sizeOfPalette) throws IOException {
final int UNIT_SIZE = 1024000;
if (sizeOfPalette < UNIT_SIZE) {
palette = new byte[sizeOfPalette];
iis.readFully(palette, 0, sizeOfPalette);
} else {
int bytesToRead = sizeOfPalette;
int bytesRead = 0;
List<byte[]> bufs = new ArrayList<>();
while (bytesToRead != 0) {
int sz = Math.min(bytesToRead, UNIT_SIZE);
byte[] unit = new byte[sz];
iis.readFully(unit, 0, sz);
bufs.add(unit);
bytesRead += sz;
bytesToRead -= sz;
}
byte[] paletteData = new byte[bytesRead];
int copiedBytes = 0;
for (byte[] ba : bufs) {
System.arraycopy(ba, 0, paletteData, copiedBytes, ba.length);
copiedBytes += ba.length;
}
palette = paletteData;
}
}
/**
* Process the image header.
*
* @exception IllegalStateException if source stream is not set.
*
* @exception IOException if image stream is corrupted.
*
* @exception IllegalArgumentException if the image stream does not contain
* a BMP image, or if a sample model instance to describe the
* image can not be created.
*/
protected void readHeader() throws IOException, IllegalArgumentException {
if (gotHeader)
return;
if (iis == null) {
throw new IllegalStateException("Input source not set!");
}
int profileData = 0, profileSize = 0;
this.metadata = new BMPMetadata();
iis.mark();
// read and check the magic marker
byte[] marker = new byte[2];
iis.read(marker);
if (marker[0] != 0x42 || marker[1] != 0x4d)
throw new IllegalArgumentException(I18N.getString("BMPImageReader1"));
// Read file size
bitmapFileSize = iis.readUnsignedInt();
// skip the two reserved fields
iis.skipBytes(4);
// Offset to the bitmap from the beginning
bitmapOffset = iis.readUnsignedInt();
// End File Header
// Start BitmapCoreHeader
long size = iis.readUnsignedInt();
if (size == 12) {
width = iis.readShort();
height = iis.readShort();
} else {
width = iis.readInt();
height = iis.readInt();
}
metadata.width = width;
metadata.height = height;
int planes = iis.readUnsignedShort();
bitsPerPixel = iis.readUnsignedShort();
//metadata.colorPlane = planes;
metadata.bitsPerPixel = (short)bitsPerPixel;
// As BMP always has 3 rgb bands, except for Version 5,
// which is bgra
numBands = 3;
if (size == 12) {
// Windows 2.x and OS/2 1.x
metadata.bmpVersion = VERSION_2;
// Classify the image type
if (bitsPerPixel == 1) {
imageType = VERSION_2_1_BIT;
} else if (bitsPerPixel == 4) {
imageType = VERSION_2_4_BIT;
} else if (bitsPerPixel == 8) {
imageType = VERSION_2_8_BIT;
} else if (bitsPerPixel == 24) {
imageType = VERSION_2_24_BIT;
} else {
throw new IIOException(I18N.getString("BMPImageReader8"));
}
// Read in the palette
int numberOfEntries = (int)((bitmapOffset - 14 - size) / 3);
int sizeOfPalette = numberOfEntries*3;
readColorPalette(sizeOfPalette);
metadata.palette = palette;
metadata.paletteSize = numberOfEntries;
} else {
compression = iis.readUnsignedInt();
imageSize = iis.readUnsignedInt();
long xPelsPerMeter = iis.readInt();
long yPelsPerMeter = iis.readInt();
long colorsUsed = iis.readUnsignedInt();
long colorsImportant = iis.readUnsignedInt();
metadata.compression = (int)compression;
metadata.xPixelsPerMeter = (int)xPelsPerMeter;
metadata.yPixelsPerMeter = (int)yPelsPerMeter;
metadata.colorsUsed = (int)colorsUsed;
metadata.colorsImportant = (int)colorsImportant;
if (size == 40) {
// Windows 3.x and Windows NT
switch((int)compression) {
case BI_JPEG:
case BI_PNG:
metadata.bmpVersion = VERSION_3;
imageType = VERSION_3_XP_EMBEDDED;
break;
case BI_RGB: // No compression
case BI_RLE8: // 8-bit RLE compression
case BI_RLE4: // 4-bit RLE compression
// Read in the palette
if (bitmapOffset < (size + 14)) {
throw new IIOException(I18N.getString("BMPImageReader7"));
}
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries * 4;
readColorPalette(sizeOfPalette);
metadata.palette = palette;
metadata.paletteSize = numberOfEntries;
if (bitsPerPixel == 1) {
imageType = VERSION_3_1_BIT;
} else if (bitsPerPixel == 4) {
imageType = VERSION_3_4_BIT;
} else if (bitsPerPixel == 8) {
imageType = VERSION_3_8_BIT;
} else if (bitsPerPixel == 24) {
imageType = VERSION_3_24_BIT;
} else if (bitsPerPixel == 16) {
imageType = VERSION_3_NT_16_BIT;
redMask = 0x7C00;
greenMask = 0x3E0;
blueMask = (1 << 5) - 1;// 0x1F;
metadata.redMask = redMask;
metadata.greenMask = greenMask;
metadata.blueMask = blueMask;
} else if (bitsPerPixel == 32) {
imageType = VERSION_3_NT_32_BIT;
redMask = 0x00FF0000;
greenMask = 0x0000FF00;
blueMask = 0x000000FF;
metadata.redMask = redMask;
metadata.greenMask = greenMask;
metadata.blueMask = blueMask;
} else {
throw new
IIOException(I18N.getString("BMPImageReader8"));
}
metadata.bmpVersion = VERSION_3;
break;
case BI_BITFIELDS:
if (bitsPerPixel == 16) {
imageType = VERSION_3_NT_16_BIT;
} else if (bitsPerPixel == 32) {
imageType = VERSION_3_NT_32_BIT;
} else {
throw new
IIOException(I18N.getString("BMPImageReader8"));
}
// BitsField encoding
redMask = (int)iis.readUnsignedInt();
greenMask = (int)iis.readUnsignedInt();
blueMask = (int)iis.readUnsignedInt();
metadata.redMask = redMask;
metadata.greenMask = greenMask;
metadata.blueMask = blueMask;
if (colorsUsed != 0) {
// there is a palette
sizeOfPalette = (int)colorsUsed*4;
readColorPalette(sizeOfPalette);
metadata.palette = palette;
metadata.paletteSize = (int)colorsUsed;
}
metadata.bmpVersion = VERSION_3_NT;
break;
default:
throw new
IIOException(I18N.getString("BMPImageReader2"));
}
} else if (size == 52 || size == 56) {
// BITMAPV2INFOHEADER or BITMAPV3INFOHEADER
redMask = (int)iis.readUnsignedInt();
greenMask = (int)iis.readUnsignedInt();
blueMask = (int)iis.readUnsignedInt();
if (size == 56) {
alphaMask = (int)iis.readUnsignedInt();
}
metadata.bmpVersion = VERSION_3_EXT;
// Read in the palette
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries*4;
readColorPalette(sizeOfPalette);
metadata.palette = palette;
metadata.paletteSize = numberOfEntries;
switch((int)compression) {
case BI_JPEG:
case BI_PNG:
imageType = VERSION_3_EXT_EMBEDDED;
break;
default:
if (bitsPerPixel == 1) {
imageType = VERSION_3_EXT_1_BIT;
} else if (bitsPerPixel == 4) {
imageType = VERSION_3_EXT_4_BIT;
} else if (bitsPerPixel == 8) {
imageType = VERSION_3_EXT_8_BIT;
} else if (bitsPerPixel == 16) {
imageType = VERSION_3_EXT_16_BIT;
if ((int)compression == BI_RGB) {
redMask = 0x7C00;
greenMask = 0x3E0;
blueMask = 0x1F;
}
} else if (bitsPerPixel == 24) {
imageType = VERSION_3_EXT_24_BIT;
} else if (bitsPerPixel == 32) {
imageType = VERSION_3_EXT_32_BIT;
if ((int)compression == BI_RGB) {
redMask = 0x00FF0000;
greenMask = 0x0000FF00;
blueMask = 0x000000FF;
}
} else {
throw new
IIOException(I18N.getString("BMPImageReader8"));
}
metadata.redMask = redMask;
metadata.greenMask = greenMask;
metadata.blueMask = blueMask;
metadata.alphaMask = alphaMask;
}
} else if (size == 108 || size == 124) {
// Windows 4.x BMP
if (size == 108)
metadata.bmpVersion = VERSION_4;
else if (size == 124)
metadata.bmpVersion = VERSION_5;
// rgb masks, valid only if comp is BI_BITFIELDS
redMask = (int)iis.readUnsignedInt();
greenMask = (int)iis.readUnsignedInt();
blueMask = (int)iis.readUnsignedInt();
// Only supported for 32bpp BI_RGB argb
alphaMask = (int)iis.readUnsignedInt();
long csType = iis.readUnsignedInt();
int redX = iis.readInt();
int redY = iis.readInt();
int redZ = iis.readInt();
int greenX = iis.readInt();
int greenY = iis.readInt();
int greenZ = iis.readInt();
int blueX = iis.readInt();
int blueY = iis.readInt();
int blueZ = iis.readInt();
long gammaRed = iis.readUnsignedInt();
long gammaGreen = iis.readUnsignedInt();
long gammaBlue = iis.readUnsignedInt();
if (size == 124) {
metadata.intent = iis.readInt();
profileData = iis.readInt();
profileSize = iis.readInt();
iis.skipBytes(4);
}
metadata.colorSpace = (int)csType;
if (csType == LCS_CALIBRATED_RGB) {
// All the new fields are valid only for this case
metadata.redX = redX;
metadata.redY = redY;
metadata.redZ = redZ;
metadata.greenX = greenX;
metadata.greenY = greenY;
metadata.greenZ = greenZ;
metadata.blueX = blueX;
metadata.blueY = blueY;
metadata.blueZ = blueZ;
metadata.gammaRed = (int)gammaRed;
metadata.gammaGreen = (int)gammaGreen;
metadata.gammaBlue = (int)gammaBlue;
}
// Read in the palette
int numberOfEntries = (int)((bitmapOffset-14-size) / 4);
int sizeOfPalette = numberOfEntries*4;
readColorPalette(sizeOfPalette);
metadata.palette = palette;
metadata.paletteSize = numberOfEntries;
switch ((int)compression) {
case BI_JPEG:
case BI_PNG:
if (size == 108) {
imageType = VERSION_4_XP_EMBEDDED;
} else if (size == 124) {
imageType = VERSION_5_XP_EMBEDDED;
}
break;
default:
if (bitsPerPixel == 1) {
imageType = VERSION_4_1_BIT;
} else if (bitsPerPixel == 4) {
imageType = VERSION_4_4_BIT;
} else if (bitsPerPixel == 8) {
imageType = VERSION_4_8_BIT;
} else if (bitsPerPixel == 16) {
imageType = VERSION_4_16_BIT;
if ((int)compression == BI_RGB) {
redMask = 0x7C00;
greenMask = 0x3E0;
blueMask = 0x1F;
}
} else if (bitsPerPixel == 24) {
imageType = VERSION_4_24_BIT;
} else if (bitsPerPixel == 32) {
imageType = VERSION_4_32_BIT;
if ((int)compression == BI_RGB) {
redMask = 0x00FF0000;
greenMask = 0x0000FF00;
blueMask = 0x000000FF;
}
} else {
throw new
IIOException(I18N.getString("BMPImageReader8"));
}
metadata.redMask = redMask;
metadata.greenMask = greenMask;
metadata.blueMask = blueMask;
metadata.alphaMask = alphaMask;
}
} else {
throw new
IIOException(I18N.getString("BMPImageReader3"));
}
}
if (height > 0) {
// bottom up image
isBottomUp = true;
} else {
// top down image
isBottomUp = false;
height = Math.abs(height);
}
if (metadata.compression == BI_RGB) {
long imageDataSize = ((long)width * height * (bitsPerPixel / 8));
if (imageDataSize > (bitmapFileSize - bitmapOffset)) {
throw new IIOException(I18N.getString("BMPImageReader9"));
}
}
// Reset Image Layout so there's only one tile.
//Define the color space
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
if (metadata.colorSpace == PROFILE_LINKED ||
metadata.colorSpace == PROFILE_EMBEDDED) {
iis.mark();
iis.skipBytes(profileData - size);
byte[] profile = new byte[profileSize];
iis.readFully(profile, 0, profileSize);
iis.reset();
try {
if (metadata.colorSpace == PROFILE_LINKED &&
isLinkedProfileAllowed() &&
!isUncOrDevicePath(profile))
{
String path = new String(profile, "windows-1252");
colorSpace =
new ICC_ColorSpace(ICC_Profile.getInstance(path));
} else {
colorSpace =
new ICC_ColorSpace(ICC_Profile.getInstance(profile));
}
} catch (Exception e) {
colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
}
}
if (bitsPerPixel == 0 ||
compression == BI_JPEG || compression == BI_PNG )
{
// the colorModel and sampleModel will be initialzed
// by the reader of embedded image
colorModel = null;
sampleModel = null;
} else if (bitsPerPixel == 1 || bitsPerPixel == 4 || bitsPerPixel == 8) {
// When number of bitsPerPixel is <= 8, we use IndexColorModel.
numBands = 1;
if (bitsPerPixel == 8) {
int[] bandOffsets = new int[numBands];
for (int i = 0; i < numBands; i++) {
bandOffsets[i] = numBands -1 -i;
}
sampleModel =
new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
width, height,
numBands,
numBands * width,
bandOffsets);
} else {
// 1 and 4 bit pixels can be stored in a packed format.
sampleModel =
new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
width, height,
bitsPerPixel);
}
// Create IndexColorModel from the palette.
byte[] r, g, b;
if (imageType == VERSION_2_1_BIT ||
imageType == VERSION_2_4_BIT ||
imageType == VERSION_2_8_BIT) {
size = palette.length/3;
if (size > 256) {
size = 256;
}
int off;
r = new byte[(int)size];
g = new byte[(int)size];
b = new byte[(int)size];
for (int i=0; i<(int)size; i++) {
off = 3 * i;
b[i] = palette[off];
g[i] = palette[off+1];
r[i] = palette[off+2];
}
} else {
size = palette.length/4;
if (size > 256) {
size = 256;
}
int off;
r = new byte[(int)size];
g = new byte[(int)size];
b = new byte[(int)size];
for (int i=0; i<size; i++) {
off = 4 * i;
b[i] = palette[off];
g[i] = palette[off+1];
r[i] = palette[off+2];
}
}
if (ImageUtil.isIndicesForGrayscale(r, g, b))
colorModel =
ImageUtil.createColorModel(null, sampleModel);
else
colorModel = new IndexColorModel(bitsPerPixel, (int)size, r, g, b);
} else if (bitsPerPixel == 16) {
numBands = 3;
sampleModel =
new SinglePixelPackedSampleModel(DataBuffer.TYPE_USHORT,
width, height,
new int[] {redMask, greenMask, blueMask});
colorModel =
new DirectColorModel(colorSpace,
16, redMask, greenMask, blueMask, 0,
false, DataBuffer.TYPE_USHORT);
} else if (bitsPerPixel == 32) {
numBands = alphaMask == 0 ? 3 : 4;
// The number of bands in the SampleModel is determined by
// the length of the mask array passed in.
int[] bitMasks = numBands == 3 ?
new int[] {redMask, greenMask, blueMask} :
new int[] {redMask, greenMask, blueMask, alphaMask};
sampleModel =
new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT,
width, height,
bitMasks);
colorModel =
new DirectColorModel(colorSpace,
32, redMask, greenMask, blueMask, alphaMask,
false, DataBuffer.TYPE_INT);
} else {
numBands = 3;
// Create SampleModel
int[] bandOffsets = new int[numBands];
for (int i = 0; i < numBands; i++) {
bandOffsets[i] = numBands -1 -i;
}
sampleModel =
new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
width, height,
numBands,
numBands * width,
bandOffsets);
colorModel =
ImageUtil.createColorModel(colorSpace, sampleModel);
}
originalSampleModel = sampleModel;
originalColorModel = colorModel;
// Reset to the start of bitmap; then jump to the
//start of image data
iis.reset();
iis.skipBytes(bitmapOffset);
bitmapStart = iis.getStreamPosition();
gotHeader = true;
}
@Override
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
throws IOException {
checkIndex(imageIndex);
try {
readHeader();
} catch (IllegalArgumentException e) {
throw new IIOException(I18N.getString("BMPImageReader6"), e);
}
ArrayList<ImageTypeSpecifier> list = new ArrayList<>(1);
list.add(new ImageTypeSpecifier(originalColorModel,
originalSampleModel));
return list.iterator();
}
@Override
public ImageReadParam getDefaultReadParam() {
return new ImageReadParam();
}
@Override
public IIOMetadata getImageMetadata(int imageIndex)
throws IOException {
checkIndex(imageIndex);
if (metadata == null) {
try {
readHeader();
} catch (IllegalArgumentException e) {
throw new IIOException(I18N.getString("BMPImageReader6"), e);
}
}
return metadata;
}
@Override
public IIOMetadata getStreamMetadata() throws IOException {
return null;
}
@Override
public boolean isRandomAccessEasy(int imageIndex) throws IOException {
checkIndex(imageIndex);
try {
readHeader();
} catch (IllegalArgumentException e) {
throw new IIOException(I18N.getString("BMPImageReader6"), e);
}
return metadata.compression == BI_RGB;
}
@Override
public BufferedImage read(int imageIndex, ImageReadParam param)
throws IOException {
if (iis == null) {
throw new IllegalStateException(I18N.getString("BMPImageReader5"));
}
checkIndex(imageIndex);
clearAbortRequest();
processImageStarted(imageIndex);
if (abortRequested()) {
processReadAborted();
return bi;
}
if (param == null)
param = getDefaultReadParam();
//read header
try {
readHeader();
} catch (IllegalArgumentException e) {
throw new IIOException(I18N.getString("BMPImageReader6"), e);
}
sourceRegion = new Rectangle(0, 0, 0, 0);
destinationRegion = new Rectangle(0, 0, 0, 0);
computeRegions(param, this.width, this.height,
param.getDestination(),
sourceRegion,
destinationRegion);
scaleX = param.getSourceXSubsampling();
scaleY = param.getSourceYSubsampling();
// If the destination band is set used it
sourceBands = param.getSourceBands();
destBands = param.getDestinationBands();
seleBand = (sourceBands != null) && (destBands != null);
noTransform =
destinationRegion.equals(new Rectangle(0, 0, width, height)) ||
seleBand;
if (!seleBand) {
sourceBands = new int[numBands];
destBands = new int[numBands];
for (int i = 0; i < numBands; i++)
destBands[i] = sourceBands[i] = i;
}
// If the destination is provided, then use it. Otherwise, create new one
bi = param.getDestination();
// Get the image data.
WritableRaster raster = null;
if (bi == null) {
if (sampleModel != null && colorModel != null) {
sampleModel =
sampleModel.createCompatibleSampleModel(destinationRegion.x +
destinationRegion.width,
destinationRegion.y +
destinationRegion.height);
if (seleBand)
sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
raster = Raster.createWritableRaster(sampleModel, new Point());
bi = new BufferedImage(colorModel, raster, false, null);
}
} else {
raster = bi.getWritableTile(0, 0);
sampleModel = bi.getSampleModel();
colorModel = bi.getColorModel();
noTransform &= destinationRegion.equals(raster.getBounds());
}
byte[] bdata = null; // buffer for byte data
short[] sdata = null; // buffer for short data
int[] idata = null; // buffer for int data
// the sampleModel can be null in case of embedded image
if (sampleModel != null) {
if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
bdata = ((DataBufferByte)raster.getDataBuffer()).getData();
else if (sampleModel.getDataType() == DataBuffer.TYPE_USHORT)
sdata = ((DataBufferUShort)raster.getDataBuffer()).getData();
else if (sampleModel.getDataType() == DataBuffer.TYPE_INT)
idata = ((DataBufferInt)raster.getDataBuffer()).getData();
}
iis.seek(bitmapStart);
// There should only be one tile.
switch(imageType) {
case VERSION_2_1_BIT:
// no compression
read1Bit(bdata);
break;
case VERSION_2_4_BIT:
// no compression
read4Bit(bdata);
break;
case VERSION_2_8_BIT:
// no compression
read8Bit(bdata);
break;
case VERSION_2_24_BIT:
// no compression
read24Bit(bdata);
break;
case VERSION_3_1_BIT:
// 1-bit images cannot be compressed.
read1Bit(bdata);
break;
case VERSION_3_4_BIT:
switch((int)compression) {
case BI_RGB:
read4Bit(bdata);
break;
case BI_RLE4:
readRLE4(bdata);
break;
default:
throw new
IIOException(I18N.getString("BMPImageReader1"));
}
break;
case VERSION_3_8_BIT:
switch((int)compression) {
case BI_RGB:
read8Bit(bdata);
break;
case BI_RLE8:
readRLE8(bdata);
break;
default:
throw new
IIOException(I18N.getString("BMPImageReader1"));
}
break;
case VERSION_3_24_BIT:
// 24-bit images are not compressed
read24Bit(bdata);
break;
case VERSION_3_NT_16_BIT:
read16Bit(sdata);
break;
case VERSION_3_NT_32_BIT:
read32Bit(idata);
break;
case VERSION_3_XP_EMBEDDED:
case VERSION_3_EXT_EMBEDDED:
case VERSION_4_XP_EMBEDDED:
case VERSION_5_XP_EMBEDDED:
bi = readEmbedded((int)compression, bi, param);
break;
case VERSION_3_EXT_1_BIT:
case VERSION_4_1_BIT:
read1Bit(bdata);
break;
case VERSION_3_EXT_4_BIT:
case VERSION_4_4_BIT:
switch((int)compression) {
case BI_RGB:
read4Bit(bdata);
break;
case BI_RLE4:
readRLE4(bdata);
break;
default:
throw new
IIOException(I18N.getString("BMPImageReader1"));
}
break;
case VERSION_3_EXT_8_BIT:
case VERSION_4_8_BIT:
switch((int)compression) {
case BI_RGB:
read8Bit(bdata);
break;
case BI_RLE8:
readRLE8(bdata);
break;
default:
throw new
IIOException(I18N.getString("BMPImageReader1"));
}
break;
case VERSION_3_EXT_16_BIT:
case VERSION_4_16_BIT:
read16Bit(sdata);
break;
case VERSION_3_EXT_24_BIT:
case VERSION_4_24_BIT:
read24Bit(bdata);
break;
case VERSION_3_EXT_32_BIT:
case VERSION_4_32_BIT:
read32Bit(idata);
break;
}
if (abortRequested())
processReadAborted();
else
processImageComplete();
return bi;
}
@Override
public boolean canReadRaster() {
return true;
}
@Override
public Raster readRaster(int imageIndex,
ImageReadParam param) throws IOException {
BufferedImage bi = read(imageIndex, param);
return bi.getData();
}
private void resetHeaderInfo() {
gotHeader = false;
bi = null;
sampleModel = originalSampleModel = null;
colorModel = originalColorModel = null;
}
@Override
public void reset() {
super.reset();
iis = null;
resetHeaderInfo();
}
// Deal with 1 Bit images using IndexColorModels
private void read1Bit(byte[] bdata) throws IOException {
int bytesPerScanline = (width + 7) / 8;
int padding = bytesPerScanline % 4;
if (padding != 0) {
padding = 4 - padding;
}
int lineLength = bytesPerScanline + padding;
if (noTransform) {
int j = isBottomUp ? (height -1)*bytesPerScanline : 0;
for (int i=0; i<height; i++) {
iis.readFully(bdata, j, bytesPerScanline);
iis.skipBytes(padding);
j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
byte[] buf = new byte[lineLength];
int lineStride =
((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(lineLength * (height - 1 - lastLine));
} else
iis.skipBytes(lineLength * sourceRegion.y);
int skipLength = lineLength * (scaleY - 1);
// cache the values to avoid duplicated computation
int[] srcOff = new int[destinationRegion.width];
int[] destOff = new int[destinationRegion.width];
int[] srcPos = new int[destinationRegion.width];
int[] destPos = new int[destinationRegion.width];
for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
i < destinationRegion.x + destinationRegion.width;
i++, j++, x += scaleX) {
srcPos[j] = x >> 3;
srcOff[j] = 7 - (x & 7);
destPos[j] = i >> 3;
destOff[j] = 7 - (i & 7);
}
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
iis.read(buf, 0, lineLength);
for (int i = 0; i < destinationRegion.width; i++) {
//get the bit and assign to the data buffer of the raster
int v = (buf[srcPos[i]] >> srcOff[i]) & 1;
bdata[k + destPos[i]] |= v << destOff[i];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
// Method to read a 4 bit BMP image data
private void read4Bit(byte[] bdata) throws IOException {
int bytesPerScanline = (width + 1) / 2;
// Padding bytes at the end of each scanline
int padding = bytesPerScanline % 4;
if (padding != 0)
padding = 4 - padding;
int lineLength = bytesPerScanline + padding;
if (noTransform) {
int j = isBottomUp ? (height -1) * bytesPerScanline : 0;
for (int i=0; i<height; i++) {
iis.readFully(bdata, j, bytesPerScanline);
iis.skipBytes(padding);
j += isBottomUp ? -bytesPerScanline : bytesPerScanline;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
byte[] buf = new byte[lineLength];
int lineStride =
((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(lineLength * (height - 1 - lastLine));
} else
iis.skipBytes(lineLength * sourceRegion.y);
int skipLength = lineLength * (scaleY - 1);
// cache the values to avoid duplicated computation
int[] srcOff = new int[destinationRegion.width];
int[] destOff = new int[destinationRegion.width];
int[] srcPos = new int[destinationRegion.width];
int[] destPos = new int[destinationRegion.width];
for (int i = destinationRegion.x, x = sourceRegion.x, j = 0;
i < destinationRegion.x + destinationRegion.width;
i++, j++, x += scaleX) {
srcPos[j] = x >> 1;
srcOff[j] = (1 - (x & 1)) << 2;
destPos[j] = i >> 1;
destOff[j] = (1 - (i & 1)) << 2;
}
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
iis.read(buf, 0, lineLength);
for (int i = 0; i < destinationRegion.width; i++) {
//get the bit and assign to the data buffer of the raster
int v = (buf[srcPos[i]] >> srcOff[i]) & 0x0F;
bdata[k + destPos[i]] |= v << destOff[i];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
// Method to read 8 bit BMP image data
private void read8Bit(byte[] bdata) throws IOException {
// Padding bytes at the end of each scanline
int padding = width % 4;
if (padding != 0) {
padding = 4 - padding;
}
int lineLength = width + padding;
if (noTransform) {
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
iis.readFully(bdata, j, width);
iis.skipBytes(padding);
j += isBottomUp ? -width : width;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
byte[] buf = new byte[lineLength];
int lineStride =
((ComponentSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(lineLength * (height - 1 - lastLine));
} else
iis.skipBytes(lineLength * sourceRegion.y);
int skipLength = lineLength * (scaleY - 1);
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
k += destinationRegion.x;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
iis.read(buf, 0, lineLength);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
//get the bit and assign to the data buffer of the raster
bdata[k + i] = buf[m];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
// Method to read 24 bit BMP image data
private void read24Bit(byte[] bdata) throws IOException {
// Padding bytes at the end of each scanline
// width * bitsPerPixel should be divisible by 32
int padding = width * 3 % 4;
if ( padding != 0)
padding = 4 - padding;
int lineStride = width * 3;
int lineLength = lineStride + padding;
if (noTransform) {
int j = isBottomUp ? (height -1) * width * 3 : 0;
for (int i=0; i<height; i++) {
iis.readFully(bdata, j, lineStride);
iis.skipBytes(padding);
j += isBottomUp ? -lineStride : lineStride;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
byte[] buf = new byte[lineLength];
lineStride =
((ComponentSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(lineLength * (height - 1 - lastLine));
} else
iis.skipBytes(lineLength * sourceRegion.y);
int skipLength = lineLength * (scaleY - 1);
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
k += destinationRegion.x * 3;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
iis.read(buf, 0, lineLength);
for (int i = 0, m = 3 * sourceRegion.x;
i < destinationRegion.width; i++, m += 3 * scaleX) {
//get the bit and assign to the data buffer of the raster
int n = 3 * i + k;
for (int b = 0; b < destBands.length; b++)
bdata[n + destBands[b]] = buf[m + sourceBands[b]];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
private void read16Bit(short[] sdata) throws IOException {
// Padding bytes at the end of each scanline
// width * bitsPerPixel should be divisible by 32
int padding = width * 2 % 4;
if ( padding != 0)
padding = 4 - padding;
int lineLength = width + padding / 2;
if (noTransform) {
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
iis.readFully(sdata, j, width);
iis.skipBytes(padding);
j += isBottomUp ? -width : width;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
short[] buf = new short[lineLength];
int lineStride =
((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(lineLength * (height - 1 - lastLine) << 1);
} else
iis.skipBytes(lineLength * sourceRegion.y << 1);
int skipLength = lineLength * (scaleY - 1) << 1;
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
k += destinationRegion.x;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
iis.readFully(buf, 0, lineLength);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
//get the bit and assign to the data buffer of the raster
sdata[k + i] = buf[m];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
private void read32Bit(int[] idata) throws IOException {
if (noTransform) {
int j = isBottomUp ? (height -1) * width : 0;
for (int i=0; i<height; i++) {
iis.readFully(idata, j, width);
j += isBottomUp ? -width : width;
processImageUpdate(bi, 0, i,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F * i/destinationRegion.height);
if (abortRequested()) {
break;
}
}
} else {
int[] buf = new int[width];
int lineStride =
((SinglePixelPackedSampleModel)sampleModel).getScanlineStride();
if (isBottomUp) {
int lastLine =
sourceRegion.y + (destinationRegion.height - 1) * scaleY;
iis.skipBytes(width * (height - 1 - lastLine) << 2);
} else
iis.skipBytes(width * sourceRegion.y << 2);
int skipLength = width * (scaleY - 1) << 2;
int k = destinationRegion.y * lineStride;
if (isBottomUp)
k += (destinationRegion.height - 1) * lineStride;
k += destinationRegion.x;
for (int j = 0, y = sourceRegion.y;
j < destinationRegion.height; j++, y+=scaleY) {
iis.readFully(buf, 0, width);
for (int i = 0, m = sourceRegion.x;
i < destinationRegion.width; i++, m += scaleX) {
//get the bit and assign to the data buffer of the raster
idata[k + i] = buf[m];
}
k += isBottomUp ? -lineStride : lineStride;
iis.skipBytes(skipLength);
processImageUpdate(bi, 0, j,
destinationRegion.width, 1, 1, 1,
new int[]{0});
processImageProgress(100.0F*j/destinationRegion.height);
if (abortRequested()) {
break;
}
}
}
}
private void readRLE8(byte[] bdata) throws IOException {
// If imageSize field is not provided, calculate it.
int imSize = (int)imageSize;
if (imSize == 0) {
imSize = (int)(bitmapFileSize - bitmapOffset);
}
int padding = 0;
// If width is not 32 bit aligned, then while uncompressing each
// scanline will have padding bytes, calculate the amount of padding
int remainder = width % 4;
if (remainder != 0) {
padding = 4 - remainder;
}
// Read till we have the whole image
byte[] values = ReaderUtil.
staggeredReadByteStream(iis, imSize);
// Since data is compressed, decompress it
decodeRLE8(imSize, padding, values, bdata);
}
private boolean copyRLE8ScanlineToDst(int lineNo,
byte[] val,
byte[] bdata) {
// Return value
boolean isSuccess = false;
// Reusing the code to copy 1 row of pixels or scanline to required
// destination buffer.
if (lineNo >= sourceRegion.y &&
lineNo < sourceRegion.y + sourceRegion.height) {
if (noTransform) {
int pos = lineNo * width;
for(int i = 0; i < width; i++)
bdata[pos++] = val[i];
processImageUpdate(bi, 0, lineNo,
destinationRegion.width, 1, 1, 1,
new int[]{0});
isSuccess = true;
} else if ((lineNo - sourceRegion.y) % scaleY == 0) {
int lineStride =
((ComponentSampleModel)sampleModel).getScanlineStride();
int currentLine = (lineNo - sourceRegion.y) / scaleY +
destinationRegion.y;
int pos = currentLine * lineStride;
pos += destinationRegion.x;
for (int i = sourceRegion.x;
i < sourceRegion.x + sourceRegion.width;
i += scaleX)
bdata[pos++] = val[i];
processImageUpdate(bi, 0, currentLine,
destinationRegion.width, 1, 1, 1,
new int[]{0});
isSuccess = true;
}
// Ensure to reset the scanline buffer once the copy is complete.
for(int scIndex = 0; scIndex < width; scIndex++) {
val[scIndex] = 0;
}
}
return isSuccess;
}
private void decodeRLE8(int imSize,
int padding,
byte[] values,
byte[] bdata) throws IOException {
byte[] val = new byte[width];
int count = 0, l = 0;
int value;
boolean flag = false;
int lineNo = isBottomUp ? height - 1 : 0;
int finished = 0;
// Ensure image source has sufficient data to decode
while ((count + 1) < imSize) {
value = values[count++] & 0xff;
if (value == 0) {
switch(values[count++] & 0xff) {
case 0:
// End-of-scanline marker
// Copy the decoded scanline to destination
if (copyRLE8ScanlineToDst(lineNo, val, bdata)) {
finished++;
}
processImageProgress(100.0F * finished / destinationRegion.height);
lineNo += isBottomUp ? -1 : 1;
l = 0;
if (abortRequested()) {
flag = true;
}
break;
case 1:
// End-of-RLE marker
flag = true;
// Check if the last decoded scanline was copied to
// destination bitmap
if (l != 0) {
// Copy the decoded scanline to destination
if (copyRLE8ScanlineToDst(lineNo, val, bdata)) {
finished++;
}
processImageProgress(100.0F * finished / destinationRegion.height);
lineNo += isBottomUp ? -1 : 1;
l = 0;
}
break;
case 2:
// delta or vector marker
if ((count+1) < imSize) {
int xoff = values[count++] & 0xff;
int yoff = values[count++] & 0xff;
// Check if the yOffset shifts the decoding to another
// row. In such cases, the decoded pixels in scanline
// buffer-val must be copied to the destination image.
if (yoff != 0) {
// Copy the decoded scanline to destination
if (copyRLE8ScanlineToDst(lineNo, val, bdata)) {
finished++;
}
processImageProgress(100.0F * finished
/ destinationRegion.height);
lineNo += isBottomUp ? -yoff : yoff;
}
// Move to the position xoff, yoff down
l += xoff + yoff*width;
l %= width;
}
break;
default:
int end = values[count-1] & 0xff;
byte readByte = 0;
// Ensure to check if the source index-count, does not
// exceed the source image size
for (int i=0; (i < end) && (count < imSize); i++) {
readByte = (byte)(values[count++] & 0xff);
// Ensure to check if scanline index-l, does not
// exceed the scanline buffer size (width of image)
if (l < width) {
val[l++] = readByte;
}
}
// Whenever end pixels can fit into odd number of bytes,
// an extra padding byte will be present, so skip that.
if ((end & 1) == 1) {
count++;
}
break;
}
} else {
// Encoded mode
// Ensure to check if the source index-count, does not
// exceed the source image size
if (count < imSize) {
for (int i=0; (i < value) && (l < width); i++) {
val[l++] = (byte)(values[count] & 0xff);
}
}
count++;
}
// If End-of-RLE data, then exit the while loop
if (flag) {
break;
}
}
}
private void readRLE4(byte[] bdata) throws IOException {
// If imageSize field is not specified, calculate it.
int imSize = (int)imageSize;
if (imSize == 0) {
imSize = (int)(bitmapFileSize - bitmapOffset);
}
int padding = 0;
// If width is not 32 byte aligned, then while uncompressing each
// scanline will have padding bytes, calculate the amount of padding
int remainder = width % 4;
if (remainder != 0) {
padding = 4 - remainder;
}
// Read till we have the whole image
byte[] values = ReaderUtil.
staggeredReadByteStream(iis, imSize);
// Decompress the RLE4 compressed data.
decodeRLE4(imSize, padding, values, bdata);
}
private boolean copyRLE4ScanlineToDst(int lineNo,
byte[] val,
byte[] bdata) throws IOException {
// Return value
boolean isSuccess = false;
// Reusing the code to copy 1 row of pixels or scanline to required
// destination buffer.
if (lineNo >= sourceRegion.y &&
lineNo < sourceRegion.y + sourceRegion.height) {
if (noTransform) {
int pos = lineNo * (width + 1 >> 1);
for(int i = 0, j = 0; i < width >> 1; i++)
bdata[pos++] =
(byte)((val[j++] << 4) | val[j++]);
if ((width & 1) == 1)
bdata[pos] |= val[width - 1] << 4;
processImageUpdate(bi, 0, lineNo,
destinationRegion.width, 1, 1, 1,
new int[]{0});
isSuccess = true;
} else if ((lineNo - sourceRegion.y) % scaleY == 0) {
int lineStride =
((MultiPixelPackedSampleModel)sampleModel).getScanlineStride();
int currentLine = (lineNo - sourceRegion.y) / scaleY +
destinationRegion.y;
int pos = currentLine * lineStride;
pos += destinationRegion.x >> 1;
int shift = (1 - (destinationRegion.x & 1)) << 2;
for (int i = sourceRegion.x;
i < sourceRegion.x + sourceRegion.width;
i += scaleX) {
bdata[pos] |= val[i] << shift;
shift += 4;
if (shift == 4) {
pos++;
}
shift &= 7;
}
processImageUpdate(bi, 0, currentLine,
destinationRegion.width, 1, 1, 1,
new int[]{0});
isSuccess = true;
}
// Ensure to reset the scanline buffer once the copy is complete.
for(int scIndex = 0; scIndex < width; scIndex++) {
val[scIndex] = 0;
}
}
return isSuccess;
}
private void decodeRLE4(int imSize,
int padding,
byte[] values,
byte[] bdata) throws IOException {
byte[] val = new byte[width];
int count = 0, l = 0;
int value;
boolean flag = false;
int lineNo = isBottomUp ? height - 1 : 0;
int finished = 0;
// Ensure the image has sufficient data before proceeding to decode
while ((count + 1) < imSize) {
value = values[count++] & 0xFF;
if (value == 0) {
// Absolute mode
switch(values[count++] & 0xFF) {
case 0:
// End-of-scanline marker
// Copy the decoded scanline to destination
if (copyRLE4ScanlineToDst(lineNo, val, bdata)) {
finished++;
}
processImageProgress(100.0F * finished / destinationRegion.height);
lineNo += isBottomUp ? -1 : 1;
l = 0;
if (abortRequested()) {
flag = true;
}
break;
case 1:
// End-of-RLE marker
flag = true;
// Check if the last decoded scanline was copied to
// destination bitmap
if (l != 0) {
// Copy the decoded scanline to destination
if (copyRLE4ScanlineToDst(lineNo, val, bdata)) {
finished++;
}
processImageProgress(100.0F * finished / destinationRegion.height);
lineNo += isBottomUp ? -1 : 1;
l = 0;
}
break;
case 2:
// delta or vector marker
if ((count + 1) < imSize) {
int xoff = values[count++] & 0xFF;
int yoff = values[count++] & 0xFF;
// Check if the yOffset shifts the decoding to another
// row. In such cases, the decoded pixels in scanline
// buffer-val must be copied to the destination image.
if (yoff != 0) {
// Copy the decoded scanline to destination
if (copyRLE4ScanlineToDst(lineNo, val, bdata)) {
finished++;
}
processImageProgress(100.0F * finished
/ destinationRegion.height);
lineNo += isBottomUp ? -yoff : yoff;
}
// Move to the position (xoff, yoff). Since l-is used
// to index into the scanline buffer, the accumulated
// offset is limited to the width of the scanline
l += xoff + yoff*width;
l %= width;
}
break;
default:
int end = values[count-1] & 0xFF;
byte readByte = 0;
// Ensure to check if the source index-count, does not
// exceed the source image size
for (int i = 0; (i < end) && (count < imSize); i++) {
readByte = (byte)(((i & 1) == 0) ?
(values[count] & 0xf0) >> 4 :
(values[count++] & 0x0f));
// Ensure to check if scanline index-l, does not
// exceed the scanline buffer size (width of image)
if (l < width) {
val[l++] = readByte;
}
}
// When end is odd, the above for loop does not
// increment count, so do it now.
if ((end & 1) == 1) {
count++;
}
// Whenever end pixels can fit into odd number of bytes,
// an extra padding byte will be present, so skip that.
if ((((end + 1) / 2) & 1) == 1) {
count++;
}
break;
}
} else {
// Encoded mode
// Ensure to check if the source index-count, does not
// exceed the source image size
if (count < imSize) {
int[] alternate = { (values[count] & 0xf0) >> 4,
values[count] & 0x0f };
for (int i=0; (i < value) && (l < width); i++) {
val[l++] = (byte)alternate[i & 1];
}
}
count++;
}
// If End-of-RLE data, then exit the while loop
if (flag) {
break;
}
}
}
/** Decodes the jpeg/png image embedded in the bitmap using any jpeg
* ImageIO-style plugin.
*
* @param bi The destination {@code BufferedImage}.
* @param bmpParam The {@code ImageReadParam} for decoding this
* BMP image. The parameters for subregion, band selection and
* subsampling are used in decoding the jpeg image.
*/
private BufferedImage readEmbedded(int type,
BufferedImage bi, ImageReadParam bmpParam)
throws IOException {
String format;
switch(type) {
case BI_JPEG:
format = "JPEG";
break;
case BI_PNG:
format = "PNG";
break;
default:
throw new
IOException("Unexpected compression type: " + type);
}
ImageReader reader =
ImageIO.getImageReadersByFormatName(format).next();
if (reader == null) {
throw new RuntimeException(I18N.getString("BMPImageReader4") +
" " + format);
}
// prepare input
byte[] buff = new byte[(int)imageSize];
iis.read(buff);
reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(buff)));
if (bi == null) {
ImageTypeSpecifier embType = reader.getImageTypes(0).next();
bi = embType.createBufferedImage(destinationRegion.x +
destinationRegion.width,
destinationRegion.y +
destinationRegion.height);
}
reader.addIIOReadProgressListener(new EmbeddedProgressAdapter() {
@Override
public void imageProgress(ImageReader source,
float percentageDone)
{
processImageProgress(percentageDone);
}
});
reader.addIIOReadUpdateListener(new IIOReadUpdateListener() {
@Override
public void imageUpdate(ImageReader source,
BufferedImage theImage,
int minX, int minY,
int width, int height,
int periodX, int periodY,
int[] bands)
{
processImageUpdate(theImage, minX, minY,
width, height,
periodX, periodY, bands);
}
@Override
public void passComplete(ImageReader source,
BufferedImage theImage)
{
processPassComplete(theImage);
}
@Override
public void passStarted(ImageReader source,
BufferedImage theImage,
int pass,
int minPass, int maxPass,
int minX, int minY,
int periodX, int periodY,
int[] bands)
{
processPassStarted(theImage, pass, minPass, maxPass,
minX, minY, periodX, periodY,
bands);
}
@Override
public void thumbnailPassComplete(ImageReader source,
BufferedImage thumb) {}
@Override
public void thumbnailPassStarted(ImageReader source,
BufferedImage thumb,
int pass,
int minPass, int maxPass,
int minX, int minY,
int periodX, int periodY,
int[] bands) {}
@Override
public void thumbnailUpdate(ImageReader source,
BufferedImage theThumbnail,
int minX, int minY,
int width, int height,
int periodX, int periodY,
int[] bands) {}
});
reader.addIIOReadWarningListener(new IIOReadWarningListener() {
@Override
public void warningOccurred(ImageReader source, String warning)
{
processWarningOccurred(warning);
}
});
ImageReadParam param = reader.getDefaultReadParam();
param.setDestination(bi);
param.setDestinationBands(bmpParam.getDestinationBands());
param.setDestinationOffset(bmpParam.getDestinationOffset());
param.setSourceBands(bmpParam.getSourceBands());
param.setSourceRegion(bmpParam.getSourceRegion());
param.setSourceSubsampling(bmpParam.getSourceXSubsampling(),
bmpParam.getSourceYSubsampling(),
bmpParam.getSubsamplingXOffset(),
bmpParam.getSubsamplingYOffset());
reader.read(0, param);
return bi;
}
private static class EmbeddedProgressAdapter implements IIOReadProgressListener {
@Override
public void imageComplete(ImageReader src) {}
@Override
public void imageProgress(ImageReader src, float percentageDone) {}
@Override
public void imageStarted(ImageReader src, int imageIndex) {}
@Override
public void thumbnailComplete(ImageReader src) {}
@Override
public void thumbnailProgress(ImageReader src, float percentageDone) {}
@Override
public void thumbnailStarted(ImageReader src, int iIdx, int tIdx) {}
@Override
public void sequenceComplete(ImageReader src) {}
@Override
public void sequenceStarted(ImageReader src, int minIndex) {}
@Override
public void readAborted(ImageReader src) {}
}
private static Boolean isLinkedProfileDisabled = null;
@SuppressWarnings("removal")
private static boolean isLinkedProfileAllowed() {
if (isLinkedProfileDisabled == null) {
PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return Boolean.getBoolean("sun.imageio.plugins.bmp.disableLinkedProfiles");
}
};
isLinkedProfileDisabled = AccessController.doPrivileged(a);
}
return !isLinkedProfileDisabled;
}
private static Boolean isWindowsPlatform = null;
/**
* Verifies whether the byte array contans a unc path.
* Non-UNC path examples:
* c:\path\to\file - simple notation
* \\?\c:\path\to\file - long notation
*
* UNC path examples:
* \\server\share - a UNC path in simple notation
* \\?\UNC\server\share - a UNC path in long notation
* \\.\some\device - a path to device.
*/
@SuppressWarnings("removal")
private static boolean isUncOrDevicePath(byte[] p) {
if (isWindowsPlatform == null) {
PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
String osname = System.getProperty("os.name");
return (osname != null &&
osname.toLowerCase().startsWith("win"));
}
};
isWindowsPlatform = AccessController.doPrivileged(a);
}
if (!isWindowsPlatform) {
/* no need for the check on platforms except windows */
return false;
}
/* normalize prefix of the path */
if (p[0] == '/') p[0] = '\\';
if (p[1] == '/') p[1] = '\\';
if (p[3] == '/') p[3] = '\\';
if ((p[0] == '\\') && (p[1] == '\\')) {
if ((p[2] == '?') && (p[3] == '\\')) {
// long path: whether unc or local
return ((p[4] == 'U' || p[4] == 'u') &&
(p[5] == 'N' || p[5] == 'n') &&
(p[6] == 'C' || p[6] == 'c'));
} else {
// device path or short unc notation
return true;
}
} else {
return false;
}
}
}
⏎ com/sun/imageio/plugins/bmp/BMPImageReader.java
Or download all of them as a single archive file:
File name: java.desktop-17.0.5-src.zip File size: 9152233 bytes Release date: 2022-09-13 Download
⇒ JDK 17 java.instrument.jmod - Instrument Module
2023-09-16, ≈269🔥, 0💬
Popular Posts:
What is jxl.jar 2.6.12? jxl.jar 2.6.12 is the JAR file for Java Excel API 2.6.12, which is a Java li...
Where to find answers to frequently asked questions on Downloading and Installing ojdbc.jar - JDBC D...
HttpComponents Client Source Code Files are provided in the source package file, httpcomponents-clie...
What Is js.jar in Rhino JavaScript 1.7R5? js.jar in Rhino JavaScript 1.7R5 is the JAR file for Rhino...
What JAR files are required to run dom\Writer.java provided in the Apache Xerces package? 3 JAR file...