mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-06 04:55:30 -04:00
BMP cleanup
This commit is contained in:
parent
a8472170c4
commit
d472191926
@ -81,8 +81,8 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
super(new BMPImageReaderSpi());
|
super(new BMPImageReaderSpi());
|
||||||
}
|
}
|
||||||
|
|
||||||
BMPImageReader(final ImageReaderSpi pProvider) {
|
BMPImageReader(final ImageReaderSpi provider) {
|
||||||
super(pProvider);
|
super(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -129,6 +129,7 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
// Read DIB header
|
// Read DIB header
|
||||||
header = DIBHeader.read(imageInput);
|
header = DIBHeader.read(imageInput);
|
||||||
|
// System.out.println("header = " + header);
|
||||||
|
|
||||||
if (pixelOffset < header.size + DIB.BMP_FILE_HEADER_SIZE) {
|
if (pixelOffset < header.size + DIB.BMP_FILE_HEADER_SIZE) {
|
||||||
throw new IIOException("Invalid pixel offset: " + pixelOffset);
|
throw new IIOException("Invalid pixel offset: " + pixelOffset);
|
||||||
@ -186,30 +187,30 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWidth(int pImageIndex) throws IOException {
|
public int getWidth(int imageIndex) throws IOException {
|
||||||
checkBounds(pImageIndex);
|
checkBounds(imageIndex);
|
||||||
|
|
||||||
return header.getWidth();
|
return header.getWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getHeight(int pImageIndex) throws IOException {
|
public int getHeight(int imageIndex) throws IOException {
|
||||||
checkBounds(pImageIndex);
|
checkBounds(imageIndex);
|
||||||
|
|
||||||
return header.getHeight();
|
return header.getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<ImageTypeSpecifier> getImageTypes(int pImageIndex) throws IOException {
|
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
|
||||||
checkBounds(pImageIndex);
|
checkBounds(imageIndex);
|
||||||
|
|
||||||
// TODO: Better implementation, include INT_RGB types for 3BYTE_BGR and 4BYTE_ABGR for INT_ARGB
|
// TODO: Better implementation, include INT_RGB types for 3BYTE_BGR and 4BYTE_ABGR for INT_ARGB
|
||||||
return Collections.singletonList(getRawImageType(pImageIndex)).iterator();
|
return Collections.singletonList(getRawImageType(imageIndex)).iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImageTypeSpecifier getRawImageType(int pImageIndex) throws IOException {
|
public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException {
|
||||||
checkBounds(pImageIndex);
|
checkBounds(imageIndex);
|
||||||
|
|
||||||
if (header.getPlanes() != 1) {
|
if (header.getPlanes() != 1) {
|
||||||
throw new IIOException("Multiple planes not supported");
|
throw new IIOException("Multiple planes not supported");
|
||||||
@ -685,8 +686,8 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "UnusedDeclaration", "SameParameterValue" })
|
@SuppressWarnings({ "unchecked", "UnusedDeclaration", "SameParameterValue" })
|
||||||
static <T extends Throwable> void throwAs(final Class<T> pType, final Throwable pThrowable) throws T {
|
static <T extends Throwable> void throwAs(final Class<T> type, final Throwable throwable) throws T {
|
||||||
throw (T) pThrowable;
|
throw (T) throwable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ListenerDelegator extends ProgressListenerBase implements IIOReadUpdateListener, IIOReadWarningListener {
|
private class ListenerDelegator extends ProgressListenerBase implements IIOReadUpdateListener, IIOReadWarningListener {
|
||||||
|
@ -65,16 +65,16 @@ public final class BMPImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canDecodeInput(final Object pSource) throws IOException {
|
public boolean canDecodeInput(final Object source) throws IOException {
|
||||||
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource);
|
return source instanceof ImageInputStream && canDecode((ImageInputStream) source);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean canDecode(final ImageInputStream pInput) throws IOException {
|
private static boolean canDecode(final ImageInputStream input) throws IOException {
|
||||||
byte[] fileHeader = new byte[18]; // Strictly: file header (14 bytes) + BMP header size field (4 bytes)
|
byte[] fileHeader = new byte[18]; // Strictly: file header (14 bytes) + BMP header size field (4 bytes)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pInput.mark();
|
input.mark();
|
||||||
pInput.readFully(fileHeader);
|
input.readFully(fileHeader);
|
||||||
|
|
||||||
// Magic: BM
|
// Magic: BM
|
||||||
if (fileHeader[0] != 'B' || fileHeader[1] != 'M') {
|
if (fileHeader[0] != 'B' || fileHeader[1] != 'M') {
|
||||||
@ -112,15 +112,15 @@ public final class BMPImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
pInput.reset();
|
input.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageReader createReaderInstance(final Object pExtension) {
|
public ImageReader createReaderInstance(final Object extension) {
|
||||||
return new BMPImageReader(this);
|
return new BMPImageReader(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescription(final Locale pLocale) {
|
public String getDescription(final Locale locale) {
|
||||||
return "Windows Device Independent Bitmap Format (BMP) Reader";
|
return "Windows Device Independent Bitmap Format (BMP) Reader";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ import java.nio.ByteOrder;
|
|||||||
* BMPImageWriter
|
* BMPImageWriter
|
||||||
*/
|
*/
|
||||||
public final class BMPImageWriter extends DIBImageWriter {
|
public final class BMPImageWriter extends DIBImageWriter {
|
||||||
protected BMPImageWriter(ImageWriterSpi provider) {
|
BMPImageWriter(ImageWriterSpi provider) {
|
||||||
super(provider);
|
super(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
|||||||
|
|
||||||
import com.twelvemonkeys.imageio.AbstractMetadata;
|
import com.twelvemonkeys.imageio.AbstractMetadata;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
@ -141,7 +142,7 @@ final class BMPMetadata extends AbstractMetadata {
|
|||||||
@Override
|
@Override
|
||||||
protected IIOMetadataNode getStandardChromaNode() {
|
protected IIOMetadataNode getStandardChromaNode() {
|
||||||
// NOTE: BMP files may contain a color map, even if true color...
|
// NOTE: BMP files may contain a color map, even if true color...
|
||||||
// Not sure if this is a good idea to expose to the meta data,
|
// Not sure if this is a good idea to expose to the metadata,
|
||||||
// as it might be unexpected... Then again...
|
// as it might be unexpected... Then again...
|
||||||
if (colorMap != null) {
|
if (colorMap != null) {
|
||||||
IIOMetadataNode chroma = new IIOMetadataNode("Chroma");
|
IIOMetadataNode chroma = new IIOMetadataNode("Chroma");
|
||||||
|
@ -29,11 +29,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
import java.awt.image.*;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes a bitmap structure.
|
* Describes a bitmap structure.
|
||||||
*
|
*
|
||||||
@ -47,9 +47,9 @@ abstract class BitmapDescriptor {
|
|||||||
protected BufferedImage image;
|
protected BufferedImage image;
|
||||||
protected BitmapMask mask;
|
protected BitmapMask mask;
|
||||||
|
|
||||||
public BitmapDescriptor(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
public BitmapDescriptor(final DirectoryEntry entry, final DIBHeader header) {
|
||||||
entry = notNull(pEntry, "entry");;
|
this.entry = notNull(entry, "entry");
|
||||||
header = notNull(pHeader, "header");
|
this.header = notNull(header, "header");
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract public BufferedImage getImage() throws IOException;
|
abstract public BufferedImage getImage() throws IOException;
|
||||||
@ -75,7 +75,7 @@ abstract class BitmapDescriptor {
|
|||||||
return getClass().getSimpleName() + "[" + entry + ", " + header + "]";
|
return getClass().getSimpleName() + "[" + entry + ", " + header + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void setMask(final BitmapMask mask) {
|
final void setMask(final BitmapMask mask) {
|
||||||
this.mask = mask;
|
this.mask = mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,10 +29,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.*;
|
||||||
import java.awt.image.DataBuffer;
|
|
||||||
import java.awt.image.IndexColorModel;
|
|
||||||
import java.awt.image.WritableRaster;
|
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,12 +38,13 @@ import java.util.Hashtable;
|
|||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: BitmapIndexed.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
* @version $Id: BitmapIndexed.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
*/
|
*/
|
||||||
class BitmapIndexed extends BitmapDescriptor {
|
final class BitmapIndexed extends BitmapDescriptor {
|
||||||
protected final int[] bits;
|
final int[] bits;
|
||||||
protected final int[] colors;
|
final int[] colors;
|
||||||
|
|
||||||
|
public BitmapIndexed(final DirectoryEntry entry, final DIBHeader header) {
|
||||||
|
super(entry, header);
|
||||||
|
|
||||||
public BitmapIndexed(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
|
||||||
super(pEntry, pHeader);
|
|
||||||
bits = new int[getWidth() * getHeight()];
|
bits = new int[getWidth() * getHeight()];
|
||||||
|
|
||||||
// NOTE: We're adding space for one extra color, for transparency
|
// NOTE: We're adding space for one extra color, for transparency
|
||||||
@ -59,20 +57,16 @@ class BitmapIndexed extends BitmapDescriptor {
|
|||||||
|
|
||||||
IndexColorModel icm = createColorModel();
|
IndexColorModel icm = createColorModel();
|
||||||
|
|
||||||
// This is slightly obscure, and should probably be moved..
|
// We add cursor hotspot as a property to images created from CUR format.
|
||||||
|
// This is slightly obscure, and should probably be moved...
|
||||||
Hashtable<String, Object> properties = null;
|
Hashtable<String, Object> properties = null;
|
||||||
if (entry instanceof DirectoryEntry.CUREntry) {
|
if (entry instanceof DirectoryEntry.CUREntry) {
|
||||||
properties = new Hashtable<>(1);
|
properties = new Hashtable<>(1);
|
||||||
properties.put("cursor_hotspot", ((DirectoryEntry.CUREntry) this.entry).getHotspot());
|
properties.put("cursor_hotspot", ((DirectoryEntry.CUREntry) this.entry).getHotspot());
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferedImage image = new BufferedImage(
|
WritableRaster raster = icm.createCompatibleWritableRaster(getWidth(), getHeight());
|
||||||
icm,
|
BufferedImage image = new BufferedImage(icm, raster, icm.isAlphaPremultiplied(), properties);
|
||||||
icm.createCompatibleWritableRaster(getWidth(), getHeight()),
|
|
||||||
icm.isAlphaPremultiplied(), properties
|
|
||||||
);
|
|
||||||
|
|
||||||
WritableRaster raster = image.getRaster();
|
|
||||||
|
|
||||||
// Make pixels transparent according to mask
|
// Make pixels transparent according to mask
|
||||||
final int trans = icm.getTransparentPixel();
|
final int trans = icm.getTransparentPixel();
|
||||||
@ -105,7 +99,7 @@ class BitmapIndexed extends BitmapDescriptor {
|
|||||||
int index = findTransparentIndexMaybeRemap(this.colors, this.bits);
|
int index = findTransparentIndexMaybeRemap(this.colors, this.bits);
|
||||||
|
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
// No duplicate found, increase bitcount
|
// No duplicate found, increase bit count
|
||||||
bits++;
|
bits++;
|
||||||
transparent = this.colors.length - 1;
|
transparent = this.colors.length - 1;
|
||||||
}
|
}
|
||||||
@ -117,10 +111,8 @@ class BitmapIndexed extends BitmapDescriptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: Setting hasAlpha to true, makes things work on 1.2
|
// NOTE: Setting hasAlpha to true, makes things work on 1.2
|
||||||
return new IndexColorModel(
|
return new IndexColorModel(bits, colors, this.colors, 0, true, transparent,
|
||||||
bits, colors, this.colors, 0, true, transparent,
|
bits <= 8 ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT);
|
||||||
bits <= 8 ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int findTransparentIndexMaybeRemap(final int[] colors, final int[] bits) {
|
private static int findTransparentIndexMaybeRemap(final int[] colors, final int[] bits) {
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.*;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,17 +39,17 @@ import java.awt.image.BufferedImage;
|
|||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: BitmapMask.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
* @version $Id: BitmapMask.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
*/
|
*/
|
||||||
class BitmapMask extends BitmapDescriptor {
|
final class BitmapMask extends BitmapDescriptor {
|
||||||
protected final BitmapIndexed bitMask;
|
final BitmapIndexed bitMask;
|
||||||
|
|
||||||
public BitmapMask(final DirectoryEntry pParent, final DIBHeader pHeader) {
|
public BitmapMask(final DirectoryEntry parent, final DIBHeader header) {
|
||||||
super(pParent, pHeader);
|
super(parent, header);
|
||||||
bitMask = new BitmapIndexed(pParent, pHeader);
|
bitMask = new BitmapIndexed(parent, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isTransparent(final int pX, final int pY) {
|
boolean isTransparent(final int x, final int y) {
|
||||||
// NOTE: 1: Fully transparent, 0: Opaque...
|
// NOTE: 1: Fully transparent, 0: Opaque...
|
||||||
return bitMask.bits[pX + pY * getWidth()] != 0;
|
return bitMask.bits[x + y * getWidth()] != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferedImage getImage() {
|
public BufferedImage getImage() {
|
||||||
|
@ -31,8 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.*;
|
||||||
import java.awt.image.WritableRaster;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes an RGB/true color bitmap structure (16, 24 and 32 bits per pixel).
|
* Describes an RGB/true color bitmap structure (16, 24 and 32 bits per pixel).
|
||||||
@ -40,10 +39,10 @@ import java.awt.image.WritableRaster;
|
|||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: BitmapRGB.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
* @version $Id: BitmapRGB.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
*/
|
*/
|
||||||
class BitmapRGB extends BitmapDescriptor {
|
final class BitmapRGB extends BitmapDescriptor {
|
||||||
|
|
||||||
public BitmapRGB(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
public BitmapRGB(final DirectoryEntry entry, final DIBHeader header) {
|
||||||
super(pEntry, pHeader);
|
super(entry, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -71,7 +70,7 @@ class BitmapRGB extends BitmapDescriptor {
|
|||||||
|
|
||||||
WritableRaster alphaRaster = masked.getAlphaRaster();
|
WritableRaster alphaRaster = masked.getAlphaRaster();
|
||||||
|
|
||||||
byte[] trans = {0x0};
|
byte[] trans = {0x00};
|
||||||
for (int y = 0; y < getHeight(); y++) {
|
for (int y = 0; y < getHeight(); y++) {
|
||||||
for (int x = 0; x < getWidth(); x++) {
|
for (int x = 0; x < getWidth(); x++) {
|
||||||
if (mask.isTransparent(x, y)) {
|
if (mask.isTransparent(x, y)) {
|
||||||
|
@ -30,10 +30,9 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents bitmap structures we can't read.
|
* Represents bitmap structures we can't read.
|
||||||
@ -42,13 +41,13 @@ import javax.imageio.IIOException;
|
|||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: BitmapUnsupported.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
* @version $Id: BitmapUnsupported.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||||
*/
|
*/
|
||||||
class BitmapUnsupported extends BitmapDescriptor {
|
final class BitmapUnsupported extends BitmapDescriptor {
|
||||||
private String message;
|
private final String message;
|
||||||
|
|
||||||
public BitmapUnsupported(final DirectoryEntry pEntry, DIBHeader header, final String pMessage) {
|
public BitmapUnsupported(final DirectoryEntry entry, DIBHeader header, final String message) {
|
||||||
super(pEntry, header);
|
super(entry, header);
|
||||||
|
|
||||||
message = pMessage;
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -48,22 +48,22 @@ public final class CURImageReader extends DIBImageReader {
|
|||||||
super(new CURImageReaderSpi());
|
super(new CURImageReaderSpi());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CURImageReader(final ImageReaderSpi pProvider) {
|
CURImageReader(final ImageReaderSpi provider) {
|
||||||
super(pProvider);
|
super(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the hot spot location for the cursor.
|
* Returns the hot spot location for the cursor.
|
||||||
*
|
*
|
||||||
* @param pImageIndex the index of the cursor in the current input.
|
* @param imageIndex the index of the cursor in the current input.
|
||||||
* @return the hot spot location for the cursor
|
* @return the hot spot location for the cursor
|
||||||
*
|
*
|
||||||
* @throws java.io.IOException if an I/O exception occurs during reading of image meta data
|
* @throws java.io.IOException if an I/O exception occurs during reading of image meta data
|
||||||
* @throws IndexOutOfBoundsException if {@code pImageIndex} is less than {@code 0} or greater than/equal to
|
* @throws IndexOutOfBoundsException if {@code pImageIndex} is less than {@code 0} or greater than/equal to
|
||||||
* the number of cursors in the file
|
* the number of cursors in the file
|
||||||
*/
|
*/
|
||||||
public final Point getHotSpot(final int pImageIndex) throws IOException {
|
public Point getHotSpot(final int imageIndex) throws IOException {
|
||||||
DirectoryEntry.CUREntry entry = (DirectoryEntry.CUREntry) getEntry(pImageIndex);
|
DirectoryEntry.CUREntry entry = (DirectoryEntry.CUREntry) getEntry(imageIndex);
|
||||||
return entry.getHotspot();
|
return entry.getHotspot();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
|||||||
|
|
||||||
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
||||||
|
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -49,15 +48,15 @@ public final class CURImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
super(new CURProviderInfo());
|
super(new CURProviderInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canDecodeInput(final Object pSource) throws IOException {
|
public boolean canDecodeInput(final Object source) throws IOException {
|
||||||
return pSource instanceof ImageInputStream && ICOImageReaderSpi.canDecode((ImageInputStream) pSource, DIB.TYPE_CUR);
|
return source instanceof ImageInputStream && ICOImageReaderSpi.canDecode((ImageInputStream) source, DIB.TYPE_CUR);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageReader createReaderInstance(final Object pExtension) throws IOException {
|
public CURImageReader createReaderInstance(final Object extension) {
|
||||||
return new CURImageReader(this);
|
return new CURImageReader(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescription(final Locale pLocale) {
|
public String getDescription(final Locale locale) {
|
||||||
return "Windows Cursor Format (CUR) Reader";
|
return "Windows Cursor Format (CUR) Reader";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,12 +30,11 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the DIB (Device Independent Bitmap) Information header structure.
|
* Represents the DIB (Device Independent Bitmap) Information header structure.
|
||||||
*
|
*
|
||||||
@ -91,17 +90,17 @@ abstract class DIBHeader {
|
|||||||
protected DIBHeader() {
|
protected DIBHeader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DIBHeader read(final DataInput pStream) throws IOException {
|
public static DIBHeader read(final DataInput stream) throws IOException {
|
||||||
int size = pStream.readInt();
|
int size = stream.readInt();
|
||||||
|
|
||||||
DIBHeader header = createHeader(size);
|
DIBHeader header = createHeader(size);
|
||||||
header.read(size, pStream);
|
header.read(size, stream);
|
||||||
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DIBHeader createHeader(final int pSize) throws IOException {
|
private static DIBHeader createHeader(final int size) throws IOException {
|
||||||
switch (pSize) {
|
switch (size) {
|
||||||
case DIB.BITMAP_CORE_HEADER_SIZE:
|
case DIB.BITMAP_CORE_HEADER_SIZE:
|
||||||
return new BitmapCoreHeader();
|
return new BitmapCoreHeader();
|
||||||
case DIB.OS2_V2_HEADER_16_SIZE:
|
case DIB.OS2_V2_HEADER_16_SIZE:
|
||||||
@ -118,11 +117,12 @@ abstract class DIBHeader {
|
|||||||
case DIB.BITMAP_V5_INFO_HEADER_SIZE:
|
case DIB.BITMAP_V5_INFO_HEADER_SIZE:
|
||||||
return new BitmapV5InfoHeader();
|
return new BitmapV5InfoHeader();
|
||||||
default:
|
default:
|
||||||
throw new IIOException(String.format("Unknown Bitmap Information Header (size: %s)", pSize));
|
throw new IIOException(String.format("Unknown Bitmap Information Header (size: %s)", size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void read(int pSize, DataInput pStream) throws IOException;
|
protected abstract void read(int size, DataInput stream) throws IOException;
|
||||||
|
protected abstract void write(final DataOutput stream) throws IOException;
|
||||||
|
|
||||||
public final int getSize() {
|
public final int getSize() {
|
||||||
return size;
|
return size;
|
||||||
@ -189,12 +189,12 @@ abstract class DIBHeader {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int[] readMasks(final DataInput pStream, final boolean hasAlphaMask) throws IOException {
|
private static int[] readMasks(final DataInput stream, final boolean hasAlphaMask) throws IOException {
|
||||||
int maskCount = hasAlphaMask ? 4 : 3;
|
int maskCount = hasAlphaMask ? 4 : 3;
|
||||||
int[] masks = new int[4];
|
int[] masks = new int[4];
|
||||||
|
|
||||||
for (int i = 0; i < maskCount; i++) {
|
for (int i = 0; i < maskCount; i++) {
|
||||||
masks[i] = pStream.readInt();
|
masks[i] = stream.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
return masks;
|
return masks;
|
||||||
@ -205,24 +205,30 @@ abstract class DIBHeader {
|
|||||||
// TODO: Get rid of code duplication below...
|
// TODO: Get rid of code duplication below...
|
||||||
|
|
||||||
static final class BitmapCoreHeader extends DIBHeader {
|
static final class BitmapCoreHeader extends DIBHeader {
|
||||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
@Override
|
||||||
if (pSize != DIB.BITMAP_CORE_HEADER_SIZE) {
|
protected void read(final int size, final DataInput stream) throws IOException {
|
||||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_CORE_HEADER_SIZE));
|
if (size != DIB.BITMAP_CORE_HEADER_SIZE) {
|
||||||
|
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_CORE_HEADER_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
size = pSize;
|
this.size = size;
|
||||||
|
|
||||||
// NOTE: Unlike all other headers, width and height are unsigned SHORT values (16 bit)!
|
// NOTE: Unlike all other headers, width and height are unsigned SHORT values (16 bit)!
|
||||||
width = pStream.readUnsignedShort();
|
width = stream.readUnsignedShort();
|
||||||
height = pStream.readShort();
|
height = stream.readShort();
|
||||||
|
|
||||||
if (height < 0) {
|
if (height < 0) {
|
||||||
height = -height;
|
height = -height;
|
||||||
topDown = true;
|
topDown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
planes = pStream.readUnsignedShort();
|
planes = stream.readUnsignedShort();
|
||||||
bitCount = pStream.readUnsignedShort();
|
bitCount = stream.readUnsignedShort();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void write(DataOutput stream) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBMPVersion() {
|
public String getBMPVersion() {
|
||||||
@ -242,45 +248,51 @@ abstract class DIBHeader {
|
|||||||
*/
|
*/
|
||||||
static final class BitmapCoreHeaderV2 extends DIBHeader {
|
static final class BitmapCoreHeaderV2 extends DIBHeader {
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
@Override
|
||||||
if (pSize != DIB.OS2_V2_HEADER_SIZE && pSize != DIB.OS2_V2_HEADER_16_SIZE) {
|
protected void read(final int size, final DataInput stream) throws IOException {
|
||||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.OS2_V2_HEADER_SIZE));
|
if (size != DIB.OS2_V2_HEADER_SIZE && size != DIB.OS2_V2_HEADER_16_SIZE) {
|
||||||
|
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.OS2_V2_HEADER_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
size = pSize;
|
this.size = size;
|
||||||
|
|
||||||
width = pStream.readInt();
|
width = stream.readInt();
|
||||||
height = pStream.readInt();
|
height = stream.readInt();
|
||||||
|
|
||||||
if (height < 0) {
|
if (height < 0) {
|
||||||
height = -height;
|
height = -height;
|
||||||
topDown = true;
|
topDown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
planes = pStream.readUnsignedShort();
|
planes = stream.readUnsignedShort();
|
||||||
bitCount = pStream.readUnsignedShort();
|
bitCount = stream.readUnsignedShort();
|
||||||
|
|
||||||
if (pSize != DIB.OS2_V2_HEADER_16_SIZE) {
|
if (size != DIB.OS2_V2_HEADER_16_SIZE) {
|
||||||
compression = pStream.readInt();
|
compression = stream.readInt();
|
||||||
|
|
||||||
imageSize = pStream.readInt();
|
imageSize = stream.readInt();
|
||||||
|
|
||||||
xPixelsPerMeter = pStream.readInt();
|
xPixelsPerMeter = stream.readInt();
|
||||||
yPixelsPerMeter = pStream.readInt();
|
yPixelsPerMeter = stream.readInt();
|
||||||
|
|
||||||
colorsUsed = pStream.readInt();
|
colorsUsed = stream.readInt();
|
||||||
colorsImportant = pStream.readInt();
|
colorsImportant = stream.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Use? These fields are not reflected in metadata as per now...
|
// TODO: Use? These fields are not reflected in metadata as per now...
|
||||||
int units = pStream.readShort();
|
int units = stream.readShort();
|
||||||
int reserved = pStream.readShort();
|
int reserved = stream.readShort();
|
||||||
int recording = pStream.readShort(); // Recording algorithm
|
int recording = stream.readShort(); // Recording algorithm
|
||||||
int rendering = pStream.readShort(); // Halftoning algorithm
|
int rendering = stream.readShort(); // Halftoning algorithm
|
||||||
int size1 = pStream.readInt(); // Reserved for halftoning use
|
int size1 = stream.readInt(); // Reserved for halftoning use
|
||||||
int size2 = pStream.readInt(); // Reserved for halftoning use
|
int size2 = stream.readInt(); // Reserved for halftoning use
|
||||||
int colorEncoding = pStream.readInt(); // Color model used in bitmap
|
int colorEncoding = stream.readInt(); // Color model used in bitmap
|
||||||
int identifier = pStream.readInt(); // Reserved for application use
|
int identifier = stream.readInt(); // Reserved for application use
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void write(DataOutput stream) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBMPVersion() {
|
public String getBMPVersion() {
|
||||||
@ -288,7 +300,6 @@ abstract class DIBHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the DIB (Device Independent Bitmap) Windows 3.0 Bitmap Information header structure.
|
* Represents the DIB (Device Independent Bitmap) Windows 3.0 Bitmap Information header structure.
|
||||||
* This is the common format for persistent DIB structures, even if Windows
|
* This is the common format for persistent DIB structures, even if Windows
|
||||||
@ -304,44 +315,46 @@ abstract class DIBHeader {
|
|||||||
* @see <a href="https://forums.adobe.com/message/3272950#3272950">BITMAPV3INFOHEADER</a>.
|
* @see <a href="https://forums.adobe.com/message/3272950#3272950">BITMAPV3INFOHEADER</a>.
|
||||||
*/
|
*/
|
||||||
static final class BitmapInfoHeader extends DIBHeader {
|
static final class BitmapInfoHeader extends DIBHeader {
|
||||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
@Override
|
||||||
if (!(pSize == DIB.BITMAP_INFO_HEADER_SIZE || pSize == DIB.BITMAP_V2_INFO_HEADER_SIZE || pSize == DIB.BITMAP_V3_INFO_HEADER_SIZE)) {
|
protected void read(final int size, final DataInput stream) throws IOException {
|
||||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_INFO_HEADER_SIZE));
|
if (!(size == DIB.BITMAP_INFO_HEADER_SIZE || size == DIB.BITMAP_V2_INFO_HEADER_SIZE || size == DIB.BITMAP_V3_INFO_HEADER_SIZE)) {
|
||||||
|
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_INFO_HEADER_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
size = pSize;
|
this.size = size;
|
||||||
|
|
||||||
width = pStream.readInt();
|
width = stream.readInt();
|
||||||
height = pStream.readInt();
|
height = stream.readInt();
|
||||||
|
|
||||||
if (height < 0) {
|
if (height < 0) {
|
||||||
height = -height;
|
height = -height;
|
||||||
topDown = true;
|
topDown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
planes = pStream.readUnsignedShort();
|
planes = stream.readUnsignedShort();
|
||||||
bitCount = pStream.readUnsignedShort();
|
bitCount = stream.readUnsignedShort();
|
||||||
compression = pStream.readInt();
|
compression = stream.readInt();
|
||||||
|
|
||||||
imageSize = pStream.readInt();
|
imageSize = stream.readInt();
|
||||||
|
|
||||||
xPixelsPerMeter = pStream.readInt();
|
xPixelsPerMeter = stream.readInt();
|
||||||
yPixelsPerMeter = pStream.readInt();
|
yPixelsPerMeter = stream.readInt();
|
||||||
|
|
||||||
colorsUsed = pStream.readInt();
|
colorsUsed = stream.readInt();
|
||||||
colorsImportant = pStream.readInt();
|
colorsImportant = stream.readInt();
|
||||||
|
|
||||||
// Read masks if we have V2 or V3
|
// Read masks if we have V2 or V3
|
||||||
// or if we have compression BITFIELDS or ALPHA_BITFIELDS
|
// or if we have compression BITFIELDS or ALPHA_BITFIELDS
|
||||||
if (size == DIB.BITMAP_V2_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_BITFIELDS) {
|
if (this.size == DIB.BITMAP_V2_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_BITFIELDS) {
|
||||||
masks = readMasks(pStream, false);
|
masks = readMasks(stream, false);
|
||||||
}
|
}
|
||||||
else if (size == DIB.BITMAP_V3_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_ALPHA_BITFIELDS) {
|
else if (this.size == DIB.BITMAP_V3_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_ALPHA_BITFIELDS) {
|
||||||
masks = readMasks(pStream, true);
|
masks = readMasks(stream, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(final DataOutput stream) throws IOException {
|
@Override
|
||||||
|
protected void write(final DataOutput stream) throws IOException {
|
||||||
stream.writeInt(DIB.BITMAP_INFO_HEADER_SIZE);
|
stream.writeInt(DIB.BITMAP_INFO_HEADER_SIZE);
|
||||||
|
|
||||||
stream.writeInt(width);
|
stream.writeInt(width);
|
||||||
@ -359,7 +372,7 @@ abstract class DIBHeader {
|
|||||||
stream.writeInt(colorsUsed);
|
stream.writeInt(colorsUsed);
|
||||||
stream.writeInt(colorsImportant);
|
stream.writeInt(colorsImportant);
|
||||||
|
|
||||||
// TODO: Write masks, if bitfields
|
// TODO: Write masks, if COMPRESSION_BITFIELDS/COMPRESSION_ALPHA_BITFIELDS
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBMPVersion() {
|
public String getBMPVersion() {
|
||||||
@ -376,105 +389,160 @@ abstract class DIBHeader {
|
|||||||
* Represents the BITMAPV4INFOHEADER structure.
|
* Represents the BITMAPV4INFOHEADER structure.
|
||||||
*/
|
*/
|
||||||
static final class BitmapV4InfoHeader extends DIBHeader {
|
static final class BitmapV4InfoHeader extends DIBHeader {
|
||||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
@Override
|
||||||
if (pSize != DIB.BITMAP_V4_INFO_HEADER_SIZE) {
|
protected void read(final int size, final DataInput stream) throws IOException {
|
||||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_V4_INFO_HEADER_SIZE));
|
if (size != DIB.BITMAP_V4_INFO_HEADER_SIZE) {
|
||||||
|
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_V4_INFO_HEADER_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
size = pSize;
|
this.size = size;
|
||||||
|
|
||||||
width = pStream.readInt();
|
width = stream.readInt();
|
||||||
height = pStream.readInt();
|
height = stream.readInt();
|
||||||
|
|
||||||
if (height < 0) {
|
if (height < 0) {
|
||||||
height = -height;
|
height = -height;
|
||||||
topDown = true;
|
topDown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
planes = pStream.readUnsignedShort();
|
planes = stream.readUnsignedShort();
|
||||||
bitCount = pStream.readUnsignedShort();
|
bitCount = stream.readUnsignedShort();
|
||||||
compression = pStream.readInt();
|
compression = stream.readInt();
|
||||||
|
|
||||||
imageSize = pStream.readInt();
|
imageSize = stream.readInt();
|
||||||
|
|
||||||
xPixelsPerMeter = pStream.readInt();
|
xPixelsPerMeter = stream.readInt();
|
||||||
yPixelsPerMeter = pStream.readInt();
|
yPixelsPerMeter = stream.readInt();
|
||||||
|
|
||||||
colorsUsed = pStream.readInt();
|
colorsUsed = stream.readInt();
|
||||||
colorsImportant = pStream.readInt();
|
colorsImportant = stream.readInt();
|
||||||
|
|
||||||
masks = readMasks(pStream, true);
|
masks = readMasks(stream, true);
|
||||||
|
|
||||||
colorSpaceType = pStream.readInt(); // Should be 0 for V4
|
colorSpaceType = stream.readInt(); // Should be 0 for V4
|
||||||
cieXYZEndpoints = new double[9];
|
cieXYZEndpoints = new double[9];
|
||||||
|
|
||||||
for (int i = 0; i < cieXYZEndpoints.length; i++) {
|
for (int i = 0; i < cieXYZEndpoints.length; i++) {
|
||||||
cieXYZEndpoints[i] = pStream.readInt(); // TODO: Hmmm...?
|
cieXYZEndpoints[i] = stream.readInt(); // TODO: Hmmm...?
|
||||||
}
|
}
|
||||||
|
|
||||||
gamma = new int[3];
|
gamma = new int[3];
|
||||||
|
|
||||||
for (int i = 0; i < gamma.length; i++) {
|
for (int i = 0; i < gamma.length; i++) {
|
||||||
gamma[i] = pStream.readInt();
|
gamma[i] = stream.readInt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBMPVersion() {
|
public String getBMPVersion() {
|
||||||
return "BMP v. 4.x";
|
return "BMP v. 4.x";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void write(DataOutput stream) throws IOException {
|
||||||
|
stream.writeInt(DIB.BITMAP_V4_INFO_HEADER_SIZE);
|
||||||
|
|
||||||
|
stream.writeInt(width);
|
||||||
|
stream.writeInt(topDown ? -height : height);
|
||||||
|
|
||||||
|
stream.writeShort(planes);
|
||||||
|
stream.writeShort(bitCount);
|
||||||
|
stream.writeInt(compression);
|
||||||
|
|
||||||
|
stream.writeInt(imageSize);
|
||||||
|
|
||||||
|
stream.writeInt(xPixelsPerMeter);
|
||||||
|
stream.writeInt(yPixelsPerMeter);
|
||||||
|
|
||||||
|
stream.writeInt(colorsUsed);
|
||||||
|
stream.writeInt(colorsImportant);
|
||||||
|
|
||||||
|
// Red, Green, Blue, Alpha masks
|
||||||
|
stream.writeInt(masks[0]);
|
||||||
|
stream.writeInt(masks[1]);
|
||||||
|
stream.writeInt(masks[2]);
|
||||||
|
stream.writeInt(masks[3]);
|
||||||
|
|
||||||
|
// color space ("sRGB" LITTLE endian)
|
||||||
|
stream.writeInt(DIB.LCS_sRGB);
|
||||||
|
|
||||||
|
// 36 bytes CIE XYZ triples, unused for sRGB
|
||||||
|
stream.writeInt(0);
|
||||||
|
stream.writeInt(0);
|
||||||
|
stream.writeInt(0);
|
||||||
|
|
||||||
|
stream.writeInt(0);
|
||||||
|
stream.writeInt(0);
|
||||||
|
stream.writeInt(0);
|
||||||
|
|
||||||
|
stream.writeInt(0);
|
||||||
|
stream.writeInt(0);
|
||||||
|
stream.writeInt(0);
|
||||||
|
|
||||||
|
// Red gamma, unused for sRGB
|
||||||
|
// Green gamma, unused for sRGB
|
||||||
|
// Blue gamma, unused for sRGB
|
||||||
|
stream.writeInt(0);
|
||||||
|
stream.writeInt(0);
|
||||||
|
stream.writeInt(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the BITMAPV5INFOHEADER structure.
|
* Represents the BITMAPV5INFOHEADER structure.
|
||||||
*/
|
*/
|
||||||
static final class BitmapV5InfoHeader extends DIBHeader {
|
static final class BitmapV5InfoHeader extends DIBHeader {
|
||||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
protected void read(final int size, final DataInput stream) throws IOException {
|
||||||
if (pSize != DIB.BITMAP_V5_INFO_HEADER_SIZE) {
|
if (size != DIB.BITMAP_V5_INFO_HEADER_SIZE) {
|
||||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_V5_INFO_HEADER_SIZE));
|
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_V5_INFO_HEADER_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
size = pSize;
|
this.size = size;
|
||||||
|
|
||||||
width = pStream.readInt();
|
width = stream.readInt();
|
||||||
height = pStream.readInt();
|
height = stream.readInt();
|
||||||
|
|
||||||
if (height < 0) {
|
if (height < 0) {
|
||||||
height = -height;
|
height = -height;
|
||||||
topDown = true;
|
topDown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
planes = pStream.readUnsignedShort();
|
planes = stream.readUnsignedShort();
|
||||||
bitCount = pStream.readUnsignedShort();
|
bitCount = stream.readUnsignedShort();
|
||||||
compression = pStream.readInt();
|
compression = stream.readInt();
|
||||||
|
|
||||||
imageSize = pStream.readInt();
|
imageSize = stream.readInt();
|
||||||
|
|
||||||
xPixelsPerMeter = pStream.readInt();
|
xPixelsPerMeter = stream.readInt();
|
||||||
yPixelsPerMeter = pStream.readInt();
|
yPixelsPerMeter = stream.readInt();
|
||||||
|
|
||||||
colorsUsed = pStream.readInt();
|
colorsUsed = stream.readInt();
|
||||||
colorsImportant = pStream.readInt();
|
colorsImportant = stream.readInt();
|
||||||
|
|
||||||
masks = readMasks(pStream, true);
|
masks = readMasks(stream, true);
|
||||||
|
|
||||||
colorSpaceType = pStream.readInt();
|
colorSpaceType = stream.readInt();
|
||||||
|
|
||||||
cieXYZEndpoints = new double[9];
|
cieXYZEndpoints = new double[9];
|
||||||
|
|
||||||
for (int i = 0; i < cieXYZEndpoints.length; i++) {
|
for (int i = 0; i < cieXYZEndpoints.length; i++) {
|
||||||
cieXYZEndpoints[i] = pStream.readInt(); // TODO: Hmmm...?
|
cieXYZEndpoints[i] = stream.readInt(); // TODO: Hmmm...?
|
||||||
}
|
}
|
||||||
|
|
||||||
gamma = new int[3];
|
gamma = new int[3];
|
||||||
|
|
||||||
for (int i = 0; i < gamma.length; i++) {
|
for (int i = 0; i < gamma.length; i++) {
|
||||||
gamma[i] = pStream.readInt();
|
gamma[i] = stream.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
intent = pStream.readInt(); // TODO: Verify if this is same as ICC intent
|
intent = stream.readInt(); // TODO: Verify if this is same as ICC intent
|
||||||
profileData = pStream.readInt() & 0xffffffffL;
|
profileData = stream.readInt() & 0xffffffffL;
|
||||||
profileSize = pStream.readInt() & 0xffffffffL;
|
profileSize = stream.readInt() & 0xffffffffL;
|
||||||
pStream.readInt(); // Reserved
|
stream.readInt(); // Reserved
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void write(DataOutput stream) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBMPVersion() {
|
public String getBMPVersion() {
|
||||||
|
@ -30,19 +30,11 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import java.awt.*;
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
import java.awt.color.ColorSpace;
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
import java.awt.event.WindowAdapter;
|
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||||
import java.awt.event.WindowEvent;
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
import java.awt.image.*;
|
import com.twelvemonkeys.util.WeakWeakMap;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
@ -52,12 +44,18 @@ import javax.imageio.ImageTypeSpecifier;
|
|||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
import com.twelvemonkeys.image.ImageUtil;
|
import java.awt.color.*;
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
import java.awt.event.*;
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
import java.awt.image.*;
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
import java.io.File;
|
||||||
import com.twelvemonkeys.util.WeakWeakMap;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageReader for Microsoft Windows ICO (icon) format.
|
* ImageReader for Microsoft Windows ICO (icon) format.
|
||||||
@ -81,13 +79,13 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
private Directory directory;
|
private Directory directory;
|
||||||
|
|
||||||
// TODO: Review these, make sure we don't have a memory leak
|
// TODO: Review these, make sure we don't have a memory leak
|
||||||
private Map<DirectoryEntry, DIBHeader> headers = new WeakHashMap<>();
|
private final Map<DirectoryEntry, DIBHeader> headers = new WeakHashMap<>();
|
||||||
private Map<DirectoryEntry, BitmapDescriptor> descriptors = new WeakWeakMap<>();
|
private final Map<DirectoryEntry, BitmapDescriptor> descriptors = new WeakWeakMap<>();
|
||||||
|
|
||||||
private ImageReader pngImageReader;
|
private ImageReader pngImageReader;
|
||||||
|
|
||||||
protected DIBImageReader(final ImageReaderSpi pProvider) {
|
protected DIBImageReader(final ImageReaderSpi provider) {
|
||||||
super(pProvider);
|
super(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void resetMembers() {
|
protected void resetMembers() {
|
||||||
@ -102,8 +100,8 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<ImageTypeSpecifier> getImageTypes(final int pImageIndex) throws IOException {
|
public Iterator<ImageTypeSpecifier> getImageTypes(final int imageIndex) throws IOException {
|
||||||
DirectoryEntry entry = getEntry(pImageIndex);
|
DirectoryEntry entry = getEntry(imageIndex);
|
||||||
|
|
||||||
// NOTE: Delegate to PNG reader
|
// NOTE: Delegate to PNG reader
|
||||||
if (isPNG(entry)) {
|
if (isPNG(entry)) {
|
||||||
@ -155,39 +153,39 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
return getDirectory().count();
|
return getDirectory().count();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getWidth(final int pImageIndex) throws IOException {
|
public int getWidth(final int imageIndex) throws IOException {
|
||||||
return getEntry(pImageIndex).getWidth();
|
return getEntry(imageIndex).getWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getHeight(final int pImageIndex) throws IOException {
|
public int getHeight(final int imageIndex) throws IOException {
|
||||||
return getEntry(pImageIndex).getHeight();
|
return getEntry(imageIndex).getHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferedImage read(final int pImageIndex, final ImageReadParam pParam) throws IOException {
|
public BufferedImage read(final int imageIndex, final ImageReadParam param) throws IOException {
|
||||||
checkBounds(pImageIndex);
|
checkBounds(imageIndex);
|
||||||
|
|
||||||
processImageStarted(pImageIndex);
|
processImageStarted(imageIndex);
|
||||||
|
|
||||||
DirectoryEntry entry = getEntry(pImageIndex);
|
DirectoryEntry entry = getEntry(imageIndex);
|
||||||
|
|
||||||
BufferedImage destination;
|
BufferedImage destination;
|
||||||
|
|
||||||
if (isPNG(entry)) {
|
if (isPNG(entry)) {
|
||||||
// NOTE: Special case for Windows Vista, 256x256 PNG encoded images, with no DIB header...
|
// NOTE: Special case for Windows Vista, 256x256 PNG encoded images, with no DIB header...
|
||||||
destination = readPNG(entry, pParam);
|
destination = readPNG(entry, param);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// NOTE: If param does not have explicit destination, we'll try to create a BufferedImage later,
|
// NOTE: If param does not have explicit destination, we'll try to create a BufferedImage later,
|
||||||
// to allow for storing the cursor hotspot for CUR images
|
// to allow for storing the cursor hotspot for CUR images
|
||||||
destination = hasExplicitDestination(pParam) ?
|
destination = hasExplicitDestination(param) ?
|
||||||
getDestination(pParam, getImageTypes(pImageIndex), getWidth(pImageIndex), getHeight(pImageIndex)) : null;
|
getDestination(param, getImageTypes(imageIndex), getWidth(imageIndex), getHeight(imageIndex)) : null;
|
||||||
|
|
||||||
BufferedImage image = readBitmap(entry);
|
BufferedImage image = readBitmap(entry);
|
||||||
|
|
||||||
// TODO: Handle AOI and subsampling inline, probably not of big importance...
|
// TODO: Handle AOI and subsampling inline, probably not of big importance...
|
||||||
if (pParam != null) {
|
if (param != null) {
|
||||||
image = fakeAOI(image, pParam);
|
image = fakeAOI(image, param);
|
||||||
image = ImageUtil.toBuffered(fakeSubsampling(image, pParam));
|
image = ImageUtil.toBuffered(fakeSubsampling(image, param));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (destination == null) {
|
if (destination == null) {
|
||||||
@ -213,10 +211,10 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPNG(final DirectoryEntry pEntry) throws IOException {
|
private boolean isPNG(final DirectoryEntry entry) throws IOException {
|
||||||
long magic;
|
long magic;
|
||||||
|
|
||||||
imageInput.seek(pEntry.getOffset());
|
imageInput.seek(entry.getOffset());
|
||||||
imageInput.setByteOrder(ByteOrder.BIG_ENDIAN);
|
imageInput.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -229,22 +227,20 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
return magic == DIB.PNG_MAGIC;
|
return magic == DIB.PNG_MAGIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BufferedImage readPNG(final DirectoryEntry pEntry, final ImageReadParam pParam) throws IOException {
|
private BufferedImage readPNG(final DirectoryEntry entry, final ImageReadParam param) throws IOException {
|
||||||
// TODO: Consider delegating listener calls
|
// TODO: Consider delegating listener calls
|
||||||
return initPNGReader(pEntry).read(0, pParam);
|
return initPNGReader(entry).read(0, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Iterator<ImageTypeSpecifier> getImageTypesPNG(final DirectoryEntry pEntry) throws IOException {
|
private Iterator<ImageTypeSpecifier> getImageTypesPNG(final DirectoryEntry entry) throws IOException {
|
||||||
return initPNGReader(pEntry).getImageTypes(0);
|
return initPNGReader(entry).getImageTypes(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImageReader initPNGReader(final DirectoryEntry pEntry) throws IOException {
|
private ImageReader initPNGReader(final DirectoryEntry entry) throws IOException {
|
||||||
ImageReader pngReader = getPNGReader();
|
ImageReader pngReader = getPNGReader();
|
||||||
|
|
||||||
imageInput.seek(pEntry.getOffset());
|
imageInput.seek(entry.getOffset());
|
||||||
// InputStream inputStream = IIOUtil.createStreamAdapter(imageInput, pEntry.getSize());
|
ImageInputStream stream = new SubImageInputStream(imageInput, entry.getSize());
|
||||||
// ImageInputStream stream = ImageIO.createImageInputStream(inputStream);
|
|
||||||
ImageInputStream stream = new SubImageInputStream(imageInput, pEntry.getSize());
|
|
||||||
|
|
||||||
// NOTE: Will throw IOException on later reads if input is not PNG
|
// NOTE: Will throw IOException on later reads if input is not PNG
|
||||||
pngReader.setInput(stream);
|
pngReader.setInput(stream);
|
||||||
@ -271,31 +267,31 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
return pngImageReader;
|
return pngImageReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DIBHeader getHeader(final DirectoryEntry pEntry) throws IOException {
|
private DIBHeader getHeader(final DirectoryEntry entry) throws IOException {
|
||||||
if (!headers.containsKey(pEntry)) {
|
if (!headers.containsKey(entry)) {
|
||||||
imageInput.seek(pEntry.getOffset());
|
imageInput.seek(entry.getOffset());
|
||||||
DIBHeader header = DIBHeader.read(imageInput);
|
DIBHeader header = DIBHeader.read(imageInput);
|
||||||
headers.put(pEntry, header);
|
headers.put(entry, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
return headers.get(pEntry);
|
return headers.get(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private BufferedImage readBitmap(final DirectoryEntry pEntry) throws IOException {
|
private BufferedImage readBitmap(final DirectoryEntry entry) throws IOException {
|
||||||
// TODO: Get rid of the caching, as the images are mutable
|
// TODO: Get rid of the caching, as the images are mutable
|
||||||
BitmapDescriptor descriptor = descriptors.get(pEntry);
|
BitmapDescriptor descriptor = descriptors.get(entry);
|
||||||
|
|
||||||
if (descriptor == null || !descriptors.containsKey(pEntry)) {
|
if (descriptor == null || !descriptors.containsKey(entry)) {
|
||||||
DIBHeader header = getHeader(pEntry);
|
DIBHeader header = getHeader(entry);
|
||||||
|
|
||||||
int offset = pEntry.getOffset() + header.getSize();
|
int offset = entry.getOffset() + header.getSize();
|
||||||
if (offset != imageInput.getStreamPosition()) {
|
if (offset != imageInput.getStreamPosition()) {
|
||||||
imageInput.seek(offset);
|
imageInput.seek(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Support this, it's already in the BMP reader, spec allows RLE4 and RLE8
|
// TODO: Support this, it's already in the BMP reader, spec allows RLE4 and RLE8
|
||||||
if (header.getCompression() != DIB.COMPRESSION_RGB) {
|
if (header.getCompression() != DIB.COMPRESSION_RGB) {
|
||||||
descriptor = new BitmapUnsupported(pEntry, header, String.format("Unsupported compression: %d", header.getCompression()));
|
descriptor = new BitmapUnsupported(entry, header, String.format("Unsupported compression: %d", header.getCompression()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int bitCount = header.getBitCount();
|
int bitCount = header.getBitCount();
|
||||||
@ -305,75 +301,75 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
case 1:
|
case 1:
|
||||||
case 4:
|
case 4:
|
||||||
case 8: // TODO: Gray!
|
case 8: // TODO: Gray!
|
||||||
descriptor = new BitmapIndexed(pEntry, header);
|
descriptor = new BitmapIndexed(entry, header);
|
||||||
readBitmapIndexed((BitmapIndexed) descriptor);
|
readBitmapIndexed((BitmapIndexed) descriptor);
|
||||||
break;
|
break;
|
||||||
// RGB style
|
// RGB style
|
||||||
case 16:
|
case 16:
|
||||||
descriptor = new BitmapRGB(pEntry, header);
|
descriptor = new BitmapRGB(entry, header);
|
||||||
readBitmap16(descriptor);
|
readBitmap16(descriptor);
|
||||||
break;
|
break;
|
||||||
case 24:
|
case 24:
|
||||||
descriptor = new BitmapRGB(pEntry, header);
|
descriptor = new BitmapRGB(entry, header);
|
||||||
readBitmap24(descriptor);
|
readBitmap24(descriptor);
|
||||||
break;
|
break;
|
||||||
case 32:
|
case 32:
|
||||||
descriptor = new BitmapRGB(pEntry, header);
|
descriptor = new BitmapRGB(entry, header);
|
||||||
readBitmap32(descriptor);
|
readBitmap32(descriptor);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
descriptor = new BitmapUnsupported(pEntry, header, String.format("Unsupported bit count %d", bitCount));
|
descriptor = new BitmapUnsupported(entry, header, String.format("Unsupported bit count %d", bitCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptors.put(pEntry, descriptor);
|
descriptors.put(entry, descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return descriptor.getImage();
|
return descriptor.getImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBitmapIndexed(final BitmapIndexed pBitmap) throws IOException {
|
private void readBitmapIndexed(final BitmapIndexed bitmap) throws IOException {
|
||||||
readColorMap(pBitmap);
|
readColorMap(bitmap);
|
||||||
|
|
||||||
switch (pBitmap.getBitCount()) {
|
switch (bitmap.getBitCount()) {
|
||||||
case 1:
|
case 1:
|
||||||
readBitmapIndexed1(pBitmap, false);
|
readBitmapIndexed1(bitmap, false);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
readBitmapIndexed4(pBitmap);
|
readBitmapIndexed4(bitmap);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
readBitmapIndexed8(pBitmap);
|
readBitmapIndexed8(bitmap);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
BitmapMask mask = new BitmapMask(pBitmap.entry, pBitmap.header);
|
BitmapMask mask = new BitmapMask(bitmap.entry, bitmap.header);
|
||||||
readBitmapIndexed1(mask.bitMask, true);
|
readBitmapIndexed1(mask.bitMask, true);
|
||||||
pBitmap.setMask(mask);
|
bitmap.setMask(mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readColorMap(final BitmapIndexed pBitmap) throws IOException {
|
private void readColorMap(final BitmapIndexed bitmap) throws IOException {
|
||||||
int colorCount = pBitmap.getColorCount();
|
int colorCount = bitmap.getColorCount();
|
||||||
|
|
||||||
for (int i = 0; i < colorCount; i++) {
|
for (int i = 0; i < colorCount; i++) {
|
||||||
// aRGB (a is "Reserved")
|
// aRGB (a is "Reserved")
|
||||||
pBitmap.colors[i] = (imageInput.readInt() & 0xffffff) | 0xff000000;
|
bitmap.colors[i] = (imageInput.readInt() & 0xffffff) | 0xff000000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBitmapIndexed1(final BitmapIndexed pBitmap, final boolean pAsMask) throws IOException {
|
private void readBitmapIndexed1(final BitmapIndexed bitmap, final boolean asMask) throws IOException {
|
||||||
int width = adjustToPadding((pBitmap.getWidth() + 7) >> 3);
|
int width = adjustToPadding((bitmap.getWidth() + 7) >> 3);
|
||||||
byte[] row = new byte[width];
|
byte[] row = new byte[width];
|
||||||
|
|
||||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||||
imageInput.readFully(row, 0, width);
|
imageInput.readFully(row, 0, width);
|
||||||
int rowPos = 0;
|
int rowPos = 0;
|
||||||
int xOrVal = 0x80;
|
int xOrVal = 0x80;
|
||||||
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
int pos = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
|
||||||
|
|
||||||
for (int x = 0; x < pBitmap.getWidth(); x++) {
|
for (int x = 0; x < bitmap.getWidth(); x++) {
|
||||||
pBitmap.bits[pos++] = ((row[rowPos] & xOrVal) / xOrVal) & 0xFF;
|
bitmap.bits[pos++] = ((row[rowPos] & xOrVal) / xOrVal) & 0xFF;
|
||||||
|
|
||||||
if (xOrVal == 1) {
|
if (xOrVal == 1) {
|
||||||
xOrVal = 0x80;
|
xOrVal = 0x80;
|
||||||
@ -384,29 +380,29 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: If we are reading the mask, we don't abort or report progress
|
// NOTE: If we are reading the mask, we can't abort or report progress
|
||||||
if (!pAsMask) {
|
if (!asMask) {
|
||||||
if (abortRequested()) {
|
if (abortRequested()) {
|
||||||
processReadAborted();
|
processReadAborted();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBitmapIndexed4(final BitmapIndexed pBitmap) throws IOException {
|
private void readBitmapIndexed4(final BitmapIndexed bitmap) throws IOException {
|
||||||
int width = adjustToPadding((pBitmap.getWidth() + 1) >> 1);
|
int width = adjustToPadding((bitmap.getWidth() + 1) >> 1);
|
||||||
byte[] row = new byte[width];
|
byte[] row = new byte[width];
|
||||||
|
|
||||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||||
imageInput.readFully(row, 0, width);
|
imageInput.readFully(row, 0, width);
|
||||||
int rowPos = 0;
|
int rowPos = 0;
|
||||||
boolean high4 = true;
|
boolean high4 = true;
|
||||||
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
int pos = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
|
||||||
|
|
||||||
for (int x = 0; x < pBitmap.getWidth(); x++) {
|
for (int x = 0; x < bitmap.getWidth(); x++) {
|
||||||
int value;
|
int value;
|
||||||
|
|
||||||
if (high4) {
|
if (high4) {
|
||||||
@ -417,7 +413,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
rowPos++;
|
rowPos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
pBitmap.bits[pos++] = value & 0xFF;
|
bitmap.bits[pos++] = value & 0xFF;
|
||||||
high4 = !high4;
|
high4 = !high4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -426,22 +422,22 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBitmapIndexed8(final BitmapIndexed pBitmap) throws IOException {
|
private void readBitmapIndexed8(final BitmapIndexed bitmap) throws IOException {
|
||||||
int width = adjustToPadding(pBitmap.getWidth());
|
int width = adjustToPadding(bitmap.getWidth());
|
||||||
|
|
||||||
byte[] row = new byte[width];
|
byte[] row = new byte[width];
|
||||||
|
|
||||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||||
imageInput.readFully(row, 0, width);
|
imageInput.readFully(row, 0, width);
|
||||||
int rowPos = 0;
|
int rowPos = 0;
|
||||||
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
int pos = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
|
||||||
|
|
||||||
for (int x = 0; x < pBitmap.getWidth(); x++) {
|
for (int x = 0; x < bitmap.getWidth(); x++) {
|
||||||
pBitmap.bits[pos++] = row[rowPos++] & 0xFF;
|
bitmap.bits[pos++] = row[rowPos++] & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abortRequested()) {
|
if (abortRequested()) {
|
||||||
@ -449,40 +445,41 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param pWidth Bytes per scan line (i.e., 1BPP, width = 9 -> bytes = 1)
|
* @param width Bytes per scan line (i.e., 1BPP, width = 9 -> bytes = 2)
|
||||||
* @return padded width
|
* @return padded width
|
||||||
*/
|
*/
|
||||||
private static int adjustToPadding(final int pWidth) {
|
private static int adjustToPadding(final int width) {
|
||||||
if ((pWidth & 0x03) != 0) {
|
if ((width & 0x03) != 0) {
|
||||||
return (pWidth & ~0x03) + 4;
|
return (width & ~0x03) + 4;
|
||||||
}
|
}
|
||||||
return pWidth;
|
|
||||||
|
return width;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBitmap16(final BitmapDescriptor pBitmap) throws IOException {
|
private void readBitmap16(final BitmapDescriptor bitmap) throws IOException {
|
||||||
short[] pixels = new short[pBitmap.getWidth() * pBitmap.getHeight()];
|
short[] pixels = new short[bitmap.getWidth() * bitmap.getHeight()];
|
||||||
|
|
||||||
// TODO: Support TYPE_USHORT_565 and the RGB 444/ARGB 4444 layouts
|
// TODO: Support TYPE_USHORT_565 and the RGB 444/ARGB 4444 layouts
|
||||||
// Will create TYPE_USHORT_555
|
// Will create TYPE_USHORT_555
|
||||||
DirectColorModel cm = new DirectColorModel(16, 0x7C00, 0x03E0, 0x001F);
|
DirectColorModel cm = new DirectColorModel(16, 0x7C00, 0x03E0, 0x001F);
|
||||||
DataBuffer buffer = new DataBufferUShort(pixels, pixels.length);
|
DataBuffer buffer = new DataBufferUShort(pixels, pixels.length);
|
||||||
WritableRaster raster = Raster.createPackedRaster(
|
WritableRaster raster = Raster.createPackedRaster(
|
||||||
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), cm.getMasks(), null
|
buffer, bitmap.getWidth(), bitmap.getHeight(), bitmap.getWidth(), cm.getMasks(), null
|
||||||
);
|
);
|
||||||
pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
bitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||||
|
|
||||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||||
int offset = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
int offset = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
|
||||||
imageInput.readFully(pixels, offset, pBitmap.getWidth());
|
imageInput.readFully(pixels, offset, bitmap.getWidth());
|
||||||
|
|
||||||
|
|
||||||
// Skip to 32 bit boundary
|
// Skip to 32 bit boundary
|
||||||
if (pBitmap.getWidth() % 2 != 0) {
|
if (bitmap.getWidth() % 2 != 0) {
|
||||||
imageInput.readShort();
|
imageInput.readShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,14 +488,14 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Might be mask!?
|
// TODO: Might be mask!?
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBitmap24(final BitmapDescriptor pBitmap) throws IOException {
|
private void readBitmap24(final BitmapDescriptor bitmap) throws IOException {
|
||||||
byte[] pixels = new byte[pBitmap.getWidth() * pBitmap.getHeight() * 3];
|
byte[] pixels = new byte[bitmap.getWidth() * bitmap.getHeight() * 3];
|
||||||
|
|
||||||
// Create TYPE_3BYTE_BGR
|
// Create TYPE_3BYTE_BGR
|
||||||
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
||||||
@ -509,17 +506,17 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE
|
cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE
|
||||||
);
|
);
|
||||||
|
|
||||||
int scanlineStride = pBitmap.getWidth() * 3;
|
int scanlineStride = bitmap.getWidth() * 3;
|
||||||
// BMP rows are padded to 4 byte boundary
|
// BMP rows are padded to 4 byte boundary
|
||||||
int rowSizeBytes = ((8 * scanlineStride + 31) / 32) * 4;
|
int rowSizeBytes = ((8 * scanlineStride + 31) / 32) * 4;
|
||||||
|
|
||||||
WritableRaster raster = Raster.createInterleavedRaster(
|
WritableRaster raster = Raster.createInterleavedRaster(
|
||||||
buffer, pBitmap.getWidth(), pBitmap.getHeight(), scanlineStride, 3, bOffs, null
|
buffer, bitmap.getWidth(), bitmap.getHeight(), scanlineStride, 3, bOffs, null
|
||||||
);
|
);
|
||||||
pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
bitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||||
|
|
||||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||||
int offset = (pBitmap.getHeight() - y - 1) * scanlineStride;
|
int offset = (bitmap.getHeight() - y - 1) * scanlineStride;
|
||||||
imageInput.readFully(pixels, offset, scanlineStride);
|
imageInput.readFully(pixels, offset, scanlineStride);
|
||||||
imageInput.skipBytes(rowSizeBytes - scanlineStride);
|
imageInput.skipBytes(rowSizeBytes - scanlineStride);
|
||||||
|
|
||||||
@ -528,38 +525,38 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 24 bit icons usually have a bit mask
|
// 24 bit icons usually have a bit mask
|
||||||
if (pBitmap.hasMask()) {
|
if (bitmap.hasMask()) {
|
||||||
BitmapMask mask = new BitmapMask(pBitmap.entry, pBitmap.header);
|
BitmapMask mask = new BitmapMask(bitmap.entry, bitmap.header);
|
||||||
readBitmapIndexed1(mask.bitMask, true);
|
readBitmapIndexed1(mask.bitMask, true);
|
||||||
|
|
||||||
pBitmap.setMask(mask);
|
bitmap.setMask(mask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBitmap32(final BitmapDescriptor pBitmap) throws IOException {
|
private void readBitmap32(final BitmapDescriptor bitmap) throws IOException {
|
||||||
int[] pixels = new int[pBitmap.getWidth() * pBitmap.getHeight()];
|
int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
|
||||||
|
|
||||||
// Will create TYPE_INT_ARGB
|
// Will create TYPE_INT_ARGB
|
||||||
DirectColorModel cm = (DirectColorModel) ColorModel.getRGBdefault();
|
DirectColorModel cm = (DirectColorModel) ColorModel.getRGBdefault();
|
||||||
DataBuffer buffer = new DataBufferInt(pixels, pixels.length);
|
DataBuffer buffer = new DataBufferInt(pixels, pixels.length);
|
||||||
WritableRaster raster = Raster.createPackedRaster(
|
WritableRaster raster = Raster.createPackedRaster(
|
||||||
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), cm.getMasks(), null
|
buffer, bitmap.getWidth(), bitmap.getHeight(), bitmap.getWidth(), cm.getMasks(), null
|
||||||
);
|
);
|
||||||
pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
bitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||||
|
|
||||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||||
int offset = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
int offset = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
|
||||||
imageInput.readFully(pixels, offset, pBitmap.getWidth());
|
imageInput.readFully(pixels, offset, bitmap.getWidth());
|
||||||
|
|
||||||
if (abortRequested()) {
|
if (abortRequested()) {
|
||||||
processReadAborted();
|
processReadAborted();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
// There might be a mask here as well, but we'll ignore it,
|
// There might be a mask here as well, but we'll ignore it,
|
||||||
@ -590,18 +587,18 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
directory = Directory.read(type, imageCount, imageInput);
|
directory = Directory.read(type, imageCount, imageInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
final DirectoryEntry getEntry(final int pImageIndex) throws IOException {
|
final DirectoryEntry getEntry(final int imageIndex) throws IOException {
|
||||||
Directory directory = getDirectory();
|
Directory directory = getDirectory();
|
||||||
if (pImageIndex < 0 || pImageIndex >= directory.count()) {
|
if (imageIndex < 0 || imageIndex >= directory.count()) {
|
||||||
throw new IndexOutOfBoundsException(String.format("Index: %d, ImageCount: %d", pImageIndex, directory.count()));
|
throw new IndexOutOfBoundsException(String.format("Index: %d, ImageCount: %d", imageIndex, directory.count()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return directory.getEntry(pImageIndex);
|
return directory.getEntry(imageIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test code below, ignore.. :-)
|
/// Test code below, ignore.. :-)
|
||||||
public static void main(final String[] pArgs) throws IOException {
|
public static void main(final String[] args) throws IOException {
|
||||||
if (pArgs.length == 0) {
|
if (args.length == 0) {
|
||||||
System.err.println("Please specify the icon file name");
|
System.err.println("Please specify the icon file name");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
@ -613,7 +610,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
// Ignore
|
// Ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
String title = new File(pArgs[0]).getName();
|
String title = new File(args[0]).getName();
|
||||||
JFrame frame = createWindow(title);
|
JFrame frame = createWindow(title);
|
||||||
JPanel root = new JPanel(new FlowLayout());
|
JPanel root = new JPanel(new FlowLayout());
|
||||||
JScrollPane scroll =
|
JScrollPane scroll =
|
||||||
@ -629,7 +626,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
ImageReader reader = readers.next();
|
ImageReader reader = readers.next();
|
||||||
|
|
||||||
for (String arg : pArgs) {
|
for (String arg : args) {
|
||||||
JPanel panel = new JPanel(null);
|
JPanel panel = new JPanel(null);
|
||||||
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
||||||
readImagesInFile(arg, reader, panel);
|
readImagesInFile(arg, reader, panel);
|
||||||
@ -640,28 +637,28 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
frame.setVisible(true);
|
frame.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void readImagesInFile(String pFileName, ImageReader pReader, final Container pContainer) throws IOException {
|
private static void readImagesInFile(String fileName, ImageReader reader, final Container container) throws IOException {
|
||||||
File file = new File(pFileName);
|
File file = new File(fileName);
|
||||||
if (!file.isFile()) {
|
if (!file.isFile()) {
|
||||||
System.err.println(pFileName + " not found, or is no file");
|
System.err.println(fileName + " not found, or is no file");
|
||||||
}
|
}
|
||||||
|
|
||||||
pReader.setInput(ImageIO.createImageInputStream(file));
|
reader.setInput(ImageIO.createImageInputStream(file));
|
||||||
int imageCount = pReader.getNumImages(true);
|
int imageCount = reader.getNumImages(true);
|
||||||
for (int i = 0; i < imageCount; i++) {
|
for (int i = 0; i < imageCount; i++) {
|
||||||
try {
|
try {
|
||||||
addImage(pContainer, pReader, i);
|
addImage(container, reader, i);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
System.err.println("FileName: " + pFileName);
|
System.err.println("FileName: " + fileName);
|
||||||
System.err.println("Icon: " + i);
|
System.err.println("Icon: " + i);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JFrame createWindow(final String pTitle) {
|
private static JFrame createWindow(final String title) {
|
||||||
JFrame frame = new JFrame(pTitle);
|
JFrame frame = new JFrame(title);
|
||||||
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
frame.addWindowListener(new WindowAdapter() {
|
frame.addWindowListener(new WindowAdapter() {
|
||||||
public void windowClosed(WindowEvent e) {
|
public void windowClosed(WindowEvent e) {
|
||||||
@ -671,15 +668,15 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addImage(final Container pParent, final ImageReader pReader, final int pImageNo) throws IOException {
|
private static void addImage(final Container parent, final ImageReader reader, final int imageNo) throws IOException {
|
||||||
final JButton button = new JButton();
|
final JButton button = new JButton();
|
||||||
|
|
||||||
BufferedImage image = pReader.read(pImageNo);
|
BufferedImage image = reader.read(imageNo);
|
||||||
button.setIcon(new ImageIcon(image) {
|
button.setIcon(new ImageIcon(image) {
|
||||||
TexturePaint texture;
|
TexturePaint texture;
|
||||||
|
|
||||||
private void createTexture(final GraphicsConfiguration pGraphicsConfiguration) {
|
private void createTexture(final GraphicsConfiguration graphicsConfiguration) {
|
||||||
BufferedImage pattern = pGraphicsConfiguration.createCompatibleImage(20, 20);
|
BufferedImage pattern = graphicsConfiguration.createCompatibleImage(20, 20);
|
||||||
Graphics2D g = pattern.createGraphics();
|
Graphics2D g = pattern.createGraphics();
|
||||||
try {
|
try {
|
||||||
g.setColor(Color.LIGHT_GRAY);
|
g.setColor(Color.LIGHT_GRAY);
|
||||||
@ -714,6 +711,6 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
String.valueOf(((IndexColorModel) image.getColorModel()).getMapSize()) :
|
String.valueOf(((IndexColorModel) image.getColorModel()).getMapSize()) :
|
||||||
"TrueColor"));
|
"TrueColor"));
|
||||||
|
|
||||||
pParent.add(button);
|
parent.add(button);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,24 +44,25 @@ import java.util.List;
|
|||||||
class Directory {
|
class Directory {
|
||||||
private final List<DirectoryEntry> entries;
|
private final List<DirectoryEntry> entries;
|
||||||
|
|
||||||
private Directory(int pImageCount) {
|
private Directory(int imageCount) {
|
||||||
entries = Arrays.asList(new DirectoryEntry[pImageCount]);
|
entries = Arrays.asList(new DirectoryEntry[imageCount]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Directory read(final int pType, final int pImageCount, final DataInput pStream) throws IOException {
|
public static Directory read(final int type, final int imageCount, final DataInput stream) throws IOException {
|
||||||
Directory directory = new Directory(pImageCount);
|
Directory directory = new Directory(imageCount);
|
||||||
directory.readEntries(pType, pStream);
|
directory.readEntries(type, stream);
|
||||||
|
|
||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readEntries(final int pType, final DataInput pStream) throws IOException {
|
private void readEntries(final int type, final DataInput stream) throws IOException {
|
||||||
for (int i = 0; i < entries.size(); i++) {
|
for (int i = 0; i < entries.size(); i++) {
|
||||||
entries.set(i, DirectoryEntry.read(pType, pStream));
|
entries.set(i, DirectoryEntry.read(type, stream));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DirectoryEntry getEntry(final int pEntryIndex) {
|
public DirectoryEntry getEntry(final int entryIndex) {
|
||||||
return entries.get(pEntryIndex);
|
return entries.get(entryIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int count() {
|
public int count() {
|
||||||
|
@ -32,8 +32,7 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
|||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.ColorModel;
|
import java.awt.image.*;
|
||||||
import java.awt.image.IndexColorModel;
|
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -58,47 +57,43 @@ abstract class DirectoryEntry {
|
|||||||
DirectoryEntry() {
|
DirectoryEntry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DirectoryEntry read(final int pType, final DataInput pStream) throws IOException {
|
public static DirectoryEntry read(final int type, final DataInput stream) throws IOException {
|
||||||
DirectoryEntry entry = createEntry(pType);
|
DirectoryEntry entry = createEntry(type);
|
||||||
entry.read(pStream);
|
entry.read(stream);
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DirectoryEntry createEntry(int pType) throws IIOException {
|
private static DirectoryEntry createEntry(int type) throws IIOException {
|
||||||
switch (pType) {
|
switch (type) {
|
||||||
case DIB.TYPE_ICO:
|
case DIB.TYPE_ICO:
|
||||||
return new ICOEntry();
|
return new ICOEntry();
|
||||||
case DIB.TYPE_CUR:
|
case DIB.TYPE_CUR:
|
||||||
return new CUREntry();
|
return new CUREntry();
|
||||||
default:
|
default:
|
||||||
throw new IIOException(
|
throw new IIOException(String.format("Unknown DIB type: %s, expected: %s (ICO) or %s (CUR)", type, DIB.TYPE_ICO, DIB.TYPE_CUR));
|
||||||
String.format(
|
|
||||||
"Unknown DIB type: %s, expected: %s (ICO) or %s (CUR)",
|
|
||||||
pType, DIB.TYPE_ICO, DIB.TYPE_CUR
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void read(final DataInput pStream) throws IOException {
|
protected void read(final DataInput stream) throws IOException {
|
||||||
// Width/height = 0, means 256
|
// Width/height = 0, means 256
|
||||||
int w = pStream.readUnsignedByte();
|
int w = stream.readUnsignedByte();
|
||||||
width = w == 0 ? 256 : w;
|
width = w == 0 ? 256 : w;
|
||||||
int h = pStream.readUnsignedByte();
|
int h = stream.readUnsignedByte();
|
||||||
height = h == 0 ? 256 : h;
|
height = h == 0 ? 256 : h;
|
||||||
|
|
||||||
// Color count = 0, means 256 or more colors
|
// Color count = 0, means 256 or more colors
|
||||||
colorCount = pStream.readUnsignedByte();
|
colorCount = stream.readUnsignedByte();
|
||||||
|
|
||||||
// Ignore. Should be 0, but .NET (System.Drawing.Icon.Save) sets this value to 255, according to Wikipedia
|
// Ignore. Should be 0, but .NET (System.Drawing.Icon.Save) sets this value to 255, according to Wikipedia
|
||||||
pStream.readUnsignedByte();
|
stream.readUnsignedByte();
|
||||||
|
|
||||||
planes = pStream.readUnsignedShort(); // Should be 0 or 1 for ICO, x hotspot for CUR
|
planes = stream.readUnsignedShort(); // Should be 0 or 1 for ICO, x hotspot for CUR
|
||||||
bitCount = pStream.readUnsignedShort(); // bit count for ICO, y hotspot for CUR
|
bitCount = stream.readUnsignedShort(); // bit count for ICO, y hotspot for CUR
|
||||||
|
|
||||||
// Size of bitmap in bytes
|
// Size of bitmap in bytes
|
||||||
size = pStream.readInt();
|
size = stream.readInt();
|
||||||
offset = pStream.readInt();
|
offset = stream.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(final DataOutput output) throws IOException {
|
void write(final DataOutput output) throws IOException {
|
||||||
@ -157,8 +152,8 @@ abstract class DirectoryEntry {
|
|||||||
private int yHotspot;
|
private int yHotspot;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void read(final DataInput pStream) throws IOException {
|
protected void read(final DataInput stream) throws IOException {
|
||||||
super.read(pStream);
|
super.read(stream);
|
||||||
|
|
||||||
// NOTE: This is a hack...
|
// NOTE: This is a hack...
|
||||||
xHotspot = planes;
|
xHotspot = planes;
|
||||||
|
@ -46,7 +46,7 @@ public final class ICOImageReader extends DIBImageReader {
|
|||||||
super(new ICOImageReaderSpi());
|
super(new ICOImageReaderSpi());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ICOImageReader(final ImageReaderSpi pProvider) {
|
ICOImageReader(final ImageReaderSpi provider) {
|
||||||
super(pProvider);
|
super(provider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
|||||||
|
|
||||||
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
||||||
|
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -49,32 +48,32 @@ public final class ICOImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
super(new ICOProviderInfo());
|
super(new ICOProviderInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canDecodeInput(final Object pSource) throws IOException {
|
public boolean canDecodeInput(final Object source) throws IOException {
|
||||||
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource, DIB.TYPE_ICO);
|
return source instanceof ImageInputStream && canDecode((ImageInputStream) source, DIB.TYPE_ICO);
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean canDecode(final ImageInputStream pInput, final int pType) throws IOException {
|
static boolean canDecode(final ImageInputStream input, final int type) throws IOException {
|
||||||
byte[] signature = new byte[4];
|
byte[] signature = new byte[4];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
pInput.mark();
|
input.mark();
|
||||||
pInput.readFully(signature);
|
input.readFully(signature);
|
||||||
|
|
||||||
int count = pInput.readByte() + (pInput.readByte() << 8);
|
int count = input.readByte() + (input.readByte() << 8);
|
||||||
|
|
||||||
return (signature[0] == 0x0 && signature[1] == 0x0 && signature[2] == pType
|
return (signature[0] == 0x0 && signature[1] == 0x0 && signature[2] == type
|
||||||
&& signature[3] == 0x0 && count > 0);
|
&& signature[3] == 0x0 && count > 0);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
pInput.reset();
|
input.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageReader createReaderInstance(final Object pExtension) throws IOException {
|
public ICOImageReader createReaderInstance(final Object extension) {
|
||||||
return new ICOImageReader(this);
|
return new ICOImageReader(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDescription(final Locale pLocale) {
|
public String getDescription(final Locale locale) {
|
||||||
return "Windows Icon Format (ICO) Reader";
|
return "Windows Icon Format (ICO) Reader";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,15 +33,19 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
|||||||
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
|
|
||||||
import javax.imageio.*;
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.IIOImage;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import javax.imageio.ImageWriteParam;
|
||||||
|
import javax.imageio.ImageWriter;
|
||||||
import javax.imageio.event.IIOWriteWarningListener;
|
import javax.imageio.event.IIOWriteWarningListener;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
import javax.imageio.spi.ImageWriterSpi;
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.*;
|
||||||
import java.awt.image.ColorModel;
|
|
||||||
import java.awt.image.RenderedImage;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@ -64,7 +68,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
|
|
||||||
private ImageWriter pngDelegate;
|
private ImageWriter pngDelegate;
|
||||||
|
|
||||||
protected ICOImageWriter(final ImageWriterSpi provider) {
|
ICOImageWriter(final ImageWriterSpi provider) {
|
||||||
super(provider);
|
super(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +128,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endWriteSequence() throws IOException {
|
public void endWriteSequence() {
|
||||||
assertOutput();
|
assertOutput();
|
||||||
|
|
||||||
if (sequenceIndex < 0) {
|
if (sequenceIndex < 0) {
|
||||||
|
@ -30,24 +30,14 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
import static org.junit.Assume.assumeNoException;
|
import com.twelvemonkeys.xml.XMLSerializer;
|
||||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
|
||||||
import static org.mockito.Mockito.inOrder;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
import java.awt.*;
|
import org.junit.Ignore;
|
||||||
import java.awt.image.BufferedImage;
|
import org.junit.Test;
|
||||||
import java.io.ByteArrayOutputStream;
|
import org.mockito.InOrder;
|
||||||
import java.io.IOException;
|
import org.w3c.dom.Node;
|
||||||
import java.lang.reflect.Constructor;
|
import org.w3c.dom.NodeList;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
@ -57,16 +47,25 @@ import javax.imageio.ImageTypeSpecifier;
|
|||||||
import javax.imageio.event.IIOReadProgressListener;
|
import javax.imageio.event.IIOReadProgressListener;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
|
import javax.imageio.spi.IIORegistry;
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import static org.junit.Assert.*;
|
||||||
import org.junit.Test;
|
import static org.junit.Assume.assumeNoException;
|
||||||
import org.mockito.InOrder;
|
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||||
import org.w3c.dom.Node;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import org.w3c.dom.NodeList;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import static org.mockito.Mockito.mock;
|
||||||
import com.twelvemonkeys.xml.XMLSerializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BMPImageReaderTest
|
* BMPImageReaderTest
|
||||||
@ -326,10 +325,8 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
public void testMetadataEqualsJRE() throws IOException {
|
public void testMetadataEqualsJRE() throws IOException {
|
||||||
ImageReader jreReader;
|
ImageReader jreReader;
|
||||||
try {
|
try {
|
||||||
@SuppressWarnings("unchecked")
|
ImageReaderSpi provider = (ImageReaderSpi) IIORegistry.getDefaultInstance().getServiceProviderByClass(Class.forName("com.sun.imageio.plugins.bmp.BMPImageReaderSpi"));
|
||||||
Class<ImageReader> jreReaderClass = (Class<ImageReader>) Class.forName("com.sun.imageio.plugins.bmp.BMPImageReader");
|
jreReader = provider.createReaderInstance();
|
||||||
Constructor<ImageReader> constructor = jreReaderClass.getConstructor(ImageReaderSpi.class);
|
|
||||||
jreReader = constructor.newInstance(new Object[] {null});
|
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.util;
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -38,14 +39,18 @@ import org.mockito.InOrder;
|
|||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
import javax.imageio.*;
|
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.IIOReadProgressListener;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
import javax.imageio.spi.IIORegistry;
|
import javax.imageio.spi.IIORegistry;
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.*;
|
||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -53,6 +58,7 @@ import java.lang.reflect.ParameterizedType;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -602,7 +608,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
assertReadWithSourceRegionParamEqualImage(new Rectangle(3, 3, 9, 9), getTestData().get(0), 0);
|
assertReadWithSourceRegionParamEqualImage(new Rectangle(3, 3, 9, 9), getTestData().get(0), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertReadWithSourceRegionParamEqualImage(final Rectangle r, final TestData data, final int imageIndex) throws IOException {
|
protected void assertReadWithSourceRegionParamEqualImage(final Rectangle r, final TestData data, @SuppressWarnings("SameParameterValue") final int imageIndex) throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
try (ImageInputStream inputStream = data.getInputStream()) {
|
try (ImageInputStream inputStream = data.getInputStream()) {
|
||||||
reader.setInput(inputStream);
|
reader.setInput(inputStream);
|
||||||
@ -1828,52 +1834,51 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
private final List<Dimension> sizes;
|
private final List<Dimension> sizes;
|
||||||
private final List<BufferedImage> images;
|
private final List<BufferedImage> images;
|
||||||
|
|
||||||
public TestData(final Object pInput, final Dimension... pSizes) {
|
public TestData(final Object input, final Dimension... dimensions) {
|
||||||
this(pInput, Arrays.asList(pSizes), null);
|
this(input, Arrays.asList(dimensions), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestData(final Object pInput, final BufferedImage... pImages) {
|
public TestData(final Object input, final BufferedImage... images) {
|
||||||
this(pInput, null, Arrays.asList(pImages));
|
this(input, null, Arrays.asList(images));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestData(final Object pInput, final List<Dimension> pSizes, final List<BufferedImage> pImages) {
|
public TestData(final Object input, final List<Dimension> dimensions, final List<BufferedImage> images) {
|
||||||
if (pInput == null) {
|
Validate.notNull(input, "input");
|
||||||
throw new IllegalArgumentException("input == null");
|
Validate.isTrue(dimensions != null || images != null, "Need either dimensions or image");
|
||||||
}
|
|
||||||
|
|
||||||
sizes = new ArrayList<>();
|
List<Dimension> combinedDimensions;
|
||||||
images = new ArrayList<>();
|
if (dimensions == null) {
|
||||||
|
// Copy dimensions from images
|
||||||
|
combinedDimensions = new ArrayList<>(images.size());
|
||||||
|
|
||||||
List<Dimension> sizes = pSizes;
|
for (BufferedImage image : images) {
|
||||||
if (sizes == null) {
|
combinedDimensions.add(new Dimension(image.getWidth(), image.getHeight()));
|
||||||
sizes = new ArrayList<>();
|
|
||||||
if (pImages != null) {
|
|
||||||
for (BufferedImage image : pImages) {
|
|
||||||
sizes.add(new Dimension(image.getWidth(), image.getHeight()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException("Need either size or image");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pImages != null) {
|
else {
|
||||||
if (pImages.size() != pSizes.size()) {
|
// Validate equal dimensions
|
||||||
throw new IllegalArgumentException("Size parameter and image size differs");
|
if (images != null) {
|
||||||
}
|
if (images.size() != dimensions.size()) {
|
||||||
for (int i = 0; i < sizes.size(); i++) {
|
throw new IllegalArgumentException("Dimensions and images parameter's size differs");
|
||||||
if (!new Dimension(pImages.get(i).getWidth(), pImages.get(i).getHeight()).equals(sizes.get(i))) {
|
|
||||||
throw new IllegalArgumentException("Size parameter and image size differs");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < dimensions.size(); i++) {
|
||||||
|
if (!new Dimension(images.get(i).getWidth(), images.get(i).getHeight()).equals(dimensions.get(i))) {
|
||||||
|
throw new IllegalArgumentException("Dimensions and images parameter's dimensions differ");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
combinedDimensions = new ArrayList<>(dimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sizes.addAll(sizes);
|
this.sizes = Collections.unmodifiableList(combinedDimensions);
|
||||||
if (pImages != null) {
|
|
||||||
images.addAll(pImages);
|
|
||||||
}
|
|
||||||
|
|
||||||
input = pInput;
|
this.images = images != null
|
||||||
|
? Collections.unmodifiableList(new ArrayList<>(images))
|
||||||
|
: Collections.<BufferedImage>emptyList();
|
||||||
|
|
||||||
|
this.input = input;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getInput() {
|
public Object getInput() {
|
||||||
@ -1898,13 +1903,13 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
return sizes.size();
|
return sizes.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Dimension getDimension(final int pIndex) {
|
public Dimension getDimension(final int index) {
|
||||||
return sizes.get(pIndex);
|
return sizes.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public BufferedImage getImage(final int pIndex) {
|
public BufferedImage getImage(final int index) {
|
||||||
return images.get(pIndex);
|
return images.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -43,15 +43,17 @@ import javax.imageio.spi.IIORegistry;
|
|||||||
import javax.imageio.spi.ImageWriterSpi;
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.*;
|
||||||
import java.awt.image.RenderedImage;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,8 +110,8 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
|||||||
return getTestData().get(index);
|
return getTestData().get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected URL getClassLoaderResource(final String pName) {
|
protected URL getClassLoaderResource(final String name) {
|
||||||
return getClass().getResource(pName);
|
return getClass().getResource(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user