mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-23 00:00:05 -04:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 873420286d | |||
| 4993331a5d | |||
| af0a3889db | |||
| 6acdfd3be6 | |||
| cfb664a76a | |||
| 86d95e1f02 | |||
| 54dd9b6d7b | |||
| 4e10fc019e | |||
| 1295951ead | |||
| d5e664cdcc | |||
| efe5f3c34a | |||
| 2488f6f67c | |||
| 6a66d2e059 | |||
| ebd5533879 | |||
| e6e4e96309 | |||
| aadc62dde9 | |||
| 24cbe57240 | |||
| f7d8ae0cd2 | |||
| 5da934e11b | |||
| 51297ad496 | |||
| 80a534cd62 | |||
| 24130d466d | |||
| 7559686782 | |||
| b6988c37a7 | |||
| bbffb1d416 | |||
| c68de3bc92 | |||
| a12b6044c6 | |||
| 9a0e2d9659 |
@@ -1,6 +1,6 @@
|
|||||||
[](https://travis-ci.org/haraldk/TwelveMonkeys)
|
[](https://travis-ci.org/haraldk/TwelveMonkeys)
|
||||||
[](https://maven-badges.herokuapp.com/maven-central/com.twelvemonkeys.imageio/imageio)
|
[](https://maven-badges.herokuapp.com/maven-central/com.twelvemonkeys.imageio/imageio)
|
||||||
[](https://stackoverflow.com/questions/tagged/twelvemonkeys)
|
[](https://stackoverflow.com/questions/tagged/twelvemonkeys)
|
||||||
[](https://paypal.me/haraldk76/100)
|
[](https://paypal.me/haraldk76/100)
|
||||||
|
|
||||||
## About
|
## About
|
||||||
@@ -28,8 +28,9 @@ The goal is to create a set of efficient and robust ImageIO plug-ins, that can b
|
|||||||
| | ICO | MS Windows Icon Format | âś” | âś” | - |
|
| | ICO | MS Windows Icon Format | âś” | âś” | - |
|
||||||
| [HDR](https://github.com/haraldk/TwelveMonkeys/wiki/HDR-Plugin) | HDR | Radiance High Dynamic Range RGBE Format | âś” | - | Standard |
|
| [HDR](https://github.com/haraldk/TwelveMonkeys/wiki/HDR-Plugin) | HDR | Radiance High Dynamic Range RGBE Format | âś” | - | Standard |
|
||||||
| [ICNS](https://github.com/haraldk/TwelveMonkeys/wiki/ICNS-Plugin) | ICNS | Apple Icon Image | âś” | âś” | - |
|
| [ICNS](https://github.com/haraldk/TwelveMonkeys/wiki/ICNS-Plugin) | ICNS | Apple Icon Image | âś” | âś” | - |
|
||||||
| [IFF](https://github.com/haraldk/TwelveMonkeys/wiki/IFF-Plugin) | IFF | Commodore Amiga/Electronic Arts Interchange File Format | âś” | âś” | - |
|
| [IFF](https://github.com/haraldk/TwelveMonkeys/wiki/IFF-Plugin) | IFF | Commodore Amiga/Electronic Arts Interchange File Format | âś” | âś” | Standard |
|
||||||
| [JPEG](https://github.com/haraldk/TwelveMonkeys/wiki/JPEG-Plugin) | **JPEG** | Joint Photographers Expert Group | âś” | âś” | Native & Standard |
|
| [JPEG](https://github.com/haraldk/TwelveMonkeys/wiki/JPEG-Plugin) | **JPEG** | Joint Photographers Expert Group | âś” | âś” | Native & Standard |
|
||||||
|
| | **JPEG Lossless** | | âś” | - | Native & Standard |
|
||||||
| [PCX](https://github.com/haraldk/TwelveMonkeys/wiki/PCX-Plugin) | PCX | ZSoft Paintbrush Format | âś” | - | Standard |
|
| [PCX](https://github.com/haraldk/TwelveMonkeys/wiki/PCX-Plugin) | PCX | ZSoft Paintbrush Format | âś” | - | Standard |
|
||||||
| | DCX | Multi-page PCX fax document | âś” | - | Standard |
|
| | DCX | Multi-page PCX fax document | âś” | - | Standard |
|
||||||
| [PICT](https://github.com/haraldk/TwelveMonkeys/wiki/PICT-Plugin) | PICT | Apple Mac Paint Picture Format | âś” | - | - |
|
| [PICT](https://github.com/haraldk/TwelveMonkeys/wiki/PICT-Plugin) | PICT | Apple Mac Paint Picture Format | âś” | - | - |
|
||||||
@@ -50,7 +51,11 @@ The goal is to create a set of efficient and robust ImageIO plug-ins, that can b
|
|||||||
|
|
||||||
|
|
||||||
**Important note on using Batik:** *Please read [The Apache™ XML Graphics Project - Security](http://xmlgraphics.apache.org/security.html),
|
**Important note on using Batik:** *Please read [The Apache™ XML Graphics Project - Security](http://xmlgraphics.apache.org/security.html),
|
||||||
and make sure you use either version 1.6.1, 1.7.1, 1.8+ or later.*
|
and make sure you use version 1.14 or later.*
|
||||||
|
|
||||||
|
Note that GIF, PNG and WBMP formats are already supported through the ImageIO API, using the
|
||||||
|
[JDK standard plugins](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/package-summary.html).
|
||||||
|
For BMP, JPEG, and TIFF formats the TwelveMonkeys plugins provides extended format support and additional features.
|
||||||
|
|
||||||
## Basic usage
|
## Basic usage
|
||||||
|
|
||||||
@@ -79,10 +84,8 @@ The plugins are discovered automatically at run time. See the [FAQ](#faq) for mo
|
|||||||
If you need more control of read parameters and the reading process, the common idiom for reading is something like:
|
If you need more control of read parameters and the reading process, the common idiom for reading is something like:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// Create input stream
|
// Create input stream (in try-with-resource block to avoid leaks)
|
||||||
ImageInputStream input = ImageIO.createImageInputStream(file);
|
try (ImageInputStream input = ImageIO.createImageInputStream(file)) {
|
||||||
|
|
||||||
try {
|
|
||||||
// Get the reader
|
// Get the reader
|
||||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||||
|
|
||||||
@@ -119,10 +122,6 @@ try {
|
|||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
// Close stream in finally block to avoid resource leaks
|
|
||||||
input.close();
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Query the reader for source image dimensions using `reader.getWidth(n)` and `reader.getHeight(n)` without reading the
|
Query the reader for source image dimensions using `reader.getWidth(n)` and `reader.getHeight(n)` without reading the
|
||||||
@@ -144,10 +143,8 @@ if (!writers.hasNext()) {
|
|||||||
ImageWriter writer = writers.next();
|
ImageWriter writer = writers.next();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create output stream
|
// Create output stream (in try-with-resource block to avoid leaks)
|
||||||
ImageOutputStream output = ImageIO.createImageOutputStream(file);
|
try (ImageOutputStream output = ImageIO.createImageOutputStream(file)) {
|
||||||
|
|
||||||
try {
|
|
||||||
writer.setOutput(output);
|
writer.setOutput(output);
|
||||||
|
|
||||||
// Optionally, listen to progress, warnings, etc.
|
// Optionally, listen to progress, warnings, etc.
|
||||||
@@ -160,10 +157,6 @@ try {
|
|||||||
// Optionally, provide thumbnails and image/stream metadata
|
// Optionally, provide thumbnails and image/stream metadata
|
||||||
writer.write(..., new IIOImage(..., image, ...), param);
|
writer.write(..., new IIOImage(..., image, ...), param);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
// Close stream in finally block to avoid resource leaks
|
|
||||||
output.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Dispose writer in finally block to avoid memory leaks
|
// Dispose writer in finally block to avoid memory leaks
|
||||||
@@ -237,7 +230,7 @@ Build the project (using [Maven](http://maven.apache.org/download.cgi)):
|
|||||||
|
|
||||||
$ mvn package
|
$ 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.
|
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 +273,22 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-jpeg</artifactId>
|
<artifactId>imageio-jpeg</artifactId>
|
||||||
<version>3.6</version>
|
<version>3.6.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-tiff</artifactId>
|
<artifactId>imageio-tiff</artifactId>
|
||||||
<version>3.6</version>
|
<version>3.6.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Optional dependency. Needed only if you deploy `ImageIO` plugins as part of a web app.
|
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.
|
Make sure you add the IIOProviderContextListener to your web.xml, see above.
|
||||||
-->
|
-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||||
<artifactId>servlet</artifactId>
|
<artifactId>servlet</artifactId>
|
||||||
<version>3.6</version>
|
<version>3.6.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
```
|
```
|
||||||
@@ -304,13 +297,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:
|
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-lang-3.6.3.jar
|
||||||
twelvemonkeys-common-io-3.6.jar
|
twelvemonkeys-common-io-3.6.3.jar
|
||||||
twelvemonkeys-common-image-3.6.jar
|
twelvemonkeys-common-image-3.6.3.jar
|
||||||
twelvemonkeys-imageio-core-3.6.jar
|
twelvemonkeys-imageio-core-3.6.3.jar
|
||||||
twelvemonkeys-imageio-metadata-3.6.jar
|
twelvemonkeys-imageio-metadata-3.6.3.jar
|
||||||
twelvemonkeys-imageio-jpeg-3.6.jar
|
twelvemonkeys-imageio-jpeg-3.6.3.jar
|
||||||
twelvemonkeys-imageio-tiff-3.6.jar
|
twelvemonkeys-imageio-tiff-3.6.3.jar
|
||||||
|
|
||||||
#### Deploying the plugins in a web app
|
#### Deploying the plugins in a web app
|
||||||
|
|
||||||
@@ -376,42 +369,42 @@ Other "fat" JAR bundlers will probably have similar mechanisms to merge entries
|
|||||||
|
|
||||||
### Links to prebuilt binaries
|
### Links to prebuilt binaries
|
||||||
|
|
||||||
##### Latest version (3.6)
|
##### Latest version (3.6.3)
|
||||||
|
|
||||||
Requires Java 7 or later.
|
Requires Java 7 or later.
|
||||||
|
|
||||||
Common dependencies
|
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-lang-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.6.3/common-lang-3.6.3.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-io-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.6.3/common-io-3.6.3.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-image-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.6.3/common-image-3.6.3.jar)
|
||||||
|
|
||||||
ImageIO dependencies
|
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-core-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.6.3/imageio-core-3.6.3.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-metadata-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.6.3/imageio-metadata-3.6.3.jar)
|
||||||
|
|
||||||
ImageIO plugins
|
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-bmp-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.6.3/imageio-bmp-3.6.3.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-hdr-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.6.3/imageio-hdr-3.6.3.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-icns-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.6.3/imageio-icns-3.6.3.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-iff-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.6.3/imageio-iff-3.6.3.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-jpeg-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.6.3/imageio-jpeg-3.6.3.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-pcx-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.6.3/imageio-pcx-3.6.3.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-pict-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.6.3/imageio-pict-3.6.3.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-pnm-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.6.3/imageio-pnm-3.6.3.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-psd-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.6.3/imageio-psd-3.6.3.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-sgi-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.6.3/imageio-sgi-3.6.3.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-tga-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.6.3/imageio-tga-3.6.3.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.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.6.3/imageio-thumbsdb-3.6.3.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-tiff-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.6.3/imageio-tiff-3.6.3.jar)
|
||||||
|
|
||||||
ImageIO plugins requiring 3rd party libs
|
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.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.6.3/imageio-batik-3.6.3.jar)
|
||||||
|
|
||||||
Photoshop Path support for ImageIO
|
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.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.6.3/imageio-clippath-3.6.3.jar)
|
||||||
|
|
||||||
Servlet support
|
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.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.6.3/servlet-3.6.3.jar)
|
||||||
|
|
||||||
##### Old version (3.0.x)
|
##### Old version (3.0.x)
|
||||||
|
|
||||||
@@ -446,7 +439,7 @@ Servlet support
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The project is distributed under the OSI approved [BSD license](http://opensource.org/licenses/BSD-3-Clause):
|
This project is provided under the OSI approved [BSD license](http://opensource.org/licenses/BSD-3-Clause):
|
||||||
|
|
||||||
Copyright (c) 2008-2020, Harald Kuhr
|
Copyright (c) 2008-2020, Harald Kuhr
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
@@ -509,10 +502,15 @@ the Sun/Oracle provided `JPEGImageReader` and `BMPImageReader`, and the Apple pr
|
|||||||
respectively. Using the pairwise ordering will not remove any functionality form these implementations, but in most
|
respectively. Using the pairwise ordering will not remove any functionality form these implementations, but in most
|
||||||
cases you'll end up using the TwelveMonkeys plug-ins instead.
|
cases you'll end up using the TwelveMonkeys plug-ins instead.
|
||||||
|
|
||||||
|
q: Why is there no support for common formats like GIF or PNG?
|
||||||
|
|
||||||
|
a: The short answer is simply that the built-in support in ImageIO for these formats are good enough as-is.
|
||||||
|
If you are looking for better PNG write performance on Java 7 and 8, see [JDK9 PNG Writer Backport](https://github.com/gredler/jdk9-png-writer-backport).
|
||||||
|
|
||||||
|
|
||||||
q: What about JAI? Several of the formats are already supported by JAI.
|
q: What about JAI? Several of the formats are already supported by JAI.
|
||||||
|
|
||||||
a: While JAI (and jai-imageio in particular) have support for some of the formats, JAI has some major issues.
|
a: While JAI (and jai-imageio in particular) have support for some of the same formats, JAI has some major issues.
|
||||||
The most obvious being:
|
The most obvious being:
|
||||||
- It's not actively developed. No issues has been fixed for years.
|
- It's not actively developed. No issues has been fixed for years.
|
||||||
- To get full format support, you need native libs.
|
- To get full format support, you need native libs.
|
||||||
|
|||||||
+6
-1
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>com.twelvemonkeys.bom</groupId>
|
<groupId>com.twelvemonkeys.bom</groupId>
|
||||||
@@ -123,6 +123,11 @@
|
|||||||
<artifactId>imageio-tiff</artifactId>
|
<artifactId>imageio-tiff</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>imageio-xwd</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- ImageIO 3rd party dependent plugins -->
|
<!-- ImageIO 3rd party dependent plugins -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-image</artifactId>
|
<artifactId>common-image</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-io</artifactId>
|
<artifactId>common-io</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-lang</artifactId>
|
<artifactId>common-lang</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>com.twelvemonkeys.contrib</groupId>
|
<groupId>com.twelvemonkeys.contrib</groupId>
|
||||||
<artifactId>contrib</artifactId>
|
<artifactId>contrib</artifactId>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.twelvemonkeys.contrib.exif;
|
|||||||
|
|
||||||
import com.twelvemonkeys.image.ImageUtil;
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
|
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
import javax.imageio.IIOImage;
|
import javax.imageio.IIOImage;
|
||||||
@@ -82,12 +83,11 @@ public class EXIFUtilities {
|
|||||||
ImageReader reader = readers.next();
|
ImageReader reader = readers.next();
|
||||||
try {
|
try {
|
||||||
reader.setInput(input, true, false);
|
reader.setInput(input, true, false);
|
||||||
IIOImage image = reader.readAll(0, reader.getDefaultReadParam());
|
|
||||||
|
|
||||||
BufferedImage bufferedImage = ImageUtil.toBuffered(image.getRenderedImage());
|
IIOMetadata metadata = reader.getImageMetadata(0);
|
||||||
image.setRenderedImage(applyOrientation(bufferedImage, findImageOrientation(image.getMetadata()).value()));
|
BufferedImage bufferedImage = applyOrientation(reader.read(0), findImageOrientation(metadata).value());
|
||||||
|
|
||||||
return image;
|
return new IIOImage(bufferedImage, null, metadata);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
@@ -123,9 +123,15 @@ public class EXIFUtilities {
|
|||||||
for (String arg : args) {
|
for (String arg : args) {
|
||||||
File input = new File(arg);
|
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);
|
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
|
// Finds the orientation as defined by the javax_imageio_1.0 format
|
||||||
Orientation orientation = findImageOrientation(image.getMetadata());
|
Orientation orientation = findImageOrientation(image.getMetadata());
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-batik</artifactId>
|
<artifactId>imageio-batik</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
|
||||||
@@ -104,6 +104,6 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<batik.version>1.12</batik.version>
|
<batik.version>1.14</batik.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-bmp</artifactId>
|
<artifactId>imageio-bmp</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-clippath</artifactId>
|
<artifactId>imageio-clippath</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
|
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.SequenceInputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -131,7 +133,13 @@ public final class Paths {
|
|||||||
List<JPEGSegment> photoshop = JPEGSegmentUtil.readSegments(stream, segmentIdentifiers);
|
List<JPEGSegment> photoshop = JPEGSegmentUtil.readSegments(stream, segmentIdentifiers);
|
||||||
|
|
||||||
if (!photoshop.isEmpty()) {
|
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
|
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");
|
IIOMetadataNode unknown = new IIOMetadataNode("unknown");
|
||||||
unknown.setAttribute("MarkerTag", Integer.toString(JPEG.APP13 & 0xFF));
|
unknown.setAttribute("MarkerTag", Integer.toString(JPEG.APP13 & 0xFF));
|
||||||
|
|
||||||
byte[] identfier = "Photoshop 3.0".getBytes(StandardCharsets.US_ASCII);
|
byte[] identifier = "Photoshop 3.0".getBytes(StandardCharsets.US_ASCII);
|
||||||
byte[] data = new byte[identfier.length + 1 + pathResource.length];
|
byte[] data = new byte[identifier.length + 1 + pathResource.length];
|
||||||
System.arraycopy(identfier, 0, data, 0, identfier.length);
|
System.arraycopy(identifier, 0, data, 0, identifier.length);
|
||||||
System.arraycopy(pathResource, 0, data, identfier.length + 1, pathResource.length);
|
System.arraycopy(pathResource, 0, data, identifier.length + 1, pathResource.length);
|
||||||
|
|
||||||
unknown.setUserObject(data);
|
unknown.setUserObject(data);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: Core</name>
|
<name>TwelveMonkeys :: ImageIO :: Core</name>
|
||||||
|
|||||||
@@ -30,16 +30,20 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio;
|
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.*;
|
||||||
import java.awt.datatransfer.DataFlavor;
|
import java.awt.datatransfer.DataFlavor;
|
||||||
import java.awt.datatransfer.Transferable;
|
import java.awt.datatransfer.Transferable;
|
||||||
import java.awt.datatransfer.UnsupportedFlavorException;
|
import java.awt.datatransfer.UnsupportedFlavorException;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.*;
|
||||||
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.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.IndexColorModel;
|
import java.awt.image.IndexColorModel;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -48,20 +52,6 @@ import java.lang.reflect.InvocationTargetException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
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.
|
* 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_IN = "zoom-in";
|
||||||
static final String ZOOM_OUT = "zoom-out";
|
static final String ZOOM_OUT = "zoom-out";
|
||||||
static final String ZOOM_ACTUAL = "zoom-actual";
|
static final String ZOOM_ACTUAL = "zoom-actual";
|
||||||
|
static final String ZOOM_FIT = "zoom-fit";
|
||||||
|
|
||||||
private BufferedImage image;
|
private BufferedImage image;
|
||||||
|
|
||||||
@@ -525,9 +516,20 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
|
|
||||||
private void setupActions() {
|
private void setupActions() {
|
||||||
// Mac weirdness... VK_MINUS/VK_PLUS seems to map to english key map always...
|
// 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 in", 2), ZOOM_IN,
|
||||||
bindAction(new ZoomAction("Zoom out", .5), ZOOM_OUT, KeyStroke.getKeyStroke('-'), KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0));
|
KeyStroke.getKeyStroke('+'),
|
||||||
bindAction(new ZoomAction("Zoom actual"), ZOOM_ACTUAL, KeyStroke.getKeyStroke('0'), KeyStroke.getKeyStroke(KeyEvent.VK_0, 0));
|
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.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()));
|
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() {
|
private JPopupMenu createPopupMenu() {
|
||||||
JPopupMenu popup = new JPopupMenu();
|
JPopupMenu popup = new JPopupMenu();
|
||||||
|
|
||||||
|
popup.add(getActionMap().get(ZOOM_FIT));
|
||||||
popup.add(getActionMap().get(ZOOM_ACTUAL));
|
popup.add(getActionMap().get(ZOOM_ACTUAL));
|
||||||
popup.add(getActionMap().get(ZOOM_IN));
|
popup.add(getActionMap().get(ZOOM_IN));
|
||||||
popup.add(getActionMap().get(ZOOM_OUT));
|
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("Dark", Color.DARK_GRAY), background, group);
|
||||||
addCheckBoxItem(new ChangeBackgroundAction("Black", Color.BLACK), background, group);
|
addCheckBoxItem(new ChangeBackgroundAction("Black", Color.BLACK), background, group);
|
||||||
background.addSeparator();
|
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);
|
chooseBackgroundAction.putValue(Action.SELECTED_KEY, backgroundPaint == defaultBG);
|
||||||
addCheckBoxItem(chooseBackgroundAction, background, group);
|
addCheckBoxItem(chooseBackgroundAction, background, group);
|
||||||
|
|
||||||
@@ -678,14 +681,41 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Icon current = getIcon();
|
Icon current = getIcon();
|
||||||
int w = (int) Math.max(Math.min(current.getIconWidth() * zoomFactor, image.getWidth() * 16), image.getWidth() / 16);
|
int w = Math.max(Math.min((int) (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 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()));
|
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 static class ImageTransferable implements Transferable {
|
||||||
private final BufferedImage image;
|
private final BufferedImage image;
|
||||||
|
|
||||||
@@ -704,7 +734,7 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getTransferData(final DataFlavor flavor) throws UnsupportedFlavorException, IOException {
|
public Object getTransferData(final DataFlavor flavor) throws UnsupportedFlavorException {
|
||||||
if (isDataFlavorSupported(flavor)) {
|
if (isDataFlavorSupported(flavor)) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-17
@@ -57,8 +57,10 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
|
|
||||||
private ImageInputStream stream;
|
private ImageInputStream stream;
|
||||||
|
|
||||||
private ByteBuffer buffer;
|
private ByteBuffer buffer;
|
||||||
private ByteBuffer integralCache = ByteBuffer.allocate(8);
|
|
||||||
|
private final ByteBuffer integralCache = ByteBuffer.allocate(8);
|
||||||
|
private final byte[] integralCacheArray = integralCache.array();
|
||||||
|
|
||||||
public BufferedImageInputStream(final ImageInputStream pStream) throws IOException {
|
public BufferedImageInputStream(final ImageInputStream pStream) throws IOException {
|
||||||
this(pStream, DEFAULT_BUFFER_SIZE);
|
this(pStream, DEFAULT_BUFFER_SIZE);
|
||||||
@@ -97,10 +99,10 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
|
|
||||||
if (!buffer.hasRemaining()) {
|
if (!buffer.hasRemaining()) {
|
||||||
fillBuffer();
|
fillBuffer();
|
||||||
}
|
|
||||||
|
|
||||||
if (!buffer.hasRemaining()) {
|
if (!buffer.hasRemaining()) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitOffset = 0;
|
bitOffset = 0;
|
||||||
@@ -172,21 +174,21 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short readShort() throws IOException {
|
public short readShort() throws IOException {
|
||||||
readFully(integralCache.array(), 0, 2);
|
readFully(integralCacheArray, 0, 2);
|
||||||
|
|
||||||
return integralCache.getShort(0);
|
return integralCache.getShort(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readInt() throws IOException {
|
public int readInt() throws IOException {
|
||||||
readFully(integralCache.array(), 0, 4);
|
readFully(integralCacheArray, 0, 4);
|
||||||
|
|
||||||
return integralCache.getInt(0);
|
return integralCache.getInt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long readLong() throws IOException {
|
public long readLong() throws IOException {
|
||||||
readFully(integralCache.array(), 0, 8);
|
readFully(integralCacheArray, 0, 8);
|
||||||
|
|
||||||
return integralCache.getLong(0);
|
return integralCache.getLong(0);
|
||||||
}
|
}
|
||||||
@@ -253,6 +255,7 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
int val = buffer.get() & 0xff;
|
int val = buffer.get() & 0xff;
|
||||||
|
streamPos++;
|
||||||
|
|
||||||
accum <<= 8;
|
accum <<= 8;
|
||||||
accum |= val;
|
accum |= val;
|
||||||
@@ -262,9 +265,7 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
// Move byte position back if in the middle of a byte
|
// Move byte position back if in the middle of a byte
|
||||||
if (newBitOffset != 0) {
|
if (newBitOffset != 0) {
|
||||||
buffer.position(buffer.position() - 1);
|
buffer.position(buffer.position() - 1);
|
||||||
}
|
streamPos--;
|
||||||
else {
|
|
||||||
streamPos++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bitOffset = newBitOffset;
|
this.bitOffset = newBitOffset;
|
||||||
@@ -279,26 +280,26 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seek(long pPosition) throws IOException {
|
public void seek(long position) throws IOException {
|
||||||
checkClosed();
|
checkClosed();
|
||||||
bitOffset = 0;
|
bitOffset = 0;
|
||||||
|
|
||||||
if (streamPos == pPosition) {
|
if (streamPos == position) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimized to not invalidate buffer if new position is within current buffer
|
// 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()) {
|
if (newBufferPos >= 0 && newBufferPos <= buffer.limit()) {
|
||||||
buffer.position((int) newBufferPos);
|
buffer.position((int) newBufferPos);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Will invalidate buffer
|
// Will invalidate buffer
|
||||||
buffer.limit(0);
|
buffer.limit(0);
|
||||||
stream.seek(pPosition);
|
stream.seek(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
streamPos = pPosition;
|
streamPos = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -330,7 +331,9 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (stream != null) {
|
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;
|
stream = null;
|
||||||
buffer = null;
|
buffer = null;
|
||||||
}
|
}
|
||||||
|
|||||||
+254
@@ -32,16 +32,19 @@ package com.twelvemonkeys.imageio.stream;
|
|||||||
|
|
||||||
import com.twelvemonkeys.io.ole2.CompoundDocument;
|
import com.twelvemonkeys.io.ole2.CompoundDocument;
|
||||||
import com.twelvemonkeys.io.ole2.Entry;
|
import com.twelvemonkeys.io.ole2.Entry;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static java.util.Arrays.fill;
|
import static java.util.Arrays.fill;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BufferedImageInputStreamTest
|
* 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: Write other tests
|
||||||
|
|
||||||
// TODO: Create test that exposes read += -1 (eof) bug
|
// 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);
|
int actualRGB = actual.getRGB(x, y);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
assertEquals(String.format("%s alpha at (%d, %d)", message, x, y), (expectedRGB >>> 24) & 0xff, (actualRGB >>> 24) & 0xff, 5);
|
assertEquals((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((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((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 & 0xff, actualRGB & 0xff, 5);
|
||||||
}
|
}
|
||||||
catch (AssertionError e) {
|
catch (AssertionError e) {
|
||||||
File tempExpected = File.createTempFile("junit-expected-", ".png");
|
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());
|
System.err.println("tempActual.getAbsolutePath(): " + tempActual.getAbsolutePath());
|
||||||
ImageIO.write(actual, "PNG", tempActual);
|
ImageIO.write(actual, "PNG", tempActual);
|
||||||
|
|
||||||
|
|
||||||
assertEquals(String.format("%s ARGB at (%d, %d)", message, x, y), String.format("#%08x", expectedRGB), String.format("#%08x", actualRGB));
|
assertEquals(String.format("%s ARGB at (%d, %d)", message, x, y), String.format("#%08x", expectedRGB), String.format("#%08x", actualRGB));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-hdr</artifactId>
|
<artifactId>imageio-hdr</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-icns</artifactId>
|
<artifactId>imageio-icns</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-iff</artifactId>
|
<artifactId>imageio-iff</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-jpeg</artifactId>
|
<artifactId>imageio-jpeg</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
|
||||||
|
|||||||
+103
-88
@@ -30,37 +30,6 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
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.ImageReaderBase;
|
||||||
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||||
import com.twelvemonkeys.imageio.color.YCbCrConverter;
|
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.jpeg.JPEGSegmentUtil;
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
||||||
import com.twelvemonkeys.imageio.stream.BufferedImageInputStream;
|
|
||||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
@@ -80,6 +48,24 @@ import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
|||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
import com.twelvemonkeys.xml.XMLSerializer;
|
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},
|
* A JPEG {@code ImageReader} implementation based on the JRE {@code JPEGImageReader},
|
||||||
* that adds support and properly handles cases where the JRE version throws exceptions.
|
* 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 List<Segment> segments;
|
||||||
|
|
||||||
private int currentStreamIndex = 0;
|
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) {
|
protected JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
|
||||||
super(provider);
|
super(provider);
|
||||||
@@ -192,19 +178,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
private boolean isLossless() throws IOException {
|
private boolean isLossless() throws IOException {
|
||||||
assertInput();
|
assertInput();
|
||||||
|
|
||||||
try {
|
return getSOF().marker == JPEG.SOF3;
|
||||||
if (getSOF().marker == JPEG.SOF3) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IIOException ignore) {
|
|
||||||
// May happen if no SOF is found, in case we'll just fall through
|
|
||||||
if (DEBUG) {
|
|
||||||
ignore.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -747,26 +721,26 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
long lastKnownSOIOffset = streamOffsets.get(streamOffsets.size() - 1);
|
long lastKnownSOIOffset = streamOffsets.get(streamOffsets.size() - 1);
|
||||||
imageInput.seek(lastKnownSOIOffset);
|
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++) {
|
for (int i = streamOffsets.size() - 1; i < imageIndex; i++) {
|
||||||
long start = 0;
|
long start = 0;
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
start = System.currentTimeMillis();
|
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)
|
// 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...
|
// Now, search for EOI and following SOI...
|
||||||
int marker;
|
int marker;
|
||||||
while ((marker = stream.read()) != -1) {
|
while ((marker = imageInput.read()) != -1) {
|
||||||
if (marker == 0xFF && (0xFF00 | stream.readUnsignedByte()) == JPEG.EOI) {
|
if (marker == 0xFF && (0xFF00 | imageInput.readUnsignedByte()) == JPEG.EOI) {
|
||||||
// Found EOI, now the SOI should be nearby...
|
// Found EOI, now the SOI should be nearby...
|
||||||
while ((marker = stream.read()) != -1) {
|
while ((marker = imageInput.read()) != -1) {
|
||||||
if (marker == 0xFF && (0xFF00 | stream.readUnsignedByte()) == JPEG.SOI) {
|
if (marker == 0xFF && (0xFF00 | imageInput.readUnsignedByte()) == JPEG.SOI) {
|
||||||
long nextSOIOffset = stream.getStreamPosition() - 2;
|
long nextSOIOffset = imageInput.getStreamPosition() - 2;
|
||||||
imageInput.seek(nextSOIOffset);
|
imageInput.seek(nextSOIOffset);
|
||||||
streamOffsets.add(nextSOIOffset);
|
streamOffsets.add(nextSOIOffset);
|
||||||
|
|
||||||
@@ -780,10 +754,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG) {
|
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) {
|
catch (EOFException eof) {
|
||||||
IndexOutOfBoundsException ioobe = new IndexOutOfBoundsException("Image index " + imageIndex + " not found in stream");
|
IndexOutOfBoundsException ioobe = new IndexOutOfBoundsException("Image index " + imageIndex + " not found in stream");
|
||||||
@@ -843,9 +816,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
return JPEGSegmentUtil.readSegments(imageInput, JPEGSegmentUtil.ALL_SEGMENTS);
|
return JPEGSegmentUtil.readSegments(imageInput, JPEGSegmentUtil.ALL_SEGMENTS);
|
||||||
}
|
}
|
||||||
catch (IIOException | IllegalArgumentException ignore) {
|
catch (IIOException | IllegalArgumentException e) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
ignore.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@@ -919,6 +892,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
try (ImageInputStream stream = new ByteArrayImageInputStream(exif.data, offset, exif.data.length - offset)) {
|
try (ImageInputStream stream = new ByteArrayImageInputStream(exif.data, offset, exif.data.length - offset)) {
|
||||||
return (CompoundDirectory) new TIFFReader().read(stream);
|
return (CompoundDirectory) new TIFFReader().read(stream);
|
||||||
}
|
}
|
||||||
|
catch (IIOException e) {
|
||||||
|
processWarningOccurred("Exif chunk is present, but can't be read: " + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1106,6 +1082,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
// Read JFIF thumbnails if present
|
// Read JFIF thumbnails if present
|
||||||
JFIF jfif = getJFIF();
|
JFIF jfif = getJFIF();
|
||||||
if (jfif != null && jfif.thumbnail != null) {
|
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));
|
thumbnails.add(new JFIFThumbnailReader(thumbnailProgressDelegator, imageIndex, thumbnails.size(), jfif));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1116,6 +1093,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
case JFXX.JPEG:
|
case JFXX.JPEG:
|
||||||
case JFXX.INDEXED:
|
case JFXX.INDEXED:
|
||||||
case JFXX.RGB:
|
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));
|
thumbnails.add(new JFXXThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), imageIndex, thumbnails.size(), jfxx));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1129,48 +1107,77 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
Application exif = exifSegments.get(0);
|
Application exif = exifSegments.get(0);
|
||||||
|
|
||||||
// Identifier is "Exif\0" + 1 byte pad
|
// 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.");
|
processWarningOccurred("Exif chunk has no data.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ImageInputStream stream = new ByteArrayImageInputStream(exif.data, offset, exif.data.length - offset);
|
ImageInputStream stream = new ByteArrayImageInputStream(exif.data, dataOffset, exif.data.length - dataOffset);
|
||||||
CompoundDirectory exifMetadata = (CompoundDirectory) new TIFFReader().read(stream);
|
try {
|
||||||
|
CompoundDirectory exifMetadata = (CompoundDirectory) new TIFFReader().read(stream);
|
||||||
|
|
||||||
if (exifMetadata.directoryCount() == 2) {
|
if (exifMetadata.directoryCount() == 2) {
|
||||||
Directory ifd1 = exifMetadata.getDirectory(1);
|
Directory ifd1 = exifMetadata.getDirectory(1);
|
||||||
|
|
||||||
// Compression: 1 = no compression, 6 = JPEG compression (default)
|
// Compression: 1 = no compression, 6 = JPEG compression (default)
|
||||||
Entry compressionEntry = ifd1.getEntryById(TIFF.TAG_COMPRESSION);
|
Entry compressionEntry = ifd1.getEntryById(TIFF.TAG_COMPRESSION);
|
||||||
int compression = compressionEntry == null ? 6 : ((Number) compressionEntry.getValue()).intValue();
|
int compression = compressionEntry == null ? 6 : ((Number) compressionEntry.getValue()).intValue();
|
||||||
|
|
||||||
if (compression == 6) {
|
if (compression == 6) {
|
||||||
if (ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT) != null) {
|
Entry jpegOffEntry = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||||
Entry jpegLength = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
if (jpegOffEntry != null) {
|
||||||
|
Entry jpegLenEntry = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||||
|
|
||||||
if ((jpegLength == null || ((Number) jpegLength.getValue()).longValue() > 0)) {
|
// Test if Exif thumbnail is contained within the Exif segment (offset + length <= segment.length)
|
||||||
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
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 {
|
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 {
|
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) {
|
catch (IIOException e) {
|
||||||
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
processWarningOccurred("Exif chunk present, but can't be read: " + e.getMessage());
|
||||||
}
|
|
||||||
else {
|
|
||||||
processWarningOccurred("EXIF IFD with uncompressed thumbnail missing StripOffsets tag");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
processWarningOccurred("EXIF IFD with unknown compression (expected 1 or 6): " + compression);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1215,7 +1222,15 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
|
public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
|
||||||
checkThumbnailBounds(imageIndex, thumbnailIndex);
|
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
|
// Metadata
|
||||||
@@ -1392,7 +1407,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
final String arg = args[argIdx];
|
final String arg = args[argIdx];
|
||||||
|
|
||||||
if (arg.charAt(0) == '-') {
|
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(",");
|
String[] sub = args[++argIdx].split(",");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1411,7 +1426,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
System.err.println("Bad sub sampling (x,y): '" + args[argIdx] + "'");
|
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(",");
|
String[] region = args[++argIdx].split(",");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
+7
-2
@@ -572,12 +572,17 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(final ImageInputStream stream) {
|
public int read(final ImageInputStream stream) {
|
||||||
return data[pos++] & 0xff;
|
return data.length > pos ? data[pos++] & 0xff : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(final ImageInputStream stream, byte[] b, int off, int len) {
|
public int read(final ImageInputStream stream, byte[] b, int off, int len) {
|
||||||
int length = Math.min(data.length - pos, len);
|
int dataLeft = data.length - pos;
|
||||||
|
if (dataLeft <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length = Math.min(dataLeft, len);
|
||||||
System.arraycopy(data, pos, b, off, length);
|
System.arraycopy(data, pos, b, off, length);
|
||||||
pos += length;
|
pos += length;
|
||||||
|
|
||||||
|
|||||||
+34
@@ -61,6 +61,8 @@ import java.util.List;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.util.IIOUtil.lookupProviderByName;
|
import static com.twelvemonkeys.imageio.util.IIOUtil.lookupProviderByName;
|
||||||
|
import static org.hamcrest.CoreMatchers.allOf;
|
||||||
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assume.assumeNoException;
|
import static org.junit.Assume.assumeNoException;
|
||||||
@@ -1959,4 +1961,36 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 1000L)
|
||||||
|
public void testInfiniteLoopCorrupt() throws IOException {
|
||||||
|
ImageReader reader = createReader();
|
||||||
|
|
||||||
|
try (ImageInputStream iis = ImageIO.createImageInputStream(getClassLoaderResource("/broken-jpeg/110115680-6d6dce80-7d84-11eb-99df-4cb21df3b09f.jpeg"))) {
|
||||||
|
reader.setInput(iis);
|
||||||
|
|
||||||
|
try {
|
||||||
|
reader.read(0, null);
|
||||||
|
}
|
||||||
|
catch (IIOException expected) {
|
||||||
|
assertThat(expected.getMessage(), allOf(containsString("SOF"), containsString("stream")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 1000L)
|
||||||
|
public void testInfiniteLoopCorruptRaster() throws IOException {
|
||||||
|
ImageReader reader = createReader();
|
||||||
|
|
||||||
|
try (ImageInputStream iis = ImageIO.createImageInputStream(getClassLoaderResource("/broken-jpeg/110115680-6d6dce80-7d84-11eb-99df-4cb21df3b09f.jpeg"))) {
|
||||||
|
reader.setInput(iis);
|
||||||
|
|
||||||
|
try {
|
||||||
|
reader.readRaster(0, null);
|
||||||
|
}
|
||||||
|
catch (IIOException expected) {
|
||||||
|
assertThat(expected.getMessage(), allOf(containsString("SOF"), containsString("stream")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
@@ -228,4 +228,29 @@ public class JPEGSegmentImageInputStreamTest {
|
|||||||
assertEquals(-1, iis.read());
|
assertEquals(-1, iis.read());
|
||||||
assertEquals(0x2012, iis.getStreamPosition());
|
assertEquals(0x2012, iis.getStreamPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test(timeout = 1000L)
|
||||||
|
public void testInfiniteLoopCorrupt() throws IOException {
|
||||||
|
try (ImageInputStream stream = new JPEGSegmentImageInputStream(ImageIO.createImageInputStream(getClassLoaderResource("/broken-jpeg/110115680-6d6dce80-7d84-11eb-99df-4cb21df3b09f.jpeg")))) {
|
||||||
|
long length = 0;
|
||||||
|
while (stream.read() != -1) {
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(25504L, length); // Sanity check: same as file size, except..?
|
||||||
|
}
|
||||||
|
|
||||||
|
try (ImageInputStream stream = new JPEGSegmentImageInputStream(ImageIO.createImageInputStream(getClassLoaderResource("/broken-jpeg/110115680-6d6dce80-7d84-11eb-99df-4cb21df3b09f.jpeg")))) {
|
||||||
|
long length = 0;
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int read;
|
||||||
|
while ((read = stream.read(buffer)) != -1) {
|
||||||
|
length += read;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(25504L, length); // Sanity check: same as file size, except..?
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>imageio-metadata</artifactId>
|
<artifactId>imageio-metadata</artifactId>
|
||||||
|
|||||||
+4
-2
@@ -48,7 +48,7 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
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) {
|
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 {
|
static void readSOI(final ImageInputStream stream) throws IOException {
|
||||||
@@ -348,6 +348,7 @@ public final class JPEGSegmentUtil {
|
|||||||
else if ("Photoshop 3.0".equals(segment.identifier())) {
|
else if ("Photoshop 3.0".equals(segment.identifier())) {
|
||||||
// TODO: The "Photoshop 3.0" segment contains several image resources, of which one might contain
|
// TODO: The "Photoshop 3.0" segment contains several image resources, of which one might contain
|
||||||
// IPTC metadata. Probably duplicated in the XMP though...
|
// 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());
|
ImageInputStream stream = new ByteArrayImageInputStream(segment.data, segment.offset(), segment.length());
|
||||||
Directory psd = new PSDReader().read(stream);
|
Directory psd = new PSDReader().read(stream);
|
||||||
Entry iccEntry = psd.getEntryById(PSD.RES_ICC_PROFILE);
|
Entry iccEntry = psd.getEntryById(PSD.RES_ICC_PROFILE);
|
||||||
@@ -359,6 +360,7 @@ public final class JPEGSegmentUtil {
|
|||||||
System.err.println(TIFFReader.HexDump.dump(segment.data));
|
System.err.println(TIFFReader.HexDump.dump(segment.data));
|
||||||
}
|
}
|
||||||
else if ("ICC_PROFILE".equals(segment.identifier())) {
|
else if ("ICC_PROFILE".equals(segment.identifier())) {
|
||||||
|
// TODO: Merge multiple APP2 segments to single ICC Profile
|
||||||
// Skip
|
// Skip
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-pcx</artifactId>
|
<artifactId>imageio-pcx</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: PCX plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PCX plugin</name>
|
||||||
|
|||||||
+2
-1
@@ -64,7 +64,7 @@ public class PCXImageReaderTest extends ImageReaderAbstractTest<PCXImageReader>
|
|||||||
@Override
|
@Override
|
||||||
protected List<TestData> getTestData() {
|
protected List<TestData> getTestData() {
|
||||||
return Arrays.asList(
|
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/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/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)
|
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/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/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/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)
|
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
|
// 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)
|
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>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-pdf</artifactId>
|
<artifactId>imageio-pdf</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: PDF plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PDF plugin</name>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-pict</artifactId>
|
<artifactId>imageio-pict</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: PICT plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PICT plugin</name>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-pnm</artifactId>
|
<artifactId>imageio-pnm</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: PNM plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PNM plugin</name>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-psd</artifactId>
|
<artifactId>imageio-psd</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: PSD plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PSD plugin</name>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-reference</artifactId>
|
<artifactId>imageio-reference</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: reference test cases</name>
|
<name>TwelveMonkeys :: ImageIO :: reference test cases</name>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-sgi</artifactId>
|
<artifactId>imageio-sgi</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: SGI plugin</name>
|
<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 {
|
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 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) {
|
if (compression == SGI.COMPRESSION_NONE) {
|
||||||
imageInput.skipBytes(rowDataByte.length);
|
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)
|
// 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);
|
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 {
|
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 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) {
|
if (compression == SGI.COMPRESSION_NONE) {
|
||||||
imageInput.skipBytes(rowDataUShort.length * 2);
|
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)
|
// 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);
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -53,7 +53,8 @@ public class SGIImageReaderTest extends ImageReaderAbstractTest<SGIImageReader>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<TestData> getTestData() {
|
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
|
new TestData(getClassLoaderResource("/sgi/MARBLES.SGI"), new Dimension(1419, 1001)) // RLE encoded RGB
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-tga</artifactId>
|
<artifactId>imageio-tga</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: TGA plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: TGA plugin</name>
|
||||||
|
|||||||
+18
-4
@@ -200,12 +200,12 @@ final class TGAHeader {
|
|||||||
int components = colorMap.hasAlpha() ? 4 : 3;
|
int components = colorMap.hasAlpha() ? 4 : 3;
|
||||||
byte[] cmap = new byte[rgb.length * components];
|
byte[] cmap = new byte[rgb.length * components];
|
||||||
for (int i = 0; i < rgb.length; i++) {
|
for (int i = 0; i < rgb.length; i++) {
|
||||||
cmap[i * components ] = (byte) ((rgb[i] >> 16) & 0xff);
|
cmap[i * components ] = (byte) ((rgb[i] ) & 0xff); // B
|
||||||
cmap[i * components + 1] = (byte) ((rgb[i] >> 8) & 0xff);
|
cmap[i * components + 1] = (byte) ((rgb[i] >> 8) & 0xff); // G
|
||||||
cmap[i * components + 2] = (byte) ((rgb[i] ) & 0xff);
|
cmap[i * components + 2] = (byte) ((rgb[i] >> 16) & 0xff); // R
|
||||||
|
|
||||||
if (components == 4) {
|
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;
|
hasAlpha = false;
|
||||||
break;
|
break;
|
||||||
case 24:
|
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;
|
hasAlpha = false;
|
||||||
break;
|
break;
|
||||||
case 32:
|
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;
|
hasAlpha = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
+5
-3
@@ -224,7 +224,7 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
byte[] rowDataByte, WritableRaster destChannel, Raster srcChannel, int y) throws IOException {
|
byte[] rowDataByte, WritableRaster destChannel, Raster srcChannel, int y) throws IOException {
|
||||||
// If subsampled or outside source region, skip entire row
|
// 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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -251,7 +251,8 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
destChannel.setDataElements(0, dstY, srcChannel);
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
break;
|
break;
|
||||||
case TGA.ORIGIN_UPPER_LEFT:
|
case TGA.ORIGIN_UPPER_LEFT:
|
||||||
destChannel.setDataElements(0, y, srcChannel);
|
dstY = y / ySub;
|
||||||
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IIOException("Unsupported origin: " + origin);
|
throw new IIOException("Unsupported origin: " + origin);
|
||||||
@@ -289,7 +290,8 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
destChannel.setDataElements(0, dstY, srcChannel);
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
break;
|
break;
|
||||||
case TGA.ORIGIN_UPPER_LEFT:
|
case TGA.ORIGIN_UPPER_LEFT:
|
||||||
destChannel.setDataElements(0, y, srcChannel);
|
dstY = y / ySub;
|
||||||
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IIOException("Unsupported origin: " + origin);
|
throw new IIOException("Unsupported origin: " + origin);
|
||||||
|
|||||||
+1
@@ -189,6 +189,7 @@ final class TGAMetadata extends AbstractMetadata {
|
|||||||
switch (header.getPixelDepth()) {
|
switch (header.getPixelDepth()) {
|
||||||
case 8:
|
case 8:
|
||||||
bitsPerSample.setAttribute("value", createListValue(1, Integer.toString(header.getPixelDepth())));
|
bitsPerSample.setAttribute("value", createListValue(1, Integer.toString(header.getPixelDepth())));
|
||||||
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
if (header.getAttributeBits() > 0 && extensions != null && extensions.hasAlpha()) {
|
if (header.getAttributeBits() > 0 && extensions != null && extensions.hasAlpha()) {
|
||||||
bitsPerSample.setAttribute("value", "5, 5, 5, 1");
|
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 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.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TGAImageReaderTest
|
* TGAImageReaderTest
|
||||||
*
|
*
|
||||||
@@ -104,4 +112,23 @@ public class TGAImageReaderTest extends ImageReaderAbstractTest<TGAImageReader>
|
|||||||
"image/targa", "image/x-targa"
|
"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>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-thumbsdb</artifactId>
|
<artifactId>imageio-thumbsdb</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: Thumbs.db plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: Thumbs.db plugin</name>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-tiff</artifactId>
|
<artifactId>imageio-tiff</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: TIFF plugin</name>
|
<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 {
|
static int findCompressionType(final int type, final InputStream in) throws IOException {
|
||||||
// Discover possible incorrect type, revert to RLE
|
// Discover possible incorrect type, revert to RLE
|
||||||
if (type == TIFFExtension.COMPRESSION_CCITT_T4 && in.markSupported()) {
|
if (type == TIFFExtension.COMPRESSION_CCITT_T4 && in.markSupported()) {
|
||||||
byte[] streamData = new byte[20];
|
byte[] streamData = new byte[32];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
in.mark(streamData.length);
|
in.mark(streamData.length);
|
||||||
@@ -173,8 +173,9 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
|
|||||||
|
|
||||||
if (streamData[0] != 0 || (streamData[1] >> 4 != 1 && streamData[1] != 1)) {
|
if (streamData[0] != 0 || (streamData[1] >> 4 != 1 && streamData[1] != 1)) {
|
||||||
// Leading EOL (0b000000000001) not found, search further and try RLE if not found
|
// 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);
|
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));
|
b = (short) ((b << 1) + ((streamData[(i / 8)] >> (7 - (i % 8))) & 0x01));
|
||||||
|
|
||||||
if ((b & 0xFFF) == 1) {
|
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
|
// 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
|
// group3_2d_fill.tif
|
||||||
static final byte[] DATA_G3_2D_FILL = { 0x00, 0x01, (byte) 0xC2, 0x70, 0x01, 0x70, 0x01, (byte) 0xC2, 0x70, 0x01,
|
static final byte[] DATA_G3_2D_FILL = {0x00, 0x01, (byte) 0xC2, 0x70, 0x01, 0x70, 0x01, (byte) 0xC2,
|
||||||
0x2C };
|
0x70, 0x01, 0x2C};
|
||||||
|
|
||||||
static final byte[] DATA_G3_2D_lsb2msb = { 0x00, 0x38, (byte) 0xE4, 0x00, (byte) 0xE8, 0x00, 0x38, (byte) 0xE4,
|
static final byte[] DATA_G3_2D_lsb2msb = {0x00, 0x38, (byte) 0xE4, 0x00, (byte) 0xE8, 0x00, 0x38, (byte) 0xE4,
|
||||||
0x00, 0x48, 0x03 };
|
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:
|
// group4.tif:
|
||||||
// Line 1: V-3, V-2, V0
|
// 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)));
|
||||||
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_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_2D_lsb2msb)));
|
||||||
|
assertEquals(TIFFExtension.COMPRESSION_CCITT_T4, CCITTFaxDecoderStream.findCompressionType(TIFFExtension.COMPRESSION_CCITT_T4, new ByteArrayInputStream(DATA_G3_LONG)));
|
||||||
|
|
||||||
// Group 4/CCITT_T6
|
// Group 4/CCITT_T6
|
||||||
assertEquals(TIFFExtension.COMPRESSION_CCITT_T6, CCITTFaxDecoderStream.findCompressionType(TIFFExtension.COMPRESSION_CCITT_T6, new ByteArrayInputStream(DATA_G4)));
|
assertEquals(TIFFExtension.COMPRESSION_CCITT_T6, CCITTFaxDecoderStream.findCompressionType(TIFFExtension.COMPRESSION_CCITT_T6, new ByteArrayInputStream(DATA_G4)));
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>Twelvemonkeys</name>
|
<name>Twelvemonkeys</name>
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@
|
|||||||
<connection>scm:git:https://github.com/haraldk/TwelveMonkeys</connection>
|
<connection>scm:git:https://github.com/haraldk/TwelveMonkeys</connection>
|
||||||
<developerConnection>scm:git:ssh://git@github.com/haraldk/TwelveMonkeys</developerConnection>
|
<developerConnection>scm:git:ssh://git@github.com/haraldk/TwelveMonkeys</developerConnection>
|
||||||
<url>https://github.com/haraldk/TwelveMonkeys</url>
|
<url>https://github.com/haraldk/TwelveMonkeys</url>
|
||||||
<tag>twelvemonkeys-3.6.1</tag>
|
<tag>twelvemonkeys-3.6</tag>
|
||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.6.1</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|||||||
Reference in New Issue
Block a user