Adding the twelvemonkeys-imageio sub-project

This commit is contained in:
Harald Kuhr
2009-09-03 20:49:59 +02:00
parent 2523f31a8c
commit 4e7316886b
304 changed files with 27557 additions and 0 deletions
@@ -0,0 +1,381 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio;
import com.twelvemonkeys.image.BufferedImageIcon;
import com.twelvemonkeys.imageio.util.IIOUtil;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
/**
* ImageReaderBase
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: ImageReaderBase.java,v 1.0 Sep 20, 2007 5:28:37 PM haraldk Exp$
*/
public abstract class ImageReaderBase extends ImageReader {
/**
* For convenience. Only set if the input is an {@code ImageInputStream}.
* @see #setInput(Object, boolean, boolean)
*/
protected ImageInputStream mImageInput;
/**
* Constructs an {@code ImageReader} and sets its
* {@code originatingProvider} field to the supplied value.
* <p/>
* <p> Subclasses that make use of extensions should provide a
* constructor with signature {@code (ImageReaderSpi,
* Object)} in order to retrieve the extension object. If
* the extension object is unsuitable, an
* {@code IllegalArgumentException} should be thrown.
*
* @param pOriginatingProvider the {@code ImageReaderSpi} that is
* invoking this constructor, or {@code null}.
*/
protected ImageReaderBase(final ImageReaderSpi pOriginatingProvider) {
super(pOriginatingProvider);
}
/**
* Overrides {@code setInput}, to allow easy access to the input, in case
* it is an {@code ImageInputStream}.
*
* @param pInput the {@code ImageInputStream} or other
* {@code Object} to use for future decoding.
* @param pSeekForwardOnly if {@code true}, images and metadata
* may only be read in ascending order from this input source.
* @param pIgnoreMetadata if {@code true}, metadata
* may be ignored during reads.
*
* @exception IllegalArgumentException if {@code input} is
* not an instance of one of the classes returned by the
* originating service provider's {@code getInputTypes}
* method, or is not an {@code ImageInputStream}.
*
* @see ImageInputStream
*/
@Override
public void setInput(Object pInput, boolean pSeekForwardOnly, boolean pIgnoreMetadata) {
resetMembers();
super.setInput(pInput, pSeekForwardOnly, pIgnoreMetadata);
if (pInput instanceof ImageInputStream) {
mImageInput = (ImageInputStream) pInput;
}
}
@Override
public void dispose() {
resetMembers();
super.dispose();
}
@Override
public void reset() {
resetMembers();
super.reset();
}
/**
* Resets all member variables. This method is by default invoked from:
* <ul>
* <li>{@link #setInput(Object, boolean, boolean)}</li>
* <li>{@link #dispose()}</li>
* <li>{@link #reset()}</li>
* </ul>
*
*/
protected abstract void resetMembers();
/**
* Defaul implementation that always return {@code null}.
*
* @param pImageIndex ignored, unless overriden
* @return {@code null}, unless overriden
* @throws IOException never, unless overriden.
*/
public IIOMetadata getImageMetadata(int pImageIndex) throws IOException {
return null;
}
/**
* Defaul implementation that always return {@code null}.
*
* @return {@code null}, unless overriden
* @throws IOException never, unless overriden.
*/
public IIOMetadata getStreamMetadata() throws IOException {
return null;
}
/**
* Default implementation that always returns {@code 1}.
*
* @param pAllowSearch ignored, unless overriden
* @return {@code 1}, unless overriden
* @throws IOException never, unless overriden
*/
public int getNumImages(boolean pAllowSearch) throws IOException {
assertInput();
return 1;
}
/**
* Convenience method to make sure image index is within bounds.
*
* @param pIndex the image index
*
* @throws java.io.IOException if an error occurs during reading
* @throws IndexOutOfBoundsException if not
* <tt>minIndex <= pIndex < numImages</tt>
*/
protected void checkBounds(int pIndex) throws IOException {
assertInput();
if (pIndex < getMinIndex()) {
throw new IndexOutOfBoundsException("index < minIndex");
}
else if (getNumImages(false) != -1 && pIndex >= getNumImages(false)) {
throw new IndexOutOfBoundsException("index >= numImages (" + pIndex + " >= " + getNumImages(false) + ")");
}
}
/**
* Makes sure input is set.
*
* @throws IllegalStateException if {@code getInput() == null}.
*/
protected void assertInput() {
if (getInput() == null) {
throw new IllegalStateException("getInput() == null");
}
}
/**
* Utility method for getting the area of interest (AOI) of an image.
* The AOI is defined by the {@link javax.imageio.IIOParam#setSourceRegion(java.awt.Rectangle)}
* method.
* <p/>
* Note: If it is possible for the reader to read the AOI directly, such a
* method should be used instead, for efficiency.
*
* @param pImage the image to get AOI from
* @param pParam the param optionally specifying the AOI
*
* @return a {@code BufferedImage} containing the area of interest (source
* region), or the original image, if no source region was set, or
* {@code pParam} was {@code null}
*/
protected static BufferedImage fakeAOI(BufferedImage pImage, ImageReadParam pParam) {
return IIOUtil.fakeAOI(pImage, getSourceRegion(pParam, pImage.getWidth(), pImage.getHeight()));
}
/**
* Utility method for getting the subsampled image.
* The subsampling is defined by the
* {@link javax.imageio.IIOParam#setSourceSubsampling(int, int, int, int)}
* method.
* <p/>
* NOTE: This method does not take the subsampling offsets into
* consideration.
* <p/>
* Note: If it is possible for the reader to subsample directly, such a
* method should be used instead, for efficiency.
*
* @param pImage the image to subsample
* @param pParam the param optionally specifying subsampling
*
* @return an {@code Image} containing the subsampled image, or the
* original image, if no subsampling was specified, or
* {@code pParam} was {@code null}
*/
protected static Image fakeSubsampling(Image pImage, ImageReadParam pParam) {
return IIOUtil.fakeSubsampling(pImage, pParam);
}
public static void main(String[] pArgs) throws IOException {
BufferedImage image = ImageIO.read(new File(pArgs[0]));
showIt(image, pArgs[0]);
}
protected static void showIt(final BufferedImage pImage, final String pTitle) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
JFrame frame = new JFrame(pTitle);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationByPlatform(true);
JPanel pane = new JPanel(new BorderLayout());
JScrollPane scroll = new JScrollPane(new ImageLabel(pImage));
scroll.setBorder(null);
pane.add(scroll);
frame.setContentPane(pane);
frame.pack();
frame.setVisible(true);
}
});
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
private static class ImageLabel extends JLabel {
Paint mBackground;
public ImageLabel(BufferedImage pImage) {
super(new BufferedImageIcon(pImage));
setOpaque(false);
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
mBackground = createTexture();
JPopupMenu popup = createBackgroundPopup();
setComponentPopupMenu(popup);
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.isPopupTrigger()) {
getComponentPopupMenu().show(ImageLabel.this, e.getX(), e.getY());
}
}
});
}
private JPopupMenu createBackgroundPopup() {
JPopupMenu popup = new JPopupMenu();
ButtonGroup group = new ButtonGroup();
addCheckBoxItem(new ChangeBackgroundAction("Default", mBackground), popup, group);
popup.addSeparator();
addCheckBoxItem(new ChangeBackgroundAction("White", Color.WHITE), popup, group);
addCheckBoxItem(new ChangeBackgroundAction("Light", Color.LIGHT_GRAY), popup, group);
addCheckBoxItem(new ChangeBackgroundAction("Gray", Color.GRAY), popup, group);
addCheckBoxItem(new ChangeBackgroundAction("Dark", Color.DARK_GRAY), popup, group);
addCheckBoxItem(new ChangeBackgroundAction("Black", Color.BLACK), popup, group);
popup.addSeparator();
addCheckBoxItem(new ChooseBackgroundAction("Choose...", Color.BLUE), popup, group);
return popup;
}
private void addCheckBoxItem(final Action pAction, final JPopupMenu pPopup, final ButtonGroup pGroup) {
JCheckBoxMenuItem item = new JCheckBoxMenuItem(pAction);
pGroup.add(item);
pPopup.add(item);
}
private Paint createTexture() {
GraphicsConfiguration graphicsConfiguration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage pattern = graphicsConfiguration.createCompatibleImage(20, 20);
Graphics2D g = pattern.createGraphics();
try {
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, pattern.getWidth(), pattern.getHeight());
g.setColor(Color.GRAY);
g.fillRect(0, 0, pattern.getWidth() / 2, pattern.getHeight() / 2);
g.fillRect(pattern.getWidth() / 2, pattern.getHeight() / 2, pattern.getWidth() / 2, pattern.getHeight() / 2);
}
finally {
g.dispose();
}
return new TexturePaint(pattern, new Rectangle(pattern.getWidth(), pattern.getHeight()));
}
@Override
protected void paintComponent(Graphics g) {
Graphics2D gr = (Graphics2D) g;
gr.setPaint(mBackground);
gr.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(g);
}
private class ChangeBackgroundAction extends AbstractAction {
protected Paint mPaint;
public ChangeBackgroundAction(final String pName, final Paint pPaint) {
super(pName);
mPaint = pPaint;
}
public void actionPerformed(ActionEvent e) {
mBackground = mPaint;
repaint();
}
}
private class ChooseBackgroundAction extends ChangeBackgroundAction {
public ChooseBackgroundAction(final String pName, final Color pColor) {
super(pName, pColor);
putValue(Action.SMALL_ICON, new Icon() {
public void paintIcon(Component c, Graphics pGraphics, int x, int y) {
Graphics g = pGraphics.create();
g.setColor((Color) mPaint);
g.fillRect(x, y, 16, 16);
g.dispose();
}
public int getIconWidth() {
return 16;
}
public int getIconHeight() {
return 16;
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
Color selected = JColorChooser.showDialog(ImageLabel.this, "Choose background", (Color) mPaint);
if (selected != null) {
mPaint = selected;
super.actionPerformed(e);
}
}
}
}
}
@@ -0,0 +1,158 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio;
import com.twelvemonkeys.imageio.util.IIOUtil;
import javax.imageio.ImageWriteParam;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
/**
* ImageWriterBase
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: ImageWriterBase.java,v 1.0 Sep 24, 2007 12:22:28 AM haraldk Exp$
*/
public abstract class ImageWriterBase extends javax.imageio.ImageWriter {
protected ImageOutputStream mImageOutput;
/**
* Constructs an {@code ImageWriter} and sets its
* {@code originatingProvider} instance variable to the
* supplied value.
* <p/>
* <p> Subclasses that make use of extensions should provide a
* constructor with signature {@code (ImageWriterSpi,
* Object)} in order to retrieve the extension object. If
* the extension object is unsuitable, an
* {@code IllegalArgumentException} should be thrown.
*
* @param pProvider the {@code ImageWriterSpi} that
* is constructing this object, or {@code null}.
*/
protected ImageWriterBase(final ImageWriterSpi pProvider) {
super(pProvider);
}
public String getFormatName() throws IOException {
return getOriginatingProvider().getFormatNames()[0];
}
@Override
public void setOutput(Object pOutput) {
super.setOutput(pOutput);
if (pOutput instanceof ImageOutputStream) {
mImageOutput = (ImageOutputStream) pOutput;
}
}
/**
* Makes sure output is set.
*
* @throws IllegalStateException if {@code getOutput() == null}.
*/
protected void assertOutput() {
if (getOutput() == null) {
throw new IllegalStateException("getOutput() == null");
}
}
/**
* Returns {@code null}
*
* @param pParam igonred.
* @return {@code null}.
*/
public IIOMetadata getDefaultStreamMetadata(javax.imageio.ImageWriteParam pParam) {
return null;
}
/**
* Returns {@code null}
*
* @param pInData ignored.
* @param pParam igonred.
* @return {@code null}.
*/
public IIOMetadata convertStreamMetadata(IIOMetadata pInData, ImageWriteParam pParam) {
return null;
}
protected static Rectangle getSourceRegion(ImageWriteParam pParam, int pWidth, int pHeight) {
return IIOUtil.getSourceRegion(pParam, pWidth, pHeight);
}
/**
* Utility method for getting the area of interest (AOI) of an image.
* The AOI is defined by the {@link IIOParam#setSourceRegion(java.awt.Rectangle)}
* method.
* <p/>
* Note: If it is possible for the reader to read the AOI directly, such a
* method should be used instead, for efficiency.
*
* @param pImage the image to get AOI from
* @param pParam the param optionally specifying the AOI
*
* @return a {@code BufferedImage} containing the area of interest (source
* region), or the original image, if no source region was set, or
* {@code pParam} was {@code null}
*/
protected static BufferedImage fakeAOI(BufferedImage pImage, ImageWriteParam pParam) {
return IIOUtil.fakeAOI(pImage, getSourceRegion(pParam, pImage.getWidth(), pImage.getHeight()));
}
/**
* Utility method for getting the subsampled image.
* The subsampling is defined by the
* {@link IIOParam#setSourceSubsampling(int, int, int, int)}
* method.
* <p/>
* NOTE: This method does not take the subsampling offsets into
* consideration.
* <p/>
* Note: If it is possible for the reader to subsample directly, such a
* method should be used instead, for efficiency.
*
* @param pImage the image to subsample
* @param pParam the param optionally specifying subsampling
*
* @return an {@code Image} containing the subsampled image, or the
* original image, if no subsampling was specified, or
* {@code pParam} was {@code null}
*/
protected static Image fakeSubsampling(Image pImage, ImageWriteParam pParam) {
return IIOUtil.fakeSubsampling(pImage, pParam);
}
}
@@ -0,0 +1,171 @@
package com.twelvemonkeys.imageio.stream;
import com.twelvemonkeys.lang.Validate;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageInputStreamImpl;
import java.io.IOException;
/**
* BufferedFileImageInputStream
* Experimental - seems to be effective for FileImageInputStream and FileCacheImageInputStream.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: BufferedFileImageInputStream.java,v 1.0 May 15, 2008 4:36:49 PM haraldk Exp$
*/
// TODO: Create a provider for this (wrapping the FileIIS and FileCacheIIS classes), and disable the Sun built-in spis?
public final class BufferedImageInputStream extends ImageInputStreamImpl implements ImageInputStream {
static final int DEFAULT_BUFFER_SIZE = 8192;
private ImageInputStream mStream;
private byte[] mBuffer;
private long mBufferStart = 0;
private int mBufferPos = 0;
private int mBufferLength = 0;
public BufferedImageInputStream(final ImageInputStream pStream) {
this(pStream, DEFAULT_BUFFER_SIZE);
}
private BufferedImageInputStream(final ImageInputStream pStream, final int pBufferSize) {
Validate.notNull(pStream, "stream");
mStream = pStream;
mBuffer = new byte[pBufferSize];
}
private void fillBuffer() throws IOException {
mBufferStart = streamPos;
mBufferLength = mStream.read(mBuffer, 0, mBuffer.length);
mBufferPos = 0;
}
private boolean isBufferValid() throws IOException {
return mBufferPos < mBufferLength && mBufferStart == mStream.getStreamPosition() - mBufferLength;
}
@Override
public int read() throws IOException {
if (!isBufferValid()) {
fillBuffer();
}
if (mBufferLength <= 0) {
return -1;
}
bitOffset = 0;
streamPos++;
return mBuffer[mBufferPos++] & 0xff;
}
@Override
public int read(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
bitOffset = 0;
boolean bypassBuffer = false;
if (!isBufferValid()) {
// Bypass cache if cache is empty for reads longer than buffer
if (pLength >= mBuffer.length) {
bypassBuffer = true;
}
else {
fillBuffer();
}
}
if (!bypassBuffer && mBufferLength <= 0) {
return -1;
}
// Read as much as possible from buffer
int length = bypassBuffer ? 0 : Math.min(mBufferLength - mBufferPos, pLength);
if (length > 0) {
System.arraycopy(mBuffer, mBufferPos, pBuffer, pOffset, length);
mBufferPos += length;
}
// Read rest directly from stream, if longer than buffer
if (pLength - length >= mBuffer.length) {
int read = mStream.read(pBuffer, pOffset + length, pLength - length);
if (read > 0) {
length += read;
}
}
streamPos += length;
return length;
}
@Override
public void seek(long pPosition) throws IOException {
// TODO: Could probably be optimized to not invalidate buffer if new pos is within current buffer
mStream.seek(pPosition);
mBufferLength = 0; // Will invalidate buffer
streamPos = mStream.getStreamPosition();
}
@Override
public void flushBefore(long pos) throws IOException {
mStream.flushBefore(pos);
}
@Override
public long getFlushedPosition() {
return mStream.getFlushedPosition();
}
@Override
public boolean isCached() {
return mStream.isCached();
}
@Override
public boolean isCachedMemory() {
return mStream.isCachedMemory();
}
@Override
public boolean isCachedFile() {
return mStream.isCachedFile();
}
@Override
public void close() throws IOException {
if (mStream != null) {
mStream.close();
mStream = null;
mBuffer = null;
}
super.close();
}
@Override
protected void finalize() throws Throwable {
super.finalize();
}
@Override
public long length() {
// WTF?! This method is allowed to throw IOException in the interface...
try {
return mStream.length();
}
catch (IOException e) {
throw unchecked(e, RuntimeException.class);
}
}
@SuppressWarnings({"unchecked", "UnusedDeclaration"})
private <T extends Throwable> T unchecked(IOException pExcption, Class<T> pClass) {
// Ugly hack to fool the compiler..
return (T) pExcption;
}
}
@@ -0,0 +1,56 @@
package com.twelvemonkeys.imageio.stream;
import com.twelvemonkeys.lang.Validate;
import javax.imageio.stream.ImageInputStreamImpl;
import java.io.IOException;
/**
* Experimental
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: ByteArrayImageInputStream.java,v 1.0 May 15, 2008 2:12:12 PM haraldk Exp$
*/
public final class ByteArrayImageInputStream extends ImageInputStreamImpl {
private final byte[] mData;
public ByteArrayImageInputStream(final byte[] pData) {
Validate.notNull(pData, "data");
mData = pData;
}
public int read() throws IOException {
if (streamPos >= mData.length) {
return -1;
}
bitOffset = 0;
return mData[((int) streamPos++)] & 0xff;
}
public int read(byte[] pBuffer, int pOffset, int pLength) throws IOException {
if (streamPos >= mData.length) {
return -1;
}
int length = (int) Math.min(mData.length - streamPos, pLength);
bitOffset = 0;
System.arraycopy(mData, (int) streamPos, pBuffer, pOffset, length);
streamPos += length;
return length;
}
@Override
public long length() {
return mData.length;
}
@Override
public boolean isCached() {
return true;
}
@Override
public boolean isCachedMemory() {
return true;
}
}
@@ -0,0 +1,36 @@
package com.twelvemonkeys.imageio.stream;
import javax.imageio.spi.ImageInputStreamSpi;
import javax.imageio.stream.ImageInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Locale;
/**
* ByteArrayImageInputStreamSpi
* Experimental
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: ByteArrayImageInputStreamSpi.java,v 1.0 May 15, 2008 2:12:12 PM haraldk Exp$
*/
public class ByteArrayImageInputStreamSpi extends ImageInputStreamSpi {
public ByteArrayImageInputStreamSpi() {
super("TwelveMonkeys", "1.0 BETA", byte[].class);
}
public ImageInputStream createInputStreamInstance(Object pInput, boolean pUseCache, File pCacheDir) throws IOException {
if (pInput instanceof byte[]) {
return new ByteArrayImageInputStream((byte[]) pInput);
}
else {
throw new IllegalArgumentException("Expected input of type byte[]: " + pInput);
}
}
public String getDescription(Locale pLocale) {
return "Service provider that instantiates an ImageInputStream from a byte array";
}
}
@@ -0,0 +1,84 @@
package com.twelvemonkeys.imageio.stream;
import javax.imageio.spi.ImageInputStreamSpi;
import javax.imageio.stream.FileCacheImageInputStream;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Locale;
/**
* URLImageInputStreamSpi
* Experimental
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: URLImageInputStreamSpi.java,v 1.0 May 15, 2008 2:14:59 PM haraldk Exp$
*/
// TODO: URI instead of URL?
public class URLImageInputStreamSpi extends ImageInputStreamSpi {
public URLImageInputStreamSpi() {
super("TwelveMonkeys", "1.0 BETA", URL.class);
}
// TODO: Create a URI or URLImageInputStream class, with a getUR[I|L] method, to allow for multiple file formats
// The good thing with that is that it does not clash with the built-in Sun-stuff or other people's hacks
// The bad thing is that most people don't expect there to be an UR[I|L]ImageInputStreamSpi..
public ImageInputStream createInputStreamInstance(final Object pInput, final boolean pUseCache, final File pCacheDir) throws IOException {
if (pInput instanceof URL) {
URL url = (URL) pInput;
// Special case for file protocol, a lot faster than FileCacheImageInputStream
if ("file".equals(url.getProtocol())) {
try {
return new BufferedImageInputStream(new FileImageInputStream(new File(url.toURI())));
// return new FileImageInputStream(new File(url.toURI()));
}
catch (URISyntaxException ignore) {
ignore.printStackTrace();
}
}
// Otherwise revert to cached
final InputStream stream = url.openStream();
if (pUseCache) {
return new BufferedImageInputStream(new FileCacheImageInputStream(stream, pCacheDir) {
@Override
public void close() throws IOException {
try {
super.close();
}
finally {
stream.close(); // NOTE: If this line throws IOE, it will shadow the original..
}
}
});
}
else {
return new MemoryCacheImageInputStream(stream) {
@Override
public void close() throws IOException {
try {
super.close();
}
finally {
stream.close(); // NOTE: If this line throws IOE, it will shadow the original..
}
}
};
}
}
else {
throw new IllegalArgumentException("Expected input of type URL: " + pInput);
}
}
public String getDescription(final Locale pLocale) {
return "Service provider that instantiates an ImageInputStream from a URL";
}
}
@@ -0,0 +1,177 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.util;
import javax.imageio.stream.ImageInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* IIOInputStreamAdapter
* <p/>
* Note: You should always wrap this stream in a {@code BufferedInputStream}.
* If not, performance may degrade significantly.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: IIOInputStreamAdapter.java,v 1.0 Sep 26, 2007 11:35:59 AM haraldk Exp$
*/
class IIOInputStreamAdapter extends InputStream {
private ImageInputStream mInput;
private final boolean mHasLength;
private long mLeft;
private long mMarkPosition;
// TODO: Enforce stream boundaries!
// TODO: Stream start position....
/**
* Creates an {@code InputStream} that reads from the given {@code ImageInputStream}.
* The input stream will read from the current stream position, until the end of the
* underlying stream.
*
* @param pInput the {@code ImageInputStream} to read from.
*/
public IIOInputStreamAdapter(final ImageInputStream pInput) {
this(pInput, -1, false);
}
/**
* Creates an {@code InputStream} that reads from the given {@code ImageInputStream}.
* The input stream will read from the current stream position, until at most
* {@code pLength} bytes has been read.
*
* @param pInput the {@code ImageInputStream} to read from.
* @param pLength the length of the stream
*/
public IIOInputStreamAdapter(final ImageInputStream pInput, final long pLength) {
this(pInput, pLength, true);
}
private IIOInputStreamAdapter(ImageInputStream pInput, long pLength, boolean pHasLength) {
if (pInput == null) {
throw new IllegalArgumentException("stream == null");
}
if (pHasLength && pLength < 0) {
throw new IllegalArgumentException("length < 0");
}
mInput = pInput;
mHasLength = pHasLength;
mLeft = pLength;
}
/**
* Marks this stream as closed.
* This implementation does <em>not</em> close the underlying stream.
*/
public void close() throws IOException {
if (mHasLength) {
mInput.seek(mInput.getStreamPosition() + mLeft);
}
mLeft = 0;
mInput = null;
}
public int available() throws IOException {
if (mHasLength) {
return mLeft > 0 ? (int) Math.min(Integer.MAX_VALUE, mLeft) : 0;
}
return 0; // We don't really know, so we say 0 to be safe.
}
@Override
public boolean markSupported() {
return true;
}
public void mark(int pReadLimit) {
try {
mMarkPosition = mInput.getStreamPosition();
}
catch (IOException e) {
// Let's hope this never happens, because it's not possible to reset then...
throw new IllegalStateException("Could not read stream position: " + e.getMessage(), e);
}
}
public void reset() throws IOException {
long diff = mInput.getStreamPosition() - mMarkPosition;
mInput.seek(mMarkPosition);
mLeft += diff;
}
public int read() throws IOException {
if (mHasLength && mLeft-- <= 0) {
mLeft = 0;
return -1;
}
return mInput.read();
}
public final int read(byte[] pBytes) throws IOException {
return read(pBytes, 0, pBytes.length);
}
public int read(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
if (mHasLength && mLeft <= 0) {
return -1;
}
int read = mInput.read(pBytes, pOffset, (int) findMaxLen(pLength));
if (mHasLength) {
mLeft = read < 0 ? 0 : mLeft - read;
}
return read;
}
/**
* Finds the maximum number of bytes we can read or skip, from this stream.
* The number will be in the range {@code [0 ... bytes left]}.
*
* @param pLength the requested length
* @return the maximum number of bytes to read
*/
private long findMaxLen(long pLength) {
if (mHasLength && mLeft < pLength) {
return Math.max(mLeft, 0);
}
else {
return Math.max(pLength, 0);
}
}
public long skip(long pLength) throws IOException {
long skipped = mInput.skipBytes(findMaxLen(pLength)); // Skips 0 or more, never -1
mLeft -= skipped;
return skipped;
}
}
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.util;
import javax.imageio.stream.ImageOutputStream;
import java.io.IOException;
import java.io.OutputStream;
/**
* IIOOutputStreamAdapter
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: IIOOutputStreamAdapter.java,v 1.0 Sep 26, 2007 11:50:38 AM haraldk Exp$
*/
class IIOOutputStreamAdapter extends OutputStream {
private ImageOutputStream mOutput;
public IIOOutputStreamAdapter(final ImageOutputStream pOutput) {
mOutput = pOutput;
}
@Override
public void write(final byte[] pBytes) throws IOException {
mOutput.write(pBytes);
}
@Override
public void write(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
mOutput.write(pBytes, pOffset, pLength);
}
@Override
public void write(final int pByte) throws IOException {
mOutput.write(pByte);
}
@Override
public void flush() throws IOException {
mOutput.flush();
}
@Override
public void close() throws IOException {
mOutput = null;
}
}
@@ -0,0 +1,131 @@
package com.twelvemonkeys.imageio.util;
import com.twelvemonkeys.image.ImageUtil;
import javax.imageio.IIOParam;
import javax.imageio.spi.IIOServiceProvider;
import javax.imageio.spi.ServiceRegistry;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
/**
* IIOUtil
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: IIOUtil.java,v 1.0 May 8, 2008 3:04:54 PM haraldk Exp$
*/
public final class IIOUtil {
private IIOUtil() {}
/**
* Creates an {@code InputStream} adapter that reads from an underlying {@code ImageInputStream}.
* The input stream will read until the end of {@code pStream}.
*
* @param pStream the stream to read from.
* @return an {@code InputStream} reading from {@code pStream}.
*/
public static InputStream createStreamAdapter(final ImageInputStream pStream) {
// TODO: Include stream start pos?
// TODO: Skip buffering for known in-memory implementations?
return new BufferedInputStream(new IIOInputStreamAdapter(pStream));
}
/**
* Creates an {@code InputStream} adapter that reads from an underlying {@code ImageInputStream}.
* The input stream will read until the end of {@code pStream}, or at most {@code pLength} bytes has been read.
*
* @param pStream the stream to read from.
* @param pLength the maximum number of bytes that can be read from {@code pStream}.
* @return an {@code InputStream} reading from {@code pStream}.
*/
public static InputStream createStreamAdapter(final ImageInputStream pStream, final long pLength) {
// TODO: Include stream start pos?
// TODO: Skip buffering for known in-memory implementations?
return new BufferedInputStream(new IIOInputStreamAdapter(pStream, pLength));
}
/**
* Creates an {@code OutputStream} adapter that writes to an underlying {@code ImageOutputStream}.
*
* @param pStream the stream to write to.
* @return an {@code OutputSteam} writing to {@code pStream}.
*/
public static OutputStream createStreamAdapter(final ImageOutputStream pStream) {
return new BufferedOutputStream(new IIOOutputStreamAdapter(pStream));
}
/*
* THIS METHOD WILL ME MOVED/RENAMED, DO NOT USE.
*/
public static <T> void deregisterProvider(final ServiceRegistry pRegistry, final IIOServiceProvider pProvider, final Class<T> pCategory) {
// http://www.ibm.com/developerworks/java/library/j-jtp04298.html
// TODO: Consider placing this method in a ImageReaderSpiBase class or similar
pRegistry.deregisterServiceProvider(pCategory.cast(pProvider), pCategory);
}
public static Image fakeSubsampling(final Image pImage, final IIOParam pParam) {
if (pImage == null) {
return null;
}
if (pParam != null) {
int x = pParam.getSourceXSubsampling();
int y = pParam.getSourceYSubsampling();
// 1 is default
if (x > 1 || y > 1) {
int w = (ImageUtil.getWidth(pImage) + x - 1) / x;
int h = (ImageUtil.getHeight(pImage) + y - 1) / y;
// Fake subsampling by scaling fast
return pImage.getScaledInstance(w, h, Image.SCALE_FAST);
}
}
return pImage;
}
public static Rectangle getSourceRegion(final IIOParam pParam, final int pSrcWidth, final int pSrcHeight) {
Rectangle sourceRegion = new Rectangle(pSrcWidth, pSrcHeight);
// If param is present, calculate region
if (pParam != null) {
// Get intersection with source region
Rectangle region = pParam.getSourceRegion();
if (region != null) {
sourceRegion = sourceRegion.intersection(region);
}
// Scale according to subsampling offsets
int subsampleXOffset = pParam.getSubsamplingXOffset();
int subsampleYOffset = pParam.getSubsamplingYOffset();
sourceRegion.x += subsampleXOffset;
sourceRegion.y += subsampleYOffset;
sourceRegion.width -= subsampleXOffset;
sourceRegion.height -= subsampleYOffset;
}
return sourceRegion;
}
public static BufferedImage fakeAOI(final BufferedImage pImage, final Rectangle pSourceRegion) {
if (pImage == null) {
return null;
}
if (pSourceRegion != null) {
if (pSourceRegion.x != 0 || pSourceRegion.y != 0 || pSourceRegion.width != pImage.getWidth() || pSourceRegion.height != pImage.getHeight()) {
return pImage.getSubimage(pSourceRegion.x, pSourceRegion.y, pSourceRegion.width, pSourceRegion.height);
}
}
return pImage;
}
}
@@ -0,0 +1,41 @@
package com.twelvemonkeys.imageio.util;
import javax.imageio.ImageTypeSpecifier;
import java.awt.image.IndexColorModel;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.util.Hashtable;
/**
* IndexedImageTypeSpecifier
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: IndexedImageTypeSpecifier.java,v 1.0 May 19, 2008 11:04:28 AM haraldk Exp$
*/
public class IndexedImageTypeSpecifier extends ImageTypeSpecifier {
IndexedImageTypeSpecifier(IndexColorModel pColorModel) {
// For some reason, we need a sample model
super(pColorModel, pColorModel.createCompatibleSampleModel(1, 1));
}
public static ImageTypeSpecifier createFromIndexColorModel(final IndexColorModel pColorModel) {
return new IndexedImageTypeSpecifier(pColorModel);
}
@Override
public final BufferedImage createBufferedImage(int pWidth, int pHeight) {
try {
// This is a fix for the super-method, that first creates a sample model, and then
// creates a raster from it, using Raster.createWritableRaster. The problem with
// that approach, is that it always creates a TYPE_CUSTOM BufferedImage for indexed images.
WritableRaster raster = colorModel.createCompatibleWritableRaster(pWidth, pHeight);
return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), new Hashtable());
}
catch (NegativeArraySizeException e) {
// Exception most likely thrown from a DataBuffer constructor
throw new IllegalArgumentException("Array size > Integer.MAX_VALUE!");
}
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.util;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriter;
import javax.imageio.event.IIOReadProgressListener;
import javax.imageio.event.IIOWriteProgressListener;
/**
* ProgressListenerBase
* <p/>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @version $Id: ProgressListenerBase.java,v 1.0 26.aug.2005 14:29:42 haku Exp$
*/
public abstract class ProgressListenerBase implements IIOReadProgressListener, IIOWriteProgressListener {
protected ProgressListenerBase() {
}
public void imageComplete(ImageReader pSource) {
}
public void imageProgress(ImageReader pSource, float pPercentageDone) {
}
public void imageStarted(ImageReader pSource, int pImageIndex) {
}
public void readAborted(ImageReader pSource) {
}
public void sequenceComplete(ImageReader pSource) {
}
public void sequenceStarted(ImageReader pSource, int pMinIndex) {
}
public void thumbnailComplete(ImageReader pSource) {
}
public void thumbnailProgress(ImageReader pSource, float pPercentageDone) {
}
public void thumbnailStarted(ImageReader pSource, int pImageIndex, int pThumbnailIndex) {
}
public void imageComplete(ImageWriter pSource) {
}
public void imageProgress(ImageWriter pSource, float pPercentageDone) {
}
public void imageStarted(ImageWriter pSource, int pImageIndex) {
}
public void thumbnailComplete(ImageWriter pSource) {
}
public void thumbnailProgress(ImageWriter pSource, float pPercentageDone) {
}
public void thumbnailStarted(ImageWriter pSource, int pImageIndex, int pThumbnailIndex) {
}
public void writeAborted(ImageWriter pSource) {
}
}
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.util;
import com.twelvemonkeys.io.FileUtil;
import com.twelvemonkeys.lang.StringUtil;
import javax.imageio.ImageIO;
import javax.swing.filechooser.FileFilter;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* ReaderFileSuffixFilter
* <p/>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haku$
* @version $Id: ReaderFileSuffixFilter.java,v 1.0 11.okt.2006 20:05:36 haku Exp$
*/
public final class ReaderFileSuffixFilter extends FileFilter implements java.io.FileFilter {
private final String mDescription;
private final Map<String, Boolean> mKnownSuffixes = new HashMap<String, Boolean>(32);
public ReaderFileSuffixFilter() {
this("Images (all supported input formats)");
}
public ReaderFileSuffixFilter(String pDescription) {
mDescription = pDescription;
}
public boolean accept(File pFile) {
// Directories are always supported
if (pFile.isDirectory()) {
return true;
}
// See if we have an ImageReader for this suffix
String suffix = FileUtil.getExtension(pFile);
return !StringUtil.isEmpty(suffix) && hasReaderForSuffix(suffix);
}
private boolean hasReaderForSuffix(String pSuffix) {
if (mKnownSuffixes.get(pSuffix) == Boolean.TRUE) {
return true;
}
try {
// Cahce lookup
Iterator iterator = ImageIO.getImageReadersBySuffix(pSuffix);
if (iterator.hasNext()) {
mKnownSuffixes.put(pSuffix, Boolean.TRUE);
return true;
}
else {
mKnownSuffixes.put(pSuffix, Boolean.FALSE);
return false;
}
}
catch (IllegalArgumentException iae) {
return false;
}
}
public String getDescription() {
return mDescription;
}
}
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.util;
import com.twelvemonkeys.io.FileUtil;
import com.twelvemonkeys.lang.StringUtil;
import javax.imageio.ImageIO;
import javax.swing.filechooser.FileFilter;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* WriterFileSuffixFilter
* <p/>
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haku$
* @version $Id: WriterFileSuffixFilter.java,v 1.0 11.okt.2006 20:05:36 haku Exp$
*/
public final class WriterFileSuffixFilter extends FileFilter implements java.io.FileFilter {
private final String mDescription;
private Map<String, Boolean>mKnownSuffixes = new HashMap<String, Boolean>(32);
public WriterFileSuffixFilter() {
this("Images (all supported output formats)");
}
public WriterFileSuffixFilter(String pDescription) {
mDescription = pDescription;
}
public boolean accept(File pFile) {
// Directories are always supported
if (pFile.isDirectory()) {
return true;
}
// Test if we have an ImageWriter for this suffix
String suffix = FileUtil.getExtension(pFile);
return !StringUtil.isEmpty(suffix) && hasWriterForSuffix(suffix);
}
private boolean hasWriterForSuffix(String pSuffix) {
if (mKnownSuffixes.get(pSuffix) == Boolean.TRUE) {
return true;
}
try {
// Cahce lookup
Iterator iterator = ImageIO.getImageWritersBySuffix(pSuffix);
if (iterator.hasNext()) {
mKnownSuffixes.put(pSuffix, Boolean.TRUE);
return true;
}
else {
mKnownSuffixes.put(pSuffix, Boolean.FALSE);
return false;
}
}
catch (IllegalArgumentException iae) {
return false;
}
}
public String getDescription() {
return mDescription;
}
}
@@ -0,0 +1,116 @@
package com.twelvemonkeys.imageio.stream;
import com.twelvemonkeys.io.ole2.CompoundDocument;
import com.twelvemonkeys.io.ole2.Entry;
import junit.framework.TestCase;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import java.io.IOException;
import java.nio.ByteOrder;
import java.util.Random;
/**
* BufferedImageInputStreamTestCase
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: BufferedImageInputStreamTestCase.java,v 1.0 Jun 30, 2008 3:07:42 PM haraldk Exp$
*/
public class BufferedImageInputStreamTestCase extends TestCase{
protected final Random mRandom = new Random();
public void testCreate() {
new BufferedImageInputStream(new ByteArrayImageInputStream(new byte[0]));
}
public void testCreateNull() {
try {
new BufferedImageInputStream(null);
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
assertNotNull("Null exception message", expected.getMessage());
String message = expected.getMessage().toLowerCase();
assertTrue("Exception message does not contain parameter name", message.contains("stream"));
assertTrue("Exception message does not contain null", message.contains("null"));
}
}
// TODO: Write other tests
// TODO: Create test that exposes read += -1 (eof) bug
public void testArrayIndexOutOfBoundsBufferedReadBug() throws IOException {
// TODO: Create a more straight forward way to prove correctness, for now this is good enough to avoid regression
ImageInputStream input = new BufferedImageInputStream(new MemoryCacheImageInputStream(getClass().getResourceAsStream("/Thumbs-camera.db")));
input.setByteOrder(ByteOrder.LITTLE_ENDIAN);
Entry root = new CompoundDocument(input).getRootEntry();
Entry child = root.getChildEntry("Catalog");
assertNotNull("Input stream can never be null", child.getInputStream());
}
public void testReadResetReadDirectBufferBug() throws IOException {
// Make sure we use the exact size of the buffer
final int size = BufferedImageInputStream.DEFAULT_BUFFER_SIZE;
// Fill bytes
byte[] bytes = new byte[size * 2];
mRandom.nextBytes(bytes);
// Create wrapper stream
BufferedImageInputStream stream = new BufferedImageInputStream(new ByteArrayImageInputStream(bytes));
// Read to fill the buffer, then reset
stream.readLong();
stream.seek(0);
// Read fully and compare
byte[] result = new byte[size];
stream.readFully(result);
assertTrue(rangeEquals(bytes, 0, result, 0, size));
stream.readFully(result);
assertTrue(rangeEquals(bytes, size, result, 0, size));
}
/**
* Test two arrays for range equality. That is, they contain the same elements for some specified range.
*
* @param pFirst one array to test for equality
* @param pFirstOffset the offset into the first array to start testing for equality
* @param pSecond the other array to test for equality
* @param pSecondOffset the offset into the second array to start testing for equality
* @param pLength the length of the range to check for equality
*
* @return {@code true} if both arrays are non-{@code null}
* and have at least {@code offset + pLength} elements
* and all elements in the range from the first array is equal to the elements from the second array,
* or if {@code pFirst == pSecond} (including both arrays being {@code null})
* and {@code pFirstOffset == pSecondOffset}.
* Otherwise {@code false}.
*/
static boolean rangeEquals(byte[] pFirst, int pFirstOffset, byte[] pSecond, int pSecondOffset, int pLength) {
if (pFirst == pSecond && pFirstOffset == pSecondOffset) {
return true;
}
if (pFirst == null || pSecond == null) {
return false;
}
if (pFirst.length < pFirstOffset + pLength || pSecond.length < pSecondOffset + pLength) {
return false;
}
for (int i = 0; i < pLength; i++) {
if (pFirst[pFirstOffset + i] != pSecond[pSecondOffset + i]) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,102 @@
package com.twelvemonkeys.imageio.stream;
import static com.twelvemonkeys.imageio.stream.BufferedImageInputStreamTestCase.rangeEquals;
import junit.framework.TestCase;
import java.io.IOException;
import java.util.Random;
/**
* ByteArrayImageInputStreamTestCase
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: ByteArrayImageInputStreamTestCase.java,v 1.0 Apr 21, 2009 10:58:48 AM haraldk Exp$
*/
public class ByteArrayImageInputStreamTestCase extends TestCase {
protected final Random mRandom = new Random();
public void testCreate() {
ByteArrayImageInputStream stream = new ByteArrayImageInputStream(new byte[0]);
assertEquals("Data length should be same as stream length", 0, stream.length());
}
public void testCreateNull() {
try {
new ByteArrayImageInputStream(null);
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException expected) {
assertNotNull("Null exception message", expected.getMessage());
String message = expected.getMessage().toLowerCase();
assertTrue("Exception message does not contain parameter name", message.contains("data"));
assertTrue("Exception message does not contain null", message.contains("null"));
}
}
public void testRead() throws IOException {
byte[] data = new byte[1024 * 1024];
mRandom.nextBytes(data);
ByteArrayImageInputStream stream = new ByteArrayImageInputStream(data);
assertEquals("Data length should be same as stream length", data.length, stream.length());
for (byte b : data) {
assertEquals("Wrong data read", b & 0xff, stream.read());
}
}
public void testReadArray() throws IOException {
byte[] data = new byte[1024 * 1024];
mRandom.nextBytes(data);
ByteArrayImageInputStream stream = new ByteArrayImageInputStream(data);
assertEquals("Data length should be same as stream length", data.length, stream.length());
byte[] result = new byte[1024];
for (int i = 0; i < data.length / result.length; i++) {
stream.readFully(result);
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
}
}
public void testReadSkip() throws IOException {
byte[] data = new byte[1024 * 14];
mRandom.nextBytes(data);
ByteArrayImageInputStream stream = new ByteArrayImageInputStream(data);
assertEquals("Data length should be same as stream length", data.length, stream.length());
byte[] result = new byte[7];
for (int i = 0; i < data.length / result.length; i += 2) {
stream.readFully(result);
stream.skipBytes(result.length);
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
}
}
public void testReadSeek() throws IOException {
byte[] data = new byte[1024 * 18];
mRandom.nextBytes(data);
ByteArrayImageInputStream stream = new ByteArrayImageInputStream(data);
assertEquals("Data length should be same as stream length", data.length, stream.length());
byte[] result = new byte[9];
for (int i = 0; i < data.length / result.length; i++) {
// Read backwards
long newPos = stream.length() - result.length - i * result.length;
stream.seek(newPos);
assertEquals("Wrong stream position", newPos, stream.getStreamPosition());
stream.readFully(result);
assertTrue("Wrong data read: " + i, rangeEquals(data, (int) newPos, result, 0, result.length));
}
}
}
@@ -0,0 +1,140 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.util;
import com.twelvemonkeys.io.InputStreamAbstractTestCase;
import javax.imageio.stream.MemoryCacheImageInputStream;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
/**
* IIOInputStreamAdapter
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: IIOInputStreamAdapter.java,v 1.0 Apr 11, 2008 1:04:42 PM haraldk Exp$
*/
public class IIOInputStreamAdapterTestCase extends InputStreamAbstractTestCase {
public IIOInputStreamAdapterTestCase(String name) {
super(name);
}
protected InputStream makeInputStream(byte[] pBytes) {
return new IIOInputStreamAdapter(new MemoryCacheImageInputStream(new ByteArrayInputStream(pBytes)), pBytes.length);
}
public void testReadSubstreamOpenEnd() throws IOException {
byte[] bytes = new byte[20];
MemoryCacheImageInputStream input = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
input.seek(10);
assertEquals(10, input.getStreamPosition());
IIOInputStreamAdapter stream = new IIOInputStreamAdapter(input);
for (int i = 0; i < 10; i++) {
assertTrue("Unexpected end of stream", -1 != stream.read());
}
assertEquals("Read value after end of stream", -1, stream.read());
assertEquals("Read value after end of stream", -1, stream.read());
// Make sure underlying stream is positioned at end of substream after close
stream.close();
assertEquals(20, input.getStreamPosition());
input.close();
}
public void testReadSubstream() throws IOException {
byte[] bytes = new byte[20];
MemoryCacheImageInputStream input = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
IIOInputStreamAdapter stream = new IIOInputStreamAdapter(input, 9);
for (int i = 0; i < 9; i++) {
assertTrue("Unexpected end of stream", -1 != stream.read());
}
assertEquals("Read value after end of stream", -1, stream.read());
assertEquals("Read value after end of stream", -1, stream.read());
// Make sure we don't read outside stream boundaries
assertTrue(input.getStreamPosition() <= 9);
input.close();
}
public void testReadSubstreamRepositionOnClose() throws IOException {
byte[] bytes = new byte[20];
MemoryCacheImageInputStream input = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
IIOInputStreamAdapter stream = new IIOInputStreamAdapter(input, 10);
for (int i = 0; i < 7; i++) {
assertTrue("Unexpected end of stream", -1 != stream.read());
}
// Make sure we don't read outside stream boundaries
assertTrue(input.getStreamPosition() <= 7);
// Make sure underlying stream is positioned at end of substream after close
stream.close();
assertEquals(10, input.getStreamPosition());
input.close();
}
public void testSeekBeforeStreamNoEnd() throws IOException {
byte[] bytes = new byte[20];
MemoryCacheImageInputStream input = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
input.seek(10);
assertEquals(10, input.getStreamPosition());
IIOInputStreamAdapter stream = new IIOInputStreamAdapter(input);
assertEquals("Should not skip backwards", 0, stream.skip(-5));
assertEquals(10, input.getStreamPosition());
}
public void testSeekBeforeStream() throws IOException {
byte[] bytes = new byte[20];
MemoryCacheImageInputStream input = new MemoryCacheImageInputStream(new ByteArrayInputStream(bytes));
input.seek(10);
assertEquals(10, input.getStreamPosition());
IIOInputStreamAdapter stream = new IIOInputStreamAdapter(input, 9);
assertEquals("Should not skip backwards", 0, stream.skip(-5));
assertEquals(10, input.getStreamPosition());
}
}
@@ -0,0 +1,322 @@
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.util;
import org.jmock.Mock;
import org.jmock.cglib.MockObjectTestCase;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.event.IIOWriteProgressListener;
import java.awt.image.RenderedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* ImageReaderAbstractTestCase class description.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haku $
* @version $Id: ImageReaderAbstractTestCase.java,v 1.0 18.nov.2004 17:38:33 haku Exp $
*/
public abstract class ImageWriterAbstractTestCase extends MockObjectTestCase {
protected abstract ImageWriter createImageWriter();
protected abstract RenderedImage getTestData();
public void testSetOutput() throws IOException {
// Should just pass with no exceptions
ImageWriter writer = createImageWriter();
assertNotNull(writer);
writer.setOutput(ImageIO.createImageOutputStream(new ByteArrayOutputStream()));
}
public void testSetOutputNull() {
// Should just pass with no exceptions
ImageWriter writer = createImageWriter();
assertNotNull(writer);
writer.setOutput(null);
}
public void testWrite() throws IOException {
ImageWriter writer = createImageWriter();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
writer.setOutput(ImageIO.createImageOutputStream(buffer));
try {
writer.write(getTestData());
}
catch (IOException e) {
fail(e.getMessage());
}
assertTrue("No image data written", buffer.size() > 0);
}
public void testWrite2() {
// Note: There's a difference between new ImageOutputStreamImpl and
// ImageIO.createImageOutputStream... Make sure writers handle both
// cases
ImageWriter writer = createImageWriter();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try {
writer.setOutput(ImageIO.createImageOutputStream(buffer));
writer.write(getTestData());
}
catch (IOException e) {
fail(e.getMessage());
}
assertTrue("No image data written", buffer.size() > 0);
}
public void testWriteNull() throws IOException {
ImageWriter writer = createImageWriter();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
writer.setOutput(ImageIO.createImageOutputStream(buffer));
try {
writer.write((RenderedImage) null);
}
catch(IllegalArgumentException ignore) {
}
catch (IOException e) {
fail(e.getMessage());
}
assertTrue("Image data written", buffer.size() == 0);
}
public void testWriteNoOutput() {
ImageWriter writer = createImageWriter();
try {
writer.write(getTestData());
}
catch (IllegalStateException ignore) {
}
catch (IOException e) {
fail(e.getMessage());
}
}
public void testGetDefaultWriteParam() {
ImageWriter writer = createImageWriter();
ImageWriteParam param = writer.getDefaultWriteParam();
assertNotNull("Default ImageWriteParam is null", param);
}
// TODO: Test writing with params
// TODO: Source region and subsampling at least
public void testAddIIOWriteProgressListener() {
ImageWriter writer = createImageWriter();
Mock mockListener = new Mock(IIOWriteProgressListener.class);
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
}
public void testAddIIOWriteProgressListenerNull() {
ImageWriter writer = createImageWriter();
writer.addIIOWriteProgressListener(null);
}
public void testAddIIOWriteProgressListenerCallbacks() throws IOException {
ImageWriter writer = createImageWriter();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
writer.setOutput(ImageIO.createImageOutputStream(buffer));
Mock mockListener = new Mock(IIOWriteProgressListener.class);
String started = "Started";
mockListener.expects(once()).method("imageStarted").withAnyArguments().id(started);
mockListener.stubs().method("imageProgress").withAnyArguments().after(started);
mockListener.expects(once()).method("imageComplete").withAnyArguments().after(started);
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
try {
writer.write(getTestData());
}
catch (IOException e) {
fail("Could not write image");
}
// At least imageStarted and imageComplete, plus any number of imageProgress
mockListener.verify();
}
public void testMultipleAddIIOWriteProgressListenerCallbacks() throws IOException {
ImageWriter writer = createImageWriter();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
writer.setOutput(ImageIO.createImageOutputStream(buffer));
Mock mockListener = new Mock(IIOWriteProgressListener.class);
String started = "Started";
mockListener.expects(once()).method("imageStarted").withAnyArguments().id(started);
mockListener.stubs().method("imageProgress").withAnyArguments().after(started);
mockListener.expects(once()).method("imageComplete").withAnyArguments().after(started);
Mock mockListenerToo = new Mock(IIOWriteProgressListener.class);
String startedToo = "Started Two";
mockListenerToo.expects(once()).method("imageStarted").withAnyArguments().id(startedToo);
mockListenerToo.stubs().method("imageProgress").withAnyArguments().after(startedToo);
mockListenerToo.expects(once()).method("imageComplete").withAnyArguments().after(startedToo);
Mock mockListenerThree = new Mock(IIOWriteProgressListener.class);
String startedThree = "Started Three";
mockListenerThree.expects(once()).method("imageStarted").withAnyArguments().id(startedThree);
mockListenerThree.stubs().method("imageProgress").withAnyArguments().after(startedThree);
mockListenerThree.expects(once()).method("imageComplete").withAnyArguments().after(startedThree);
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListenerToo.proxy());
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListenerThree.proxy());
try {
writer.write(getTestData());
}
catch (IOException e) {
fail("Could not write image");
}
// At least imageStarted and imageComplete, plus any number of imageProgress
mockListener.verify();
mockListenerToo.verify();
mockListenerThree.verify();
}
public void testRemoveIIOWriteProgressListenerNull() {
ImageWriter writer = createImageWriter();
writer.removeIIOWriteProgressListener(null);
}
public void testRemoveIIOWriteProgressListenerNone() {
ImageWriter writer = createImageWriter();
Mock mockListener = new Mock(IIOWriteProgressListener.class);
writer.removeIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
}
public void testRemoveIIOWriteProgressListener() throws IOException {
ImageWriter writer = createImageWriter();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
writer.setOutput(ImageIO.createImageOutputStream(buffer));
Mock mockListener = new Mock(IIOWriteProgressListener.class);
IIOWriteProgressListener listener = (IIOWriteProgressListener) mockListener.proxy();
writer.addIIOWriteProgressListener(listener);
writer.removeIIOWriteProgressListener(listener);
try {
writer.write(getTestData());
}
catch (IOException e) {
fail("Could not write image");
}
// Should not have called any methods...
mockListener.verify();
}
public void testRemoveIIOWriteProgressListenerMultiple() throws IOException {
ImageWriter writer = createImageWriter();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
writer.setOutput(ImageIO.createImageOutputStream(buffer));
Mock mockListener = new Mock(IIOWriteProgressListener.class);
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
Mock mockListenerToo = new Mock(IIOWriteProgressListener.class);
mockListenerToo.stubs().method("imageStarted").withAnyArguments();
mockListenerToo.stubs().method("imageProgress").withAnyArguments();
mockListenerToo.stubs().method("imageComplete").withAnyArguments();
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListenerToo.proxy());
writer.removeIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
try {
writer.write(getTestData());
}
catch (IOException e) {
fail("Could not write image");
}
// Should not have called any methods...
mockListener.verify();
mockListenerToo.verify();
}
public void testRemoveAllIIOWriteProgressListeners() throws IOException {
ImageWriter writer = createImageWriter();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
writer.setOutput(ImageIO.createImageOutputStream(buffer));
Mock mockListener = new Mock(IIOWriteProgressListener.class);
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
writer.removeAllIIOWriteProgressListeners();
try {
writer.write(getTestData());
}
catch (IOException e) {
fail("Could not write image");
}
// Should not have called any methods...
mockListener.verify();
}
public void testRemoveAllIIOWriteProgressListenersMultiple() throws IOException {
ImageWriter writer = createImageWriter();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
writer.setOutput(ImageIO.createImageOutputStream(buffer));
Mock mockListener = new Mock(IIOWriteProgressListener.class);
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListener.proxy());
Mock mockListenerToo = new Mock(IIOWriteProgressListener.class);
writer.addIIOWriteProgressListener((IIOWriteProgressListener) mockListenerToo.proxy());
writer.removeAllIIOWriteProgressListeners();
try {
writer.write(getTestData());
}
catch (IOException e) {
fail("Could not write image");
}
// Should not have called any methods...
mockListener.verify();
mockListenerToo.verify();
}
}
@@ -0,0 +1,28 @@
package com.twelvemonkeys.imageio.util;
import junit.framework.TestCase;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
/**
* IndexedImageTypeSpecifierTestCase
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: IndexedImageTypeSpecifierTestCase.java,v 1.0 Jun 9, 2008 2:42:03 PM haraldk Exp$
*/
public class IndexedImageTypeSpecifierTestCase extends TestCase {
public void testEquals() {
IndexColorModel cm = new IndexColorModel(1, 2, new int[]{0xffffff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE);
IndexedImageTypeSpecifier spec = new IndexedImageTypeSpecifier(cm);
IndexedImageTypeSpecifier other = new IndexedImageTypeSpecifier(cm);
assertEquals(spec, other);
assertEquals(other, spec);
assertTrue(spec.equals(other));
assertTrue(other.equals(spec));
}
}
Binary file not shown.