diff --git a/README.md b/README.md index 75269d5..b4f36af 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,15 @@ Download and run "ant". The jar "target/jj2000.jar" contains the API code, the " ImageIO support --------------- -The Jar supplies an ImageIO reader implementation, so reading is as simple as `javax.imageio.ImageIO.read(new File("input.jp2"))` -(thanks to @keinhaar for the PR). The reader doesn't support metadata. +The Jar supplies an ImageIO support, so reading is as simple as -There is currently no ImageIO writer support. +`javax.imageio.ImageIO.read(new File("input.jp2"))` + +and for writing + +`ImageIO.write(image, "JPEG2000", new File("image.jp2"));` + +(thanks to @keinhaar for the PR). Both, reader and writer, do not support metadata. How to read a JP2 or JPX image ------------------------------ diff --git a/src/main/java/com/github/jpeg2000/imageio/ImageReaderImpl.java b/src/main/java/com/github/jpeg2000/imageio/ImageReaderImpl.java index 2ce63ab..df9bada 100644 --- a/src/main/java/com/github/jpeg2000/imageio/ImageReaderImpl.java +++ b/src/main/java/com/github/jpeg2000/imageio/ImageReaderImpl.java @@ -60,7 +60,7 @@ public String[] getFileSuffixes() @Override public String getDescription(Locale locale) { - return "JPEG2000 ImageIO Support"; + return "JPEG2000 ImageIO Reader Support"; } } diff --git a/src/main/java/com/github/jpeg2000/imageio/ImageWriterImpl.java b/src/main/java/com/github/jpeg2000/imageio/ImageWriterImpl.java new file mode 100644 index 0000000..b661f88 --- /dev/null +++ b/src/main/java/com/github/jpeg2000/imageio/ImageWriterImpl.java @@ -0,0 +1,52 @@ +package com.github.jpeg2000.imageio; + +import java.io.IOException; +import java.util.Locale; + +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriter; +import javax.imageio.spi.ImageWriterSpi; +import javax.imageio.stream.ImageOutputStream; + +/** + * JPEG2000 ImageIO Writer SPI. + */ +public class ImageWriterImpl extends ImageWriterSpi +{ + @Override + public Class[] getOutputTypes() + { + return new Class[] {ImageOutputStream.class}; + } + + @Override + public ImageWriter createWriterInstance(Object extension) throws IOException + { + return new JPEG2000Writer(this); + } + + @Override + public String[] getFormatNames() + { + return new String[] {"jpeg2000", "JPEG2000"}; + } + + @Override + public String[] getFileSuffixes() + { + return new String[] {"jp2", "j2k"}; + } + + @Override + public String getDescription(Locale locale) + { + return "JPEG2000 ImageIO Writer Support"; + } + + @Override + public boolean canEncodeImage(ImageTypeSpecifier type) + { + return true; + } + +} diff --git a/src/main/java/com/github/jpeg2000/imageio/JPEG2000Writer.java b/src/main/java/com/github/jpeg2000/imageio/JPEG2000Writer.java new file mode 100644 index 0000000..4f35224 --- /dev/null +++ b/src/main/java/com/github/jpeg2000/imageio/JPEG2000Writer.java @@ -0,0 +1,128 @@ +package com.github.jpeg2000.imageio; + +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Hashtable; + +import javax.imageio.IIOImage; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +import com.github.jpeg2000.J2KWriter; + +public class JPEG2000Writer extends ImageWriter +{ + public JPEG2000Writer(ImageWriterImpl imageWriterImpl) + { + super(imageWriterImpl); + } + + @Override + public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) + { + return null; + } + + @Override + public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) + { + return null; + } + + @Override + public IIOMetadata convertStreamMetadata(IIOMetadata inData, ImageWriteParam param) + { + return null; + } + + @Override + public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) + { + return null; + } + + @Override + public void write(IIOMetadata streamMetadata, IIOImage iioimage, ImageWriteParam param) throws IOException + { + //We can savely cast here, because the setOutput does not accept anything else. + ImageOutputStream stream = (ImageOutputStream) getOutput(); + RenderedImage image = iioimage.getRenderedImage(); + BufferedImage bimage = null; + if(image instanceof BufferedImage) + { + bimage = (BufferedImage) image; + } + else + { + bimage = convertToBufferedImage(image); + } + J2KWriter writer = new J2KWriter(); + writer.setCompressionRatio(15, false); + writer.setSource(bimage, 128); + writer.write(new Output(stream)); + } + + /** + * Translate between OutputStream and ImageOutputStream + */ + class Output extends OutputStream + { + private ImageOutputStream stream; + + public Output(ImageOutputStream stream) + { + this.stream = stream; + } + + @Override + public void write(int b) throws IOException + { + stream.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException + { + stream.write(b, off, len); + } + + @Override + public void close() throws IOException + { + stream.close(); + } + } + + /** + * Convert any other RenderedImage to BufferedImage + * @param img + * @return + */ + private BufferedImage convertToBufferedImage(RenderedImage img) + { + ColorModel cm = img.getColorModel(); + int width = img.getWidth(); + int height = img.getHeight(); + WritableRaster raster = cm.createCompatibleWritableRaster(width, height); + boolean isAlphaPremultiplied = cm.isAlphaPremultiplied(); + Hashtable properties = new Hashtable(); + String[] keys = img.getPropertyNames(); + if(keys != null) + { + for(String key : keys) + { + properties.put(key, img.getProperty(key)); + } + } + BufferedImage bimage = new BufferedImage(cm, raster, isAlphaPremultiplied, properties); + img.copyData(raster); + return bimage; + } +} diff --git a/src/main/resources/META-INF/services/javax.imageio.spi.ImageWriterSpi b/src/main/resources/META-INF/services/javax.imageio.spi.ImageWriterSpi new file mode 100644 index 0000000..c5fc199 --- /dev/null +++ b/src/main/resources/META-INF/services/javax.imageio.spi.ImageWriterSpi @@ -0,0 +1 @@ +com.github.jpeg2000.imageio.ImageWriterImpl \ No newline at end of file