mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-01 00:00:02 -04:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 54dd9b6d7b | |||
| 4e10fc019e | |||
| 1295951ead | |||
| d5e664cdcc | |||
| efe5f3c34a | |||
| 2488f6f67c | |||
| 6a66d2e059 | |||
| ebd5533879 | |||
| e6e4e96309 | |||
| aadc62dde9 | |||
| 24cbe57240 | |||
| f7d8ae0cd2 | |||
| 5da934e11b | |||
| 51297ad496 | |||
| 80a534cd62 | |||
| 24130d466d | |||
| 7559686782 | |||
| b6988c37a7 | |||
| bbffb1d416 | |||
| c68de3bc92 | |||
| a12b6044c6 | |||
| 9a0e2d9659 |
@@ -237,7 +237,7 @@ Build the project (using [Maven](http://maven.apache.org/download.cgi)):
|
||||
|
||||
$ mvn package
|
||||
|
||||
Currently, the recommended JDK for making a build is Oracle JDK 7.x or 8.x.
|
||||
Currently, the recommended JDK for making a build is Oracle JDK 8.x.
|
||||
|
||||
It's possible to build using OpenJDK, but some tests might fail due to some minor differences between the color management systems used. You will need to either disable the tests in question, or build without tests altogether.
|
||||
|
||||
@@ -280,22 +280,22 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-jpeg</artifactId>
|
||||
<version>3.6</version>
|
||||
<version>3.6.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-tiff</artifactId>
|
||||
<version>3.6</version>
|
||||
<version>3.6.2</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Optional dependency. Needed only if you deploy `ImageIO` plugins as part of a web app.
|
||||
Make sure you add the `IIOProviderContextListener` to your `web.xml`, see above.
|
||||
Optional dependency. Needed only if you deploy ImageIO plugins as part of a web app.
|
||||
Make sure you add the IIOProviderContextListener to your web.xml, see above.
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||
<artifactId>servlet</artifactId>
|
||||
<version>3.6</version>
|
||||
<version>3.6.2</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
@@ -304,13 +304,13 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
|
||||
To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path:
|
||||
|
||||
twelvemonkeys-common-lang-3.6.jar
|
||||
twelvemonkeys-common-io-3.6.jar
|
||||
twelvemonkeys-common-image-3.6.jar
|
||||
twelvemonkeys-imageio-core-3.6.jar
|
||||
twelvemonkeys-imageio-metadata-3.6.jar
|
||||
twelvemonkeys-imageio-jpeg-3.6.jar
|
||||
twelvemonkeys-imageio-tiff-3.6.jar
|
||||
twelvemonkeys-common-lang-3.6.2.jar
|
||||
twelvemonkeys-common-io-3.6.2.jar
|
||||
twelvemonkeys-common-image-3.6.2.jar
|
||||
twelvemonkeys-imageio-core-3.6.2.jar
|
||||
twelvemonkeys-imageio-metadata-3.6.2.jar
|
||||
twelvemonkeys-imageio-jpeg-3.6.2.jar
|
||||
twelvemonkeys-imageio-tiff-3.6.2.jar
|
||||
|
||||
#### Deploying the plugins in a web app
|
||||
|
||||
@@ -376,42 +376,42 @@ Other "fat" JAR bundlers will probably have similar mechanisms to merge entries
|
||||
|
||||
### Links to prebuilt binaries
|
||||
|
||||
##### Latest version (3.6)
|
||||
##### Latest version (3.6.2)
|
||||
|
||||
Requires Java 7 or later.
|
||||
|
||||
Common dependencies
|
||||
* [common-lang-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.6/common-lang-3.6.jar)
|
||||
* [common-io-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.6/common-io-3.6.jar)
|
||||
* [common-image-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.6/common-image-3.6.jar)
|
||||
* [common-lang-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.6.2/common-lang-3.6.2.jar)
|
||||
* [common-io-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.6.2/common-io-3.6.2.jar)
|
||||
* [common-image-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.6.2/common-image-3.6.2.jar)
|
||||
|
||||
ImageIO dependencies
|
||||
* [imageio-core-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.6/imageio-core-3.6.jar)
|
||||
* [imageio-metadata-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.6/imageio-metadata-3.6.jar)
|
||||
* [imageio-core-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.6.2/imageio-core-3.6.2.jar)
|
||||
* [imageio-metadata-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.6.2/imageio-metadata-3.6.2.jar)
|
||||
|
||||
ImageIO plugins
|
||||
* [imageio-bmp-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.6/imageio-bmp-3.6.jar)
|
||||
* [imageio-jpeg-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.6/imageio-jpeg-3.6.jar)
|
||||
* [imageio-tiff-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.6/imageio-tiff-3.6.jar)
|
||||
* [imageio-pnm-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.6/imageio-pnm-3.6.jar)
|
||||
* [imageio-psd-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.6/imageio-psd-3.6.jar)
|
||||
* [imageio-hdr-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.6/imageio-hdr-3.6.jar)
|
||||
* [imageio-iff-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.6/imageio-iff-3.6.jar)
|
||||
* [imageio-pcx-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.6/imageio-pcx-3.6.jar)
|
||||
* [imageio-pict-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.6/imageio-pict-3.6.jar)
|
||||
* [imageio-sgi-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.6/imageio-sgi-3.6.jar)
|
||||
* [imageio-tga-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.6/imageio-tga-3.6.jar)
|
||||
* [imageio-icns-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.6/imageio-icns-3.6.jar)
|
||||
* [imageio-thumbsdb-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.6/imageio-thumbsdb-3.6.jar)
|
||||
* [imageio-bmp-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.6.2/imageio-bmp-3.6.2.jar)
|
||||
* [imageio-hdr-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.6.2/imageio-hdr-3.6.2.jar)
|
||||
* [imageio-icns-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.6.2/imageio-icns-3.6.2.jar)
|
||||
* [imageio-iff-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.6.2/imageio-iff-3.6.2.jar)
|
||||
* [imageio-jpeg-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.6.2/imageio-jpeg-3.6.2.jar)
|
||||
* [imageio-pcx-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.6.2/imageio-pcx-3.6.2.jar)
|
||||
* [imageio-pict-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.6.2/imageio-pict-3.6.2.jar)
|
||||
* [imageio-pnm-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.6.2/imageio-pnm-3.6.2.jar)
|
||||
* [imageio-psd-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.6.2/imageio-psd-3.6.2.jar)
|
||||
* [imageio-sgi-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.6.2/imageio-sgi-3.6.2.jar)
|
||||
* [imageio-tga-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.6.2/imageio-tga-3.6.2.jar)
|
||||
* [imageio-thumbsdb-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.6.2/imageio-thumbsdb-3.6.2.jar)
|
||||
* [imageio-tiff-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.6.2/imageio-tiff-3.6.2.jar)
|
||||
|
||||
ImageIO plugins requiring 3rd party libs
|
||||
* [imageio-batik-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.6/imageio-batik-3.6.jar)
|
||||
* [imageio-batik-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.6.2/imageio-batik-3.6.2.jar)
|
||||
|
||||
Photoshop Path support for ImageIO
|
||||
* [imageio-clippath-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.6/imageio-clippath-3.6.jar)
|
||||
* [imageio-clippath-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.6.2/imageio-clippath-3.6.2.jar)
|
||||
|
||||
Servlet support
|
||||
* [servlet-3.6.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.6/servlet-3.6.jar)
|
||||
* [servlet-3.6.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.6.2/servlet-3.6.2.jar)
|
||||
|
||||
##### Old version (3.0.x)
|
||||
|
||||
|
||||
+6
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
|
||||
<groupId>com.twelvemonkeys.bom</groupId>
|
||||
@@ -123,6 +123,11 @@
|
||||
<artifactId>imageio-tiff</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-xwd</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- ImageIO 3rd party dependent plugins -->
|
||||
<dependency>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>common-image</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>common-io</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>common-lang</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<groupId>com.twelvemonkeys.contrib</groupId>
|
||||
<artifactId>contrib</artifactId>
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.twelvemonkeys.contrib.exif;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.imageio.IIOImage;
|
||||
@@ -82,12 +83,11 @@ public class EXIFUtilities {
|
||||
ImageReader reader = readers.next();
|
||||
try {
|
||||
reader.setInput(input, true, false);
|
||||
IIOImage image = reader.readAll(0, reader.getDefaultReadParam());
|
||||
|
||||
BufferedImage bufferedImage = ImageUtil.toBuffered(image.getRenderedImage());
|
||||
image.setRenderedImage(applyOrientation(bufferedImage, findImageOrientation(image.getMetadata()).value()));
|
||||
IIOMetadata metadata = reader.getImageMetadata(0);
|
||||
BufferedImage bufferedImage = applyOrientation(reader.read(0), findImageOrientation(metadata).value());
|
||||
|
||||
return image;
|
||||
return new IIOImage(bufferedImage, null, metadata);
|
||||
}
|
||||
finally {
|
||||
reader.dispose();
|
||||
@@ -123,9 +123,15 @@ public class EXIFUtilities {
|
||||
for (String arg : args) {
|
||||
File input = new File(arg);
|
||||
|
||||
// Read everything (similar to ImageReader.readAll(0, null)), but applies the correct image orientation
|
||||
// Read everything but thumbnails (similar to ImageReader.readAll(0, null)),
|
||||
// and applies the correct image orientation
|
||||
IIOImage image = readWithOrientation(input);
|
||||
|
||||
if (image == null) {
|
||||
System.err.printf("No reader for %s%n", input);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Finds the orientation as defined by the javax_imageio_1.0 format
|
||||
Orientation orientation = findImageOrientation(image.getMetadata());
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-batik</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
|
||||
@@ -104,6 +104,6 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<batik.version>1.12</batik.version>
|
||||
<batik.version>1.14</batik.version>
|
||||
</properties>
|
||||
</project>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-bmp</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-clippath</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
|
||||
|
||||
@@ -56,6 +56,8 @@ import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
@@ -131,7 +133,13 @@ public final class Paths {
|
||||
List<JPEGSegment> photoshop = JPEGSegmentUtil.readSegments(stream, segmentIdentifiers);
|
||||
|
||||
if (!photoshop.isEmpty()) {
|
||||
return readPathFromPhotoshopResources(new MemoryCacheImageInputStream(photoshop.get(0).data()));
|
||||
InputStream data = null;
|
||||
|
||||
for (JPEGSegment ps : photoshop) {
|
||||
data = data == null ? ps.data() : new SequenceInputStream(data, ps.data());
|
||||
}
|
||||
|
||||
return readPathFromPhotoshopResources(new MemoryCacheImageInputStream(data));
|
||||
}
|
||||
}
|
||||
else if (magic >>> 16 == TIFF.BYTE_ORDER_MARK_BIG_ENDIAN && (magic & 0xffff) == TIFF.TIFF_MAGIC
|
||||
@@ -350,10 +358,10 @@ public final class Paths {
|
||||
IIOMetadataNode unknown = new IIOMetadataNode("unknown");
|
||||
unknown.setAttribute("MarkerTag", Integer.toString(JPEG.APP13 & 0xFF));
|
||||
|
||||
byte[] identfier = "Photoshop 3.0".getBytes(StandardCharsets.US_ASCII);
|
||||
byte[] data = new byte[identfier.length + 1 + pathResource.length];
|
||||
System.arraycopy(identfier, 0, data, 0, identfier.length);
|
||||
System.arraycopy(pathResource, 0, data, identfier.length + 1, pathResource.length);
|
||||
byte[] identifier = "Photoshop 3.0".getBytes(StandardCharsets.US_ASCII);
|
||||
byte[] data = new byte[identifier.length + 1 + pathResource.length];
|
||||
System.arraycopy(identifier, 0, data, 0, identifier.length);
|
||||
System.arraycopy(pathResource, 0, data, identifier.length + 1, pathResource.length);
|
||||
|
||||
unknown.setUserObject(data);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-core</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: Core</name>
|
||||
|
||||
@@ -30,16 +30,20 @@
|
||||
|
||||
package com.twelvemonkeys.imageio;
|
||||
|
||||
import com.twelvemonkeys.image.BufferedImageIcon;
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
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.datatransfer.DataFlavor;
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.event.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.io.File;
|
||||
@@ -48,20 +52,6 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.swing.*;
|
||||
|
||||
import com.twelvemonkeys.image.BufferedImageIcon;
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
|
||||
/**
|
||||
* Abstract base class for image readers.
|
||||
*
|
||||
@@ -450,6 +440,7 @@ public abstract class ImageReaderBase extends ImageReader {
|
||||
static final String ZOOM_IN = "zoom-in";
|
||||
static final String ZOOM_OUT = "zoom-out";
|
||||
static final String ZOOM_ACTUAL = "zoom-actual";
|
||||
static final String ZOOM_FIT = "zoom-fit";
|
||||
|
||||
private BufferedImage image;
|
||||
|
||||
@@ -525,9 +516,20 @@ public abstract class ImageReaderBase extends ImageReader {
|
||||
|
||||
private void setupActions() {
|
||||
// Mac weirdness... VK_MINUS/VK_PLUS seems to map to english key map always...
|
||||
bindAction(new ZoomAction("Zoom in", 2), ZOOM_IN, KeyStroke.getKeyStroke('+'), KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0));
|
||||
bindAction(new ZoomAction("Zoom out", .5), ZOOM_OUT, KeyStroke.getKeyStroke('-'), KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0));
|
||||
bindAction(new ZoomAction("Zoom actual"), ZOOM_ACTUAL, KeyStroke.getKeyStroke('0'), KeyStroke.getKeyStroke(KeyEvent.VK_0, 0));
|
||||
bindAction(new ZoomAction("Zoom in", 2), ZOOM_IN,
|
||||
KeyStroke.getKeyStroke('+'),
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_ADD, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||
bindAction(new ZoomAction("Zoom out", .5), ZOOM_OUT,
|
||||
KeyStroke.getKeyStroke('-'),
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||
bindAction(new ZoomAction("Zoom actual"), ZOOM_ACTUAL,
|
||||
KeyStroke.getKeyStroke('0'),
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_0, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||
bindAction(new ZoomToFitAction("Zoom fit"), ZOOM_FIT,
|
||||
KeyStroke.getKeyStroke('9'),
|
||||
KeyStroke.getKeyStroke(KeyEvent.VK_9, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||
|
||||
bindAction(TransferHandler.getCopyAction(), (String) TransferHandler.getCopyAction().getValue(Action.NAME), KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||
bindAction(TransferHandler.getPasteAction(), (String) TransferHandler.getPasteAction().getValue(Action.NAME), KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||
@@ -544,6 +546,7 @@ public abstract class ImageReaderBase extends ImageReader {
|
||||
private JPopupMenu createPopupMenu() {
|
||||
JPopupMenu popup = new JPopupMenu();
|
||||
|
||||
popup.add(getActionMap().get(ZOOM_FIT));
|
||||
popup.add(getActionMap().get(ZOOM_ACTUAL));
|
||||
popup.add(getActionMap().get(ZOOM_IN));
|
||||
popup.add(getActionMap().get(ZOOM_OUT));
|
||||
@@ -564,7 +567,7 @@ public abstract class ImageReaderBase extends ImageReader {
|
||||
addCheckBoxItem(new ChangeBackgroundAction("Dark", Color.DARK_GRAY), background, group);
|
||||
addCheckBoxItem(new ChangeBackgroundAction("Black", Color.BLACK), background, group);
|
||||
background.addSeparator();
|
||||
ChooseBackgroundAction chooseBackgroundAction = new ChooseBackgroundAction("Choose...", defaultBG != null ? defaultBG : Color.BLUE);
|
||||
ChooseBackgroundAction chooseBackgroundAction = new ChooseBackgroundAction("Choose...", defaultBG != null ? defaultBG : new Color(0xFF6600));
|
||||
chooseBackgroundAction.putValue(Action.SELECTED_KEY, backgroundPaint == defaultBG);
|
||||
addCheckBoxItem(chooseBackgroundAction, background, group);
|
||||
|
||||
@@ -678,14 +681,41 @@ public abstract class ImageReaderBase extends ImageReader {
|
||||
}
|
||||
else {
|
||||
Icon current = getIcon();
|
||||
int w = (int) Math.max(Math.min(current.getIconWidth() * zoomFactor, image.getWidth() * 16), image.getWidth() / 16);
|
||||
int h = (int) Math.max(Math.min(current.getIconHeight() * zoomFactor, image.getHeight() * 16), image.getHeight() / 16);
|
||||
int w = Math.max(Math.min((int) (current.getIconWidth() * zoomFactor), image.getWidth() * 16), image.getWidth() / 16);
|
||||
int h = Math.max(Math.min((int) (current.getIconHeight() * zoomFactor), image.getHeight() * 16), image.getHeight() / 16);
|
||||
|
||||
setIcon(new BufferedImageIcon(image, Math.max(w, 2), Math.max(h, 2), w > image.getWidth() || h > image.getHeight()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ZoomToFitAction extends ZoomAction {
|
||||
public ZoomToFitAction(final String name) {
|
||||
super(name, -1);
|
||||
}
|
||||
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
JComponent source = (JComponent) e.getSource();
|
||||
|
||||
if (source instanceof JMenuItem) {
|
||||
JPopupMenu menu = (JPopupMenu) SwingUtilities.getAncestorOfClass(JPopupMenu.class, source);
|
||||
source = (JComponent) menu.getInvoker();
|
||||
}
|
||||
|
||||
Container container = SwingUtilities.getAncestorOfClass(JViewport.class, source);
|
||||
|
||||
double ratioX = container.getWidth() / (double) image.getWidth();
|
||||
double ratioY = container.getHeight() / (double) image.getHeight();
|
||||
|
||||
double zoomFactor = Math.min(ratioX, ratioY);
|
||||
|
||||
int w = Math.max(Math.min((int) (image.getWidth() * zoomFactor), image.getWidth() * 16), image.getWidth() / 16);
|
||||
int h = Math.max(Math.min((int) (image.getHeight() * zoomFactor), image.getHeight() * 16), image.getHeight() / 16);
|
||||
|
||||
setIcon(new BufferedImageIcon(image, w, h, zoomFactor > 1));
|
||||
}
|
||||
}
|
||||
|
||||
private static class ImageTransferable implements Transferable {
|
||||
private final BufferedImage image;
|
||||
|
||||
@@ -704,7 +734,7 @@ public abstract class ImageReaderBase extends ImageReader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTransferData(final DataFlavor flavor) throws UnsupportedFlavorException, IOException {
|
||||
public Object getTransferData(final DataFlavor flavor) throws UnsupportedFlavorException {
|
||||
if (isDataFlavorSupported(flavor)) {
|
||||
return image;
|
||||
}
|
||||
|
||||
+20
-17
@@ -57,8 +57,10 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
||||
|
||||
private ImageInputStream stream;
|
||||
|
||||
private ByteBuffer buffer;
|
||||
private ByteBuffer integralCache = ByteBuffer.allocate(8);
|
||||
private ByteBuffer buffer;
|
||||
|
||||
private final ByteBuffer integralCache = ByteBuffer.allocate(8);
|
||||
private final byte[] integralCacheArray = integralCache.array();
|
||||
|
||||
public BufferedImageInputStream(final ImageInputStream pStream) throws IOException {
|
||||
this(pStream, DEFAULT_BUFFER_SIZE);
|
||||
@@ -97,10 +99,10 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
||||
|
||||
if (!buffer.hasRemaining()) {
|
||||
fillBuffer();
|
||||
}
|
||||
|
||||
if (!buffer.hasRemaining()) {
|
||||
return -1;
|
||||
if (!buffer.hasRemaining()) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
bitOffset = 0;
|
||||
@@ -172,21 +174,21 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
||||
|
||||
@Override
|
||||
public short readShort() throws IOException {
|
||||
readFully(integralCache.array(), 0, 2);
|
||||
readFully(integralCacheArray, 0, 2);
|
||||
|
||||
return integralCache.getShort(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readInt() throws IOException {
|
||||
readFully(integralCache.array(), 0, 4);
|
||||
readFully(integralCacheArray, 0, 4);
|
||||
|
||||
return integralCache.getInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readLong() throws IOException {
|
||||
readFully(integralCache.array(), 0, 8);
|
||||
readFully(integralCacheArray, 0, 8);
|
||||
|
||||
return integralCache.getLong(0);
|
||||
}
|
||||
@@ -253,6 +255,7 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
||||
}
|
||||
|
||||
int val = buffer.get() & 0xff;
|
||||
streamPos++;
|
||||
|
||||
accum <<= 8;
|
||||
accum |= val;
|
||||
@@ -262,9 +265,7 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
||||
// Move byte position back if in the middle of a byte
|
||||
if (newBitOffset != 0) {
|
||||
buffer.position(buffer.position() - 1);
|
||||
}
|
||||
else {
|
||||
streamPos++;
|
||||
streamPos--;
|
||||
}
|
||||
|
||||
this.bitOffset = newBitOffset;
|
||||
@@ -279,26 +280,26 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(long pPosition) throws IOException {
|
||||
public void seek(long position) throws IOException {
|
||||
checkClosed();
|
||||
bitOffset = 0;
|
||||
|
||||
if (streamPos == pPosition) {
|
||||
if (streamPos == position) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Optimized to not invalidate buffer if new position is within current buffer
|
||||
long newBufferPos = buffer.position() + pPosition - streamPos;
|
||||
long newBufferPos = buffer.position() + position - streamPos;
|
||||
if (newBufferPos >= 0 && newBufferPos <= buffer.limit()) {
|
||||
buffer.position((int) newBufferPos);
|
||||
}
|
||||
else {
|
||||
// Will invalidate buffer
|
||||
buffer.limit(0);
|
||||
stream.seek(pPosition);
|
||||
stream.seek(position);
|
||||
}
|
||||
|
||||
streamPos = pPosition;
|
||||
streamPos = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -330,7 +331,9 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (stream != null) {
|
||||
//stream.close();
|
||||
// TODO: FixMe: Need to close underlying stream here!
|
||||
// For call sites that relies on not closing, we should instead not close the buffered stream.
|
||||
// stream.close();
|
||||
stream = null;
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
+254
@@ -32,16 +32,19 @@ package com.twelvemonkeys.imageio.stream;
|
||||
|
||||
import com.twelvemonkeys.io.ole2.CompoundDocument;
|
||||
import com.twelvemonkeys.io.ole2.Entry;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Random;
|
||||
|
||||
import static java.util.Arrays.fill;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* BufferedImageInputStreamTest
|
||||
@@ -72,6 +75,257 @@ public class BufferedImageInputStreamTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadBit() throws IOException {
|
||||
byte[] bytes = new byte[] {(byte) 0xF0, (byte) 0x0F};
|
||||
|
||||
// Create wrapper stream
|
||||
BufferedImageInputStream stream = new BufferedImageInputStream(new ByteArrayImageInputStream(bytes));
|
||||
|
||||
// Read all bits
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(1, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(2, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(3, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(4, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(5, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(6, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(7, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBit()); // last bit
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
// Full reset, read same sequence again
|
||||
stream.seek(0);
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(0, stream.readBit());
|
||||
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
// Full reset, read partial
|
||||
stream.seek(0);
|
||||
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(1, stream.readBit());
|
||||
|
||||
// Byte reset, read same sequence again
|
||||
stream.setBitOffset(0);
|
||||
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(0, stream.readBit());
|
||||
|
||||
// Byte reset, read partial sequence again
|
||||
stream.setBitOffset(3);
|
||||
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
// Byte reset, read partial sequence again
|
||||
stream.setBitOffset(6);
|
||||
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
// Read all bits, second byte
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(1, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(2, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(3, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBit());
|
||||
assertEquals(4, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(5, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(6, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(1, stream.readBit());
|
||||
assertEquals(7, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(1, stream.readBit()); // last bit
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(2, stream.getStreamPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadBits() throws IOException {
|
||||
byte[] bytes = new byte[] {(byte) 0xF0, (byte) 0xCC, (byte) 0xAA};
|
||||
|
||||
// Create wrapper stream
|
||||
BufferedImageInputStream stream = new BufferedImageInputStream(new ByteArrayImageInputStream(bytes));
|
||||
|
||||
// Read all bits, first byte
|
||||
assertEquals(3, stream.readBits(2));
|
||||
assertEquals(2, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(3, stream.readBits(2));
|
||||
assertEquals(4, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBits(2));
|
||||
assertEquals(6, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBits(2));
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
// Read all bits, second byte
|
||||
assertEquals(3, stream.readBits(2));
|
||||
assertEquals(2, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBits(2));
|
||||
assertEquals(4, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(3, stream.readBits(2));
|
||||
assertEquals(6, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0, stream.readBits(2));
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(2, stream.getStreamPosition());
|
||||
|
||||
// Read all bits, third byte
|
||||
assertEquals(2, stream.readBits(2));
|
||||
assertEquals(2, stream.getBitOffset());
|
||||
assertEquals(2, stream.getStreamPosition());
|
||||
|
||||
assertEquals(2, stream.readBits(2));
|
||||
assertEquals(4, stream.getBitOffset());
|
||||
assertEquals(2, stream.getStreamPosition());
|
||||
|
||||
assertEquals(2, stream.readBits(2));
|
||||
assertEquals(6, stream.getBitOffset());
|
||||
assertEquals(2, stream.getStreamPosition());
|
||||
|
||||
assertEquals(2, stream.readBits(2));
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(3, stream.getStreamPosition());
|
||||
|
||||
// Full reset, read same sequence again
|
||||
stream.seek(0);
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
// Read all bits, increasing size
|
||||
assertEquals(7, stream.readBits(3)); // 111
|
||||
assertEquals(3, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(8, stream.readBits(4)); // 1000
|
||||
assertEquals(7, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(12, stream.readBits(5)); // 01100
|
||||
assertEquals(4, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(50, stream.readBits(6)); // 110010
|
||||
assertEquals(2, stream.getBitOffset());
|
||||
assertEquals(2, stream.getStreamPosition());
|
||||
|
||||
assertEquals(42, stream.readBits(6)); // 101010
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(3, stream.getStreamPosition());
|
||||
|
||||
// Full reset, read same sequence again
|
||||
stream.seek(0);
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
// Read all bits multi-byte
|
||||
assertEquals(0xF0C, stream.readBits(12)); // 111100001100
|
||||
assertEquals(4, stream.getBitOffset());
|
||||
assertEquals(1, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0xCAA, stream.readBits(12)); // 110010101010
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(3, stream.getStreamPosition());
|
||||
|
||||
// Full reset, read same sequence again, all bits in one go
|
||||
stream.seek(0);
|
||||
assertEquals(0, stream.getBitOffset());
|
||||
assertEquals(0, stream.getStreamPosition());
|
||||
|
||||
assertEquals(0xF0CCAA, stream.readBits(24));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadBitsRandom() throws IOException {
|
||||
long value = random.nextLong();
|
||||
byte[] bytes = new byte[8];
|
||||
ByteBuffer.wrap(bytes).putLong(value);
|
||||
|
||||
// Create wrapper stream
|
||||
BufferedImageInputStream stream = new BufferedImageInputStream(new ByteArrayImageInputStream(bytes));
|
||||
|
||||
for (int i = 1; i < 64; i++) {
|
||||
stream.seek(0);
|
||||
assertEquals(i + " bits differ", value >>> (64L - i), stream.readBits(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClose() throws IOException {
|
||||
// Create wrapper stream
|
||||
ImageInputStream mock = mock(ImageInputStream.class);
|
||||
BufferedImageInputStream stream = new BufferedImageInputStream(mock);
|
||||
|
||||
stream.close();
|
||||
verify(mock, never()).close();
|
||||
}
|
||||
|
||||
// TODO: Write other tests
|
||||
|
||||
// TODO: Create test that exposes read += -1 (eof) bug
|
||||
|
||||
+4
-5
@@ -553,10 +553,10 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
||||
int actualRGB = actual.getRGB(x, y);
|
||||
|
||||
try {
|
||||
assertEquals(String.format("%s alpha at (%d, %d)", message, x, y), (expectedRGB >>> 24) & 0xff, (actualRGB >>> 24) & 0xff, 5);
|
||||
assertEquals(String.format("%s red at (%d, %d)", message, x, y), (expectedRGB >> 16) & 0xff, (actualRGB >> 16) & 0xff, 5);
|
||||
assertEquals(String.format("%s green at (%d, %d)", message, x, y), (expectedRGB >> 8) & 0xff, (actualRGB >> 8) & 0xff, 5);
|
||||
assertEquals(String.format("%s blue at (%d, %d)", message, x, y), expectedRGB & 0xff, actualRGB & 0xff, 5);
|
||||
assertEquals((expectedRGB >>> 24) & 0xff, (actualRGB >>> 24) & 0xff, 5);
|
||||
assertEquals((expectedRGB >> 16) & 0xff, (actualRGB >> 16) & 0xff, 5);
|
||||
assertEquals((expectedRGB >> 8) & 0xff, (actualRGB >> 8) & 0xff, 5);
|
||||
assertEquals(expectedRGB & 0xff, actualRGB & 0xff, 5);
|
||||
}
|
||||
catch (AssertionError e) {
|
||||
File tempExpected = File.createTempFile("junit-expected-", ".png");
|
||||
@@ -566,7 +566,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
||||
System.err.println("tempActual.getAbsolutePath(): " + tempActual.getAbsolutePath());
|
||||
ImageIO.write(actual, "PNG", tempActual);
|
||||
|
||||
|
||||
assertEquals(String.format("%s ARGB at (%d, %d)", message, x, y), String.format("#%08x", expectedRGB), String.format("#%08x", actualRGB));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-hdr</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-icns</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-iff</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-jpeg</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
|
||||
|
||||
+104
-77
@@ -30,37 +30,6 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_ColorSpace;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.awt.image.*;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.event.IIOReadUpdateListener;
|
||||
import javax.imageio.event.IIOReadWarningListener;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||
import com.twelvemonkeys.imageio.color.YCbCrConverter;
|
||||
@@ -72,7 +41,6 @@ import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
||||
import com.twelvemonkeys.imageio.stream.BufferedImageInputStream;
|
||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||
@@ -80,6 +48,24 @@ import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
import com.twelvemonkeys.xml.XMLSerializer;
|
||||
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.event.IIOReadUpdateListener;
|
||||
import javax.imageio.event.IIOReadWarningListener;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_ColorSpace;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.awt.image.*;
|
||||
import java.io.*;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* A JPEG {@code ImageReader} implementation based on the JRE {@code JPEGImageReader},
|
||||
* that adds support and properly handles cases where the JRE version throws exceptions.
|
||||
@@ -140,7 +126,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
private List<Segment> segments;
|
||||
|
||||
private int currentStreamIndex = 0;
|
||||
private List<Long> streamOffsets = new ArrayList<>();
|
||||
private final List<Long> streamOffsets = new ArrayList<>();
|
||||
|
||||
protected JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
|
||||
super(provider);
|
||||
@@ -197,10 +183,10 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (IIOException ignore) {
|
||||
catch (IIOException e) {
|
||||
// May happen if no SOF is found, in case we'll just fall through
|
||||
if (DEBUG) {
|
||||
ignore.printStackTrace();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -747,26 +733,26 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
long lastKnownSOIOffset = streamOffsets.get(streamOffsets.size() - 1);
|
||||
imageInput.seek(lastKnownSOIOffset);
|
||||
|
||||
try (ImageInputStream stream = new BufferedImageInputStream(imageInput)) { // Extreme (10s -> 50ms) speedup if imageInput is FileIIS
|
||||
try {
|
||||
for (int i = streamOffsets.size() - 1; i < imageIndex; i++) {
|
||||
long start = 0;
|
||||
|
||||
if (DEBUG) {
|
||||
start = System.currentTimeMillis();
|
||||
System.out.println(String.format("Start seeking for image index %d", i + 1));
|
||||
System.out.printf("Start seeking for image index %d%n", i + 1);
|
||||
}
|
||||
|
||||
// Need to skip over segments, as they may contain JPEG markers (eg. JFXX or EXIF thumbnail)
|
||||
JPEGSegmentUtil.readSegments(stream, Collections.<Integer, List<String>>emptyMap());
|
||||
JPEGSegmentUtil.readSegments(imageInput, Collections.<Integer, List<String>>emptyMap());
|
||||
|
||||
// Now, search for EOI and following SOI...
|
||||
int marker;
|
||||
while ((marker = stream.read()) != -1) {
|
||||
if (marker == 0xFF && (0xFF00 | stream.readUnsignedByte()) == JPEG.EOI) {
|
||||
while ((marker = imageInput.read()) != -1) {
|
||||
if (marker == 0xFF && (0xFF00 | imageInput.readUnsignedByte()) == JPEG.EOI) {
|
||||
// Found EOI, now the SOI should be nearby...
|
||||
while ((marker = stream.read()) != -1) {
|
||||
if (marker == 0xFF && (0xFF00 | stream.readUnsignedByte()) == JPEG.SOI) {
|
||||
long nextSOIOffset = stream.getStreamPosition() - 2;
|
||||
while ((marker = imageInput.read()) != -1) {
|
||||
if (marker == 0xFF && (0xFF00 | imageInput.readUnsignedByte()) == JPEG.SOI) {
|
||||
long nextSOIOffset = imageInput.getStreamPosition() - 2;
|
||||
imageInput.seek(nextSOIOffset);
|
||||
streamOffsets.add(nextSOIOffset);
|
||||
|
||||
@@ -780,10 +766,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
System.out.println(String.format("Seek in %d ms", System.currentTimeMillis() - start));
|
||||
System.out.printf("Seek in %d ms%n", System.currentTimeMillis() - start);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (EOFException eof) {
|
||||
IndexOutOfBoundsException ioobe = new IndexOutOfBoundsException("Image index " + imageIndex + " not found in stream");
|
||||
@@ -843,9 +828,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
|
||||
return JPEGSegmentUtil.readSegments(imageInput, JPEGSegmentUtil.ALL_SEGMENTS);
|
||||
}
|
||||
catch (IIOException | IllegalArgumentException ignore) {
|
||||
catch (IIOException | IllegalArgumentException e) {
|
||||
if (DEBUG) {
|
||||
ignore.printStackTrace();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@@ -919,6 +904,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
try (ImageInputStream stream = new ByteArrayImageInputStream(exif.data, offset, exif.data.length - offset)) {
|
||||
return (CompoundDirectory) new TIFFReader().read(stream);
|
||||
}
|
||||
catch (IIOException e) {
|
||||
processWarningOccurred("Exif chunk is present, but can't be read: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1106,6 +1094,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
// Read JFIF thumbnails if present
|
||||
JFIF jfif = getJFIF();
|
||||
if (jfif != null && jfif.thumbnail != null) {
|
||||
// TODO: Check if the JFIF segment really has room for this thumbnail?
|
||||
thumbnails.add(new JFIFThumbnailReader(thumbnailProgressDelegator, imageIndex, thumbnails.size(), jfif));
|
||||
}
|
||||
|
||||
@@ -1116,6 +1105,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
case JFXX.JPEG:
|
||||
case JFXX.INDEXED:
|
||||
case JFXX.RGB:
|
||||
// TODO: Check if the JFXX segment really has room for this thumbnail?
|
||||
thumbnails.add(new JFXXThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), imageIndex, thumbnails.size(), jfxx));
|
||||
break;
|
||||
default:
|
||||
@@ -1129,48 +1119,77 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
Application exif = exifSegments.get(0);
|
||||
|
||||
// Identifier is "Exif\0" + 1 byte pad
|
||||
int offset = exif.identifier.length() + 2;
|
||||
int dataOffset = exif.identifier.length() + 2;
|
||||
|
||||
if (exif.data.length <= offset) {
|
||||
if (exif.data.length <= dataOffset) {
|
||||
processWarningOccurred("Exif chunk has no data.");
|
||||
}
|
||||
else {
|
||||
ImageInputStream stream = new ByteArrayImageInputStream(exif.data, offset, exif.data.length - offset);
|
||||
CompoundDirectory exifMetadata = (CompoundDirectory) new TIFFReader().read(stream);
|
||||
ImageInputStream stream = new ByteArrayImageInputStream(exif.data, dataOffset, exif.data.length - dataOffset);
|
||||
try {
|
||||
CompoundDirectory exifMetadata = (CompoundDirectory) new TIFFReader().read(stream);
|
||||
|
||||
if (exifMetadata.directoryCount() == 2) {
|
||||
Directory ifd1 = exifMetadata.getDirectory(1);
|
||||
if (exifMetadata.directoryCount() == 2) {
|
||||
Directory ifd1 = exifMetadata.getDirectory(1);
|
||||
|
||||
// Compression: 1 = no compression, 6 = JPEG compression (default)
|
||||
Entry compressionEntry = ifd1.getEntryById(TIFF.TAG_COMPRESSION);
|
||||
int compression = compressionEntry == null ? 6 : ((Number) compressionEntry.getValue()).intValue();
|
||||
// Compression: 1 = no compression, 6 = JPEG compression (default)
|
||||
Entry compressionEntry = ifd1.getEntryById(TIFF.TAG_COMPRESSION);
|
||||
int compression = compressionEntry == null ? 6 : ((Number) compressionEntry.getValue()).intValue();
|
||||
|
||||
if (compression == 6) {
|
||||
if (ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT) != null) {
|
||||
Entry jpegLength = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||
if (compression == 6) {
|
||||
Entry jpegOffEntry = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||
if (jpegOffEntry != null) {
|
||||
Entry jpegLenEntry = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||
|
||||
if ((jpegLength == null || ((Number) jpegLength.getValue()).longValue() > 0)) {
|
||||
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
||||
// Test if Exif thumbnail is contained within the Exif segment (offset + length <= segment.length)
|
||||
long jpegOffset = ((Number) jpegOffEntry.getValue()).longValue();
|
||||
long jpegLength = jpegLenEntry != null ? ((Number) jpegLenEntry.getValue()).longValue() : -1;
|
||||
if (jpegLength > 0 && jpegOffset + jpegLength <= stream.length()) {
|
||||
// Verify first bytes are FFD8
|
||||
stream.seek(jpegOffset);
|
||||
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||
if (stream.readUnsignedShort() == JPEG.SOI) {
|
||||
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
||||
}
|
||||
// TODO: Simplify this warning fallback stuff...
|
||||
else {
|
||||
processWarningOccurred("EXIF IFD with empty or incomplete JPEG thumbnail");
|
||||
}
|
||||
}
|
||||
else {
|
||||
processWarningOccurred("EXIF IFD with empty or incomplete JPEG thumbnail");
|
||||
}
|
||||
}
|
||||
else {
|
||||
processWarningOccurred("EXIF IFD with empty (zero-length) thumbnail");
|
||||
processWarningOccurred("EXIF IFD with JPEG thumbnail missing JPEGInterchangeFormat tag");
|
||||
}
|
||||
}
|
||||
else if (compression == 1) {
|
||||
Entry stripOffEntry = ifd1.getEntryById(TIFF.TAG_STRIP_OFFSETS);
|
||||
if (stripOffEntry != null) {
|
||||
long stripOffset = ((Number) stripOffEntry.getValue()).longValue();
|
||||
|
||||
if (stripOffset < stream.length()) {
|
||||
// TODO: Verify length of Exif thumbnail vs length of segment like in JPEG
|
||||
// ...but this requires so many extra values... Instead move this logic to the
|
||||
// EXIFThumbnailReader?
|
||||
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
||||
}
|
||||
else {
|
||||
processWarningOccurred("EXIF IFD with empty or incomplete uncompressed thumbnail");
|
||||
}
|
||||
}
|
||||
else {
|
||||
processWarningOccurred("EXIF IFD with uncompressed thumbnail missing StripOffsets tag");
|
||||
}
|
||||
}
|
||||
else {
|
||||
processWarningOccurred("EXIF IFD with JPEG thumbnail missing JPEGInterchangeFormat tag");
|
||||
processWarningOccurred("EXIF IFD with unknown compression (expected 1 or 6): " + compression);
|
||||
}
|
||||
}
|
||||
else if (compression == 1) {
|
||||
if (ifd1.getEntryById(TIFF.TAG_STRIP_OFFSETS) != null) {
|
||||
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
||||
}
|
||||
else {
|
||||
processWarningOccurred("EXIF IFD with uncompressed thumbnail missing StripOffsets tag");
|
||||
}
|
||||
}
|
||||
else {
|
||||
processWarningOccurred("EXIF IFD with unknown compression (expected 1 or 6): " + compression);
|
||||
}
|
||||
}
|
||||
catch (IIOException e) {
|
||||
processWarningOccurred("Exif chunk present, but can't be read: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1215,7 +1234,15 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
|
||||
checkThumbnailBounds(imageIndex, thumbnailIndex);
|
||||
|
||||
return thumbnails.get(thumbnailIndex).read();
|
||||
// processThumbnailStarted(imageIndex, thumbnailIndex);
|
||||
// processThumbnailProgress(0f);
|
||||
|
||||
BufferedImage thumbnail = thumbnails.get(thumbnailIndex).read();;
|
||||
|
||||
// processThumbnailProgress(100f);
|
||||
// processThumbnailComplete();
|
||||
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
// Metadata
|
||||
@@ -1392,7 +1419,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
final String arg = args[argIdx];
|
||||
|
||||
if (arg.charAt(0) == '-') {
|
||||
if (arg.equals("-s") || arg.equals("--subsample") && args.length > argIdx) {
|
||||
if (arg.equals("-s") || arg.equals("--subsample") && args.length > argIdx + 1) {
|
||||
String[] sub = args[++argIdx].split(",");
|
||||
|
||||
try {
|
||||
@@ -1411,7 +1438,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
System.err.println("Bad sub sampling (x,y): '" + args[argIdx] + "'");
|
||||
}
|
||||
}
|
||||
else if (arg.equals("-r") || arg.equals("--roi") && args.length > argIdx) {
|
||||
else if (arg.equals("-r") || arg.equals("--roi") && args.length > argIdx + 1) {
|
||||
String[] region = args[++argIdx].split(",");
|
||||
|
||||
try {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>imageio-metadata</artifactId>
|
||||
|
||||
+4
-2
@@ -48,7 +48,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
@@ -154,7 +154,7 @@ public final class JPEGSegmentUtil {
|
||||
}
|
||||
|
||||
static String asAsciiString(final byte[] data, final int offset, final int length) {
|
||||
return new String(data, offset, length, Charset.forName("ascii"));
|
||||
return new String(data, offset, length, StandardCharsets.US_ASCII);
|
||||
}
|
||||
|
||||
static void readSOI(final ImageInputStream stream) throws IOException {
|
||||
@@ -348,6 +348,7 @@ public final class JPEGSegmentUtil {
|
||||
else if ("Photoshop 3.0".equals(segment.identifier())) {
|
||||
// TODO: The "Photoshop 3.0" segment contains several image resources, of which one might contain
|
||||
// IPTC metadata. Probably duplicated in the XMP though...
|
||||
// TODO: Merge multiple APP13 segments to single resource block
|
||||
ImageInputStream stream = new ByteArrayImageInputStream(segment.data, segment.offset(), segment.length());
|
||||
Directory psd = new PSDReader().read(stream);
|
||||
Entry iccEntry = psd.getEntryById(PSD.RES_ICC_PROFILE);
|
||||
@@ -359,6 +360,7 @@ public final class JPEGSegmentUtil {
|
||||
System.err.println(TIFFReader.HexDump.dump(segment.data));
|
||||
}
|
||||
else if ("ICC_PROFILE".equals(segment.identifier())) {
|
||||
// TODO: Merge multiple APP2 segments to single ICC Profile
|
||||
// Skip
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-pcx</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: PCX plugin</name>
|
||||
|
||||
+2
-1
@@ -64,7 +64,7 @@ public class PCXImageReaderTest extends ImageReaderAbstractTest<PCXImageReader>
|
||||
@Override
|
||||
protected List<TestData> getTestData() {
|
||||
return Arrays.asList(
|
||||
new TestData(getClassLoaderResource("/pcx/MARBLES.PCX"), new Dimension(1419, 1001)), // RLE encoded RGB
|
||||
new TestData(getClassLoaderResource("/pcx/input.pcx"), new Dimension(70, 46)), // RLE encoded RGB
|
||||
new TestData(getClassLoaderResource("/pcx/lena.pcx"), new Dimension(512, 512)), // RLE encoded RGB
|
||||
new TestData(getClassLoaderResource("/pcx/lena2.pcx"), new Dimension(512, 512)), // RLE encoded, 256 color indexed (8 bps/1 channel)
|
||||
new TestData(getClassLoaderResource("/pcx/lena3.pcx"), new Dimension(512, 512)), // RLE encoded, 16 color indexed (4 bps/1 channel)
|
||||
@@ -76,6 +76,7 @@ public class PCXImageReaderTest extends ImageReaderAbstractTest<PCXImageReader>
|
||||
new TestData(getClassLoaderResource("/pcx/lena9.pcx"), new Dimension(512, 512)), // RLE encoded, 2 color indexed (1 bps/1 channel)
|
||||
new TestData(getClassLoaderResource("/pcx/lena10.pcx"), new Dimension(512, 512)), // RLE encoded, 16 color indexed (4 bps/1 channel) (uses only 8 colors)
|
||||
new TestData(getClassLoaderResource("/pcx/DARKSTAR.PCX"), new Dimension(88, 52)), // RLE encoded monochrome (1 bps/1 channel)
|
||||
new TestData(getClassLoaderResource("/pcx/MARBLES.PCX"), new Dimension(1419, 1001)), // RLE encoded RGB
|
||||
new TestData(getClassLoaderResource("/pcx/no-palette-monochrome.pcx"), new Dimension(128, 152)), // RLE encoded monochrome (1 bps/1 channel)
|
||||
// See cga-pcx.txt, however, the text seems to be in error, the bits can not not as described
|
||||
new TestData(getClassLoaderResource("/pcx/CGA_BW.PCX"), new Dimension(640, 200)), // RLE encoded indexed (CGA mode)
|
||||
|
||||
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-pdf</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: PDF plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-pict</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: PICT plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-pnm</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: PNM plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-psd</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: PSD plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-reference</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: reference test cases</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-sgi</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: SGI plugin</name>
|
||||
|
||||
+8
-6
@@ -218,7 +218,8 @@ public final class SGIImageReader extends ImageReaderBase {
|
||||
|
||||
private void readRowByte(int height, Rectangle srcRegion, int[] scanlineOffsets, int[] scanlineLengths, int compression, int xSub, int ySub, int c, byte[] rowDataByte, WritableRaster destChannel, Raster srcChannel, int y) throws IOException {
|
||||
// If subsampled or outside source region, skip entire row
|
||||
if (y % ySub != 0 || height - 1 - y < srcRegion.y || height - 1 - y >= srcRegion.y + srcRegion.height) {
|
||||
int destY = height - 1 - y;
|
||||
if (destY % ySub != 0 || destY < srcRegion.y || destY >= srcRegion.y + srcRegion.height) {
|
||||
if (compression == SGI.COMPRESSION_NONE) {
|
||||
imageInput.skipBytes(rowDataByte.length);
|
||||
}
|
||||
@@ -245,16 +246,17 @@ public final class SGIImageReader extends ImageReaderBase {
|
||||
}
|
||||
}
|
||||
|
||||
normalize(rowDataByte, 9, srcRegion.width / xSub);
|
||||
normalize(rowDataByte, 0, srcRegion.width / xSub);
|
||||
|
||||
// Flip into position (SGI images are stored bottom/up)
|
||||
int dstY = (height - 1 - y - srcRegion.y) / ySub;
|
||||
int dstY = (destY - srcRegion.y) / ySub;
|
||||
destChannel.setDataElements(0, dstY, srcChannel);
|
||||
}
|
||||
|
||||
private void readRowUShort(int height, Rectangle srcRegion, int[] scanlineOffsets, int[] scanlineLengths, int compression, int xSub, int ySub, int c, short[] rowDataUShort, WritableRaster destChannel, Raster srcChannel, int y) throws IOException {
|
||||
// If subsampled or outside source region, skip entire row
|
||||
if (y % ySub != 0 || height - 1 - y < srcRegion.y || height - 1 - y >= srcRegion.y + srcRegion.height) {
|
||||
int destY = height - 1 - y;
|
||||
if (destY % ySub != 0 || destY < srcRegion.y || destY >= srcRegion.y + srcRegion.height) {
|
||||
if (compression == SGI.COMPRESSION_NONE) {
|
||||
imageInput.skipBytes(rowDataUShort.length * 2);
|
||||
}
|
||||
@@ -281,10 +283,10 @@ public final class SGIImageReader extends ImageReaderBase {
|
||||
}
|
||||
}
|
||||
|
||||
normalize(rowDataUShort, 9, srcRegion.width / xSub);
|
||||
normalize(rowDataUShort, 0, srcRegion.width / xSub);
|
||||
|
||||
// Flip into position (SGI images are stored bottom/up)
|
||||
int dstY = (height - 1 - y - srcRegion.y) / ySub;
|
||||
int dstY = (destY - srcRegion.y) / ySub;
|
||||
destChannel.setDataElements(0, dstY, srcChannel);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -53,7 +53,8 @@ public class SGIImageReaderTest extends ImageReaderAbstractTest<SGIImageReader>
|
||||
|
||||
@Override
|
||||
protected List<TestData> getTestData() {
|
||||
return Collections.singletonList(
|
||||
return Arrays.asList(
|
||||
new TestData(getClassLoaderResource("/sgi/input.sgi"), new Dimension(70, 46)), // RLE encoded RGB
|
||||
new TestData(getClassLoaderResource("/sgi/MARBLES.SGI"), new Dimension(1419, 1001)) // RLE encoded RGB
|
||||
);
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-tga</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: TGA plugin</name>
|
||||
|
||||
+18
-4
@@ -200,12 +200,12 @@ final class TGAHeader {
|
||||
int components = colorMap.hasAlpha() ? 4 : 3;
|
||||
byte[] cmap = new byte[rgb.length * components];
|
||||
for (int i = 0; i < rgb.length; i++) {
|
||||
cmap[i * components ] = (byte) ((rgb[i] >> 16) & 0xff);
|
||||
cmap[i * components + 1] = (byte) ((rgb[i] >> 8) & 0xff);
|
||||
cmap[i * components + 2] = (byte) ((rgb[i] ) & 0xff);
|
||||
cmap[i * components ] = (byte) ((rgb[i] ) & 0xff); // B
|
||||
cmap[i * components + 1] = (byte) ((rgb[i] >> 8) & 0xff); // G
|
||||
cmap[i * components + 2] = (byte) ((rgb[i] >> 16) & 0xff); // R
|
||||
|
||||
if (components == 4) {
|
||||
cmap[i * components + 3] = (byte) ((rgb[i] >>> 24) & 0xff);
|
||||
cmap[i * components + 3] = (byte) ((rgb[i] >>> 24) & 0xff); // A
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,9 +298,23 @@ final class TGAHeader {
|
||||
hasAlpha = false;
|
||||
break;
|
||||
case 24:
|
||||
// BGR -> RGB
|
||||
for (int i = 0; i < cmap.length; i += 3) {
|
||||
byte b = cmap[i];
|
||||
cmap[i ] = cmap[i + 2];
|
||||
cmap[i + 2] = b;
|
||||
}
|
||||
|
||||
hasAlpha = false;
|
||||
break;
|
||||
case 32:
|
||||
// BGRA -> RGBA
|
||||
for (int i = 0; i < cmap.length; i += 4) {
|
||||
byte b = cmap[i];
|
||||
cmap[i ] = cmap[i + 2];
|
||||
cmap[i + 2] = b;
|
||||
}
|
||||
|
||||
hasAlpha = true;
|
||||
break;
|
||||
default:
|
||||
|
||||
+5
-3
@@ -224,7 +224,7 @@ final class TGAImageReader extends ImageReaderBase {
|
||||
byte[] rowDataByte, WritableRaster destChannel, Raster srcChannel, int y) throws IOException {
|
||||
// If subsampled or outside source region, skip entire row
|
||||
if (y % ySub != 0 || height - 1 - y < srcRegion.y || height - 1 - y >= srcRegion.y + srcRegion.height) {
|
||||
imageInput.skipBytes(rowDataByte.length);
|
||||
input.skipBytes(rowDataByte.length);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -251,7 +251,8 @@ final class TGAImageReader extends ImageReaderBase {
|
||||
destChannel.setDataElements(0, dstY, srcChannel);
|
||||
break;
|
||||
case TGA.ORIGIN_UPPER_LEFT:
|
||||
destChannel.setDataElements(0, y, srcChannel);
|
||||
dstY = y / ySub;
|
||||
destChannel.setDataElements(0, dstY, srcChannel);
|
||||
break;
|
||||
default:
|
||||
throw new IIOException("Unsupported origin: " + origin);
|
||||
@@ -289,7 +290,8 @@ final class TGAImageReader extends ImageReaderBase {
|
||||
destChannel.setDataElements(0, dstY, srcChannel);
|
||||
break;
|
||||
case TGA.ORIGIN_UPPER_LEFT:
|
||||
destChannel.setDataElements(0, y, srcChannel);
|
||||
dstY = y / ySub;
|
||||
destChannel.setDataElements(0, dstY, srcChannel);
|
||||
break;
|
||||
default:
|
||||
throw new IIOException("Unsupported origin: " + origin);
|
||||
|
||||
+1
@@ -189,6 +189,7 @@ final class TGAMetadata extends AbstractMetadata {
|
||||
switch (header.getPixelDepth()) {
|
||||
case 8:
|
||||
bitsPerSample.setAttribute("value", createListValue(1, Integer.toString(header.getPixelDepth())));
|
||||
break;
|
||||
case 16:
|
||||
if (header.getAttributeBits() > 0 && extensions != null && extensions.hasAlpha()) {
|
||||
bitsPerSample.setAttribute("value", "5, 5, 5, 1");
|
||||
|
||||
+27
@@ -32,11 +32,19 @@ package com.twelvemonkeys.imageio.plugins.tga;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* TGAImageReaderTest
|
||||
*
|
||||
@@ -104,4 +112,23 @@ public class TGAImageReaderTest extends ImageReaderAbstractTest<TGAImageReader>
|
||||
"image/targa", "image/x-targa"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubsampling() throws IOException {
|
||||
ImageReader reader = createReader();
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
param.setSourceSubsampling(3, 5, 0, 0);
|
||||
|
||||
for (TestData testData : getTestData()) {
|
||||
try (ImageInputStream input = testData.getInputStream()) {
|
||||
reader.setInput(input);
|
||||
assertNotNull(reader.read(0, param));
|
||||
}
|
||||
finally {
|
||||
reader.reset();
|
||||
}
|
||||
}
|
||||
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-thumbsdb</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: Thumbs.db plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-tiff</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: TIFF plugin</name>
|
||||
|
||||
+3
-2
@@ -152,7 +152,7 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
|
||||
static int findCompressionType(final int type, final InputStream in) throws IOException {
|
||||
// Discover possible incorrect type, revert to RLE
|
||||
if (type == TIFFExtension.COMPRESSION_CCITT_T4 && in.markSupported()) {
|
||||
byte[] streamData = new byte[20];
|
||||
byte[] streamData = new byte[32];
|
||||
|
||||
try {
|
||||
in.mark(streamData.length);
|
||||
@@ -173,8 +173,9 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
|
||||
|
||||
if (streamData[0] != 0 || (streamData[1] >> 4 != 1 && streamData[1] != 1)) {
|
||||
// Leading EOL (0b000000000001) not found, search further and try RLE if not found
|
||||
int numBits = streamData.length * 8;
|
||||
short b = (short) (((streamData[0] << 8) + streamData[1]) >> 4);
|
||||
for (int i = 12; i < 160; i++) {
|
||||
for (int i = 12; i < numBits; i++) {
|
||||
b = (short) ((b << 1) + ((streamData[(i / 8)] >> (7 - (i % 8))) & 0x01));
|
||||
|
||||
if ((b & 0xFFF) == 1) {
|
||||
|
||||
+11
-5
@@ -68,14 +68,19 @@ public class CCITTFaxDecoderStreamTest {
|
||||
};
|
||||
|
||||
// group3_2d.tif: EOL|k=1|3W|1B|2W|EOL|k=0|V|V|V|EOL|k=1|3W|1B|2W|EOL|k=0|V-1|V|V|6*F
|
||||
static final byte[] DATA_G3_2D = { 0x00, 0x1C, 0x27, 0x00, 0x17, 0x00, 0x1C, 0x27, 0x00, 0x12, (byte) 0xC0 };
|
||||
static final byte[] DATA_G3_2D = {0x00, 0x1C, 0x27, 0x00, 0x17, 0x00, 0x1C, 0x27, 0x00, 0x12, (byte) 0xC0};
|
||||
|
||||
// group3_2d_fill.tif
|
||||
static final byte[] DATA_G3_2D_FILL = { 0x00, 0x01, (byte) 0xC2, 0x70, 0x01, 0x70, 0x01, (byte) 0xC2, 0x70, 0x01,
|
||||
0x2C };
|
||||
static final byte[] DATA_G3_2D_FILL = {0x00, 0x01, (byte) 0xC2, 0x70, 0x01, 0x70, 0x01, (byte) 0xC2,
|
||||
0x70, 0x01, 0x2C};
|
||||
|
||||
static final byte[] DATA_G3_2D_lsb2msb = { 0x00, 0x38, (byte) 0xE4, 0x00, (byte) 0xE8, 0x00, 0x38, (byte) 0xE4,
|
||||
0x00, 0x48, 0x03 };
|
||||
static final byte[] DATA_G3_2D_lsb2msb = {0x00, 0x38, (byte) 0xE4, 0x00, (byte) 0xE8, 0x00, 0x38, (byte) 0xE4,
|
||||
0x00, 0x48, 0x03};
|
||||
|
||||
static final byte[] DATA_G3_LONG = {0x00, 0x68, 0x0A, (byte) 0xC9, 0x3A, 0x3A, 0x00, 0x68,
|
||||
(byte) 0x8A, (byte) 0xD8, 0x3A, 0x35, 0x00, 0x68, 0x0A, 0x06,
|
||||
(byte) 0xDD, 0x3A, 0x19, 0x00, 0x68, (byte) 0x8A, (byte) 0x9E, 0x75,
|
||||
0x08, 0x00, 0x68};
|
||||
|
||||
// group4.tif:
|
||||
// Line 1: V-3, V-2, V0
|
||||
@@ -189,6 +194,7 @@ public class CCITTFaxDecoderStreamTest {
|
||||
assertEquals(TIFFExtension.COMPRESSION_CCITT_T4, CCITTFaxDecoderStream.findCompressionType(TIFFExtension.COMPRESSION_CCITT_T4, new ByteArrayInputStream(DATA_G3_2D)));
|
||||
assertEquals(TIFFExtension.COMPRESSION_CCITT_T4, CCITTFaxDecoderStream.findCompressionType(TIFFExtension.COMPRESSION_CCITT_T4, new ByteArrayInputStream(DATA_G3_2D_FILL)));
|
||||
assertEquals(TIFFExtension.COMPRESSION_CCITT_T4, CCITTFaxDecoderStream.findCompressionType(TIFFExtension.COMPRESSION_CCITT_T4, new ByteArrayInputStream(DATA_G3_2D_lsb2msb)));
|
||||
assertEquals(TIFFExtension.COMPRESSION_CCITT_T4, CCITTFaxDecoderStream.findCompressionType(TIFFExtension.COMPRESSION_CCITT_T4, new ByteArrayInputStream(DATA_G3_LONG)));
|
||||
|
||||
// Group 4/CCITT_T6
|
||||
assertEquals(TIFFExtension.COMPRESSION_CCITT_T6, CCITTFaxDecoderStream.findCompressionType(TIFFExtension.COMPRESSION_CCITT_T6, new ByteArrayInputStream(DATA_G4)));
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Twelvemonkeys</name>
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<connection>scm:git:https://github.com/haraldk/TwelveMonkeys</connection>
|
||||
<developerConnection>scm:git:ssh://git@github.com/haraldk/TwelveMonkeys</developerConnection>
|
||||
<url>https://github.com/haraldk/TwelveMonkeys</url>
|
||||
<tag>twelvemonkeys-3.6.1</tag>
|
||||
<tag>twelvemonkeys-3.6.3</tag>
|
||||
</scm>
|
||||
|
||||
<properties>
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.3</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
Reference in New Issue
Block a user