mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-28 00:00:03 -04:00
It all works
This commit is contained in:
@@ -0,0 +1,478 @@
|
||||
/*
|
||||
* 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.*;
|
||||
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.awt.image.IndexColorModel;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Abstract base class for image readers.
|
||||
*
|
||||
* @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 pProvider the {@code ImageReaderSpi} that is invoking this constructor, or {@code null}.
|
||||
*/
|
||||
protected ImageReaderBase(final ImageReaderSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(final Object pInput, final boolean pSeekForwardOnly, final 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();
|
||||
|
||||
/**
|
||||
* Default implementation that always returns {@code null}.
|
||||
*
|
||||
* @param pImageIndex ignored, unless overridden
|
||||
* @return {@code null}, unless overridden
|
||||
* @throws IOException never, unless overridden.
|
||||
*/
|
||||
public IIOMetadata getImageMetadata(int pImageIndex) throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation that always returns {@code null}.
|
||||
*
|
||||
* @return {@code null}, unless overridden
|
||||
* @throws IOException never, unless overridden.
|
||||
*/
|
||||
public IIOMetadata getStreamMetadata() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation that always returns {@code 1}.
|
||||
*
|
||||
* @param pAllowSearch ignored, unless overridden
|
||||
* @return {@code 1}, unless overridden
|
||||
* @throws IOException never, unless overridden
|
||||
*/
|
||||
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 {@code minIndex <= pIndex < numImages}
|
||||
*/
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code BufferedImage} to which decoded pixel
|
||||
* data should be written.
|
||||
* <p/>
|
||||
* As {@link javax.imageio.ImageReader#getDestination} but tests if the explicit destination
|
||||
* image (if set) is valid according to the {@code ImageTypeSpecifier}s given in {@code pTypes}
|
||||
*
|
||||
*
|
||||
* @param pParam an {@code ImageReadParam} to be used to get
|
||||
* the destination image or image type, or {@code null}.
|
||||
* @param pTypes an {@code Iterator} of
|
||||
* {@code ImageTypeSpecifier}s indicating the legal image
|
||||
* types, with the default first.
|
||||
* @param pWidth the true width of the image or tile begin decoded.
|
||||
* @param pHeight the true width of the image or tile being decoded.
|
||||
*
|
||||
* @return the {@code BufferedImage} to which decoded pixel
|
||||
* data should be written.
|
||||
*
|
||||
* @exception IIOException if the {@code ImageTypeSpecifier} or {@code BufferedImage}
|
||||
* specified by {@code pParam} does not match any of the legal
|
||||
* ones from {@code pTypes}.
|
||||
* @throws IllegalArgumentException if {@code pTypes}
|
||||
* is {@code null} or empty, or if an object not of type
|
||||
* {@code ImageTypeSpecifier} is retrieved from it.
|
||||
* Or, if the resulting image would have a width or height less than 1,
|
||||
* or if the product of {@code pWidth} and {@code pHeight} is greater than
|
||||
* {@code Integer.MAX_VALUE}.
|
||||
*/
|
||||
public static BufferedImage getDestination(final ImageReadParam pParam, final Iterator<ImageTypeSpecifier> pTypes,
|
||||
final int pWidth, final int pHeight) throws IIOException {
|
||||
BufferedImage image = ImageReader.getDestination(pParam, pTypes, pWidth, pHeight);
|
||||
|
||||
if (pParam != null) {
|
||||
BufferedImage dest = pParam.getDestination();
|
||||
if (dest != null) {
|
||||
boolean found = false;
|
||||
|
||||
// NOTE: This is bad, as it relies on implementation details of super method...
|
||||
// We know that the iterator has not been touched if explicit destination..
|
||||
while (pTypes.hasNext()) {
|
||||
ImageTypeSpecifier specifier = pTypes.next();
|
||||
int imageType = specifier.getBufferedImageType();
|
||||
|
||||
if (imageType != 0 && imageType == dest.getType()) {
|
||||
// Known types equal, perfect match
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// If types are different, or TYPE_CUSTOM, test if
|
||||
// - transferType is ok
|
||||
// - bands are ok
|
||||
// TODO: Test if color model is ok?
|
||||
if (specifier.getSampleModel().getTransferType() == dest.getSampleModel().getTransferType() &&
|
||||
specifier.getNumBands() <= dest.getSampleModel().getNumBands()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
throw new IIOException(String.format("Illegal explicit destination image %s", dest));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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]));
|
||||
if (image == null) {
|
||||
System.err.println("Supported formats: " + Arrays.toString(ImageIO.getReaderFormatNames()));
|
||||
System.exit(1);
|
||||
}
|
||||
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;
|
||||
|
||||
final Paint mCheckeredBG;
|
||||
final Color mDefaultBG;
|
||||
|
||||
public ImageLabel(final BufferedImage pImage) {
|
||||
super(new BufferedImageIcon(pImage));
|
||||
setOpaque(false);
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
|
||||
|
||||
mCheckeredBG = createTexture();
|
||||
|
||||
// For indexed color, default to the color of the transparent pixel, if any
|
||||
mDefaultBG = getDefaultBackground(pImage);
|
||||
|
||||
mBackground = mDefaultBG != null ? mDefaultBG : mCheckeredBG;
|
||||
|
||||
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("Checkered", mCheckeredBG), 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...", mDefaultBG != null ? mDefaultBG : 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 static Color getDefaultBackground(BufferedImage pImage) {
|
||||
if (pImage.getColorModel() instanceof IndexColorModel) {
|
||||
IndexColorModel cm = (IndexColorModel) pImage.getColorModel();
|
||||
int transparent = cm.getTransparentPixel();
|
||||
if (transparent >= 0) {
|
||||
return new Color(cm.getRGB(transparent), false);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* 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.ImageWriter;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Abstract base class for image writers.
|
||||
*
|
||||
* @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 ImageWriter {
|
||||
|
||||
/**
|
||||
* For convenience. Only set if the output is an {@code ImageInputStream}.
|
||||
* @see #setOutput(Object)
|
||||
*/
|
||||
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(final 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 ignored.
|
||||
* @return {@code null}.
|
||||
*/
|
||||
public IIOMetadata getDefaultStreamMetadata(final ImageWriteParam pParam) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code null}
|
||||
*
|
||||
* @param pInData ignored.
|
||||
* @param pParam ignored.
|
||||
* @return {@code null}.
|
||||
*/
|
||||
public IIOMetadata convertStreamMetadata(final IIOMetadata pInData, final ImageWriteParam pParam) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static Rectangle getSourceRegion(final ImageWriteParam pParam, final int pWidth, final 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 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(final BufferedImage pImage, final 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 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(final Image pImage, final ImageWriteParam pParam) {
|
||||
return IIOUtil.fakeSubsampling(pImage, pParam);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.twelvemonkeys.imageio.spi;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
/**
|
||||
* Provides provider info, like vendor name and version,
|
||||
* for {@link javax.imageio.spi.ImageReaderWriterSpi} subclasses based on information in the manifest.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: ProviderInfo.java,v 1.0 Oct 31, 2009 3:49:39 PM haraldk Exp$
|
||||
*
|
||||
* @see <a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#JAR%20Manifest">JAR Manifest</a>
|
||||
*/
|
||||
public class ProviderInfo {
|
||||
// TODO: Consider reading the META-INF/MANIFEST.MF from the class path using java.util.jar.Manifest.
|
||||
// Use the manifest that is located in the same class path folder as the package.
|
||||
|
||||
private final String mTitle;
|
||||
private final String mVendorName;
|
||||
private final String mVersion;
|
||||
|
||||
/**
|
||||
* Creates a provider information instance based on the given package.
|
||||
*
|
||||
* @param pPackage the package to get provider information from.
|
||||
* This should typically be the package containing the Spi class.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code pPackage == null}
|
||||
*/
|
||||
public ProviderInfo(final Package pPackage) {
|
||||
Validate.notNull(pPackage, "package");
|
||||
|
||||
String title = pPackage.getImplementationTitle();
|
||||
mTitle = title != null ? title : pPackage.getName();
|
||||
|
||||
String vendor = pPackage.getImplementationVendor();
|
||||
mVendorName = vendor != null ? vendor : fakeVendor(pPackage);
|
||||
|
||||
String version = pPackage.getImplementationVersion();
|
||||
mVersion = version != null ? version : fakeVersion(pPackage);
|
||||
}
|
||||
|
||||
private static String fakeVendor(final Package pPackage) {
|
||||
String name = pPackage.getName();
|
||||
return name.startsWith("com.twelvemonkeys") ? "TwelveMonkeys" : name;
|
||||
}
|
||||
|
||||
private String fakeVersion(Package pPackage) {
|
||||
String name = pPackage.getName();
|
||||
return name.startsWith("com.twelvemonkeys") ? "DEV" : "Unspecified";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the implementation title, as specified in the manifest entry
|
||||
* {@code Implementation-Title} for the package.
|
||||
* If the title is unavailable, the package name or some default name
|
||||
* for known packages are used.
|
||||
*
|
||||
* @return the implementation title
|
||||
*/
|
||||
final String getImplementationTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vendor name, as specified in the manifest entry
|
||||
* {@code Implementation-Vendor} for the package.
|
||||
* If the vendor name is unavailable, the package name or some default name
|
||||
* for known packages are used.
|
||||
*
|
||||
* @return the vendor name.
|
||||
*/
|
||||
public final String getVendorName() {
|
||||
return mVendorName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version/build number string, as specified in the manifest entry
|
||||
* {@code Implementation-Version} for the package.
|
||||
* If the version is unavailable, some arbitrary (non-{@code null}) value is used.
|
||||
*
|
||||
* @return the vendor name.
|
||||
*/
|
||||
public final String getVersion() {
|
||||
return mVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mTitle + ", " + mVersion + " by " + mVendorName;
|
||||
}
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
package com.twelvemonkeys.imageio.stream;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.ImageInputStreamImpl;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A buffered {@code ImageInputStream}.
|
||||
* Experimental - seems to be effective for {@link javax.imageio.stream.FileImageInputStream}
|
||||
* and {@link javax.imageio.stream.FileCacheImageInputStream} when doing a lot of single-byte reads
|
||||
* (or short byte-array reads) on OS X at least.
|
||||
* Code that uses the {@code readFully} methods are not affected by the issue.
|
||||
*
|
||||
* @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?
|
||||
// TODO: Test on other platforms, might be just an OS X issue
|
||||
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) throws IOException {
|
||||
this(pStream, DEFAULT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
private BufferedImageInputStream(final ImageInputStream pStream, final int pBufferSize) throws IOException {
|
||||
Validate.notNull(pStream, "stream");
|
||||
|
||||
mStream = pStream;
|
||||
streamPos = pStream.getStreamPosition();
|
||||
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;
|
||||
|
||||
if (!isBufferValid()) {
|
||||
// Bypass cache if cache is empty for reads longer than buffer
|
||||
if (pLength >= mBuffer.length) {
|
||||
return readDirect(pBuffer, pOffset, pLength);
|
||||
}
|
||||
else {
|
||||
fillBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
return readBuffered(pBuffer, pOffset, pLength);
|
||||
}
|
||||
|
||||
private int readDirect(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
|
||||
// TODO: Figure out why reading more than the buffer length causes alignment issues...
|
||||
int read = mStream.read(pBuffer, pOffset, Math.min(mBuffer.length, pLength));
|
||||
|
||||
if (read > 0) {
|
||||
streamPos += read;
|
||||
}
|
||||
|
||||
mBufferStart = mStream.getStreamPosition();
|
||||
mBufferLength = 0;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
|
||||
private int readBuffered(final byte[] pBuffer, final int pOffset, final int pLength) {
|
||||
if (mBufferLength <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read as much as possible from buffer
|
||||
int length = Math.min(mBufferLength - mBufferPos, pLength);
|
||||
|
||||
if (length > 0) {
|
||||
System.arraycopy(mBuffer, mBufferPos, pBuffer, pOffset, length);
|
||||
mBufferPos += length;
|
||||
}
|
||||
|
||||
streamPos += length;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(long pPosition) throws IOException {
|
||||
// TODO: Could probably be optimized to not invalidate buffer if new position 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;
|
||||
}
|
||||
}
|
||||
Executable
+56
@@ -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;
|
||||
}
|
||||
}
|
||||
+36
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
+84
@@ -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())));
|
||||
}
|
||||
catch (URISyntaxException ignore) {
|
||||
// This should never happen, but if it does, we'll fall back to using the stream
|
||||
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";
|
||||
}
|
||||
}
|
||||
Executable
+177
@@ -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;
|
||||
}
|
||||
}
|
||||
Executable
+73
@@ -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;
|
||||
}
|
||||
}
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
package com.twelvemonkeys.imageio.util;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.imageio.spi.ProviderInfo;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ProviderInfo} instance for the given service provider.
|
||||
*
|
||||
* @param pProviderClass the provider class to get info for.
|
||||
* @return the newly created {@link ProviderInfo}.
|
||||
*/
|
||||
public static ProviderInfo getProviderInfo(final Class<? extends IIOServiceProvider> pProviderClass) {
|
||||
return new ProviderInfo(pProviderClass.getPackage());
|
||||
}
|
||||
|
||||
/**
|
||||
* THIS METHOD WILL ME MOVED/RENAMED, DO NOT USE.
|
||||
*
|
||||
* @param pRegistry the registry to unregister from
|
||||
* @param pProvider the provider to unregister
|
||||
* @param pCategory the category to unregister from
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+41
@@ -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!");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Executable
+94
@@ -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) {
|
||||
}
|
||||
}
|
||||
Executable
+98
@@ -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;
|
||||
}
|
||||
}
|
||||
Executable
+98
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user