mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-20 00:00:03 -04:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c61e47b3e7 | |||
| 1d47d2ef90 | |||
| 94554b0660 | |||
| a39bca4d2f | |||
| fdbbcc54a8 | |||
| 00cd9471dd | |||
| eb6a3bde39 | |||
| d3dd4c29d5 | |||
| 3355acfa03 | |||
| b70e52561a | |||
| 49ddbfa85e | |||
| 215db21569 | |||
| 0ac8011053 | |||
| abbbca9be3 | |||
| bc5473aec6 | |||
| aca8b1256a | |||
| 18c1edf0e5 | |||
| 6a01466ebb | |||
| b19df1640b | |||
| e8e3e0f1d6 | |||
| c249a21c8c | |||
| 182b2fdfa9 | |||
| df068e350d | |||
| b55c623b87 | |||
| 09573b52ac | |||
| ff7edbd223 | |||
| d8f0cd97a2 | |||
| f6971a9bce | |||
| 821965df0d | |||
| ed46305d31 | |||
| ca3adb7c45 | |||
| 59f76209bc | |||
| 2076235313 | |||
| 88bebf31f8 | |||
| 37beb21c29 | |||
| 88c0d27516 | |||
| dcd4ffccf4 | |||
| f35f5c6b24 | |||
| 9dcf53d985 | |||
| 44a2066b79 | |||
| 382c51db7c | |||
| 660f3f7e86 | |||
| b4c30872c4 | |||
| 402d4d466d | |||
| 7860bf7e17 | |||
| d52522fb80 | |||
| 8a8c6b1931 | |||
| 2930708a54 | |||
| 5661e7459c | |||
| 4d45ea4966 | |||
| 34852f7be5 | |||
| abc929a531 | |||
| 247a09ca61 | |||
| c2880fe793 | |||
| c9e522475b | |||
| 1da16e4d7a |
@@ -0,0 +1 @@
|
|||||||
|
github: haraldk
|
||||||
+5
-3
@@ -1,9 +1,11 @@
|
|||||||
dist: trusty
|
dist: trusty
|
||||||
language: java
|
language: java
|
||||||
jdk:
|
jdk:
|
||||||
- oraclejdk8 # Legacy
|
- oraclejdk8 # LTS until Mar 2022
|
||||||
- oraclejdk11 # LTS
|
- oraclejdk11 # LTS until Sep 2023
|
||||||
- oraclejdk15 # Latest
|
- oraclejdk15 # out of support
|
||||||
|
- oraclejdk16 # out of support
|
||||||
|
- oraclejdk17 # LTS until Sep 2026
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
# Extra job, testing legacy CMM option
|
# Extra job, testing legacy CMM option
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
[](https://travis-ci.org/haraldk/TwelveMonkeys)
|
[](https://travis-ci.com/github/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
|
||||||
|
|
||||||
TwelveMonkeys ImageIO is a collection of plugins and extensions for Java's ImageIO.
|
TwelveMonkeys ImageIO provides extended image file format support for the Java platform, through plugins for the `javax.imageio.*` package.
|
||||||
|
|
||||||
These plugins extend the number of image file formats supported in Java, using the `javax.imageio.*` package.
|
The main goal of this project is to provide support for formats not covered by the JRE itself.
|
||||||
The main purpose of this project is to provide support for formats not covered by the JRE itself.
|
Support for these formats is important, to be able to read data found
|
||||||
|
|
||||||
Support for formats is important, both to be able to read data found
|
|
||||||
"in the wild", as well as to maintain access to data in legacy formats.
|
"in the wild", as well as to maintain access to data in legacy formats.
|
||||||
Because there is lots of legacy data out there, we see the need for open implementations of readers for popular formats.
|
As there is lots of legacy data out there, we see the need for open implementations of readers for popular formats.
|
||||||
The goal is to create a set of efficient and robust ImageIO plug-ins, that can be distributed independently.
|
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
@@ -47,11 +44,11 @@ The goal is to create a set of efficient and robust ImageIO plug-ins, that can b
|
|||||||
|ThumbsDB| Thumbs.db| MS Windows Thumbs DB | âś” | - | - | OLE2 Compound Document based format only
|
|ThumbsDB| Thumbs.db| MS Windows Thumbs DB | âś” | - | - | OLE2 Compound Document based format only
|
||||||
| [TIFF](https://github.com/haraldk/TwelveMonkeys/wiki/TIFF-Plugin) | **TIFF** | Aldus/Adobe Tagged Image File Format | âś” | âś” | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/tiff_metadata.html#ImageMetadata) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [TIFF](https://github.com/haraldk/TwelveMonkeys/wiki/TIFF-Plugin) | **TIFF** | Aldus/Adobe Tagged Image File Format | âś” | âś” | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/tiff_metadata.html#ImageMetadata) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||||
| | BigTIFF | | âś” | - | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/tiff_metadata.html#ImageMetadata) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| | BigTIFF | | âś” | - | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/tiff_metadata.html#ImageMetadata) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||||
| [WebP](https://github.com/haraldk/TwelveMonkeys/wiki/WebP-Plugin) | **WebP** | Google WebP Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) | In progress
|
| [WebP](https://github.com/haraldk/TwelveMonkeys/wiki/WebP-Plugin) | **WebP** | Google WebP Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||||
| XWD | XWD | X11 Window Dump Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| XWD | XWD | X11 Window Dump Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||||
|
|
||||||
|
|
||||||
**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](https://xmlgraphics.apache.org/security.html),
|
||||||
and make sure you use version 1.14 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
|
Note that GIF, PNG and WBMP formats are already supported through the ImageIO API, using the
|
||||||
@@ -166,7 +163,7 @@ finally {
|
|||||||
```
|
```
|
||||||
|
|
||||||
For more advanced usage, and information on how to use the ImageIO API, I suggest you read the
|
For more advanced usage, and information on how to use the ImageIO API, I suggest you read the
|
||||||
[Java Image I/O API Guide](http://docs.oracle.com/javase/7/docs/technotes/guides/imageio/spec/imageio_guideTOC.fm.html)
|
[Java Image I/O API Guide](https://docs.oracle.com/javase/7/docs/technotes/guides/imageio/spec/imageio_guideTOC.fm.html)
|
||||||
from Oracle.
|
from Oracle.
|
||||||
|
|
||||||
#### Adobe Clipping Path support
|
#### Adobe Clipping Path support
|
||||||
@@ -220,14 +217,14 @@ BufferedImage output = ditherer.filter(input, null);
|
|||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
Download the project (using [Git](http://git-scm.com/downloads)):
|
Download the project (using [Git](https://git-scm.com/downloads)):
|
||||||
|
|
||||||
$ git clone git@github.com:haraldk/TwelveMonkeys.git
|
$ git clone git@github.com:haraldk/TwelveMonkeys.git
|
||||||
|
|
||||||
This should create a folder named `TwelveMonkeys` in your current directory. Change directory to the `TwelveMonkeys`
|
This should create a folder named `TwelveMonkeys` in your current directory. Change directory to the `TwelveMonkeys`
|
||||||
folder, and issue the command below to build.
|
folder, and issue the command below to build.
|
||||||
|
|
||||||
Build the project (using [Maven](http://maven.apache.org/download.cgi)):
|
Build the project (using [Maven](https://maven.apache.org/download.cgi)):
|
||||||
|
|
||||||
$ mvn package
|
$ mvn package
|
||||||
|
|
||||||
@@ -274,12 +271,12 @@ 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.4</version>
|
<version>3.7.0</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.4</version>
|
<version>3.7.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@@ -289,7 +286,7 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||||
<artifactId>servlet</artifactId>
|
<artifactId>servlet</artifactId>
|
||||||
<version>3.6.4</version>
|
<version>3.7.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
```
|
```
|
||||||
@@ -298,13 +295,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.4.jar
|
twelvemonkeys-common-lang-3.7.0.jar
|
||||||
twelvemonkeys-common-io-3.6.4.jar
|
twelvemonkeys-common-io-3.7.0.jar
|
||||||
twelvemonkeys-common-image-3.6.4.jar
|
twelvemonkeys-common-image-3.7.0.jar
|
||||||
twelvemonkeys-imageio-core-3.6.4.jar
|
twelvemonkeys-imageio-core-3.7.0.jar
|
||||||
twelvemonkeys-imageio-metadata-3.6.4.jar
|
twelvemonkeys-imageio-metadata-3.7.0.jar
|
||||||
twelvemonkeys-imageio-jpeg-3.6.4.jar
|
twelvemonkeys-imageio-jpeg-3.7.0.jar
|
||||||
twelvemonkeys-imageio-tiff-3.6.4.jar
|
twelvemonkeys-imageio-tiff-3.7.0.jar
|
||||||
|
|
||||||
#### Deploying the plugins in a web app
|
#### Deploying the plugins in a web app
|
||||||
|
|
||||||
@@ -370,77 +367,79 @@ Other "fat" JAR bundlers will probably have similar mechanisms to merge entries
|
|||||||
|
|
||||||
### Links to prebuilt binaries
|
### Links to prebuilt binaries
|
||||||
|
|
||||||
##### Latest version (3.6.4)
|
##### Latest version (3.7.0)
|
||||||
|
|
||||||
Requires Java 7 or later.
|
Requires Java 7 or later.
|
||||||
|
|
||||||
Common dependencies
|
Common dependencies
|
||||||
* [common-lang-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.6.4/common-lang-3.6.4.jar)
|
* [common-lang-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.7.0/common-lang-3.7.0.jar)
|
||||||
* [common-io-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.6.4/common-io-3.6.4.jar)
|
* [common-io-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.7.0/common-io-3.7.0.jar)
|
||||||
* [common-image-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.6.4/common-image-3.6.4.jar)
|
* [common-image-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.7.0/common-image-3.7.0.jar)
|
||||||
|
|
||||||
ImageIO dependencies
|
ImageIO dependencies
|
||||||
* [imageio-core-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.6.4/imageio-core-3.6.4.jar)
|
* [imageio-core-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.7.0/imageio-core-3.7.0.jar)
|
||||||
* [imageio-metadata-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.6.4/imageio-metadata-3.6.4.jar)
|
* [imageio-metadata-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.7.0/imageio-metadata-3.7.0.jar)
|
||||||
|
|
||||||
ImageIO plugins
|
ImageIO plugins
|
||||||
* [imageio-bmp-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.6.4/imageio-bmp-3.6.4.jar)
|
* [imageio-bmp-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.7.0/imageio-bmp-3.7.0.jar)
|
||||||
* [imageio-hdr-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.6.4/imageio-hdr-3.6.4.jar)
|
* [imageio-hdr-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.7.0/imageio-hdr-3.7.0.jar)
|
||||||
* [imageio-icns-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.6.4/imageio-icns-3.6.4.jar)
|
* [imageio-icns-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.7.0/imageio-icns-3.7.0.jar)
|
||||||
* [imageio-iff-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.6.4/imageio-iff-3.6.4.jar)
|
* [imageio-iff-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.7.0/imageio-iff-3.7.0.jar)
|
||||||
* [imageio-jpeg-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.6.4/imageio-jpeg-3.6.4.jar)
|
* [imageio-jpeg-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.7.0/imageio-jpeg-3.7.0.jar)
|
||||||
* [imageio-pcx-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.6.4/imageio-pcx-3.6.4.jar)
|
* [imageio-pcx-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.7.0/imageio-pcx-3.7.0.jar)
|
||||||
* [imageio-pict-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.6.4/imageio-pict-3.6.4.jar)
|
* [imageio-pict-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.7.0/imageio-pict-3.7.0.jar)
|
||||||
* [imageio-pnm-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.6.4/imageio-pnm-3.6.4.jar)
|
* [imageio-pnm-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.7.0/imageio-pnm-3.7.0.jar)
|
||||||
* [imageio-psd-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.6.4/imageio-psd-3.6.4.jar)
|
* [imageio-psd-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.7.0/imageio-psd-3.7.0.jar)
|
||||||
* [imageio-sgi-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.6.4/imageio-sgi-3.6.4.jar)
|
* [imageio-sgi-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.7.0/imageio-sgi-3.7.0.jar)
|
||||||
* [imageio-tga-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.6.4/imageio-tga-3.6.4.jar)
|
* [imageio-tga-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.7.0/imageio-tga-3.7.0.jar)
|
||||||
* [imageio-thumbsdb-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.6.4/imageio-thumbsdb-3.6.4.jar)
|
* [imageio-thumbsdb-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.7.0/imageio-thumbsdb-3.7.0.jar)
|
||||||
* [imageio-tiff-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.6.4/imageio-tiff-3.6.4.jar)
|
* [imageio-tiff-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.7.0/imageio-tiff-3.7.0.jar)
|
||||||
|
* [imageio-webp-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-webp/3.7.0/imageio-webp-3.7.0.jar)
|
||||||
|
* [imageio-xwd-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-xwd/3.7.0/imageio-xwd-3.7.0.jar)
|
||||||
|
|
||||||
ImageIO plugins requiring 3rd party libs
|
ImageIO plugins requiring 3rd party libs
|
||||||
* [imageio-batik-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.6.4/imageio-batik-3.6.4.jar)
|
* [imageio-batik-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.7.0/imageio-batik-3.7.0.jar)
|
||||||
|
|
||||||
Photoshop Path support for ImageIO
|
Photoshop Path support for ImageIO
|
||||||
* [imageio-clippath-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.6.4/imageio-clippath-3.6.4.jar)
|
* [imageio-clippath-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.7.0/imageio-clippath-3.7.0.jar)
|
||||||
|
|
||||||
Servlet support
|
Servlet support
|
||||||
* [servlet-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.6.4/servlet-3.6.4.jar)
|
* [servlet-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.7.0/servlet-3.7.0.jar)
|
||||||
|
|
||||||
##### Old version (3.0.x)
|
##### Old version (3.0.x)
|
||||||
|
|
||||||
Use this version for projects that requires Java 6 or need the JMagick support. *Does not support Java 8 or later*.
|
Use this version for projects that requires Java 6 or need the JMagick support. *Does not support Java 8 or later*.
|
||||||
|
|
||||||
Common dependencies
|
Common dependencies
|
||||||
* [common-lang-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.0.2/common-lang-3.0.2.jar)
|
* [common-lang-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.0.2/common-lang-3.0.2.jar)
|
||||||
* [common-io-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.0.2/common-io-3.0.2.jar)
|
* [common-io-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.0.2/common-io-3.0.2.jar)
|
||||||
* [common-image-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.0.2/common-image-3.0.2.jar)
|
* [common-image-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.0.2/common-image-3.0.2.jar)
|
||||||
|
|
||||||
ImageIO dependencies
|
ImageIO dependencies
|
||||||
* [imageio-core-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.0.2/imageio-core-3.0.2.jar)
|
* [imageio-core-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.0.2/imageio-core-3.0.2.jar)
|
||||||
* [imageio-metadata-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.0.2/imageio-metadata-3.0.2.jar)
|
* [imageio-metadata-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.0.2/imageio-metadata-3.0.2.jar)
|
||||||
|
|
||||||
ImageIO plugins
|
ImageIO plugins
|
||||||
* [imageio-jpeg-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.0.2/imageio-jpeg-3.0.2.jar)
|
* [imageio-jpeg-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.0.2/imageio-jpeg-3.0.2.jar)
|
||||||
* [imageio-tiff-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.0.2/imageio-tiff-3.0.2.jar)
|
* [imageio-tiff-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.0.2/imageio-tiff-3.0.2.jar)
|
||||||
* [imageio-psd-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.0.2/imageio-psd-3.0.2.jar)
|
* [imageio-psd-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.0.2/imageio-psd-3.0.2.jar)
|
||||||
* [imageio-pict-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.0.2/imageio-pict-3.0.2.jar)
|
* [imageio-pict-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.0.2/imageio-pict-3.0.2.jar)
|
||||||
* [imageio-iff-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.0.2/imageio-iff-3.0.2.jar)
|
* [imageio-iff-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.0.2/imageio-iff-3.0.2.jar)
|
||||||
* [imageio-icns-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.0.2/imageio-icns-3.0.2.jar)
|
* [imageio-icns-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.0.2/imageio-icns-3.0.2.jar)
|
||||||
* [imageio-ico-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-ico/3.0.2/imageio-ico-3.0.2.jar)
|
* [imageio-ico-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-ico/3.0.2/imageio-ico-3.0.2.jar)
|
||||||
* [imageio-thumbsdb-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.0.2/imageio-thumbsdb-3.0.2.jar)
|
* [imageio-thumbsdb-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.0.2/imageio-thumbsdb-3.0.2.jar)
|
||||||
|
|
||||||
ImageIO plugins requiring 3rd party libs
|
ImageIO plugins requiring 3rd party libs
|
||||||
* [imageio-batik-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.0.2/imageio-batik-3.0.2.jar)
|
* [imageio-batik-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.0.2/imageio-batik-3.0.2.jar)
|
||||||
* [imageio-jmagick-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jmagick/3.0.2/imageio-jmagick-3.0.2.jar)
|
* [imageio-jmagick-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jmagick/3.0.2/imageio-jmagick-3.0.2.jar)
|
||||||
|
|
||||||
Servlet support
|
Servlet support
|
||||||
* [servlet-3.0.2.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.0.2/servlet-3.0.2.jar)
|
* [servlet-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.0.2/servlet-3.0.2.jar)
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is provided under the OSI approved [BSD license](http://opensource.org/licenses/BSD-3-Clause):
|
This project is provided under the OSI approved [BSD license](https://opensource.org/licenses/BSD-3-Clause):
|
||||||
|
|
||||||
Copyright (c) 2008-2020, Harald Kuhr
|
Copyright (c) 2008-2020, Harald Kuhr
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
@@ -495,7 +494,7 @@ a: The TwelveMonkeys ImageIO project contains plug-ins for ImageIO. ImageIO uses
|
|||||||
|
|
||||||
All you have have to do, is to make sure you have the TwelveMonkeys JARs in your classpath.
|
All you have have to do, is to make sure you have the TwelveMonkeys JARs in your classpath.
|
||||||
|
|
||||||
You can read more about the registry and the lookup mechanism in the [IIORegistry API doc](http://docs.oracle.com/javase/7/docs/api/javax/imageio/spi/IIORegistry.html).
|
You can read more about the registry and the lookup mechanism in the [IIORegistry API doc](https://docs.oracle.com/javase/7/docs/api/javax/imageio/spi/IIORegistry.html).
|
||||||
|
|
||||||
The fine print: The TwelveMonkeys service providers for JPEG, BMP and TIFF, overrides the onRegistration method, and
|
The fine print: The TwelveMonkeys service providers for JPEG, BMP and TIFF, overrides the onRegistration method, and
|
||||||
utilizes the pairwise partial ordering mechanism of the `IIOServiceRegistry` to make sure it is installed before
|
utilizes the pairwise partial ordering mechanism of the `IIOServiceRegistry` to make sure it is installed before
|
||||||
|
|||||||
+6
-1
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-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-webp</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-xwd</artifactId>
|
<artifactId>imageio-xwd</artifactId>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-image</artifactId>
|
<artifactId>common-image</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -34,7 +34,13 @@ import java.awt.*;
|
|||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.image.*;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.BufferedImageOp;
|
||||||
|
import java.awt.image.ColorModel;
|
||||||
|
import java.awt.image.ImagingOpException;
|
||||||
|
import java.awt.image.Raster;
|
||||||
|
import java.awt.image.RasterOp;
|
||||||
|
import java.awt.image.WritableRaster;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a drop-in replacement for {@link java.awt.image.AffineTransformOp}.
|
* This is a drop-in replacement for {@link java.awt.image.AffineTransformOp}.
|
||||||
@@ -70,6 +76,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp {
|
|||||||
delegate = new java.awt.image.AffineTransformOp(xform, interpolationType);
|
delegate = new java.awt.image.AffineTransformOp(xform, interpolationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("ConstantConditions")
|
||||||
@Override
|
@Override
|
||||||
public BufferedImage filter(final BufferedImage src, BufferedImage dst) {
|
public BufferedImage filter(final BufferedImage src, BufferedImage dst) {
|
||||||
try {
|
try {
|
||||||
@@ -80,10 +87,9 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp {
|
|||||||
dst = createCompatibleDestImage(src, src.getColorModel());
|
dst = createCompatibleDestImage(src, src.getColorModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
Graphics2D g2d = null;
|
Graphics2D g2d = dst.createGraphics();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
g2d = dst.createGraphics();
|
|
||||||
int interpolationType = delegate.getInterpolationType();
|
int interpolationType = delegate.getInterpolationType();
|
||||||
|
|
||||||
if (interpolationType > 0) {
|
if (interpolationType > 0) {
|
||||||
@@ -109,9 +115,7 @@ public class AffineTransformOp implements BufferedImageOp, RasterOp {
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (g2d != null) {
|
g2d.dispose();
|
||||||
g2d.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ import java.awt.image.BufferedImage;
|
|||||||
*/
|
*/
|
||||||
public class BufferedImageIcon implements Icon {
|
public class BufferedImageIcon implements Icon {
|
||||||
private final BufferedImage image;
|
private final BufferedImage image;
|
||||||
private int width;
|
private final int width;
|
||||||
private int height;
|
private final int height;
|
||||||
private final boolean fast;
|
private final boolean fast;
|
||||||
|
|
||||||
public BufferedImageIcon(BufferedImage pImage) {
|
public BufferedImageIcon(BufferedImage pImage) {
|
||||||
@@ -81,11 +81,10 @@ public class BufferedImageIcon implements Icon {
|
|||||||
else {
|
else {
|
||||||
//System.out.println("Scaling using interpolation");
|
//System.out.println("Scaling using interpolation");
|
||||||
Graphics2D g2 = (Graphics2D) g;
|
Graphics2D g2 = (Graphics2D) g;
|
||||||
AffineTransform xform = AffineTransform.getTranslateInstance(x, y);
|
AffineTransform transform = AffineTransform.getTranslateInstance(x, y);
|
||||||
xform.scale(width / (double) image.getWidth(), height / (double) image.getHeight());
|
transform.scale(width / (double) image.getWidth(), height / (double) image.getHeight());
|
||||||
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
|
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
g2.drawImage(image, transform, null);
|
||||||
g2.drawImage(image, xform, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -587,6 +587,7 @@ class IndexImage {
|
|||||||
* @deprecated Use {@link #getIndexColorModel(Image,int,int)} instead!
|
* @deprecated Use {@link #getIndexColorModel(Image,int,int)} instead!
|
||||||
* This version will be removed in a later version of the API.
|
* This version will be removed in a later version of the API.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static IndexColorModel getIndexColorModel(Image pImage, int pNumberOfColors, boolean pFast) {
|
public static IndexColorModel getIndexColorModel(Image pImage, int pNumberOfColors, boolean pFast) {
|
||||||
return getIndexColorModel(pImage, pNumberOfColors, pFast ? COLOR_SELECTION_FAST : COLOR_SELECTION_QUALITY);
|
return getIndexColorModel(pImage, pNumberOfColors, pFast ? COLOR_SELECTION_FAST : COLOR_SELECTION_QUALITY);
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-16
@@ -30,17 +30,26 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.image;
|
package com.twelvemonkeys.image;
|
||||||
|
|
||||||
import org.junit.Test;
|
import static java.lang.Math.min;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.geom.Point2D;
|
import java.awt.geom.Point2D;
|
||||||
import java.awt.image.*;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.BufferedImageOp;
|
||||||
|
import java.awt.image.DataBuffer;
|
||||||
|
import java.awt.image.ImagingOpException;
|
||||||
|
import java.awt.image.Raster;
|
||||||
|
import java.awt.image.RasterOp;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AffineTransformOpTest.
|
* AffineTransformOpTest.
|
||||||
@@ -101,6 +110,7 @@ public class AffineTransformOpTest {
|
|||||||
|
|
||||||
private final int width = 30;
|
private final int width = 30;
|
||||||
private final int height = 20;
|
private final int height = 20;
|
||||||
|
private final double anchor = min(width, height) / 2.0;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetPoint2D() {
|
public void testGetPoint2D() {
|
||||||
@@ -128,8 +138,8 @@ public class AffineTransformOpTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFilterRotateBIStandard() {
|
public void testFilterRotateBIStandard() {
|
||||||
BufferedImageOp jreOp = new java.awt.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, Math.min(width, height) / 2, Math.min(width, height) / 2), null);
|
BufferedImageOp jreOp = new java.awt.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, anchor, anchor), null);
|
||||||
BufferedImageOp tmOp = new com.twelvemonkeys.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, Math.min(width, height) / 2, Math.min(width, height) / 2), null);
|
BufferedImageOp tmOp = new com.twelvemonkeys.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, anchor, anchor), null);
|
||||||
|
|
||||||
for (Integer type : TYPES) {
|
for (Integer type : TYPES) {
|
||||||
BufferedImage image = new BufferedImage(width, height, type);
|
BufferedImage image = new BufferedImage(width, height, type);
|
||||||
@@ -147,8 +157,8 @@ public class AffineTransformOpTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFilterRotateBICustom() {
|
public void testFilterRotateBICustom() {
|
||||||
BufferedImageOp jreOp = new java.awt.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, Math.min(width, height) / 2, Math.min(width, height) / 2), null);
|
BufferedImageOp jreOp = new java.awt.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, anchor, anchor), null);
|
||||||
BufferedImageOp tmOp = new com.twelvemonkeys.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, Math.min(width, height) / 2, Math.min(width, height) / 2), null);
|
BufferedImageOp tmOp = new com.twelvemonkeys.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, anchor, anchor), null);
|
||||||
|
|
||||||
for (ImageTypeSpecifier spec : SPECS) {
|
for (ImageTypeSpecifier spec : SPECS) {
|
||||||
BufferedImage image = spec.createBufferedImage(width, height);
|
BufferedImage image = spec.createBufferedImage(width, height);
|
||||||
@@ -197,8 +207,8 @@ public class AffineTransformOpTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFilterRotateRasterStandard() {
|
public void testFilterRotateRasterStandard() {
|
||||||
RasterOp jreOp = new java.awt.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, Math.min(width, height) / 2, Math.min(width, height) / 2), null);
|
RasterOp jreOp = new java.awt.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, anchor, anchor), null);
|
||||||
RasterOp tmOp = new com.twelvemonkeys.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, Math.min(width, height) / 2, Math.min(width, height) / 2), null);
|
RasterOp tmOp = new com.twelvemonkeys.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, anchor, anchor), null);
|
||||||
|
|
||||||
for (Integer type : TYPES) {
|
for (Integer type : TYPES) {
|
||||||
Raster raster = new BufferedImage(width, height, type).getRaster();
|
Raster raster = new BufferedImage(width, height, type).getRaster();
|
||||||
@@ -221,8 +231,6 @@ public class AffineTransformOpTest {
|
|||||||
fail("No result!");
|
fail("No result!");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
System.err.println("AffineTransformOpTest.testFilterRotateRasterStandard");
|
|
||||||
System.err.println("type: " + type);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,8 +248,8 @@ public class AffineTransformOpTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFilterRotateRasterCustom() {
|
public void testFilterRotateRasterCustom() {
|
||||||
RasterOp jreOp = new java.awt.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, Math.min(width, height) / 2, Math.min(width, height) / 2), null);
|
RasterOp jreOp = new java.awt.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, anchor, anchor), null);
|
||||||
RasterOp tmOp = new com.twelvemonkeys.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, Math.min(width, height) / 2, Math.min(width, height) / 2), null);
|
RasterOp tmOp = new com.twelvemonkeys.image.AffineTransformOp(AffineTransform.getQuadrantRotateInstance(1, anchor, anchor), null);
|
||||||
|
|
||||||
for (ImageTypeSpecifier spec : SPECS) {
|
for (ImageTypeSpecifier spec : SPECS) {
|
||||||
Raster raster = spec.createBufferedImage(width, height).getRaster();
|
Raster raster = spec.createBufferedImage(width, height).getRaster();
|
||||||
@@ -264,8 +272,6 @@ public class AffineTransformOpTest {
|
|||||||
fail("No result!");
|
fail("No result!");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
System.err.println("AffineTransformOpTest.testFilterRotateRasterCustom");
|
|
||||||
System.err.println("spec: " + spec);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-io</artifactId>
|
<artifactId>common-io</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ import java.io.FilenameFilter;
|
|||||||
* @see WildcardStringParser
|
* @see WildcardStringParser
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class FilenameMaskFilter implements FilenameFilter {
|
public class FilenameMaskFilter implements FilenameFilter {
|
||||||
|
|
||||||
// TODO: Rewrite to use regexp, or create new class
|
// TODO: Rewrite to use regexp, or create new class
|
||||||
|
|||||||
@@ -442,6 +442,7 @@ public class LittleEndianDataInputStream extends FilterInputStream implements Da
|
|||||||
* @see java.io.BufferedReader#readLine()
|
* @see java.io.BufferedReader#readLine()
|
||||||
* @see java.io.DataInputStream#readLine()
|
* @see java.io.DataInputStream#readLine()
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String readLine() throws IOException {
|
public String readLine() throws IOException {
|
||||||
DataInputStream ds = new DataInputStream(in);
|
DataInputStream ds = new DataInputStream(in);
|
||||||
return ds.readLine();
|
return ds.readLine();
|
||||||
|
|||||||
@@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.xml;
|
package com.twelvemonkeys.xml;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
import org.w3c.dom.DOMConfiguration;
|
import org.w3c.dom.DOMConfiguration;
|
||||||
import org.w3c.dom.DOMImplementationList;
|
import org.w3c.dom.DOMImplementationList;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
@@ -38,9 +41,6 @@ import org.w3c.dom.ls.DOMImplementationLS;
|
|||||||
import org.w3c.dom.ls.LSOutput;
|
import org.w3c.dom.ls.LSOutput;
|
||||||
import org.w3c.dom.ls.LSSerializer;
|
import org.w3c.dom.ls.LSSerializer;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.Writer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code DOMImplementationLS} backed implementation.
|
* {@code DOMImplementationLS} backed implementation.
|
||||||
*
|
*
|
||||||
@@ -88,17 +88,6 @@ public final class DOMSerializer {
|
|||||||
output.setCharacterStream(pStream);
|
output.setCharacterStream(pStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// TODO: Is it useful?
|
|
||||||
public void setNewLine(final String pNewLine) {
|
|
||||||
serializer.setNewLine(pNewLine);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getNewLine() {
|
|
||||||
return serializer.getNewLine();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies wether the serializer should use indentation and optimize for
|
* Specifies wether the serializer should use indentation and optimize for
|
||||||
* readability.
|
* readability.
|
||||||
@@ -169,13 +158,7 @@ public final class DOMSerializer {
|
|||||||
try {
|
try {
|
||||||
return DOMImplementationRegistry.newInstance();
|
return DOMImplementationRegistry.newInstance();
|
||||||
}
|
}
|
||||||
catch (ClassNotFoundException e) {
|
catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
catch (InstantiationException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
catch (IllegalAccessException e) {
|
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,16 +30,23 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.xml;
|
package com.twelvemonkeys.xml;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import java.io.ByteArrayInputStream;
|
||||||
import org.w3c.dom.*;
|
import java.io.ByteArrayOutputStream;
|
||||||
import org.xml.sax.SAXException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import java.io.*;
|
|
||||||
import java.nio.charset.Charset;
|
import org.w3c.dom.*;
|
||||||
import java.util.Date;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XMLSerializer
|
* XMLSerializer
|
||||||
@@ -290,7 +297,7 @@ public class XMLSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int appendAndEscape(final String pString, int pStart, final int pEnd, final StringBuilder pBuilder, final String pEntity) {
|
private static int appendAndEscape(final String pString, int pStart, final int pEnd, final StringBuilder pBuilder, final String pEntity) {
|
||||||
pBuilder.append(pString.substring(pStart, pEnd));
|
pBuilder.append(pString, pStart, pEnd);
|
||||||
pBuilder.append(pEntity);
|
pBuilder.append(pEntity);
|
||||||
return pEnd + 1;
|
return pEnd + 1;
|
||||||
}
|
}
|
||||||
@@ -527,8 +534,7 @@ public class XMLSerializer {
|
|||||||
builder = factory.newDocumentBuilder();
|
builder = factory.newDocumentBuilder();
|
||||||
}
|
}
|
||||||
catch (ParserConfigurationException e) {
|
catch (ParserConfigurationException e) {
|
||||||
//noinspection ThrowableInstanceNeverThrown BOGUS
|
throw new IOException(e);
|
||||||
throw (IOException) new IOException(e.getMessage()).initCause(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMImplementation dom = builder.getDOMImplementation();
|
DOMImplementation dom = builder.getDOMImplementation();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-lang</artifactId>
|
<artifactId>common-lang</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -770,6 +770,7 @@ public final class StringUtil {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*public*/
|
/*public*/
|
||||||
|
@Deprecated
|
||||||
static String formatNumber(long pNum, int pLen) throws IllegalArgumentException {
|
static String formatNumber(long pNum, int pLen) throws IllegalArgumentException {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
|
|
||||||
@@ -1464,6 +1465,7 @@ public final class StringUtil {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*public*/
|
/*public*/
|
||||||
|
@Deprecated
|
||||||
static String removeSubstring(final String pSource, final char pBeginBoundaryChar, final char pEndBoundaryChar, final int pOffset) {
|
static String removeSubstring(final String pSource, final char pBeginBoundaryChar, final char pEndBoundaryChar, final int pOffset) {
|
||||||
StringBuilder filteredString = new StringBuilder();
|
StringBuilder filteredString = new StringBuilder();
|
||||||
boolean insideDemarcatedArea = false;
|
boolean insideDemarcatedArea = false;
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ public class Time {
|
|||||||
* @see #parseTime(String)
|
* @see #parseTime(String)
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public String toString(String pFormatStr) {
|
public String toString(String pFormatStr) {
|
||||||
TimeFormat tf = new TimeFormat(pFormatStr);
|
TimeFormat tf = new TimeFormat(pFormatStr);
|
||||||
|
|
||||||
@@ -174,6 +175,7 @@ public class Time {
|
|||||||
* @see #toString(String)
|
* @see #toString(String)
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static Time parseTime(String pStr) {
|
public static Time parseTime(String pStr) {
|
||||||
TimeFormat tf = TimeFormat.getInstance();
|
TimeFormat tf = TimeFormat.getInstance();
|
||||||
|
|
||||||
|
|||||||
+1
@@ -111,6 +111,7 @@ import java.io.PrintStream;
|
|||||||
* @author <a href="mailto:eirik.torske@iconmedialab.no">Eirik Torske</a>
|
* @author <a href="mailto:eirik.torske@iconmedialab.no">Eirik Torske</a>
|
||||||
* @deprecated Will probably be removed in the near future
|
* @deprecated Will probably be removed in the near future
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public class WildcardStringParser {
|
public class WildcardStringParser {
|
||||||
// TODO: Get rid of this class
|
// TODO: Get rid of this class
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-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.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>com.twelvemonkeys.contrib</groupId>
|
<groupId>com.twelvemonkeys.contrib</groupId>
|
||||||
<artifactId>contrib</artifactId>
|
<artifactId>contrib</artifactId>
|
||||||
|
|||||||
@@ -31,8 +31,9 @@
|
|||||||
package com.twelvemonkeys.contrib.tiff;
|
package com.twelvemonkeys.contrib.tiff;
|
||||||
|
|
||||||
import com.twelvemonkeys.contrib.tiff.TIFFUtilities.TIFFExtension;
|
import com.twelvemonkeys.contrib.tiff.TIFFUtilities.TIFFExtension;
|
||||||
import com.twelvemonkeys.imageio.plugins.tiff.TIFFMedataFormat;
|
import com.twelvemonkeys.imageio.plugins.tiff.TIFFImageMetadataFormat;
|
||||||
import com.twelvemonkeys.io.FileUtil;
|
import com.twelvemonkeys.io.FileUtil;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
@@ -154,7 +155,7 @@ public class TIFFUtilitiesTest {
|
|||||||
reader.setInput(checkTest1);
|
reader.setInput(checkTest1);
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
Node metaData = reader.getImageMetadata(i)
|
Node metaData = reader.getImageMetadata(i)
|
||||||
.getAsTree(TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME);
|
.getAsTree(TIFFImageMetadataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME);
|
||||||
short orientation = ((Number) expression.evaluate(metaData, XPathConstants.NUMBER)).shortValue();
|
short orientation = ((Number) expression.evaluate(metaData, XPathConstants.NUMBER)).shortValue();
|
||||||
Assert.assertEquals(orientation, TIFFExtension.ORIENTATION_RIGHTTOP);
|
Assert.assertEquals(orientation, TIFFExtension.ORIENTATION_RIGHTTOP);
|
||||||
}
|
}
|
||||||
@@ -171,7 +172,7 @@ public class TIFFUtilitiesTest {
|
|||||||
reader.setInput(checkTest2);
|
reader.setInput(checkTest2);
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
Node metaData = reader.getImageMetadata(i)
|
Node metaData = reader.getImageMetadata(i)
|
||||||
.getAsTree(TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME);
|
.getAsTree(TIFFImageMetadataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME);
|
||||||
short orientation = ((Number) expression.evaluate(metaData, XPathConstants.NUMBER)).shortValue();
|
short orientation = ((Number) expression.evaluate(metaData, XPathConstants.NUMBER)).shortValue();
|
||||||
Assert.assertEquals(orientation, i == 1
|
Assert.assertEquals(orientation, i == 1
|
||||||
? TIFFExtension.ORIENTATION_BOTRIGHT
|
? TIFFExtension.ORIENTATION_BOTRIGHT
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-batik</artifactId>
|
<artifactId>imageio-batik</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
|
||||||
@@ -68,13 +68,6 @@
|
|||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.xmlgraphics</groupId>
|
|
||||||
<artifactId>xmlgraphics-commons</artifactId>
|
|
||||||
<version>2.2</version>
|
|
||||||
<scope>provided</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.xmlgraphics</groupId>
|
<groupId>org.apache.xmlgraphics</groupId>
|
||||||
<artifactId>batik-anim</artifactId>
|
<artifactId>batik-anim</artifactId>
|
||||||
@@ -98,7 +91,7 @@
|
|||||||
<!--
|
<!--
|
||||||
There seems to be some weirdness in the
|
There seems to be some weirdness in the
|
||||||
Batik/FOP poms (Batik depends on FOP 0.20-5) that screws things up,
|
Batik/FOP poms (Batik depends on FOP 0.20-5) that screws things up,
|
||||||
making everything end up depending on Batik 1.5, not 1.6
|
making everything end up depending on Batik 1.5, not the specified version
|
||||||
-->
|
-->
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
|
|||||||
+36
-34
@@ -30,37 +30,8 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.svg;
|
package com.twelvemonkeys.imageio.plugins.svg;
|
||||||
|
|
||||||
import com.twelvemonkeys.image.ImageUtil;
|
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
|
||||||
import org.apache.batik.anim.dom.SVGDOMImplementation;
|
|
||||||
import org.apache.batik.anim.dom.SVGOMDocument;
|
|
||||||
import org.apache.batik.bridge.*;
|
|
||||||
import org.apache.batik.css.parser.CSSLexicalUnit;
|
|
||||||
import org.apache.batik.dom.util.DOMUtilities;
|
|
||||||
import org.apache.batik.ext.awt.image.GraphicsUtil;
|
|
||||||
import org.apache.batik.gvt.CanvasGraphicsNode;
|
|
||||||
import org.apache.batik.gvt.GraphicsNode;
|
|
||||||
import org.apache.batik.gvt.renderer.ConcreteImageRendererFactory;
|
|
||||||
import org.apache.batik.gvt.renderer.ImageRenderer;
|
|
||||||
import org.apache.batik.gvt.renderer.ImageRendererFactory;
|
|
||||||
import org.apache.batik.transcoder.*;
|
|
||||||
import org.apache.batik.transcoder.image.ImageTranscoder;
|
|
||||||
import org.apache.batik.util.ParsedURL;
|
|
||||||
import org.apache.batik.util.SVGConstants;
|
|
||||||
import org.apache.batik.xml.LexicalUnits;
|
|
||||||
import org.w3c.dom.DOMImplementation;
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
import org.w3c.dom.svg.SVGSVGElement;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.ImageReadParam;
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.AffineTransform;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.geom.Dimension2D;
|
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -70,6 +41,38 @@ import java.util.Collections;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.ImageReadParam;
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
|
||||||
|
import org.apache.batik.anim.dom.SVGDOMImplementation;
|
||||||
|
import org.apache.batik.anim.dom.SVGOMDocument;
|
||||||
|
import org.apache.batik.bridge.*;
|
||||||
|
import org.apache.batik.dom.util.DOMUtilities;
|
||||||
|
import org.apache.batik.ext.awt.image.GraphicsUtil;
|
||||||
|
import org.apache.batik.gvt.CanvasGraphicsNode;
|
||||||
|
import org.apache.batik.gvt.GraphicsNode;
|
||||||
|
import org.apache.batik.gvt.renderer.ConcreteImageRendererFactory;
|
||||||
|
import org.apache.batik.gvt.renderer.ImageRenderer;
|
||||||
|
import org.apache.batik.gvt.renderer.ImageRendererFactory;
|
||||||
|
import org.apache.batik.transcoder.SVGAbstractTranscoder;
|
||||||
|
import org.apache.batik.transcoder.TranscoderException;
|
||||||
|
import org.apache.batik.transcoder.TranscoderInput;
|
||||||
|
import org.apache.batik.transcoder.TranscoderOutput;
|
||||||
|
import org.apache.batik.transcoder.TranscodingHints;
|
||||||
|
import org.apache.batik.transcoder.image.ImageTranscoder;
|
||||||
|
import org.apache.batik.util.ParsedURL;
|
||||||
|
import org.apache.batik.util.SVGConstants;
|
||||||
|
import org.w3c.dom.DOMImplementation;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.svg.SVGSVGElement;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image reader for SVG document fragments.
|
* Image reader for SVG document fragments.
|
||||||
*
|
*
|
||||||
@@ -132,6 +135,7 @@ public class SVGImageReader extends ImageReaderBase {
|
|||||||
// Set ImageReadParams as hints
|
// Set ImageReadParams as hints
|
||||||
// Note: The cast to Map invokes a different method that preserves
|
// Note: The cast to Map invokes a different method that preserves
|
||||||
// unset defaults, DO NOT REMOVE!
|
// unset defaults, DO NOT REMOVE!
|
||||||
|
//noinspection rawtypes
|
||||||
rasterizer.setTranscodingHints((Map) paramsToHints(svgParam));
|
rasterizer.setTranscodingHints((Map) paramsToHints(svgParam));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +264,7 @@ public class SVGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
|
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) {
|
||||||
return Collections.singleton(ImageTypeSpecifier.createFromRenderedImage(rasterizer.createImage(1, 1))).iterator();
|
return Collections.singleton(ImageTypeSpecifier.createFromRenderedImage(rasterizer.createImage(1, 1))).iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,7 +293,7 @@ public class SVGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is cheating... We don't fully transcode after all
|
// This is cheating... We don't fully transcode after all
|
||||||
protected void transcode(Document document, final String uri, final TranscoderOutput output) throws TranscoderException {
|
protected void transcode(Document document, final String uri, final TranscoderOutput output) {
|
||||||
// Sets up root, curTxf & curAoi
|
// Sets up root, curTxf & curAoi
|
||||||
// ----
|
// ----
|
||||||
if (document != null) {
|
if (document != null) {
|
||||||
@@ -584,9 +588,7 @@ public class SVGImageReader extends ImageReaderBase {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
TranscoderException exception = new TranscoderException(ex.getMessage());
|
throw new TranscoderException(ex.getMessage(), ex);
|
||||||
exception.initCause(ex);
|
|
||||||
throw exception;
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
|
|||||||
+2
-4
@@ -54,8 +54,6 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Matchers.any;
|
|
||||||
import static org.mockito.Matchers.anyString;
|
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -225,7 +223,7 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
|||||||
assertEquals(500, image.getHeight());
|
assertEquals(500, image.getHeight());
|
||||||
|
|
||||||
// CSS and embedded resources all go!
|
// CSS and embedded resources all go!
|
||||||
verifyZeroInteractions(listener);
|
verifyNoInteractions(listener);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
@@ -266,7 +264,7 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
|||||||
assertEquals(500, image.getHeight());
|
assertEquals(500, image.getHeight());
|
||||||
|
|
||||||
// No more warnings now that the base URI is set
|
// No more warnings now that the base URI is set
|
||||||
verifyZeroInteractions(listener);
|
verifyNoInteractions(listener);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
reader.dispose();
|
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.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-bmp</artifactId>
|
<artifactId>imageio-bmp</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
|
||||||
|
|||||||
+34
-45
@@ -30,6 +30,22 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
|
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||||
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
|
import com.twelvemonkeys.io.LittleEndianDataInputStream;
|
||||||
|
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||||
|
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.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
@@ -40,27 +56,6 @@ import java.nio.ByteOrder;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
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.event.IIOReadUpdateListener;
|
|
||||||
import javax.imageio.event.IIOReadWarningListener;
|
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
|
||||||
import com.twelvemonkeys.io.LittleEndianDataInputStream;
|
|
||||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
|
||||||
import com.twelvemonkeys.xml.XMLSerializer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageReader for Microsoft Windows Bitmap (BMP) format.
|
* ImageReader for Microsoft Windows Bitmap (BMP) format.
|
||||||
*
|
*
|
||||||
@@ -482,8 +477,12 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
private void readRowByte(final DataInput input, final int height, final Rectangle srcRegion, final int xSub, final int ySub,
|
private void readRowByte(final DataInput input, final int height, final Rectangle srcRegion, final int xSub, final int ySub,
|
||||||
final byte[] rowDataByte, final WritableRaster destChannel, final Raster srcChannel, final int y) throws IOException {
|
final byte[] rowDataByte, final WritableRaster destChannel, final Raster srcChannel, final int y) throws IOException {
|
||||||
|
// Flip into position?
|
||||||
|
int srcY = !header.topDown ? height - 1 - y : y;
|
||||||
|
int dstY = (srcY - srcRegion.y) / ySub;
|
||||||
|
|
||||||
// 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 (srcY % ySub != 0 || srcY < srcRegion.y || srcY >= srcRegion.y + srcRegion.height) {
|
||||||
input.skipBytes(rowDataByte.length);
|
input.skipBytes(rowDataByte.length);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -498,19 +497,17 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.topDown) {
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
destChannel.setDataElements(0, y, srcChannel);
|
|
||||||
} else {
|
|
||||||
// Flip into position
|
|
||||||
int dstY = (height - 1 - y - srcRegion.y) / ySub;
|
|
||||||
destChannel.setDataElements(0, dstY, srcChannel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readRowUShort(final DataInput input, final int height, final Rectangle srcRegion, final int xSub, final int ySub,
|
private void readRowUShort(final DataInput input, final int height, final Rectangle srcRegion, final int xSub, final int ySub,
|
||||||
final short[] rowDataUShort, final WritableRaster destChannel, final Raster srcChannel, final int y) throws IOException {
|
final short[] rowDataUShort, final WritableRaster destChannel, final Raster srcChannel, final int y) throws IOException {
|
||||||
|
// Flip into position?
|
||||||
|
int srcY = !header.topDown ? height - 1 - y : y;
|
||||||
|
int dstY = (srcY - srcRegion.y) / ySub;
|
||||||
|
|
||||||
// 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 (srcY % ySub != 0 || srcY < srcRegion.y || srcY >= srcRegion.y + srcRegion.height) {
|
||||||
input.skipBytes(rowDataUShort.length * 2 + (rowDataUShort.length % 2) * 2);
|
input.skipBytes(rowDataUShort.length * 2 + (rowDataUShort.length % 2) * 2);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -530,19 +527,17 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.topDown) {
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
destChannel.setDataElements(0, y, srcChannel);
|
|
||||||
} else {
|
|
||||||
// Flip into position
|
|
||||||
int dstY = (height - 1 - y - srcRegion.y) / ySub;
|
|
||||||
destChannel.setDataElements(0, dstY, srcChannel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readRowInt(final DataInput input, final int height, final Rectangle srcRegion, final int xSub, final int ySub,
|
private void readRowInt(final DataInput input, final int height, final Rectangle srcRegion, final int xSub, final int ySub,
|
||||||
final int[] rowDataInt, final WritableRaster destChannel, final Raster srcChannel, final int y) throws IOException {
|
final int[] rowDataInt, final WritableRaster destChannel, final Raster srcChannel, final int y) throws IOException {
|
||||||
|
// Flip into position?
|
||||||
|
int srcY = !header.topDown ? height - 1 - y : y;
|
||||||
|
int dstY = (srcY - srcRegion.y) / ySub;
|
||||||
|
|
||||||
// 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 (srcY % ySub != 0 || srcY < srcRegion.y || srcY >= srcRegion.y + srcRegion.height) {
|
||||||
input.skipBytes(rowDataInt.length * 4);
|
input.skipBytes(rowDataInt.length * 4);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -557,13 +552,7 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.topDown) {
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
destChannel.setDataElements(0, y, srcChannel);
|
|
||||||
} else {
|
|
||||||
// Flip into position
|
|
||||||
int dstY = (height - 1 - y - srcRegion.y) / ySub;
|
|
||||||
destChannel.setDataElements(0, dstY, srcChannel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Candidate util method
|
// TODO: Candidate util method
|
||||||
|
|||||||
+4
-4
@@ -32,8 +32,8 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
|||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assume.assumeNoException;
|
import static org.junit.Assume.assumeNoException;
|
||||||
import static org.mockito.Matchers.anyInt;
|
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.inOrder;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
@@ -295,7 +295,7 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
// At least imageStarted and imageComplete, plus any number of imageProgress
|
// At least imageStarted and imageComplete, plus any number of imageProgress
|
||||||
InOrder ordered = inOrder(listener);
|
InOrder ordered = inOrder(listener);
|
||||||
ordered.verify(listener).imageStarted(reader, 0);
|
ordered.verify(listener).imageStarted(reader, 0);
|
||||||
ordered.verify(listener, atLeastOnce()).imageProgress(eq(reader), anyInt());
|
ordered.verify(listener, atLeastOnce()).imageProgress(eq(reader), anyFloat());
|
||||||
ordered.verify(listener).imageComplete(reader);
|
ordered.verify(listener).imageComplete(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +318,7 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
// At least imageStarted and imageComplete, plus any number of imageProgress
|
// At least imageStarted and imageComplete, plus any number of imageProgress
|
||||||
InOrder ordered = inOrder(listener);
|
InOrder ordered = inOrder(listener);
|
||||||
ordered.verify(listener).imageStarted(reader, 0);
|
ordered.verify(listener).imageStarted(reader, 0);
|
||||||
ordered.verify(listener, atLeastOnce()).imageProgress(eq(reader), anyInt());
|
ordered.verify(listener, atLeastOnce()).imageProgress(eq(reader), anyFloat());
|
||||||
ordered.verify(listener).imageComplete(reader);
|
ordered.verify(listener).imageComplete(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-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>
|
||||||
|
|||||||
+1
@@ -39,6 +39,7 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @deprecated Use {@link AdobePathReader} instead. This class will be removed in a future release.
|
* @deprecated Use {@link AdobePathReader} instead. This class will be removed in a future release.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class AdobePathBuilder {
|
public final class AdobePathBuilder {
|
||||||
|
|
||||||
private final AdobePathReader delegate;
|
private final AdobePathReader delegate;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: Core</name>
|
<name>TwelveMonkeys :: ImageIO :: Core</name>
|
||||||
|
|||||||
+174
-20
@@ -39,6 +39,7 @@ import com.twelvemonkeys.util.LRUHashMap;
|
|||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.color.ICC_ColorSpace;
|
import java.awt.color.ICC_ColorSpace;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
@@ -96,6 +97,8 @@ public final class ColorSpaces {
|
|||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
public static final int CS_GENERIC_CMYK = 5001;
|
public static final int CS_GENERIC_CMYK = 5001;
|
||||||
|
|
||||||
|
static final int ICC_PROFILE_HEADER_SIZE = 128;
|
||||||
|
|
||||||
// Weak references to hold the color spaces while cached
|
// Weak references to hold the color spaces while cached
|
||||||
private static WeakReference<ICC_Profile> adobeRGB1998 = new WeakReference<>(null);
|
private static WeakReference<ICC_Profile> adobeRGB1998 = new WeakReference<>(null);
|
||||||
private static WeakReference<ICC_Profile> genericCMYK = new WeakReference<>(null);
|
private static WeakReference<ICC_Profile> genericCMYK = new WeakReference<>(null);
|
||||||
@@ -104,16 +107,8 @@ public final class ColorSpaces {
|
|||||||
private static final Map<Key, ICC_ColorSpace> cache = new LRUHashMap<>(10);
|
private static final Map<Key, ICC_ColorSpace> cache = new LRUHashMap<>(10);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
// In case we didn't activate through SPI already
|
||||||
// Force invocation of ProfileDeferralMgr.activateProfiles() to avoid JDK-6986863
|
ProfileDeferralActivator.activateProfiles();
|
||||||
ICC_Profile.getInstance(ColorSpace.CS_sRGB).getData();
|
|
||||||
}
|
|
||||||
catch (Throwable disasters) {
|
|
||||||
System.err.println("ICC Color Profile not properly activated due to the exception below.");
|
|
||||||
System.err.println("Expect to see JDK-6986863 in action, and consider filing a bug report to your JRE provider.");
|
|
||||||
|
|
||||||
disasters.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ColorSpaces() {}
|
private ColorSpaces() {}
|
||||||
@@ -148,9 +143,11 @@ public final class ColorSpaces {
|
|||||||
|
|
||||||
private static byte[] getProfileHeaderWithProfileId(final ICC_Profile profile) {
|
private static byte[] getProfileHeaderWithProfileId(final ICC_Profile profile) {
|
||||||
// Get *entire profile data*... :-/
|
// Get *entire profile data*... :-/
|
||||||
byte[] data = profile.getData();
|
return getProfileHeaderWithProfileId(profile.getData());
|
||||||
|
}
|
||||||
|
|
||||||
// Clear out preferred CMM, platform & creator, as these does not affect the profile in any way
|
private static byte[] getProfileHeaderWithProfileId(byte[] data) {
|
||||||
|
// Clear out preferred CMM, platform & creator, as these don't affect the profile in any way
|
||||||
// - LCMS updates CMM + creator to "lcms" and platform to current platform
|
// - LCMS updates CMM + creator to "lcms" and platform to current platform
|
||||||
// - KCMS keeps the values in the file...
|
// - KCMS keeps the values in the file...
|
||||||
Arrays.fill(data, ICC_Profile.icHdrCmmId, ICC_Profile.icHdrCmmId + 4, (byte) 0);
|
Arrays.fill(data, ICC_Profile.icHdrCmmId, ICC_Profile.icHdrCmmId + 4, (byte) 0);
|
||||||
@@ -167,7 +164,7 @@ public final class ColorSpaces {
|
|||||||
System.arraycopy(md5, 0, data, ICC_Profile.icHdrProfileID, md5.length);
|
System.arraycopy(md5, 0, data, ICC_Profile.icHdrProfileID, md5.length);
|
||||||
|
|
||||||
// ICC profile header is the first 128 bytes
|
// ICC profile header is the first 128 bytes
|
||||||
return Arrays.copyOf(data, 128);
|
return Arrays.copyOf(data, ICC_PROFILE_HEADER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] computeMD5(byte[] data) {
|
private static byte[] computeMD5(byte[] data) {
|
||||||
@@ -203,25 +200,35 @@ public final class ColorSpaces {
|
|||||||
Key key = new Key(profileHeader);
|
Key key = new Key(profileHeader);
|
||||||
|
|
||||||
synchronized (cache) {
|
synchronized (cache) {
|
||||||
ICC_ColorSpace cs = cache.get(key);
|
ICC_ColorSpace cs = getCachedCS(key);
|
||||||
|
|
||||||
if (cs == null) {
|
if (cs == null) {
|
||||||
cs = new ICC_ColorSpace(profile);
|
cs = new ICC_ColorSpace(profile);
|
||||||
|
|
||||||
validateColorSpace(cs);
|
validateColorSpace(cs);
|
||||||
|
|
||||||
// On LCMS, validation *alters* the profile header, need to re-generate key
|
|
||||||
key = profileCleaner.validationAltersProfileHeader()
|
|
||||||
? new Key(getProfileHeaderWithProfileId(cs.getProfile()))
|
|
||||||
: key;
|
|
||||||
|
|
||||||
cache.put(key, cs);
|
cache.put(key, cs);
|
||||||
|
|
||||||
|
// On LCMS, validation *alters* the profile header, need to re-generate key
|
||||||
|
if (profileCleaner.validationAltersProfileHeader()) {
|
||||||
|
cache.put(new Key(getProfileHeaderWithProfileId(cs.getProfile())), cs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cs;
|
return cs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ICC_ColorSpace getCachedCS(Key profileKey) {
|
||||||
|
synchronized (cache) {
|
||||||
|
return cache.get(profileKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ICC_ColorSpace getCachedCS(final byte[] profileHeader) {
|
||||||
|
return getCachedCS(new Key(profileHeader));
|
||||||
|
}
|
||||||
|
|
||||||
private static void validateColorSpace(final ICC_ColorSpace cs) {
|
private static void validateColorSpace(final ICC_ColorSpace cs) {
|
||||||
// Validate the color space, to avoid caching bad profiles/color spaces
|
// Validate the color space, to avoid caching bad profiles/color spaces
|
||||||
// Will throw IllegalArgumentException or CMMException if the profile is bad
|
// Will throw IllegalArgumentException or CMMException if the profile is bad
|
||||||
@@ -239,6 +246,7 @@ public final class ColorSpaces {
|
|||||||
* @return {@code true} if {@code profile} is equal to the default sRGB profile.
|
* @return {@code true} if {@code profile} is equal to the default sRGB profile.
|
||||||
* @throws IllegalArgumentException if {@code profile} is {@code null}
|
* @throws IllegalArgumentException if {@code profile} is {@code null}
|
||||||
*
|
*
|
||||||
|
* @see java.awt.color.ColorSpace#CS_sRGB
|
||||||
* @see java.awt.color.ColorSpace#isCS_sRGB()
|
* @see java.awt.color.ColorSpace#isCS_sRGB()
|
||||||
*/
|
*/
|
||||||
public static boolean isCS_sRGB(final ICC_Profile profile) {
|
public static boolean isCS_sRGB(final ICC_Profile profile) {
|
||||||
@@ -247,6 +255,21 @@ public final class ColorSpaces {
|
|||||||
return profile.getColorSpaceType() == ColorSpace.TYPE_RGB && Arrays.equals(getProfileHeaderWithProfileId(profile), sRGB.header);
|
return profile.getColorSpaceType() == ColorSpace.TYPE_RGB && Arrays.equals(getProfileHeaderWithProfileId(profile), sRGB.header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether an ICC color profile is equal to the default GRAY profile.
|
||||||
|
*
|
||||||
|
* @param profile the ICC profile to test. May not be {@code null}.
|
||||||
|
* @return {@code true} if {@code profile} is equal to the default GRAY profile.
|
||||||
|
* @throws IllegalArgumentException if {@code profile} is {@code null}
|
||||||
|
*
|
||||||
|
* @see java.awt.color.ColorSpace#CS_GRAY
|
||||||
|
*/
|
||||||
|
public static boolean isCS_GRAY(final ICC_Profile profile) {
|
||||||
|
Validate.notNull(profile, "profile");
|
||||||
|
|
||||||
|
return profile.getColorSpaceType() == ColorSpace.TYPE_GRAY && Arrays.equals(getProfileHeaderWithProfileId(profile), GRAY.header);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests whether an ICC color profile is known to cause problems for {@link java.awt.image.ColorConvertOp}.
|
* Tests whether an ICC color profile is known to cause problems for {@link java.awt.image.ColorConvertOp}.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -302,6 +325,137 @@ public final class ColorSpaces {
|
|||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ICC_Profile readProfileRaw(final InputStream input) throws IOException {
|
||||||
|
return ICC_Profile.getInstance(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ICC_Profile readProfile(final InputStream input) throws IOException {
|
||||||
|
// TODO: Implement this smarter?
|
||||||
|
// Could read the header 128 bytes, get size + magic, then read read rest into array and feed the byte[] method...
|
||||||
|
ICC_Profile profile = ICC_Profile.getInstance(input);
|
||||||
|
|
||||||
|
if (profile == null) {
|
||||||
|
throw new IllegalArgumentException("Invalid ICC Profile Data");
|
||||||
|
}
|
||||||
|
|
||||||
|
return createProfile(profile.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ICC_Profile createProfileRaw(final byte[] input) {
|
||||||
|
try {
|
||||||
|
return readProfileRaw(new ByteArrayInputStream(input));
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
throw new IllegalArgumentException("Invalid ICC Profile Data", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ICC_Profile createProfile(final byte[] input) {
|
||||||
|
Validate.notNull(input, "input");
|
||||||
|
|
||||||
|
if (input.length < ICC_PROFILE_HEADER_SIZE) { // Can't be less than size of ICC header
|
||||||
|
throw new IllegalArgumentException("Truncated ICC profile, length < 128: " + input.length);
|
||||||
|
}
|
||||||
|
int size = intBigEndian(input, 0);
|
||||||
|
if (size < 0 || size > input.length) {
|
||||||
|
throw new IllegalArgumentException("Truncated ICC profile, length < " + size + ": " + input.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input[36] != 'a' || input[37] != 'c' || input[38] != 's' || input[39] != 'p') {
|
||||||
|
throw new IllegalArgumentException("Not an ICC profile, missing file signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look up in cache before returning, these are already validated
|
||||||
|
byte[] profileHeader = getProfileHeaderWithProfileId(input);
|
||||||
|
int csType = getCsType(profileHeader);
|
||||||
|
|
||||||
|
ICC_ColorSpace internal = getInternalCS(csType, profileHeader);
|
||||||
|
if (internal != null) {
|
||||||
|
return internal.getProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
ICC_ColorSpace cached = getCachedCS(profileHeader);
|
||||||
|
if (cached != null) {
|
||||||
|
return cached.getProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
// WEIRDNESS: Unlike the InputStream version, the byte version
|
||||||
|
// of ICC_Profile.getInstance() does not discard extra bytes at the end.
|
||||||
|
// We'll chop them off here for convenience
|
||||||
|
byte[] profileBytes = input.length == size ? input : Arrays.copyOf(input, size);
|
||||||
|
ICC_Profile profile = ICC_Profile.getInstance(profileBytes);
|
||||||
|
|
||||||
|
// We'll validate & cache by creating a color space and returning its profile...
|
||||||
|
// TODO: Rewrite with separate cache for profiles...
|
||||||
|
return createColorSpace(profile).getProfile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int intBigEndian(byte[] data, int index) {
|
||||||
|
return (data[index] & 0xff) << 24 | (data[index + 1] & 0xff) << 16 | (data[index + 2] & 0xff) << 8 | (data[index + 3] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getCsType(byte[] profileHeader) {
|
||||||
|
int csSig = intBigEndian(profileHeader, ICC_Profile.icHdrColorSpace);
|
||||||
|
|
||||||
|
// TODO: Wonder why they didn't just use the sig as type, when there is obviously a 1:1 mapping...
|
||||||
|
|
||||||
|
switch (csSig) {
|
||||||
|
case ICC_Profile.icSigXYZData:
|
||||||
|
return ColorSpace.TYPE_XYZ;
|
||||||
|
case ICC_Profile.icSigLabData:
|
||||||
|
return ColorSpace.TYPE_Lab;
|
||||||
|
case ICC_Profile.icSigLuvData:
|
||||||
|
return ColorSpace.TYPE_Luv;
|
||||||
|
case ICC_Profile.icSigYCbCrData:
|
||||||
|
return ColorSpace.TYPE_YCbCr;
|
||||||
|
case ICC_Profile.icSigYxyData:
|
||||||
|
return ColorSpace.TYPE_Yxy;
|
||||||
|
case ICC_Profile.icSigRgbData:
|
||||||
|
return ColorSpace.TYPE_RGB;
|
||||||
|
case ICC_Profile.icSigGrayData:
|
||||||
|
return ColorSpace.TYPE_GRAY;
|
||||||
|
case ICC_Profile.icSigHsvData:
|
||||||
|
return ColorSpace.TYPE_HSV;
|
||||||
|
case ICC_Profile.icSigHlsData:
|
||||||
|
return ColorSpace.TYPE_HLS;
|
||||||
|
case ICC_Profile.icSigCmykData:
|
||||||
|
return ColorSpace.TYPE_CMYK;
|
||||||
|
// Note: There is no TYPE_* 10...
|
||||||
|
case ICC_Profile.icSigCmyData:
|
||||||
|
return ColorSpace.TYPE_CMY;
|
||||||
|
case ICC_Profile.icSigSpace2CLR:
|
||||||
|
return ColorSpace.TYPE_2CLR;
|
||||||
|
case ICC_Profile.icSigSpace3CLR:
|
||||||
|
return ColorSpace.TYPE_3CLR;
|
||||||
|
case ICC_Profile.icSigSpace4CLR:
|
||||||
|
return ColorSpace.TYPE_4CLR;
|
||||||
|
case ICC_Profile.icSigSpace5CLR:
|
||||||
|
return ColorSpace.TYPE_5CLR;
|
||||||
|
case ICC_Profile.icSigSpace6CLR:
|
||||||
|
return ColorSpace.TYPE_6CLR;
|
||||||
|
case ICC_Profile.icSigSpace7CLR:
|
||||||
|
return ColorSpace.TYPE_7CLR;
|
||||||
|
case ICC_Profile.icSigSpace8CLR:
|
||||||
|
return ColorSpace.TYPE_8CLR;
|
||||||
|
case ICC_Profile.icSigSpace9CLR:
|
||||||
|
return ColorSpace.TYPE_9CLR;
|
||||||
|
case ICC_Profile.icSigSpaceACLR:
|
||||||
|
return ColorSpace.TYPE_ACLR;
|
||||||
|
case ICC_Profile.icSigSpaceBCLR:
|
||||||
|
return ColorSpace.TYPE_BCLR;
|
||||||
|
case ICC_Profile.icSigSpaceCCLR:
|
||||||
|
return ColorSpace.TYPE_CCLR;
|
||||||
|
case ICC_Profile.icSigSpaceDCLR:
|
||||||
|
return ColorSpace.TYPE_DCLR;
|
||||||
|
case ICC_Profile.icSigSpaceECLR:
|
||||||
|
return ColorSpace.TYPE_ECLR;
|
||||||
|
case ICC_Profile.icSigSpaceFCLR:
|
||||||
|
return ColorSpace.TYPE_FCLR;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid ICC color space signature: " + csSig); // TODO: fourCC?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the color space specified by the given color space constant.
|
* Returns the color space specified by the given color space constant.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -449,7 +603,7 @@ public final class ColorSpaces {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache header profile data to avoid excessive array creation/copying in static inner class for on-demand lazy init
|
// Cache header profile data to avoid excessive array creation/copying. Use static inner class for on-demand lazy init
|
||||||
private static class sRGB {
|
private static class sRGB {
|
||||||
private static final byte[] header = getProfileHeaderWithProfileId(ICC_Profile.getInstance(ColorSpace.CS_sRGB));
|
private static final byte[] header = getProfileHeaderWithProfileId(ICC_Profile.getInstance(ColorSpace.CS_sRGB));
|
||||||
}
|
}
|
||||||
|
|||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
package com.twelvemonkeys.imageio.color;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageInputStreamSpi;
|
||||||
|
import javax.imageio.spi.ServiceRegistry;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.imageio.util.IIOUtil.deregisterProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class exists to force early invocation of {@code ProfileDeferralMgr.activateProfiles()},
|
||||||
|
* in an attempt to avoid JDK-6986863 and related bugs in Java < 17.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @see <a href="https://bugs.openjdk.java.net/browse/JDK-6986863">JDK-6986863</a>
|
||||||
|
*/
|
||||||
|
final class ProfileDeferralActivator {
|
||||||
|
|
||||||
|
static {
|
||||||
|
activateProfilesInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void activateProfilesInternal() {
|
||||||
|
try {
|
||||||
|
// Force invocation of ProfileDeferralMgr.activateProfiles() to avoid JDK-6986863 and friends.
|
||||||
|
// Relies on static initializer in ColorConvertOp to actually invoke ProfileDeferralMgr.activateProfiles()
|
||||||
|
Class.forName("java.awt.image.ColorConvertOp");
|
||||||
|
}
|
||||||
|
catch (Throwable disasters) {
|
||||||
|
System.err.println("ProfileDeferralMgr.activateProfiles() failed. ICC Color Profiles may not work properly, see stack trace below.");
|
||||||
|
System.err.println("For more information, see https://bugs.openjdk.java.net/browse/JDK-6986863");
|
||||||
|
System.err.println("Please upgrade to Java 17 or later where this bug is fixed, or ask your JRE provider to backport the fix.");
|
||||||
|
System.err.println();
|
||||||
|
System.err.println("If you can't update to Java 17, a possible workaround is to add");
|
||||||
|
System.err.println("\tClass.forName(\"java.awt.image.ColorConvertOp\");");
|
||||||
|
System.err.println("*early* in your application startup code, to force profile activation before profiles are accessed.");
|
||||||
|
System.err.println();
|
||||||
|
|
||||||
|
disasters.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void activateProfiles() {
|
||||||
|
// This method exists for other classes in the package to
|
||||||
|
// ensure this class' static initializer is run.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is not a service provider, but exploits the SPI mechanism as a hook to force early profile activation.
|
||||||
|
*/
|
||||||
|
public static final class Spi extends ImageInputStreamSpi {
|
||||||
|
@Override public void onRegistration(ServiceRegistry registry, Class<?> category) {
|
||||||
|
activateProfiles();
|
||||||
|
|
||||||
|
deregisterProvider(registry, this, category);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String getDescription(Locale locale) {
|
||||||
|
return getClass().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public ImageInputStream createInputStreamInstance(Object input, boolean useCache, File cacheDir) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+87
-31
@@ -45,36 +45,82 @@ public final class YCbCrConverter {
|
|||||||
private final static int CENTERJSAMPLE = 128;
|
private final static int CENTERJSAMPLE = 128;
|
||||||
private final static int ONE_HALF = 1 << (SCALEBITS - 1);
|
private final static int ONE_HALF = 1 << (SCALEBITS - 1);
|
||||||
|
|
||||||
private final static int[] Cr_R_LUT = new int[MAXJSAMPLE + 1];
|
private final static class JPEG {
|
||||||
private final static int[] Cb_B_LUT = new int[MAXJSAMPLE + 1];
|
private final static int[] Cr_R_LUT = new int[MAXJSAMPLE + 1];
|
||||||
private final static int[] Cr_G_LUT = new int[MAXJSAMPLE + 1];
|
private final static int[] Cb_B_LUT = new int[MAXJSAMPLE + 1];
|
||||||
private final static int[] Cb_G_LUT = new int[MAXJSAMPLE + 1];
|
private final static int[] Cr_G_LUT = new int[MAXJSAMPLE + 1];
|
||||||
|
private final static int[] Cb_G_LUT = new int[MAXJSAMPLE + 1];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes tables for YCC->RGB color space conversion.
|
* Initializes tables for YCC->RGB color space conversion.
|
||||||
*/
|
*/
|
||||||
private static void buildYCCtoRGBtable() {
|
private static void buildYCCtoRGBtable() {
|
||||||
if (ColorSpaces.DEBUG) {
|
if (ColorSpaces.DEBUG) {
|
||||||
System.err.println("Building YCC conversion table");
|
System.err.println("Building JPEG YCbCr conversion table");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
|
||||||
|
// i is the actual input pixel value, in the range 0..MAXJSAMPLE
|
||||||
|
// The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE
|
||||||
|
// Cr=>R value is nearest int to 1.40200 * x
|
||||||
|
Cr_R_LUT[i] = (int) ((1.40200 * (1 << SCALEBITS) + 0.5) * x + ONE_HALF) >> SCALEBITS;
|
||||||
|
// Cb=>B value is nearest int to 1.77200 * x
|
||||||
|
Cb_B_LUT[i] = (int) ((1.77200 * (1 << SCALEBITS) + 0.5) * x + ONE_HALF) >> SCALEBITS;
|
||||||
|
// Cr=>G value is scaled-up -0.71414 * x
|
||||||
|
Cr_G_LUT[i] = -(int) (0.71414 * (1 << SCALEBITS) + 0.5) * x;
|
||||||
|
// Cb=>G value is scaled-up -0.34414 * x
|
||||||
|
// We also add in ONE_HALF so that need not do it in inner loop
|
||||||
|
Cb_G_LUT[i] = -(int) ((0.34414) * (1 << SCALEBITS) + 0.5) * x + ONE_HALF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
|
static {
|
||||||
// i is the actual input pixel value, in the range 0..MAXJSAMPLE
|
buildYCCtoRGBtable();
|
||||||
// The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE
|
|
||||||
// Cr=>R value is nearest int to 1.40200 * x
|
|
||||||
Cr_R_LUT[i] = (int) ((1.40200 * (1 << SCALEBITS) + 0.5) * x + ONE_HALF) >> SCALEBITS;
|
|
||||||
// Cb=>B value is nearest int to 1.77200 * x
|
|
||||||
Cb_B_LUT[i] = (int) ((1.77200 * (1 << SCALEBITS) + 0.5) * x + ONE_HALF) >> SCALEBITS;
|
|
||||||
// Cr=>G value is scaled-up -0.71414 * x
|
|
||||||
Cr_G_LUT[i] = -(int) (0.71414 * (1 << SCALEBITS) + 0.5) * x;
|
|
||||||
// Cb=>G value is scaled-up -0.34414 * x
|
|
||||||
// We also add in ONE_HALF so that need not do it in inner loop
|
|
||||||
Cb_G_LUT[i] = -(int) ((0.34414) * (1 << SCALEBITS) + 0.5) * x + ONE_HALF;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static {
|
private final static class ITU_R_601 {
|
||||||
buildYCCtoRGBtable();
|
private final static int[] Cr_R_LUT = new int[MAXJSAMPLE + 1];
|
||||||
|
private final static int[] Cb_B_LUT = new int[MAXJSAMPLE + 1];
|
||||||
|
private final static int[] Cr_G_LUT = new int[MAXJSAMPLE + 1];
|
||||||
|
private final static int[] Cb_G_LUT = new int[MAXJSAMPLE + 1];
|
||||||
|
private final static int[] Y_LUT = new int[MAXJSAMPLE + 1];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes tables for YCC->RGB color space conversion.
|
||||||
|
*/
|
||||||
|
private static void buildYCCtoRGBtable() {
|
||||||
|
if (ColorSpaces.DEBUG) {
|
||||||
|
System.err.println("Building ITU-R REC.601 YCbCr conversion table");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) {
|
||||||
|
// i is the actual input pixel value, in the range 0..MAXJSAMPLE
|
||||||
|
// The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE
|
||||||
|
|
||||||
|
// Y'CbCr to RGB conversion, using values from BT.601 specification:
|
||||||
|
// R = 1.16438 * (Y'-16) + 1.59603 * (Cr-128)
|
||||||
|
// G = 1.16438 * (Y'-16) - 0.39176 * (Cb-128) - 0.81297 * (Cr-128)
|
||||||
|
// B = 1.16438 * (Y'-16) + 2.01723 * (Cb-128)
|
||||||
|
|
||||||
|
// Cr=>R value is nearest int to 1.59603 * x
|
||||||
|
Cr_R_LUT[i] = ((int) (1.59603 * (1 << SCALEBITS) + 0.5) * x + ONE_HALF) >> SCALEBITS;
|
||||||
|
// Cb=>B value is nearest int to 2.01723 * x
|
||||||
|
Cb_B_LUT[i] = ((int) (2.01723 * (1 << SCALEBITS) + 0.5) * x + ONE_HALF) >> SCALEBITS;
|
||||||
|
// Cr=>G value is scaled-up -0.81297 * x
|
||||||
|
Cr_G_LUT[i] = -(int) (0.81297 * (1 << SCALEBITS) + 0.5) * x;
|
||||||
|
// Cb=>G value is scaled-up -0.39176 * x
|
||||||
|
// We also add in ONE_HALF so that need not do it in inner loop
|
||||||
|
Cb_G_LUT[i] = -(int) ((0.39176) * (1 << SCALEBITS) + 0.5) * x + ONE_HALF;
|
||||||
|
|
||||||
|
// Y`=>RGB
|
||||||
|
Y_LUT[i] = ((int) (1.16438 * (1 << SCALEBITS) + 0.5) * (i - 16) + ONE_HALF) >> SCALEBITS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
buildYCCtoRGBtable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void convertYCbCr2RGB(final byte[] yCbCr, final byte[] rgb, final double[] coefficients, double[] referenceBW, final int offset) {
|
public static void convertYCbCr2RGB(final byte[] yCbCr, final byte[] rgb, final double[] coefficients, double[] referenceBW, final int offset) {
|
||||||
@@ -108,17 +154,27 @@ public final class YCbCrConverter {
|
|||||||
rgb[offset + 1] = clamp(green);
|
rgb[offset + 1] = clamp(green);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void convertYCbCr2RGB(final byte[] yCbCr, final byte[] rgb, final int offset) {
|
public static void convertJPEGYCbCr2RGB(final byte[] yCbCr, final byte[] rgb, final int offset) {
|
||||||
int y = yCbCr[offset] & 0xff;
|
int y = yCbCr[offset ] & 0xff;
|
||||||
int cr = yCbCr[offset + 2] & 0xff;
|
|
||||||
int cb = yCbCr[offset + 1] & 0xff;
|
int cb = yCbCr[offset + 1] & 0xff;
|
||||||
|
int cr = yCbCr[offset + 2] & 0xff;
|
||||||
|
|
||||||
rgb[offset] = clamp(y + Cr_R_LUT[cr]);
|
rgb[offset ] = clamp(y + JPEG.Cr_R_LUT[cr]);
|
||||||
rgb[offset + 1] = clamp(y + (Cb_G_LUT[cb] + Cr_G_LUT[cr] >> SCALEBITS));
|
rgb[offset + 1] = clamp(y + (JPEG.Cb_G_LUT[cb] + JPEG.Cr_G_LUT[cr] >> SCALEBITS));
|
||||||
rgb[offset + 2] = clamp(y + Cb_B_LUT[cb]);
|
rgb[offset + 2] = clamp(y + JPEG.Cb_B_LUT[cb]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte clamp(int val) {
|
public static void convertRec601YCbCr2RGB(final byte[] yCbCr, final byte[] rgb, final int offset) {
|
||||||
|
int y = yCbCr[offset ] & 0xff;
|
||||||
|
int cb = yCbCr[offset + 1] & 0xff;
|
||||||
|
int cr = yCbCr[offset + 2] & 0xff;
|
||||||
|
|
||||||
|
rgb[offset ] = clamp(ITU_R_601.Y_LUT[y] + ITU_R_601.Cr_R_LUT[cr]);
|
||||||
|
rgb[offset + 1] = clamp(ITU_R_601.Y_LUT[y] + (ITU_R_601.Cr_G_LUT[cr] + ITU_R_601.Cb_G_LUT[cb] >> SCALEBITS));
|
||||||
|
rgb[offset + 2] = clamp(ITU_R_601.Y_LUT[y] + ITU_R_601.Cb_B_LUT[cb]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte clamp(final int val) {
|
||||||
return (byte) Math.max(0, Math.min(255, val));
|
return (byte) Math.max(0, Math.min(255, val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-15
@@ -93,8 +93,8 @@ public final class BufferedFileImageInputStream extends ImageInputStreamImpl {
|
|||||||
|
|
||||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||||
private boolean fillBuffer() throws IOException {
|
private boolean fillBuffer() throws IOException {
|
||||||
bufferPos = 0;
|
|
||||||
int length = raf.read(buffer, 0, buffer.length);
|
int length = raf.read(buffer, 0, buffer.length);
|
||||||
|
bufferPos = 0;
|
||||||
bufferLimit = max(length, 0);
|
bufferLimit = max(length, 0);
|
||||||
|
|
||||||
return bufferLimit > 0;
|
return bufferLimit > 0;
|
||||||
@@ -125,27 +125,35 @@ public final class BufferedFileImageInputStream extends ImageInputStreamImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
|
public int read(final byte[] bytes, final int offset, final int length) throws IOException {
|
||||||
checkClosed();
|
checkClosed();
|
||||||
bitOffset = 0;
|
bitOffset = 0;
|
||||||
|
|
||||||
if (bufferEmpty()) {
|
if (bufferEmpty()) {
|
||||||
// Bypass buffer if buffer is empty for reads longer than buffer
|
// Bypass buffer if buffer is empty for reads longer than buffer
|
||||||
if (pLength >= buffer.length) {
|
if (length >= buffer.length) {
|
||||||
return readDirect(pBuffer, pOffset, pLength);
|
return readDirect(bytes, offset, length);
|
||||||
}
|
}
|
||||||
else if (!fillBuffer()) {
|
else if (!fillBuffer()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return readBuffered(pBuffer, pOffset, pLength);
|
int fromBuffer = readBuffered(bytes, offset, length);
|
||||||
|
|
||||||
|
if (length > fromBuffer) {
|
||||||
|
// Due to known bugs in certain JDK-bundled ImageIO plugins expecting read to behave as readFully,
|
||||||
|
// we'll read as much as possible from the buffer, and the rest directly after
|
||||||
|
return fromBuffer + max(0, readDirect(bytes, offset + fromBuffer, length - fromBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fromBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readDirect(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
|
private int readDirect(final byte[] bytes, final int offset, final int length) throws IOException {
|
||||||
// Invalidate the buffer, as its contents is no longer in sync with the stream's position.
|
// Invalidate the buffer, as its contents is no longer in sync with the stream's position.
|
||||||
bufferLimit = 0;
|
bufferLimit = 0;
|
||||||
int read = raf.read(pBuffer, pOffset, pLength);
|
int read = raf.read(bytes, offset, length);
|
||||||
|
|
||||||
if (read > 0) {
|
if (read > 0) {
|
||||||
streamPos += read;
|
streamPos += read;
|
||||||
@@ -154,17 +162,17 @@ public final class BufferedFileImageInputStream extends ImageInputStreamImpl {
|
|||||||
return read;
|
return read;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readBuffered(final byte[] pBuffer, final int pOffset, final int pLength) {
|
private int readBuffered(final byte[] bytes, final int offset, final int length) {
|
||||||
// Read as much as possible from buffer
|
// Read as much as possible from buffer
|
||||||
int length = Math.min(bufferLimit - bufferPos, pLength);
|
int available = Math.min(bufferLimit - bufferPos, length);
|
||||||
|
|
||||||
if (length > 0) {
|
if (available > 0) {
|
||||||
System.arraycopy(buffer, bufferPos, pBuffer, pOffset, length);
|
System.arraycopy(buffer, bufferPos, bytes, offset, available);
|
||||||
bufferPos += length;
|
bufferPos += available;
|
||||||
streamPos += length;
|
streamPos += available;
|
||||||
}
|
}
|
||||||
|
|
||||||
return length;
|
return available;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long length() {
|
public long length() {
|
||||||
@@ -237,7 +245,7 @@ public final class BufferedFileImageInputStream extends ImageInputStreamImpl {
|
|||||||
|
|
||||||
// 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 = bufferPos + position - streamPos;
|
long newBufferPos = bufferPos + position - streamPos;
|
||||||
if (newBufferPos >= 0 && newBufferPos <= bufferLimit) {
|
if (newBufferPos >= 0 && newBufferPos < bufferLimit) {
|
||||||
bufferPos = (int) newBufferPos;
|
bufferPos = (int) newBufferPos;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -158,19 +158,18 @@ public final class IIOUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* THIS METHOD WILL ME MOVED/RENAMED, DO NOT USE.
|
* THIS METHOD WILL BE MOVED/RENAMED, DO NOT USE.
|
||||||
*
|
*
|
||||||
* @param registry the registry to unregister from.
|
* @param registry the registry to unregister from.
|
||||||
* @param provider the provider to unregister.
|
* @param provider the provider to unregister.
|
||||||
* @param category the category to unregister from.
|
* @param category the category to unregister from.
|
||||||
*/
|
*/
|
||||||
public static <T> void deregisterProvider(final ServiceRegistry registry, final IIOServiceProvider provider, final Class<T> category) {
|
public static <T> void deregisterProvider(final ServiceRegistry registry, final IIOServiceProvider provider, final Class<T> category) {
|
||||||
// http://www.ibm.com/developerworks/java/library/j-jtp04298.html
|
|
||||||
registry.deregisterServiceProvider(category.cast(provider), category);
|
registry.deregisterServiceProvider(category.cast(provider), category);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* THIS METHOD WILL ME MOVED/RENAMED, DO NOT USE.
|
* THIS METHOD WILL BE MOVED/RENAMED, DO NOT USE.
|
||||||
*
|
*
|
||||||
* @param registry the registry to lookup from.
|
* @param registry the registry to lookup from.
|
||||||
* @param providerClassName name of the provider class.
|
* @param providerClassName name of the provider class.
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Harald Kuhr
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.*;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class containing various raster utility methods.
|
||||||
|
*/
|
||||||
|
public final class RasterUtils {
|
||||||
|
|
||||||
|
private RasterUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a raster with {@code DataBuffer.TYPE_BYTE} transfer type.
|
||||||
|
* Works for any raster from a {@code BufferedImage.TYPE_INT_*} image
|
||||||
|
*
|
||||||
|
* @param raster a {@code Raster} with either transfer type {@code DataBuffer.TYPE_BYTE}
|
||||||
|
* or {@code DataBuffer.TYPE_INT} with `SinglePixelPackedSampleModel`, not {@code null}.
|
||||||
|
* @return a raster with {@code DataBuffer.TYPE_BYTE} transfer type.
|
||||||
|
* @throws IllegalArgumentException if {@code raster} does not have transfer type {@code DataBuffer.TYPE_BYTE}
|
||||||
|
* or {@code DataBuffer.TYPE_INT} with `SinglePixelPackedSampleModel`
|
||||||
|
* @throws NullPointerException if {@code raster} is {@code null}.
|
||||||
|
*/
|
||||||
|
public static Raster asByteRaster(final Raster raster) {
|
||||||
|
return asByteRaster0(raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a writable raster with {@code DataBuffer.TYPE_BYTE} transfer type.
|
||||||
|
* Works for any raster from a {@code BufferedImage.TYPE_INT_*} image.
|
||||||
|
*
|
||||||
|
* @param raster a {@code WritableRaster} with either transfer type {@code DataBuffer.TYPE_BYTE}
|
||||||
|
* or {@code DataBuffer.TYPE_INT} with `SinglePixelPackedSampleModel`, not {@code null}.
|
||||||
|
* @return a writable raster with {@code DataBuffer.TYPE_BYTE} transfer type.
|
||||||
|
* @throws IllegalArgumentException if {@code raster} does not have transfer type {@code DataBuffer.TYPE_BYTE}
|
||||||
|
* or {@code DataBuffer.TYPE_INT} with `SinglePixelPackedSampleModel`
|
||||||
|
* @throws NullPointerException if {@code raster} is {@code null}.
|
||||||
|
*/
|
||||||
|
public static WritableRaster asByteRaster(final WritableRaster raster) {
|
||||||
|
return (WritableRaster) asByteRaster0(raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Raster asByteRaster0(final Raster raster) {
|
||||||
|
switch (raster.getTransferType()) {
|
||||||
|
case DataBuffer.TYPE_BYTE:
|
||||||
|
return raster;
|
||||||
|
case DataBuffer.TYPE_INT:
|
||||||
|
SampleModel sampleModel = raster.getSampleModel();
|
||||||
|
|
||||||
|
if (!(sampleModel instanceof SinglePixelPackedSampleModel)) {
|
||||||
|
throw new IllegalArgumentException(String.format("Requires SinglePixelPackedSampleModel, %s not supported", sampleModel.getClass().getSimpleName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
final int bands = 4;
|
||||||
|
final DataBufferInt buffer = (DataBufferInt) raster.getDataBuffer();
|
||||||
|
|
||||||
|
int w = raster.getWidth();
|
||||||
|
int h = raster.getHeight();
|
||||||
|
int size = buffer.getSize();
|
||||||
|
|
||||||
|
return new WritableRaster(
|
||||||
|
new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, w, h, bands, w * bands, createBandOffsets((SinglePixelPackedSampleModel) sampleModel)),
|
||||||
|
new DataBuffer(DataBuffer.TYPE_BYTE, size * bands) {
|
||||||
|
final int[] MASKS = {
|
||||||
|
0xffffff00,
|
||||||
|
0xffff00ff,
|
||||||
|
0xff00ffff,
|
||||||
|
0x00ffffff,
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getElem(int bank, int i) {
|
||||||
|
int index = i / bands;
|
||||||
|
int shift = (i % bands) * 8;
|
||||||
|
|
||||||
|
return (buffer.getElem(index) >>> shift) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setElem(int bank, int i, int val) {
|
||||||
|
int index = i / bands;
|
||||||
|
int element = i % bands;
|
||||||
|
int shift = element * 8;
|
||||||
|
|
||||||
|
int value = (buffer.getElem(index) & MASKS[element]) | ((val & 0xff) << shift);
|
||||||
|
buffer.setElem(index, value);
|
||||||
|
}
|
||||||
|
}, new Point()) {
|
||||||
|
};
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(String.format("Raster type %d not supported", raster.getTransferType()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int[] createBandOffsets(final SinglePixelPackedSampleModel sampleModel) {
|
||||||
|
notNull(sampleModel, "sampleModel");
|
||||||
|
|
||||||
|
int[] masks = sampleModel.getBitMasks();
|
||||||
|
int[] offs = new int[masks.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < masks.length; i++) {
|
||||||
|
int mask = masks[i];
|
||||||
|
int off = 0;
|
||||||
|
|
||||||
|
// TODO: FixMe! This only works for standard 8 bit masks (0xFF)
|
||||||
|
if (mask != 0) {
|
||||||
|
while ((mask & 0xFF) == 0) {
|
||||||
|
mask >>>= 8;
|
||||||
|
off++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
offs[i] = off;
|
||||||
|
}
|
||||||
|
|
||||||
|
return offs;
|
||||||
|
}
|
||||||
|
}
|
||||||
+85
-1
@@ -35,6 +35,7 @@ import org.junit.Test;
|
|||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.color.ICC_ColorSpace;
|
import java.awt.color.ICC_ColorSpace;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
@@ -184,9 +185,27 @@ public class ColorSpacesTest {
|
|||||||
ColorSpaces.isCS_sRGB(null);
|
ColorSpaces.isCS_sRGB(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsCS_GRAYTrue() {
|
||||||
|
assertTrue(ColorSpaces.isCS_GRAY(ICC_Profile.getInstance(ColorSpace.CS_GRAY)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsCS_GRAYFalse() {
|
||||||
|
assertFalse(ColorSpaces.isCS_GRAY(ICC_Profile.getInstance(ColorSpace.CS_sRGB)));
|
||||||
|
assertFalse(ColorSpaces.isCS_GRAY(ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB)));
|
||||||
|
assertFalse(ColorSpaces.isCS_GRAY(ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ)));
|
||||||
|
assertFalse(ColorSpaces.isCS_GRAY(ICC_Profile.getInstance(ColorSpace.CS_PYCC)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testIsCS_GRAYNull() {
|
||||||
|
ColorSpaces.isCS_GRAY(null);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEqualHeadersDifferentProfile() throws IOException {
|
public void testEqualHeadersDifferentProfile() throws IOException {
|
||||||
// These profiles are extracted from various JPEGs, and have the exact same profile header...
|
// These profiles are extracted from various JPEGs, and have the exact same profile header (but are different)...
|
||||||
ICC_Profile profile1 = ICC_Profile.getInstance(getClass().getResourceAsStream("/profiles/adobe_rgb_1998.icc"));
|
ICC_Profile profile1 = ICC_Profile.getInstance(getClass().getResourceAsStream("/profiles/adobe_rgb_1998.icc"));
|
||||||
ICC_Profile profile2 = ICC_Profile.getInstance(getClass().getResourceAsStream("/profiles/color_match_rgb.icc"));
|
ICC_Profile profile2 = ICC_Profile.getInstance(getClass().getResourceAsStream("/profiles/color_match_rgb.icc"));
|
||||||
|
|
||||||
@@ -197,4 +216,69 @@ public class ColorSpacesTest {
|
|||||||
|
|
||||||
assertNotSame(cs1, cs2);
|
assertNotSame(cs1, cs2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadProfileBytesSame() throws IOException {
|
||||||
|
ICC_Profile profile = ICC_Profile.getInstance(getClass().getResourceAsStream("/profiles/adobe_rgb_1998.icc"));
|
||||||
|
ICC_Profile profile1 = ColorSpaces.createProfile(profile.getData());
|
||||||
|
ICC_Profile profile2 = ColorSpaces.createProfile(profile.getData());
|
||||||
|
|
||||||
|
assertEquals(profile1, profile2);
|
||||||
|
assertSame(profile1, profile2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadProfileInputStreamSame() throws IOException {
|
||||||
|
ICC_Profile profile1 = ColorSpaces.readProfile(getClass().getResourceAsStream("/profiles/adobe_rgb_1998.icc"));
|
||||||
|
ICC_Profile profile2 = ColorSpaces.readProfile(getClass().getResourceAsStream("/profiles/adobe_rgb_1998.icc"));
|
||||||
|
|
||||||
|
assertEquals(profile1, profile2);
|
||||||
|
assertSame(profile1, profile2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadProfileDifferent() throws IOException {
|
||||||
|
// These profiles are extracted from various JPEGs, and have the exact same profile header (but are different profiles)...
|
||||||
|
ICC_Profile profile1 = ColorSpaces.readProfile(getClass().getResourceAsStream("/profiles/adobe_rgb_1998.icc"));
|
||||||
|
ICC_Profile profile2 = ColorSpaces.readProfile(getClass().getResourceAsStream("/profiles/color_match_rgb.icc"));
|
||||||
|
|
||||||
|
assertNotSame(profile1, profile2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadProfileBytesSameAsCached() throws IOException {
|
||||||
|
ICC_Profile profile = ICC_Profile.getInstance(getClass().getResourceAsStream("/profiles/adobe_rgb_1998.icc"));
|
||||||
|
ICC_ColorSpace cs1 = ColorSpaces.createColorSpace(profile);
|
||||||
|
ICC_Profile profile2 = ColorSpaces.createProfile(profile.getData());
|
||||||
|
|
||||||
|
assertEquals(cs1.getProfile(), profile2);
|
||||||
|
assertSame(cs1.getProfile(), profile2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadProfileInputStreamSameAsCached() throws IOException {
|
||||||
|
ICC_ColorSpace cs1 = ColorSpaces.createColorSpace(ICC_Profile.getInstance(getClass().getResourceAsStream("/profiles/adobe_rgb_1998.icc")));
|
||||||
|
ICC_Profile profile2 = ColorSpaces.readProfile(getClass().getResourceAsStream("/profiles/adobe_rgb_1998.icc"));
|
||||||
|
|
||||||
|
assertEquals(cs1.getProfile(), profile2);
|
||||||
|
assertSame(cs1.getProfile(), profile2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadProfileBytesSameAsInternal() {
|
||||||
|
ICC_Profile profile1 = ICC_Profile.getInstance(ColorSpace.CS_sRGB);
|
||||||
|
ICC_Profile profile2 = ColorSpaces.createProfile(ICC_Profile.getInstance(ColorSpace.CS_sRGB).getData());
|
||||||
|
|
||||||
|
assertEquals(profile1, profile2);
|
||||||
|
assertSame(profile1, profile2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadProfileInputStreamSameAsInternal() throws IOException {
|
||||||
|
ICC_Profile profile1 = ICC_Profile.getInstance(ColorSpace.CS_sRGB);
|
||||||
|
ICC_Profile profile2 = ColorSpaces.readProfile(new ByteArrayInputStream(ICC_Profile.getInstance(ColorSpace.CS_sRGB).getData()));
|
||||||
|
|
||||||
|
assertEquals(profile1, profile2);
|
||||||
|
assertSame(profile1, profile2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-2
@@ -39,8 +39,6 @@ import java.io.IOException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.mockito.Matchers.any;
|
|
||||||
import static org.mockito.Matchers.eq;
|
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
public class KCMSSanitizerStrategyTest {
|
public class KCMSSanitizerStrategyTest {
|
||||||
|
|||||||
+197
-154
@@ -67,8 +67,9 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreate() throws IOException {
|
public void testCreate() throws IOException {
|
||||||
BufferedFileImageInputStream stream = new BufferedFileImageInputStream(File.createTempFile("empty", ".tmp"));
|
try (BufferedFileImageInputStream stream = new BufferedFileImageInputStream(File.createTempFile("empty", ".tmp"))) {
|
||||||
assertEquals("Data length should be same as stream length", 0, stream.length());
|
assertEquals("Data length should be same as stream length", 0, stream.length());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -104,12 +105,12 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
byte[] data = new byte[1024 * 1024];
|
byte[] data = new byte[1024 * 1024];
|
||||||
File file = randomDataToFile(data);
|
File file = randomDataToFile(data);
|
||||||
|
|
||||||
BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file);
|
try (BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
|
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
||||||
|
|
||||||
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
for (byte value : data) {
|
||||||
|
assertEquals("Wrong data read", value & 0xff, stream.read());
|
||||||
for (byte value : data) {
|
}
|
||||||
assertEquals("Wrong data read", value & 0xff, stream.read());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,15 +119,15 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
byte[] data = new byte[1024 * 1024];
|
byte[] data = new byte[1024 * 1024];
|
||||||
File file = randomDataToFile(data);
|
File file = randomDataToFile(data);
|
||||||
|
|
||||||
BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file);
|
try (BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
|
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
||||||
|
|
||||||
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
byte[] result = new byte[1024];
|
||||||
|
|
||||||
byte[] result = new byte[1024];
|
for (int i = 0; i < data.length / result.length; i++) {
|
||||||
|
stream.readFully(result);
|
||||||
for (int i = 0; i < data.length / result.length; i++) {
|
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
|
||||||
stream.readFully(result);
|
}
|
||||||
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,16 +136,16 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
byte[] data = new byte[1024 * 14];
|
byte[] data = new byte[1024 * 14];
|
||||||
File file = randomDataToFile(data);
|
File file = randomDataToFile(data);
|
||||||
|
|
||||||
BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file);
|
try (BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
|
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
||||||
|
|
||||||
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
byte[] result = new byte[7];
|
||||||
|
|
||||||
byte[] result = new byte[7];
|
for (int i = 0; i < data.length / result.length; i += 2) {
|
||||||
|
stream.readFully(result);
|
||||||
for (int i = 0; i < data.length / result.length; i += 2) {
|
stream.skipBytes(result.length);
|
||||||
stream.readFully(result);
|
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
|
||||||
stream.skipBytes(result.length);
|
}
|
||||||
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,19 +154,35 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
byte[] data = new byte[1024 * 18];
|
byte[] data = new byte[1024 * 18];
|
||||||
File file = randomDataToFile(data);
|
File file = randomDataToFile(data);
|
||||||
|
|
||||||
BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file);
|
try (BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
|
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
||||||
|
|
||||||
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
byte[] result = new byte[9];
|
||||||
|
|
||||||
byte[] result = new byte[9];
|
for (int i = 0; i < data.length / result.length; i++) {
|
||||||
|
// Read backwards
|
||||||
|
long newPos = stream.length() - result.length - i * result.length;
|
||||||
|
stream.seek(newPos);
|
||||||
|
assertEquals("Wrong stream position", newPos, stream.getStreamPosition());
|
||||||
|
stream.readFully(result);
|
||||||
|
assertTrue("Wrong data read: " + i, rangeEquals(data, (int) newPos, result, 0, result.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < data.length / result.length; i++) {
|
@Test
|
||||||
// Read backwards
|
public void testReadOutsideDataSeek0Read() throws IOException {
|
||||||
long newPos = stream.length() - result.length - i * result.length;
|
byte[] data = new byte[256];
|
||||||
stream.seek(newPos);
|
File file = randomDataToFile(data);
|
||||||
assertEquals("Wrong stream position", newPos, stream.getStreamPosition());
|
|
||||||
stream.readFully(result);
|
try (BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
assertTrue("Wrong data read: " + i, rangeEquals(data, (int) newPos, result, 0, result.length));
|
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
||||||
|
|
||||||
|
byte[] buffer = new byte[data.length * 2];
|
||||||
|
stream.read(buffer);
|
||||||
|
stream.seek(0);
|
||||||
|
assertNotEquals(-1, stream.read());
|
||||||
|
assertNotEquals(-1, stream.read(buffer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,10 +193,10 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
long value = ByteBuffer.wrap(bytes).getLong();
|
long value = ByteBuffer.wrap(bytes).getLong();
|
||||||
|
|
||||||
// Create stream
|
// Create stream
|
||||||
ImageInputStream stream = new BufferedFileImageInputStream(file);
|
try (ImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
|
for (int i = 1; i <= 64; i++) {
|
||||||
for (int i = 1; i <= 64; i++) {
|
assertEquals(String.format("bit %d differ", i), (value << (i - 1L)) >>> 63L, stream.readBit());
|
||||||
assertEquals(String.format("bit %d differ", i), (value << (i - 1L)) >>> 63L, stream.readBit());
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,12 +207,12 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
long value = ByteBuffer.wrap(bytes).getLong();
|
long value = ByteBuffer.wrap(bytes).getLong();
|
||||||
|
|
||||||
// Create stream
|
// Create stream
|
||||||
ImageInputStream stream = new BufferedFileImageInputStream(file);
|
try (ImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
|
for (int i = 1; i <= 64; i++) {
|
||||||
for (int i = 1; i <= 64; i++) {
|
stream.seek(0);
|
||||||
stream.seek(0);
|
assertEquals(String.format("bit %d differ", i), value >>> (64L - i), stream.readBits(i));
|
||||||
assertEquals(String.format("bit %d differ", i), value >>> (64L - i), stream.readBits(i));
|
assertEquals(i % 8, stream.getBitOffset());
|
||||||
assertEquals(i % 8, stream.getBitOffset());
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,13 +223,13 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
long value = ByteBuffer.wrap(bytes).getLong();
|
long value = ByteBuffer.wrap(bytes).getLong();
|
||||||
|
|
||||||
// Create stream
|
// Create stream
|
||||||
ImageInputStream stream = new BufferedFileImageInputStream(file);
|
try (ImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
|
for (int i = 1; i <= 60; i++) {
|
||||||
for (int i = 1; i <= 60; i++) {
|
stream.seek(0);
|
||||||
stream.seek(0);
|
stream.setBitOffset(i % 8);
|
||||||
stream.setBitOffset(i % 8);
|
assertEquals(String.format("bit %d differ", i), (value << (i % 8)) >>> (64L - i), stream.readBits(i));
|
||||||
assertEquals(String.format("bit %d differ", i), (value << (i % 8)) >>> (64L - i), stream.readBits(i));
|
assertEquals(i * 2 % 8, stream.getBitOffset());
|
||||||
assertEquals(i * 2 % 8, stream.getBitOffset());
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,35 +238,37 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
byte[] bytes = new byte[8743]; // Slightly more than one buffer size
|
byte[] bytes = new byte[8743]; // Slightly more than one buffer size
|
||||||
File file = randomDataToFile(bytes);
|
File file = randomDataToFile(bytes);
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||||
final ImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length / 2; i++) {
|
try (final ImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
assertEquals(buffer.getShort(), stream.readShort());
|
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
for (int i = 0; i < bytes.length / 2; i++) {
|
||||||
@Override
|
assertEquals(buffer.getShort(), stream.readShort());
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readShort();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
stream.seek(0);
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
@Override
|
||||||
buffer.position(0);
|
public void run() throws Throwable {
|
||||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
stream.readShort();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length / 2; i++) {
|
stream.seek(0);
|
||||||
assertEquals(buffer.getShort(), stream.readShort());
|
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||||
}
|
buffer.position(0);
|
||||||
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
for (int i = 0; i < bytes.length / 2; i++) {
|
||||||
@Override
|
assertEquals(buffer.getShort(), stream.readShort());
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readShort();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() throws Throwable {
|
||||||
|
stream.readShort();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -257,35 +276,37 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
byte[] bytes = new byte[8743]; // Slightly more than one buffer size
|
byte[] bytes = new byte[8743]; // Slightly more than one buffer size
|
||||||
File file = randomDataToFile(bytes);
|
File file = randomDataToFile(bytes);
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||||
final ImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length / 4; i++) {
|
try (final ImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
assertEquals(buffer.getInt(), stream.readInt());
|
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
for (int i = 0; i < bytes.length / 4; i++) {
|
||||||
@Override
|
assertEquals(buffer.getInt(), stream.readInt());
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readInt();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
stream.seek(0);
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
@Override
|
||||||
buffer.position(0);
|
public void run() throws Throwable {
|
||||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
stream.readInt();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length / 4; i++) {
|
stream.seek(0);
|
||||||
assertEquals(buffer.getInt(), stream.readInt());
|
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||||
}
|
buffer.position(0);
|
||||||
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
for (int i = 0; i < bytes.length / 4; i++) {
|
||||||
@Override
|
assertEquals(buffer.getInt(), stream.readInt());
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readInt();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() throws Throwable {
|
||||||
|
stream.readInt();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -293,35 +314,37 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
byte[] bytes = new byte[8743]; // Slightly more than one buffer size
|
byte[] bytes = new byte[8743]; // Slightly more than one buffer size
|
||||||
File file = randomDataToFile(bytes);
|
File file = randomDataToFile(bytes);
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||||
final ImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length / 8; i++) {
|
try (final ImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
assertEquals(buffer.getLong(), stream.readLong());
|
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
for (int i = 0; i < bytes.length / 8; i++) {
|
||||||
@Override
|
assertEquals(buffer.getLong(), stream.readLong());
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readLong();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
stream.seek(0);
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
@Override
|
||||||
buffer.position(0);
|
public void run() throws Throwable {
|
||||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
stream.readLong();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length / 8; i++) {
|
stream.seek(0);
|
||||||
assertEquals(buffer.getLong(), stream.readLong());
|
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||||
}
|
buffer.position(0);
|
||||||
|
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
for (int i = 0; i < bytes.length / 8; i++) {
|
||||||
@Override
|
assertEquals(buffer.getLong(), stream.readLong());
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readLong();
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() throws Throwable {
|
||||||
|
stream.readLong();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -329,49 +352,50 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
byte[] bytes = new byte[9];
|
byte[] bytes = new byte[9];
|
||||||
File file = randomDataToFile(bytes);
|
File file = randomDataToFile(bytes);
|
||||||
|
|
||||||
final ImageInputStream stream = new BufferedFileImageInputStream(file);
|
try (final ImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
stream.seek(1000);
|
stream.seek(1000);
|
||||||
|
|
||||||
assertEquals(-1, stream.read());
|
assertEquals(-1, stream.read());
|
||||||
assertEquals(-1, stream.read(new byte[1], 0, 1));
|
assertEquals(-1, stream.read(new byte[1], 0, 1));
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Throwable {
|
public void run() throws Throwable {
|
||||||
stream.readFully(new byte[1]);
|
stream.readFully(new byte[1]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Throwable {
|
public void run() throws Throwable {
|
||||||
stream.readByte();
|
stream.readByte();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Throwable {
|
public void run() throws Throwable {
|
||||||
stream.readShort();
|
stream.readShort();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Throwable {
|
public void run() throws Throwable {
|
||||||
stream.readInt();
|
stream.readInt();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Throwable {
|
public void run() throws Throwable {
|
||||||
stream.readLong();
|
stream.readLong();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
stream.seek(0);
|
stream.seek(0);
|
||||||
for (byte value : bytes) {
|
for (byte value : bytes) {
|
||||||
assertEquals(value, stream.readByte());
|
assertEquals(value, stream.readByte());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(-1, stream.read());
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(-1, stream.read());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -383,4 +407,23 @@ public class BufferedFileImageInputStreamTest {
|
|||||||
stream.close();
|
stream.close();
|
||||||
verify(mock, only()).close();
|
verify(mock, only()).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWorkaroundForWBMPImageReaderExpectsReadToBehaveAsReadFully() throws IOException {
|
||||||
|
// See #606 for details.
|
||||||
|
// Bug in JDK WBMPImageReader, uses read(byte[], int, int) instead of readFully(byte[], int, int).
|
||||||
|
// Ie: Relies on read to return all bytes at once, without blocking
|
||||||
|
int size = BufferedFileImageInputStream.DEFAULT_BUFFER_SIZE * 7;
|
||||||
|
byte[] bytes = new byte[size];
|
||||||
|
File file = randomDataToFile(bytes);
|
||||||
|
|
||||||
|
try (BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file)) {
|
||||||
|
byte[] result = new byte[size];
|
||||||
|
int head = stream.read(result, 0, 12); // Provoke a buffered read
|
||||||
|
int len = stream.read(result, 12, size - 12); // Rest of buffer + direct read
|
||||||
|
|
||||||
|
assertEquals(size, len + head);
|
||||||
|
assertArrayEquals(bytes, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+51
-14
@@ -45,9 +45,8 @@ import javax.imageio.spi.IIORegistry;
|
|||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.geom.AffineTransform;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.*;
|
||||||
import java.awt.image.SampleModel;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
@@ -57,6 +56,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.lang.Math.min;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
@@ -1151,7 +1151,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
// At least imageStarted and imageComplete, plus any number of imageProgress
|
// At least imageStarted and imageComplete, plus any number of imageProgress
|
||||||
InOrder ordered = inOrder(listener);
|
InOrder ordered = inOrder(listener);
|
||||||
ordered.verify(listener).imageStarted(reader, 0);
|
ordered.verify(listener).imageStarted(reader, 0);
|
||||||
ordered.verify(listener, atLeastOnce()).imageProgress(eq(reader), anyInt());
|
ordered.verify(listener, atLeastOnce()).imageProgress(eq(reader), anyFloat());
|
||||||
ordered.verify(listener).imageComplete(reader);
|
ordered.verify(listener).imageComplete(reader);
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
@@ -1184,9 +1184,9 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
ordered.verify(listenerToo).imageStarted(reader, 0);
|
ordered.verify(listenerToo).imageStarted(reader, 0);
|
||||||
ordered.verify(listenerThree).imageStarted(reader, 0);
|
ordered.verify(listenerThree).imageStarted(reader, 0);
|
||||||
|
|
||||||
ordered.verify(listener, atLeastOnce()).imageProgress(eq(reader), anyInt());
|
ordered.verify(listener, atLeastOnce()).imageProgress(eq(reader), anyFloat());
|
||||||
ordered.verify(listenerToo, atLeastOnce()).imageProgress(eq(reader), anyInt());
|
ordered.verify(listenerToo, atLeastOnce()).imageProgress(eq(reader), anyFloat());
|
||||||
ordered.verify(listenerThree, atLeastOnce()).imageProgress(eq(reader), anyInt());
|
ordered.verify(listenerThree, atLeastOnce()).imageProgress(eq(reader), anyFloat());
|
||||||
|
|
||||||
ordered.verify(listener).imageComplete(reader);
|
ordered.verify(listener).imageComplete(reader);
|
||||||
ordered.verify(listenerToo).imageComplete(reader);
|
ordered.verify(listenerToo).imageComplete(reader);
|
||||||
@@ -1226,7 +1226,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should not have called any methods...
|
// Should not have called any methods...
|
||||||
verifyZeroInteractions(listener);
|
verifyNoInteractions(listener);
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1253,11 +1253,11 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should not have called any methods on listener1...
|
// Should not have called any methods on listener1...
|
||||||
verifyZeroInteractions(listener);
|
verifyNoInteractions(listener);
|
||||||
|
|
||||||
InOrder ordered = inOrder(listenerToo);
|
InOrder ordered = inOrder(listenerToo);
|
||||||
ordered.verify(listenerToo).imageStarted(reader, 0);
|
ordered.verify(listenerToo).imageStarted(reader, 0);
|
||||||
ordered.verify(listenerToo, atLeastOnce()).imageProgress(eq(reader), anyInt());
|
ordered.verify(listenerToo, atLeastOnce()).imageProgress(eq(reader), anyFloat());
|
||||||
ordered.verify(listenerToo).imageComplete(reader);
|
ordered.verify(listenerToo).imageComplete(reader);
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
@@ -1281,7 +1281,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should not have called any methods...
|
// Should not have called any methods...
|
||||||
verifyZeroInteractions(listener);
|
verifyNoInteractions(listener);
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1307,8 +1307,8 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should not have called any methods...
|
// Should not have called any methods...
|
||||||
verifyZeroInteractions(listener);
|
verifyNoInteractions(listener);
|
||||||
verifyZeroInteractions(listenerToo);
|
verifyNoInteractions(listenerToo);
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1333,7 +1333,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
doAnswer(abort).when(abortingListener).imageStarted(any(ImageReader.class), anyInt());
|
doAnswer(abort).when(abortingListener).imageStarted(any(ImageReader.class), anyInt());
|
||||||
doAnswer(abort).when(abortingListener).imageProgress(any(ImageReader.class), anyInt());
|
doAnswer(abort).when(abortingListener).imageProgress(any(ImageReader.class), anyFloat());
|
||||||
|
|
||||||
reader.addIIOReadProgressListener(abortingListener);
|
reader.addIIOReadProgressListener(abortingListener);
|
||||||
|
|
||||||
@@ -1738,6 +1738,43 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected List<TestData> getTestDataForAffineTransformOpCompatibility() {
|
||||||
|
// Allow subclasses to filter out test data that can't be converted to a compatible image without data loss
|
||||||
|
return getTestData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAffineTransformOpCompatibility() throws IOException {
|
||||||
|
// Test that the output of normal images are compatible with AffineTransformOp. Is unlikely to work on all test data
|
||||||
|
ImageReader reader = createReader();
|
||||||
|
|
||||||
|
for (TestData testData : getTestDataForAffineTransformOpCompatibility()) {
|
||||||
|
try (ImageInputStream input = testData.getInputStream()) {
|
||||||
|
reader.setInput(input);
|
||||||
|
|
||||||
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
|
param.setSourceRegion(new Rectangle(min(reader.getWidth(0), 64), min(reader.getHeight(0), 64)));
|
||||||
|
|
||||||
|
BufferedImage originalImage = reader.read(0, param);
|
||||||
|
|
||||||
|
AffineTransform transform = AffineTransform.getTranslateInstance(10, 10);
|
||||||
|
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
|
||||||
|
|
||||||
|
try {
|
||||||
|
BufferedImage resultImage = op.filter(originalImage, null); // The exception happens here
|
||||||
|
assertNotNull(resultImage);
|
||||||
|
}
|
||||||
|
catch (ImagingOpException e) {
|
||||||
|
fail(e.getMessage() + ".\n\t"
|
||||||
|
+ originalImage + "\n\t"
|
||||||
|
+ testData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@Ignore("TODO: Implement")
|
@Ignore("TODO: Implement")
|
||||||
@Test
|
@Test
|
||||||
public void testSetDestinationBands() {
|
public void testSetDestinationBands() {
|
||||||
|
|||||||
+11
-12
@@ -52,7 +52,6 @@ import java.net.URL;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Matchers.anyInt;
|
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -104,7 +103,7 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
|||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final RenderedImage getTestData(final int index) {
|
protected final RenderedImage getTestData(final int index) {
|
||||||
return getTestData().get(index);
|
return getTestData().get(index);
|
||||||
}
|
}
|
||||||
@@ -219,7 +218,7 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
|||||||
// At least imageStarted and imageComplete, plus any number of imageProgress
|
// At least imageStarted and imageComplete, plus any number of imageProgress
|
||||||
InOrder ordered = inOrder(listener);
|
InOrder ordered = inOrder(listener);
|
||||||
ordered.verify(listener).imageStarted(writer, 0);
|
ordered.verify(listener).imageStarted(writer, 0);
|
||||||
ordered.verify(listener, atLeastOnce()).imageProgress(eq(writer), anyInt());
|
ordered.verify(listener, atLeastOnce()).imageProgress(eq(writer), anyFloat());
|
||||||
ordered.verify(listener).imageComplete(writer);
|
ordered.verify(listener).imageComplete(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,9 +250,9 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
|||||||
ordered.verify(listenerToo).imageStarted(writer, 0);
|
ordered.verify(listenerToo).imageStarted(writer, 0);
|
||||||
ordered.verify(listenerThree).imageStarted(writer, 0);
|
ordered.verify(listenerThree).imageStarted(writer, 0);
|
||||||
|
|
||||||
ordered.verify(listener, atLeastOnce()).imageProgress(eq(writer), anyInt());
|
ordered.verify(listener, atLeastOnce()).imageProgress(eq(writer), anyFloat());
|
||||||
ordered.verify(listenerToo, atLeastOnce()).imageProgress(eq(writer), anyInt());
|
ordered.verify(listenerToo, atLeastOnce()).imageProgress(eq(writer), anyFloat());
|
||||||
ordered.verify(listenerThree, atLeastOnce()).imageProgress(eq(writer), anyInt());
|
ordered.verify(listenerThree, atLeastOnce()).imageProgress(eq(writer), anyFloat());
|
||||||
|
|
||||||
ordered.verify(listener).imageComplete(writer);
|
ordered.verify(listener).imageComplete(writer);
|
||||||
ordered.verify(listenerToo).imageComplete(writer);
|
ordered.verify(listenerToo).imageComplete(writer);
|
||||||
@@ -290,7 +289,7 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should not have called any methods...
|
// Should not have called any methods...
|
||||||
verifyZeroInteractions(listener);
|
verifyNoInteractions(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -315,12 +314,12 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should not have called any methods...
|
// Should not have called any methods...
|
||||||
verifyZeroInteractions(listener);
|
verifyNoInteractions(listener);
|
||||||
|
|
||||||
// At least imageStarted and imageComplete, plus any number of imageProgress
|
// At least imageStarted and imageComplete, plus any number of imageProgress
|
||||||
InOrder ordered = inOrder(listenerToo);
|
InOrder ordered = inOrder(listenerToo);
|
||||||
ordered.verify(listenerToo).imageStarted(writer, 0);
|
ordered.verify(listenerToo).imageStarted(writer, 0);
|
||||||
ordered.verify(listenerToo, atLeastOnce()).imageProgress(eq(writer), anyInt());
|
ordered.verify(listenerToo, atLeastOnce()).imageProgress(eq(writer), anyFloat());
|
||||||
ordered.verify(listenerToo).imageComplete(writer);
|
ordered.verify(listenerToo).imageComplete(writer);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -345,7 +344,7 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should not have called any methods...
|
// Should not have called any methods...
|
||||||
verifyZeroInteractions(listener);
|
verifyNoInteractions(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -371,7 +370,7 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Should not have called any methods...
|
// Should not have called any methods...
|
||||||
verifyZeroInteractions(listener);
|
verifyNoInteractions(listener);
|
||||||
verifyZeroInteractions(listenerToo);
|
verifyNoInteractions(listenerToo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+199
@@ -0,0 +1,199 @@
|
|||||||
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.color.ColorSpace;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RasterUtilsTest.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: RasterUtilsTest.java,v 1.0 05/05/2021 haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class RasterUtilsTest {
|
||||||
|
@Test(expected = NullPointerException.class)
|
||||||
|
public void testAsByteRasterFromNull() {
|
||||||
|
RasterUtils.asByteRaster((Raster) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("RedundantCast")
|
||||||
|
@Test(expected = NullPointerException.class)
|
||||||
|
public void testAsByteRasterWritableFromNull() {
|
||||||
|
RasterUtils.asByteRaster((WritableRaster) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAsByteRasterPassThrough() {
|
||||||
|
WritableRaster[] rasters = new WritableRaster[] {
|
||||||
|
new BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR).getRaster(),
|
||||||
|
new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR).getRaster(),
|
||||||
|
new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE).getRaster(),
|
||||||
|
new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY).getRaster(),
|
||||||
|
Raster.createBandedRaster(DataBuffer.TYPE_BYTE, 1, 1, 7, null),
|
||||||
|
Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1, 1, 2, null),
|
||||||
|
new WritableRaster(new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE, 1, 1, 1, 1, new int[1]), new Point(0, 0)) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (Raster raster : rasters) {
|
||||||
|
assertSame(raster, RasterUtils.asByteRaster(raster));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (WritableRaster raster : rasters) {
|
||||||
|
assertSame(raster, RasterUtils.asByteRaster(raster));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAsByteRasterWritableFromTYPE_INT_RGB() {
|
||||||
|
BufferedImage image = new BufferedImage(9, 11, BufferedImage.TYPE_INT_RGB);
|
||||||
|
|
||||||
|
WritableRaster raster = RasterUtils.asByteRaster(image.getRaster());
|
||||||
|
|
||||||
|
assertEquals(DataBuffer.TYPE_BYTE, raster.getTransferType());
|
||||||
|
assertEquals(PixelInterleavedSampleModel.class, raster.getSampleModel().getClass());
|
||||||
|
assertEquals(image.getWidth(), raster.getWidth());
|
||||||
|
assertEquals(image.getHeight(), raster.getHeight());
|
||||||
|
|
||||||
|
assertEquals(3, raster.getNumBands());
|
||||||
|
assertEquals(3, raster.getNumDataElements());
|
||||||
|
|
||||||
|
assertImageRasterEquals(image, raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAsByteRasterWritableFromTYPE_INT_ARGB() {
|
||||||
|
BufferedImage image = new BufferedImage(9, 11, BufferedImage.TYPE_INT_ARGB);
|
||||||
|
|
||||||
|
WritableRaster raster = RasterUtils.asByteRaster(image.getRaster());
|
||||||
|
|
||||||
|
assertEquals(DataBuffer.TYPE_BYTE, raster.getTransferType());
|
||||||
|
assertEquals(PixelInterleavedSampleModel.class, raster.getSampleModel().getClass());
|
||||||
|
assertEquals(image.getWidth(), raster.getWidth());
|
||||||
|
assertEquals(image.getHeight(), raster.getHeight());
|
||||||
|
|
||||||
|
assertEquals(4, raster.getNumBands());
|
||||||
|
assertEquals(4, raster.getNumDataElements());
|
||||||
|
|
||||||
|
assertImageRasterEquals(image, raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAsByteRasterWritableFromTYPE_INT_ARGB_PRE() {
|
||||||
|
BufferedImage image = new BufferedImage(9, 11, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||||
|
|
||||||
|
WritableRaster raster = RasterUtils.asByteRaster(image.getRaster());
|
||||||
|
|
||||||
|
assertEquals(DataBuffer.TYPE_BYTE, raster.getTransferType());
|
||||||
|
assertEquals(PixelInterleavedSampleModel.class, raster.getSampleModel().getClass());
|
||||||
|
assertEquals(image.getWidth(), raster.getWidth());
|
||||||
|
assertEquals(image.getHeight(), raster.getHeight());
|
||||||
|
|
||||||
|
assertEquals(4, raster.getNumBands());
|
||||||
|
assertEquals(4, raster.getNumDataElements());
|
||||||
|
|
||||||
|
// We don't assert on values here, as the premultiplied values makes it hard...
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAsByteRasterWritableFromTYPE_INT_BGR() {
|
||||||
|
BufferedImage image = new BufferedImage(9, 11, BufferedImage.TYPE_INT_BGR);
|
||||||
|
|
||||||
|
WritableRaster raster = RasterUtils.asByteRaster(image.getRaster());
|
||||||
|
|
||||||
|
assertEquals(DataBuffer.TYPE_BYTE, raster.getTransferType());
|
||||||
|
assertEquals(PixelInterleavedSampleModel.class, raster.getSampleModel().getClass());
|
||||||
|
assertEquals(image.getWidth(), raster.getWidth());
|
||||||
|
assertEquals(image.getHeight(), raster.getHeight());
|
||||||
|
|
||||||
|
assertEquals(3, raster.getNumBands());
|
||||||
|
assertEquals(3, raster.getNumDataElements());
|
||||||
|
|
||||||
|
assertImageRasterEquals(image, raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAsByteRasterWritableFromTYPE_CUSTOM_GRAB() {
|
||||||
|
BufferedImage image = ImageTypeSpecifier.createPacked(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||||
|
0x00FF0000,
|
||||||
|
0xFF000000,
|
||||||
|
0x000000FF,
|
||||||
|
0x0000FF00,
|
||||||
|
DataBuffer.TYPE_INT, false).createBufferedImage(7, 13);
|
||||||
|
|
||||||
|
WritableRaster raster = RasterUtils.asByteRaster(image.getRaster());
|
||||||
|
|
||||||
|
assertEquals(DataBuffer.TYPE_BYTE, raster.getTransferType());
|
||||||
|
assertEquals(PixelInterleavedSampleModel.class, raster.getSampleModel().getClass());
|
||||||
|
assertEquals(image.getWidth(), raster.getWidth());
|
||||||
|
assertEquals(image.getHeight(), raster.getHeight());
|
||||||
|
|
||||||
|
assertEquals(4, raster.getNumBands());
|
||||||
|
assertEquals(4, raster.getNumDataElements());
|
||||||
|
|
||||||
|
assertImageRasterEquals(image, raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAsByteRasterWritableFromTYPE_CUSTOM_BxRG() {
|
||||||
|
BufferedImage image = ImageTypeSpecifier.createPacked(ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||||
|
0x0000FF00,
|
||||||
|
0x000000FF,
|
||||||
|
0xFF000000,
|
||||||
|
0,
|
||||||
|
DataBuffer.TYPE_INT, false).createBufferedImage(7, 13);
|
||||||
|
|
||||||
|
WritableRaster raster = RasterUtils.asByteRaster(image.getRaster());
|
||||||
|
|
||||||
|
assertEquals(DataBuffer.TYPE_BYTE, raster.getTransferType());
|
||||||
|
assertEquals(PixelInterleavedSampleModel.class, raster.getSampleModel().getClass());
|
||||||
|
assertEquals(image.getWidth(), raster.getWidth());
|
||||||
|
assertEquals(image.getHeight(), raster.getHeight());
|
||||||
|
|
||||||
|
assertEquals(3, raster.getNumBands());
|
||||||
|
assertEquals(3, raster.getNumDataElements());
|
||||||
|
|
||||||
|
assertImageRasterEquals(image, raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertImageRasterEquals(BufferedImage image, WritableRaster raster) {
|
||||||
|
// NOTE: This is NOT necessarily how the values are stored in the data buffer
|
||||||
|
int[] argbOffs = new int[] {16, 8, 0, 24};
|
||||||
|
|
||||||
|
Raster imageRaster = image.getRaster();
|
||||||
|
|
||||||
|
Random rng = new Random(27365481723L);
|
||||||
|
|
||||||
|
for (int y = 0; y < raster.getHeight(); y++) {
|
||||||
|
for (int x = 0; x < raster.getWidth(); x++) {
|
||||||
|
int argb = 0;
|
||||||
|
|
||||||
|
for (int b = 0; b < raster.getNumBands(); b++) {
|
||||||
|
int s = rng.nextInt(0xFF);
|
||||||
|
raster.setSample(x, y, b, s);
|
||||||
|
|
||||||
|
assertEquals(s, raster.getSample(x, y, b));
|
||||||
|
assertEquals(s, imageRaster.getSample(x, y, b));
|
||||||
|
|
||||||
|
argb |= (s << argbOffs[b]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raster.getNumBands() < 4) {
|
||||||
|
argb |= 0xFF000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int expectedArgb = image.getRGB(x, y);
|
||||||
|
if (argb != expectedArgb) {
|
||||||
|
assertEquals(x + ", " + y + ": ", String.format("#%08x", expectedArgb), String.format("#%08x", argb));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-hdr</artifactId>
|
<artifactId>imageio-hdr</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
|
||||||
|
|||||||
+10
-2
@@ -38,12 +38,14 @@ import java.util.Arrays;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TGAImageReaderTest
|
* HDRImageReaderTest
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @author last modified by $Author: haraldk$
|
* @author last modified by $Author: haraldk$
|
||||||
* @version $Id: TGAImageReaderTest.java,v 1.0 03.07.14 22:28 haraldk Exp$
|
* @version $Id: HDRImageReaderTest.java,v 1.0 03.07.14 22:28 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class HDRImageReaderTest extends ImageReaderAbstractTest<HDRImageReader> {
|
public class HDRImageReaderTest extends ImageReaderAbstractTest<HDRImageReader> {
|
||||||
@Override
|
@Override
|
||||||
@@ -58,6 +60,12 @@ public class HDRImageReaderTest extends ImageReaderAbstractTest<HDRImageReader>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<TestData> getTestDataForAffineTransformOpCompatibility() {
|
||||||
|
// HDR images uses floating point buffers...
|
||||||
|
return emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Arrays.asList("HDR", "hdr", "RGBE", "rgbe");
|
return Arrays.asList("HDR", "hdr", "RGBE", "rgbe");
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-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.7.0</version>
|
<version>3.7.2-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.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-jpeg-jai-interop</artifactId>
|
<artifactId>imageio-jpeg-jai-interop</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: JPEG/JAI TIFF Interop</name>
|
<name>TwelveMonkeys :: ImageIO :: JPEG/JAI TIFF Interop</name>
|
||||||
@@ -13,14 +13,27 @@
|
|||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.jaiinterop</project.jpms.module.name>
|
<project.jpms.module.name>com.twelvemonkeys.imageio.jpeg.jaiinterop</project.jpms.module.name>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.jai-imageio</groupId>
|
<groupId>com.github.jai-imageio</groupId>
|
||||||
<artifactId>jai-imageio-core</artifactId>
|
<artifactId>jai-imageio-core</artifactId>
|
||||||
<version>1.3.0</version>
|
<version>1.4.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
+1
-1
@@ -78,7 +78,7 @@ public class JAITIFFImageReaderInteroperabilityTest extends ImageReaderAbstractT
|
|||||||
@Override
|
@Override
|
||||||
protected List<TestData> getTestData() {
|
protected List<TestData> getTestData() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
new TestData(getClassLoaderResource("/tiff/foto_0001.tif"), new Dimension(1663, 2338)), // Little endian, Old JPEG
|
new TestData(getClassLoaderResource("/tiff/foto_0001.tif"), new Dimension(1663, 2338), new Dimension(1663, 2337)), // Little endian, Old JPEG
|
||||||
new TestData(getClassLoaderResource("/tiff/cmyk_jpeg.tif"), new Dimension(100, 100)), // CMYK, JPEG compressed, with ICC profile
|
new TestData(getClassLoaderResource("/tiff/cmyk_jpeg.tif"), new Dimension(100, 100)), // CMYK, JPEG compressed, with ICC profile
|
||||||
new TestData(getClassLoaderResource("/tiff/jpeg-lossless-8bit-gray.tif"), new Dimension(512, 512)) // Lossless JPEG Gray, 8 bit/sample
|
new TestData(getClassLoaderResource("/tiff/jpeg-lossless-8bit-gray.tif"), new Dimension(512, 512)) // Lossless JPEG Gray, 8 bit/sample
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-jpeg-jep262-interop</artifactId>
|
<artifactId>imageio-jpeg-jep262-interop</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: JPEG/JEP-262 Interop</name>
|
<name>TwelveMonkeys :: ImageIO :: JPEG/JEP-262 Interop</name>
|
||||||
@@ -13,9 +13,21 @@
|
|||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.jep262interop</project.jpms.module.name>
|
<project.jpms.module.name>com.twelvemonkeys.imageio.jpeg.jep262interop</project.jpms.module.name>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
+3
-5
@@ -33,6 +33,7 @@ package com.twelvemonkeys.imageio.plugins.jpeg.jep262interop;
|
|||||||
import com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReaderSpi;
|
import com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReaderSpi;
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
|
|
||||||
|
import org.junit.AssumptionViolatedException;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -48,7 +49,6 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.junit.Assume.assumeTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the JEP 262 TIFFImageReader delegating to our JPEGImageReader.
|
* Tests the JEP 262 TIFFImageReader delegating to our JPEGImageReader.
|
||||||
@@ -74,15 +74,13 @@ public class JEP262TIFFImageReaderInteroperabilityTest extends ImageReaderAbstra
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skip tests if we have no Spi (ie. pre JDK 9)
|
// Skip tests if we have no Spi (ie. pre JDK 9)
|
||||||
assumeTrue("Provider " + JEP_262_PROVIDER_CLASS_NAME + " not found", false);
|
throw new AssumptionViolatedException("Provider " + JEP_262_PROVIDER_CLASS_NAME + " not found");
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<TestData> getTestData() {
|
protected List<TestData> getTestData() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
new TestData(getClassLoaderResource("/tiff/foto_0001.tif"), new Dimension(1663, 2338)), // Little endian, Old JPEG
|
new TestData(getClassLoaderResource("/tiff/foto_0001.tif"), new Dimension(1663, 2338), new Dimension(1663, 2337)), // Little endian, Old JPEG
|
||||||
new TestData(getClassLoaderResource("/tiff/cmyk_jpeg.tif"), new Dimension(100, 100)), // CMYK, JPEG compressed, with ICC profile
|
new TestData(getClassLoaderResource("/tiff/cmyk_jpeg.tif"), new Dimension(100, 100)), // CMYK, JPEG compressed, with ICC profile
|
||||||
new TestData(getClassLoaderResource("/tiff/jpeg-lossless-8bit-gray.tif"), new Dimension(512, 512)) // Lossless JPEG Gray, 8 bit/sample
|
new TestData(getClassLoaderResource("/tiff/jpeg-lossless-8bit-gray.tif"), new Dimension(512, 512)) // Lossless JPEG Gray, 8 bit/sample
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-jpeg</artifactId>
|
<artifactId>imageio-jpeg</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
|
||||||
|
|||||||
+1
-1
@@ -119,7 +119,7 @@ final class EXIFThumbnail {
|
|||||||
case 6:
|
case 6:
|
||||||
// YCbCr
|
// YCbCr
|
||||||
for (int i = 0; i < thumbLength; i += 3) {
|
for (int i = 0; i < thumbLength; i += 3) {
|
||||||
YCbCrConverter.convertYCbCr2RGB(thumbData, thumbData, i);
|
YCbCrConverter.convertJPEGYCbCr2RGB(thumbData, thumbData, i);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
+11
-16
@@ -123,7 +123,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
private int currentStreamIndex = 0;
|
private int currentStreamIndex = 0;
|
||||||
private final List<Long> streamOffsets = new ArrayList<>();
|
private final List<Long> streamOffsets = new ArrayList<>();
|
||||||
|
|
||||||
protected JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
|
JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
|
||||||
super(provider);
|
super(provider);
|
||||||
|
|
||||||
this.delegate = Validate.notNull(delegate);
|
this.delegate = Validate.notNull(delegate);
|
||||||
@@ -614,7 +614,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICC_Profile ensureDisplayProfile(final ICC_Profile profile) {
|
private ICC_Profile ensureDisplayProfile(final ICC_Profile profile) throws IOException {
|
||||||
// NOTE: This is probably not the right way to do it... :-P
|
// NOTE: This is probably not the right way to do it... :-P
|
||||||
// TODO: Consider moving method to ColorSpaces class or new class in imageio.color package
|
// TODO: Consider moving method to ColorSpaces class or new class in imageio.color package
|
||||||
|
|
||||||
@@ -630,7 +630,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); // Header is first
|
intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); // Header is first
|
||||||
|
|
||||||
return ICC_Profile.getInstance(profileData);
|
return ColorSpaces.createProfile(profileData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -954,7 +954,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
int iccChunkDataSize = segment.data.length - segmentDataStart;
|
int iccChunkDataSize = segment.data.length - segmentDataStart;
|
||||||
int iccSize = segment.data.length < segmentDataStart + 4 ? 0 : intFromBigEndian(segment.data, segmentDataStart);
|
int iccSize = segment.data.length < segmentDataStart + 4 ? 0 : intFromBigEndian(segment.data, segmentDataStart);
|
||||||
|
|
||||||
return readICCProfileSafe(stream, allowBadIndexes, iccSize, iccChunkDataSize);
|
return readICCProfileSafe(stream, allowBadIndexes);
|
||||||
}
|
}
|
||||||
else if (!segments.isEmpty()) {
|
else if (!segments.isEmpty()) {
|
||||||
// NOTE: This is probably over-complicated, as I've never encountered ICC_PROFILE chunks out of order...
|
// NOTE: This is probably over-complicated, as I've never encountered ICC_PROFILE chunks out of order...
|
||||||
@@ -1012,25 +1012,20 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return readICCProfileSafe(new SequenceInputStream(Collections.enumeration(Arrays.asList(streams))), allowBadIndexes, iccSize, iccChunkDataSize);
|
return readICCProfileSafe(new SequenceInputStream(Collections.enumeration(Arrays.asList(streams))), allowBadIndexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICC_Profile readICCProfileSafe(final InputStream stream, final boolean allowBadProfile, final int iccSize, final int iccChunkDataSize) throws IOException {
|
private ICC_Profile readICCProfileSafe(final InputStream stream, final boolean allowBadProfile) {
|
||||||
if (iccSize < 0 || iccSize > iccChunkDataSize) {
|
|
||||||
processWarningOccurred(String.format("Truncated 'ICC_PROFILE' chunk(s), size: %d. Ignoring ICC profile.", iccSize));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ICC_Profile profile = ICC_Profile.getInstance(stream);
|
ICC_Profile profile = ColorSpaces.readProfileRaw(stream);
|
||||||
|
|
||||||
// NOTE: Need to ensure we have a display profile *before* validating, for the caching to work
|
// NOTE: Need to ensure we have a display profile *before* validating, for the caching to work
|
||||||
return allowBadProfile ? profile : ColorSpaces.validateProfile(ensureDisplayProfile(profile));
|
return allowBadProfile ? profile : ColorSpaces.validateProfile(ensureDisplayProfile(profile));
|
||||||
}
|
}
|
||||||
catch (RuntimeException e) {
|
catch (IOException | RuntimeException e) {
|
||||||
// NOTE: Throws either IllegalArgumentException or CMMException, depending on platform.
|
// NOTE: Throws either IllegalArgumentException or CMMException, depending on platform.
|
||||||
// Usual reason: Broken tools store truncated ICC profiles in a single ICC_PROFILE chunk...
|
// Usual reason: Broken tools store truncated ICC profiles in a single ICC_PROFILE chunk...
|
||||||
processWarningOccurred(String.format("Bad 'ICC_PROFILE' chunk(s): %s. Ignoring ICC profile.", e.getMessage()));
|
processWarningOccurred(String.format("Bad 'ICC_PROFILE' chunk(s): %s. Ignoring ICC profile.", e.getMessage()));
|
||||||
@@ -1169,7 +1164,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
processThumbnailStarted(imageIndex, thumbnailIndex);
|
processThumbnailStarted(imageIndex, thumbnailIndex);
|
||||||
processThumbnailProgress(0f);
|
processThumbnailProgress(0f);
|
||||||
|
|
||||||
BufferedImage thumbnail = thumbnails.get(thumbnailIndex).read();;
|
BufferedImage thumbnail = thumbnails.get(thumbnailIndex).read();
|
||||||
|
|
||||||
processThumbnailProgress(100f);
|
processThumbnailProgress(100f);
|
||||||
processThumbnailComplete();
|
processThumbnailComplete();
|
||||||
@@ -1211,7 +1206,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
YCbCrConverter.convertYCbCr2RGB(data, data, (x + y * width) * numComponents);
|
YCbCrConverter.convertJPEGYCbCr2RGB(data, data, (x + y * width) * numComponents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1225,7 +1220,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
for (int x = 0; x < width; x++) {
|
for (int x = 0; x < width; x++) {
|
||||||
int offset = (x + y * width) * 4;
|
int offset = (x + y * width) * 4;
|
||||||
// YCC -> CMY
|
// YCC -> CMY
|
||||||
YCbCrConverter.convertYCbCr2RGB(data, data, offset);
|
YCbCrConverter.convertJPEGYCbCr2RGB(data, data, offset);
|
||||||
// Inverse K
|
// Inverse K
|
||||||
data[offset + 3] = (byte) (0xff - data[offset + 3] & 0xff);
|
data[offset + 3] = (byte) (0xff - data[offset + 3] & 0xff);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-4
@@ -36,7 +36,6 @@ import com.twelvemonkeys.lang.StringUtil;
|
|||||||
|
|
||||||
import org.hamcrest.core.IsInstanceOf;
|
import org.hamcrest.core.IsInstanceOf;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.internal.matchers.GreaterThan;
|
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.NamedNodeMap;
|
import org.w3c.dom.NamedNodeMap;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
@@ -66,12 +65,11 @@ import static com.twelvemonkeys.imageio.util.IIOUtil.lookupProviderByName;
|
|||||||
import static org.hamcrest.CoreMatchers.allOf;
|
import static org.hamcrest.CoreMatchers.allOf;
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assume.assumeNoException;
|
import static org.junit.Assume.assumeNoException;
|
||||||
import static org.junit.Assume.assumeNotNull;
|
import static org.junit.Assume.assumeNotNull;
|
||||||
import static org.mockito.AdditionalMatchers.and;
|
import static org.mockito.AdditionalMatchers.and;
|
||||||
import static org.mockito.Matchers.anyString;
|
|
||||||
import static org.mockito.Matchers.eq;
|
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1456,7 +1454,7 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
assertTrue(markerSequences.getLength() == 1 || markerSequences.getLength() == 2); // In case of JPEG encoded thumbnail, there will be 2
|
assertTrue(markerSequences.getLength() == 1 || markerSequences.getLength() == 2); // In case of JPEG encoded thumbnail, there will be 2
|
||||||
IIOMetadataNode markerSequence = (IIOMetadataNode) markerSequences.item(markerSequences.getLength() - 1); // The last will be the "main" image
|
IIOMetadataNode markerSequence = (IIOMetadataNode) markerSequences.item(markerSequences.getLength() - 1); // The last will be the "main" image
|
||||||
assertNotNull(markerSequence);
|
assertNotNull(markerSequence);
|
||||||
assertThat(markerSequence.getChildNodes().getLength(), new GreaterThan<>(0));
|
assertThat(markerSequence.getChildNodes().getLength(), greaterThan(0));
|
||||||
|
|
||||||
NodeList unknowns = markerSequence.getElementsByTagName("unknown");
|
NodeList unknowns = markerSequence.getElementsByTagName("unknown");
|
||||||
for (int j = 0; j < unknowns.getLength(); j++) {
|
for (int j = 0; j < unknowns.getLength(); j++) {
|
||||||
|
|||||||
+2
-2
@@ -36,7 +36,6 @@ import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
|||||||
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.internal.matchers.LessOrEqual;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
@@ -48,6 +47,7 @@ import java.net.URL;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ public class JPEGSegmentImageInputStreamTest {
|
|||||||
length++;
|
length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(length, new LessOrEqual<>(10203L)); // In no case should length increase
|
assertThat(length, lessThanOrEqualTo(10203L)); // In no case should length increase
|
||||||
|
|
||||||
assertEquals(9607L, length); // May change, if more chunks are passed to reader...
|
assertEquals(9607L, length); // May change, if more chunks are passed to reader...
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>imageio-metadata</artifactId>
|
<artifactId>imageio-metadata</artifactId>
|
||||||
|
|||||||
+1
@@ -46,6 +46,7 @@ import java.io.IOException;
|
|||||||
*
|
*
|
||||||
* @deprecated Use com.twelvemonkeys.imageio.metadata.tiff.TIFFReader instead.
|
* @deprecated Use com.twelvemonkeys.imageio.metadata.tiff.TIFFReader instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class EXIFReader extends MetadataReader {
|
public final class EXIFReader extends MetadataReader {
|
||||||
|
|
||||||
private final TIFFReader delegate = new TIFFReader();
|
private final TIFFReader delegate = new TIFFReader();
|
||||||
|
|||||||
+1
@@ -48,6 +48,7 @@ import java.util.Collection;
|
|||||||
*
|
*
|
||||||
* @deprecated Use com.twelvemonkeys.imageio.metadata.tiff.TIFFWriter instead.
|
* @deprecated Use com.twelvemonkeys.imageio.metadata.tiff.TIFFWriter instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class EXIFWriter extends MetadataWriter {
|
public final class EXIFWriter extends MetadataWriter {
|
||||||
|
|
||||||
private final TIFFWriter delegate = new TIFFWriter();
|
private final TIFFWriter delegate = new TIFFWriter();
|
||||||
|
|||||||
+1
@@ -41,6 +41,7 @@ package com.twelvemonkeys.imageio.metadata.exif;
|
|||||||
*
|
*
|
||||||
* @deprecated Use com.twelvemonkeys.imageio.metadata.tiff.Rational instead.
|
* @deprecated Use com.twelvemonkeys.imageio.metadata.tiff.Rational instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public final class Rational extends Number implements Comparable<Rational> {
|
public final class Rational extends Number implements Comparable<Rational> {
|
||||||
private final com.twelvemonkeys.imageio.metadata.tiff.Rational delegate;
|
private final com.twelvemonkeys.imageio.metadata.tiff.Rational delegate;
|
||||||
|
|
||||||
|
|||||||
+1
@@ -39,5 +39,6 @@ package com.twelvemonkeys.imageio.metadata.exif;
|
|||||||
*
|
*
|
||||||
* @deprecated Use com.twelvemonkeys.imageio.metadata.tiff.TIFF instead.
|
* @deprecated Use com.twelvemonkeys.imageio.metadata.tiff.TIFF instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public interface TIFF extends com.twelvemonkeys.imageio.metadata.tiff.TIFF {
|
public interface TIFF extends com.twelvemonkeys.imageio.metadata.tiff.TIFF {
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.metadata.jpeg;
|
package com.twelvemonkeys.imageio.metadata.jpeg;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||||
import com.twelvemonkeys.imageio.metadata.psd.PSD;
|
import com.twelvemonkeys.imageio.metadata.psd.PSD;
|
||||||
@@ -42,7 +43,6 @@ import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
|||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.color.ICC_ColorSpace;
|
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
@@ -353,8 +353,8 @@ public final class JPEGSegmentUtil {
|
|||||||
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);
|
||||||
if (iccEntry != null) {
|
if (iccEntry != null) {
|
||||||
ICC_ColorSpace colorSpace = new ICC_ColorSpace(ICC_Profile.getInstance((byte[]) iccEntry.getValue()));
|
ICC_Profile profile = ColorSpaces.createProfileRaw((byte[]) iccEntry.getValue());
|
||||||
System.err.println("colorSpace: " + colorSpace);
|
System.err.println("ICC Profile: " + profile);
|
||||||
}
|
}
|
||||||
System.err.println("PSD: " + psd);
|
System.err.println("PSD: " + psd);
|
||||||
System.err.println(TIFFReader.HexDump.dump(segment.data));
|
System.err.println(TIFFReader.HexDump.dump(segment.data));
|
||||||
|
|||||||
+13
-13
@@ -30,8 +30,15 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.metadata.tiff;
|
package com.twelvemonkeys.imageio.metadata.tiff;
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry.getValueLength;
|
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.MetadataReader;
|
||||||
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -39,15 +46,7 @@ import java.nio.ByteOrder;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import static com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry.getValueLength;
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.MetadataReader;
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
|
||||||
import com.twelvemonkeys.lang.Validate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TIFFReader
|
* TIFFReader
|
||||||
@@ -73,16 +72,17 @@ public final class TIFFReader extends MetadataReader {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
map.put(TIFF.TAG_SUB_IFD, Collections.unmodifiableCollection(Collections.singleton(TIFF.TAG_SUB_IFD)));
|
map.put(TIFF.TAG_SUB_IFD, Collections.singleton(TIFF.TAG_SUB_IFD));
|
||||||
map.put(TIFF.TAG_EXIF_IFD, Collections.unmodifiableCollection(Collections.singleton(TIFF.TAG_INTEROP_IFD)));
|
map.put(TIFF.TAG_EXIF_IFD, Collections.singleton(TIFF.TAG_INTEROP_IFD));
|
||||||
|
|
||||||
return Collections.unmodifiableMap(map);
|
return Collections.unmodifiableMap(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final Set<Long> parsedIFDs = new TreeSet<>();
|
||||||
|
|
||||||
private long length;
|
private long length;
|
||||||
private boolean longOffsets;
|
private boolean longOffsets;
|
||||||
private int offsetSize;
|
private int offsetSize;
|
||||||
private Set<Long> parsedIFDs = new TreeSet<>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Directory read(final ImageInputStream input) throws IOException {
|
public Directory read(final ImageInputStream input) throws IOException {
|
||||||
|
|||||||
+18
-14
@@ -30,23 +30,27 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.metadata.tiff;
|
package com.twelvemonkeys.imageio.metadata.tiff;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry.getType;
|
||||||
|
import static com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry.getValueLength;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
||||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||||
import com.twelvemonkeys.imageio.metadata.MetadataWriter;
|
import com.twelvemonkeys.imageio.metadata.MetadataWriter;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry.getType;
|
|
||||||
import static com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry.getValueLength;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TIFFWriter
|
* TIFFWriter
|
||||||
*
|
*
|
||||||
@@ -58,9 +62,9 @@ public final class TIFFWriter extends MetadataWriter {
|
|||||||
|
|
||||||
private static final int WORD_LENGTH = 2;
|
private static final int WORD_LENGTH = 2;
|
||||||
private static final int LONGWORD_LENGTH = 4;
|
private static final int LONGWORD_LENGTH = 4;
|
||||||
private static final int ENTRY_LENGTH = 12;
|
private static final long ENTRY_LENGTH = 12;
|
||||||
|
|
||||||
public boolean write(final Collection<Entry> entries, final ImageOutputStream stream) throws IOException {
|
public boolean write(final Collection<? extends Entry> entries, final ImageOutputStream stream) throws IOException {
|
||||||
return write(new IFD(entries), stream);
|
return write(new IFD(entries), stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +252,7 @@ public final class TIFFWriter extends MetadataWriter {
|
|||||||
|
|
||||||
private int getCount(final Entry entry) {
|
private int getCount(final Entry entry) {
|
||||||
Object value = entry.getValue();
|
Object value = entry.getValue();
|
||||||
return value instanceof String ? ((String) value).getBytes(Charset.forName("UTF-8")).length + 1 : entry.valueCount();
|
return value instanceof String ? ((String) value).getBytes(StandardCharsets.UTF_8).length + 1 : entry.valueCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeValueInline(final Object value, final short type, final ImageOutputStream stream) throws IOException {
|
private void writeValueInline(final Object value, final short type, final ImageOutputStream stream) throws IOException {
|
||||||
|
|||||||
+54
-27
@@ -30,11 +30,21 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.metadata.xmp;
|
package com.twelvemonkeys.imageio.metadata.xmp;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
import java.io.IOException;
|
||||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
import java.util.ArrayList;
|
||||||
import com.twelvemonkeys.imageio.metadata.MetadataReader;
|
import java.util.Collections;
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
import java.util.Iterator;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.NamedNodeMap;
|
import org.w3c.dom.NamedNodeMap;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
@@ -43,13 +53,11 @@ import org.xml.sax.InputSource;
|
|||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||||
import javax.xml.parsers.DocumentBuilder;
|
import com.twelvemonkeys.imageio.metadata.MetadataReader;
|
||||||
import javax.xml.parsers.DocumentBuilderFactory;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XMPReader
|
* XMPReader
|
||||||
@@ -67,10 +75,9 @@ public final class XMPReader extends MetadataReader {
|
|||||||
public Directory read(final ImageInputStream input) throws IOException {
|
public Directory read(final ImageInputStream input) throws IOException {
|
||||||
Validate.notNull(input, "input");
|
Validate.notNull(input, "input");
|
||||||
|
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
|
||||||
factory.setNamespaceAware(true);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
DocumentBuilderFactory factory = createDocumentBuilderFactory();
|
||||||
|
|
||||||
// TODO: Consider parsing using SAX?
|
// TODO: Consider parsing using SAX?
|
||||||
// TODO: Determine encoding and parse using a Reader...
|
// TODO: Determine encoding and parse using a Reader...
|
||||||
// TODO: Refactor scanner to return inputstream?
|
// TODO: Refactor scanner to return inputstream?
|
||||||
@@ -79,9 +86,6 @@ public final class XMPReader extends MetadataReader {
|
|||||||
builder.setErrorHandler(new DefaultHandler());
|
builder.setErrorHandler(new DefaultHandler());
|
||||||
Document document = builder.parse(new InputSource(IIOUtil.createStreamAdapter(input)));
|
Document document = builder.parse(new InputSource(IIOUtil.createStreamAdapter(input)));
|
||||||
|
|
||||||
// XMLSerializer serializer = new XMLSerializer(System.err, System.getProperty("file.encoding"));
|
|
||||||
// serializer.serialize(document);
|
|
||||||
|
|
||||||
String toolkit = getToolkit(document);
|
String toolkit = getToolkit(document);
|
||||||
Node rdfRoot = document.getElementsByTagNameNS(XMP.NS_RDF, "RDF").item(0);
|
Node rdfRoot = document.getElementsByTagNameNS(XMP.NS_RDF, "RDF").item(0);
|
||||||
NodeList descriptions = document.getElementsByTagNameNS(XMP.NS_RDF, "Description");
|
NodeList descriptions = document.getElementsByTagNameNS(XMP.NS_RDF, "Description");
|
||||||
@@ -92,10 +96,33 @@ public final class XMPReader extends MetadataReader {
|
|||||||
throw new IIOException(e.getMessage(), e);
|
throw new IIOException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
catch (ParserConfigurationException e) {
|
catch (ParserConfigurationException e) {
|
||||||
throw new RuntimeException(e); // TODO: Or IOException?
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private DocumentBuilderFactory createDocumentBuilderFactory() throws ParserConfigurationException {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
factory.setNamespaceAware(true);
|
||||||
|
|
||||||
|
// Security: Disable XInclude & expanding entity references ("bombs"), not needed for XMP
|
||||||
|
factory.setXIncludeAware(false);
|
||||||
|
factory.setExpandEntityReferences(false);
|
||||||
|
|
||||||
|
// Security: Enable "secure processing", to prevent DoS attacks
|
||||||
|
factory.setAttribute(XMLConstants.FEATURE_SECURE_PROCESSING, true);
|
||||||
|
|
||||||
|
// Security: Remove possibility to access external DTDs or Schema, not needed for XMP
|
||||||
|
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
|
||||||
|
factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
|
||||||
|
|
||||||
|
// Security: Disable loading of external DTD and entities, not needed for XMP
|
||||||
|
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||||||
|
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||||||
|
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
|
||||||
|
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
private String getToolkit(Document document) {
|
private String getToolkit(Document document) {
|
||||||
NodeList xmpmeta = document.getElementsByTagNameNS(XMP.NS_X, "xmpmeta");
|
NodeList xmpmeta = document.getElementsByTagNameNS(XMP.NS_X, "xmpmeta");
|
||||||
|
|
||||||
@@ -109,7 +136,7 @@ public final class XMPReader extends MetadataReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private XMPDirectory parseDirectories(final Node pParentNode, NodeList pNodes, String toolkit) {
|
private XMPDirectory parseDirectories(final Node pParentNode, NodeList pNodes, String toolkit) {
|
||||||
Map<String, List<Entry>> subdirs = new LinkedHashMap<String, List<Entry>>();
|
Map<String, List<Entry>> subdirs = new LinkedHashMap<>();
|
||||||
|
|
||||||
for (Node desc : asIterable(pNodes)) {
|
for (Node desc : asIterable(pNodes)) {
|
||||||
if (desc.getParentNode() != pParentNode) {
|
if (desc.getParentNode() != pParentNode) {
|
||||||
@@ -127,7 +154,7 @@ public final class XMPReader extends MetadataReader {
|
|||||||
// Lookup
|
// Lookup
|
||||||
List<Entry> dir = subdirs.get(node.getNamespaceURI());
|
List<Entry> dir = subdirs.get(node.getNamespaceURI());
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
dir = new ArrayList<Entry>();
|
dir = new ArrayList<>();
|
||||||
subdirs.put(node.getNamespaceURI(), dir);
|
subdirs.put(node.getNamespaceURI(), dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +166,7 @@ public final class XMPReader extends MetadataReader {
|
|||||||
else {
|
else {
|
||||||
// TODO: This method contains loads of duplication an should be cleaned up...
|
// TODO: This method contains loads of duplication an should be cleaned up...
|
||||||
// Support attribute short-hand syntax
|
// Support attribute short-hand syntax
|
||||||
Map<String, List<Entry>> subsubdirs = new LinkedHashMap<String, List<Entry>>();
|
Map<String, List<Entry>> subsubdirs = new LinkedHashMap<>();
|
||||||
|
|
||||||
parseAttributesForKnownElements(subsubdirs, node);
|
parseAttributesForKnownElements(subsubdirs, node);
|
||||||
|
|
||||||
@@ -161,7 +188,7 @@ public final class XMPReader extends MetadataReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Directory> entries = new ArrayList<Directory>(subdirs.size());
|
List<Directory> entries = new ArrayList<>(subdirs.size());
|
||||||
|
|
||||||
// TODO: Should we still allow asking for a subdirectory by item id?
|
// TODO: Should we still allow asking for a subdirectory by item id?
|
||||||
for (Map.Entry<String, List<Entry>> entry : subdirs.entrySet()) {
|
for (Map.Entry<String, List<Entry>> entry : subdirs.entrySet()) {
|
||||||
@@ -179,7 +206,7 @@ public final class XMPReader extends MetadataReader {
|
|||||||
|
|
||||||
private RDFDescription parseAsResource(Node node) {
|
private RDFDescription parseAsResource(Node node) {
|
||||||
// See: http://www.w3.org/TR/REC-rdf-syntax/#section-Syntax-parsetype-resource
|
// See: http://www.w3.org/TR/REC-rdf-syntax/#section-Syntax-parsetype-resource
|
||||||
List<Entry> entries = new ArrayList<Entry>();
|
List<Entry> entries = new ArrayList<>();
|
||||||
|
|
||||||
for (Node child : asIterable(node.getChildNodes())) {
|
for (Node child : asIterable(node.getChildNodes())) {
|
||||||
if (child.getNodeType() != Node.ELEMENT_NODE) {
|
if (child.getNodeType() != Node.ELEMENT_NODE) {
|
||||||
@@ -204,7 +231,7 @@ public final class XMPReader extends MetadataReader {
|
|||||||
List<Entry> dir = subdirs.get(attr.getNamespaceURI());
|
List<Entry> dir = subdirs.get(attr.getNamespaceURI());
|
||||||
|
|
||||||
if (dir == null) {
|
if (dir == null) {
|
||||||
dir = new ArrayList<Entry>();
|
dir = new ArrayList<>();
|
||||||
subdirs.put(attr.getNamespaceURI(), dir);
|
subdirs.put(attr.getNamespaceURI(), dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +243,7 @@ public final class XMPReader extends MetadataReader {
|
|||||||
for (Node child : asIterable(node.getChildNodes())) {
|
for (Node child : asIterable(node.getChildNodes())) {
|
||||||
if (XMP.NS_RDF.equals(child.getNamespaceURI()) && "Alt".equals(child.getLocalName())) {
|
if (XMP.NS_RDF.equals(child.getNamespaceURI()) && "Alt".equals(child.getLocalName())) {
|
||||||
// Support for <rdf:Alt><rdf:li> -> return a Map<String, Object> keyed on xml:lang
|
// Support for <rdf:Alt><rdf:li> -> return a Map<String, Object> keyed on xml:lang
|
||||||
Map<String, Object> alternatives = new LinkedHashMap<String, Object>();
|
Map<String, Object> alternatives = new LinkedHashMap<>();
|
||||||
for (Node alternative : asIterable(child.getChildNodes())) {
|
for (Node alternative : asIterable(child.getChildNodes())) {
|
||||||
if (XMP.NS_RDF.equals(alternative.getNamespaceURI()) && "li".equals(alternative.getLocalName())) {
|
if (XMP.NS_RDF.equals(alternative.getNamespaceURI()) && "li".equals(alternative.getLocalName())) {
|
||||||
NamedNodeMap attributes = alternative.getAttributes();
|
NamedNodeMap attributes = alternative.getAttributes();
|
||||||
@@ -230,7 +257,7 @@ public final class XMPReader extends MetadataReader {
|
|||||||
else if (XMP.NS_RDF.equals(child.getNamespaceURI()) && ("Seq".equals(child.getLocalName()) || "Bag".equals(child.getLocalName()))) {
|
else if (XMP.NS_RDF.equals(child.getNamespaceURI()) && ("Seq".equals(child.getLocalName()) || "Bag".equals(child.getLocalName()))) {
|
||||||
// Support for <rdf:Seq><rdf:li> -> return array
|
// Support for <rdf:Seq><rdf:li> -> return array
|
||||||
// Support for <rdf:Bag><rdf:li> -> return array/unordered collection (how can a serialized collection not have order?)
|
// Support for <rdf:Bag><rdf:li> -> return array/unordered collection (how can a serialized collection not have order?)
|
||||||
List<Object> seq = new ArrayList<Object>();
|
List<Object> seq = new ArrayList<>();
|
||||||
|
|
||||||
for (Node sequence : asIterable(child.getChildNodes())) {
|
for (Node sequence : asIterable(child.getChildNodes())) {
|
||||||
if (XMP.NS_RDF.equals(sequence.getNamespaceURI()) && "li".equals(sequence.getLocalName())) {
|
if (XMP.NS_RDF.equals(sequence.getNamespaceURI()) && "li".equals(sequence.getLocalName())) {
|
||||||
|
|||||||
+83
-12
@@ -30,26 +30,32 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.metadata.xmp;
|
package com.twelvemonkeys.imageio.metadata.xmp;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
import static org.junit.Assert.assertEquals;
|
||||||
import com.twelvemonkeys.imageio.metadata.MetadataReaderAbstractTest;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
import javax.imageio.ImageIO;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.MetadataReaderAbstractTest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* XMPReaderTest
|
* XMPReaderTest
|
||||||
@@ -483,4 +489,69 @@ public class XMPReaderTest extends MetadataReaderAbstractTest {
|
|||||||
assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/PixelYDimension"), hasValue("550"));
|
assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/PixelYDimension"), hasValue("550"));
|
||||||
assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/NativeDigest"), hasValue("36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;A7F21D25E2C562F152B2C4ECC9E534DA"));
|
assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/NativeDigest"), hasValue("36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;A7F21D25E2C562F152B2C4ECC9E534DA"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 1500L)
|
||||||
|
public void testNoExternalRequest() throws Exception {
|
||||||
|
// TODO: Use dynamic port?
|
||||||
|
try (HTTPServer server = new HTTPServer(7777)) {
|
||||||
|
try {
|
||||||
|
createReader().read(getResourceAsIIS("/xmp/xmp-jpeg-xxe.xml"));
|
||||||
|
} catch (IOException ioe) {
|
||||||
|
if (ioe.getMessage().contains("501")) {
|
||||||
|
throw new AssertionError("Reading should not cause external requests", ioe);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any other exception is a bug (but might happen if the parser does not support certain features)
|
||||||
|
throw ioe;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class HTTPServer implements AutoCloseable {
|
||||||
|
private final ServerSocket server;
|
||||||
|
private final Thread thread;
|
||||||
|
|
||||||
|
HTTPServer(int port) throws IOException {
|
||||||
|
server = new ServerSocket(port, 1);
|
||||||
|
thread = new Thread(new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
serve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void serve() {
|
||||||
|
try {
|
||||||
|
Socket client = server.accept();
|
||||||
|
|
||||||
|
// Get the input stream, don't care about the request
|
||||||
|
try (InputStream inputStream = client.getInputStream()) {
|
||||||
|
while (inputStream.available() > 0) {
|
||||||
|
if (inputStream.read() == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Answer with 501, this will cause the client to throw IOException
|
||||||
|
try (OutputStream outputStream = client.getOutputStream()) {
|
||||||
|
outputStream.write("HTTP/1.0 501 Not Implemented\r\n\r\n".getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
if (server.isClosed() && e instanceof SocketException) {
|
||||||
|
// Socket closed due to server close, all good
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void close() throws Exception {
|
||||||
|
server.close();
|
||||||
|
thread.join(); // It's advised against throwing InterruptedException here, but this is not production code...
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?><!DOCTYPE root [<!ENTITY % ext SYSTEM 'http://localhost:7777/xxx'> %ext;]>
|
||||||
|
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 10.16'>
|
||||||
|
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
|
||||||
|
|
||||||
|
<rdf:Description rdf:about=''
|
||||||
|
xmlns:xmpMM='http://ns.adobe.com/xap/1.0/mm/'>
|
||||||
|
<xmpMM:InstanceID>xmp.iid:7EDC21BF-371B-4189-90AF-C83A54A6A190</xmpMM:InstanceID>
|
||||||
|
</rdf:Description>
|
||||||
|
</rdf:RDF>
|
||||||
|
</x:xmpmeta>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<?xpacket end='w'?>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-pcx</artifactId>
|
<artifactId>imageio-pcx</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: PCX plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PCX plugin</name>
|
||||||
|
|||||||
+11
-4
@@ -104,8 +104,15 @@ public final class PCXImageReader extends ImageReaderBase {
|
|||||||
ImageTypeSpecifier rawType = getRawImageType(imageIndex);
|
ImageTypeSpecifier rawType = getRawImageType(imageIndex);
|
||||||
|
|
||||||
List<ImageTypeSpecifier> specifiers = new ArrayList<>();
|
List<ImageTypeSpecifier> specifiers = new ArrayList<>();
|
||||||
|
if (rawType.getSampleModel() instanceof BandedSampleModel) {
|
||||||
// TODO: Implement
|
if (rawType.getNumBands() == 3) {
|
||||||
|
specifiers.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR));
|
||||||
|
}
|
||||||
|
else if (rawType.getNumBands() == 4) {
|
||||||
|
specifiers.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR));
|
||||||
|
specifiers.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR_PRE));
|
||||||
|
}
|
||||||
|
}
|
||||||
specifiers.add(rawType);
|
specifiers.add(rawType);
|
||||||
|
|
||||||
return specifiers.iterator();
|
return specifiers.iterator();
|
||||||
@@ -142,10 +149,10 @@ public final class PCXImageReader extends ImageReaderBase {
|
|||||||
// PCX RGB has channels for 24 bit RGB, will be validated by ImageTypeSpecifier
|
// PCX RGB has channels for 24 bit RGB, will be validated by ImageTypeSpecifier
|
||||||
return ImageTypeSpecifiers.createBanded(ColorSpace.getInstance(ColorSpace.CS_sRGB), createIndices(channels, 1), createIndices(channels, 0), DataBuffer.TYPE_BYTE, channels == 4, false);
|
return ImageTypeSpecifiers.createBanded(ColorSpace.getInstance(ColorSpace.CS_sRGB), createIndices(channels, 1), createIndices(channels, 0), DataBuffer.TYPE_BYTE, channels == 4, false);
|
||||||
case 24:
|
case 24:
|
||||||
// Some sources says this is possible...
|
// Some sources say this is possible...
|
||||||
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
|
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
|
||||||
case 32:
|
case 32:
|
||||||
// Some sources says this is possible...
|
// Some sources say this is possible...
|
||||||
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR);
|
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR);
|
||||||
default:
|
default:
|
||||||
throw new IIOException("Unknown number of bytes per pixel: " + header.getBitsPerPixel());
|
throw new IIOException("Unknown number of bytes per pixel: " + header.getBitsPerPixel());
|
||||||
|
|||||||
+1
-1
@@ -78,7 +78,7 @@ public class PCXImageReaderTest extends ImageReaderAbstractTest<PCXImageReader>
|
|||||||
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/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, I don't see how the bits can be 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)
|
||||||
new TestData(getClassLoaderResource("/pcx/CGA_FSD.PCX"), new Dimension(320, 200)), // RLE encoded indexed (CGA mode)
|
new TestData(getClassLoaderResource("/pcx/CGA_FSD.PCX"), new Dimension(320, 200)), // RLE encoded indexed (CGA mode)
|
||||||
new TestData(getClassLoaderResource("/pcx/CGA_RGBI.PCX"), new Dimension(320, 200)), // RLE encoded indexed (CGA mode)
|
new TestData(getClassLoaderResource("/pcx/CGA_RGBI.PCX"), new Dimension(320, 200)), // RLE encoded indexed (CGA mode)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-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.7.0</version>
|
<version>3.7.2-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.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-pnm</artifactId>
|
<artifactId>imageio-pnm</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: PNM plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PNM plugin</name>
|
||||||
|
|||||||
+14
@@ -61,6 +61,20 @@ public class PNMImageReaderTest extends ImageReaderAbstractTest<PNMImageReader>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<TestData> getTestDataForAffineTransformOpCompatibility() {
|
||||||
|
return Arrays.asList(
|
||||||
|
new TestData(getClassLoaderResource("/ppm/lena.ppm"), new Dimension(128, 128)), // P6 (PPM RAW)
|
||||||
|
new TestData(getClassLoaderResource("/ppm/colors.ppm"), new Dimension(3, 2)), // P3 (PPM PLAIN)
|
||||||
|
new TestData(getClassLoaderResource("/pbm/j.pbm"), new Dimension(6, 10)), // P1 (PBM PLAIN)
|
||||||
|
new TestData(getClassLoaderResource("/pgm/feep.pgm"), new Dimension(24, 7)), // P2 (PGM PLAIN)
|
||||||
|
new TestData(getClassLoaderResource("/pgm/feep16.pgm"), new Dimension(24, 7)), // P2 (PGM PLAIN, 16 bits/sample)
|
||||||
|
new TestData(getClassLoaderResource("/pgm/house.l.pgm"), new Dimension(367, 241)), // P5 (PGM RAW)
|
||||||
|
new TestData(getClassLoaderResource("/ppm/lighthouse_rgb48.ppm"), new Dimension(768, 512)) // P6 (PPM RAW, 16 bits/sample)
|
||||||
|
// "/pfm/memorial.pfm" uses floating point
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-psd</artifactId>
|
<artifactId>imageio-psd</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: PSD plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PSD plugin</name>
|
||||||
|
|||||||
+18
-7
@@ -30,9 +30,11 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.psd;
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -52,14 +54,23 @@ final class ICCProfile extends PSDImageResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void readData(ImageInputStream pInput) throws IOException {
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
InputStream stream = IIOUtil.createStreamAdapter(pInput, size);
|
try (InputStream stream = IIOUtil.createStreamAdapter(pInput, size)) {
|
||||||
try {
|
profile = ColorSpaces.readProfile(stream);
|
||||||
profile = ICC_Profile.getInstance(stream);
|
|
||||||
}
|
}
|
||||||
finally {
|
}
|
||||||
// Make sure stream has correct position after read
|
|
||||||
stream.close();
|
static void writeData(final ImageOutputStream output, final ICC_Profile profile) throws IOException {
|
||||||
|
output.writeInt(PSD.RESOURCE_TYPE);
|
||||||
|
output.writeShort(PSD.RES_ICC_PROFILE);
|
||||||
|
output.writeShort(0); // Zero-length Pascal name + pad
|
||||||
|
|
||||||
|
byte[] data = profile.getData();
|
||||||
|
output.writeInt(data.length + data.length % 2);
|
||||||
|
output.write(data);
|
||||||
|
|
||||||
|
if (data.length % 2 != 0) {
|
||||||
|
output.write(0); // pad
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+26
@@ -31,11 +31,16 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.psd;
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFFWriter;
|
||||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||||
|
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EXIF metadata.
|
* EXIF metadata.
|
||||||
@@ -60,6 +65,27 @@ final class PSDEXIF1Data extends PSDDirectoryResource {
|
|||||||
return new TIFFReader().read(new ByteArrayImageInputStream(data));
|
return new TIFFReader().read(new ByteArrayImageInputStream(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void writeData(final ImageOutputStream output, final Collection<? extends Entry> directory) throws IOException {
|
||||||
|
output.writeInt(PSD.RESOURCE_TYPE);
|
||||||
|
output.writeShort(PSD.RES_EXIF_DATA_1);
|
||||||
|
output.writeShort(0); // Zero-length Pascal name + pad
|
||||||
|
output.writeInt(0); // Dummy length
|
||||||
|
|
||||||
|
long beforeExif = output.getStreamPosition();
|
||||||
|
new TIFFWriter().write(directory, new SubImageOutputStream(output));
|
||||||
|
|
||||||
|
long afterExif = output.getStreamPosition();
|
||||||
|
if ((afterExif - beforeExif) % 2 != 0) {
|
||||||
|
afterExif++;
|
||||||
|
output.write(0); // Pad
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update length
|
||||||
|
output.seek(beforeExif - 4);
|
||||||
|
output.writeInt((int) (afterExif - beforeExif));
|
||||||
|
output.seek(afterExif);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
Directory directory = getDirectory();
|
Directory directory = getDirectory();
|
||||||
|
|||||||
+76
-8
@@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.psd;
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -57,8 +58,8 @@ final class PSDHeader {
|
|||||||
// WORD Mode; /* Color mode */
|
// WORD Mode; /* Color mode */
|
||||||
// } PSD_HEADER;
|
// } PSD_HEADER;
|
||||||
|
|
||||||
private static final int PSD_MAX_SIZE = 30000;
|
static final int PSD_MAX_SIZE = 30000;
|
||||||
private static final int PSB_MAX_SIZE = 300000;
|
static final int PSB_MAX_SIZE = 300000;
|
||||||
|
|
||||||
final short channels;
|
final short channels;
|
||||||
final int width;
|
final int width;
|
||||||
@@ -67,7 +68,57 @@ final class PSDHeader {
|
|||||||
final short mode;
|
final short mode;
|
||||||
final boolean largeFormat;
|
final boolean largeFormat;
|
||||||
|
|
||||||
PSDHeader(final DataInput pInput) throws IOException {
|
PSDHeader(int channels, int width, int height, int bits, int mode, boolean largeFormat) {
|
||||||
|
this((short) channels, width, height, (short) bits, (short) mode, largeFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PSDHeader(short channels, int width, int height, short bits, short mode, boolean largeFormat) {
|
||||||
|
if (channels < 1 || channels > 56) {
|
||||||
|
throw new IllegalArgumentException(String.format("Unsupported number of channels for PSD: %d", channels));
|
||||||
|
}
|
||||||
|
this.channels = channels;
|
||||||
|
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
|
||||||
|
switch (bits) {
|
||||||
|
case 1:
|
||||||
|
case 8:
|
||||||
|
case 16:
|
||||||
|
case 32:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(String.format("Unsupported bit depth for PSD: %d bits", bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bits = bits;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case PSD.COLOR_MODE_BITMAP:
|
||||||
|
case PSD.COLOR_MODE_GRAYSCALE:
|
||||||
|
case PSD.COLOR_MODE_INDEXED:
|
||||||
|
case PSD.COLOR_MODE_RGB:
|
||||||
|
case PSD.COLOR_MODE_CMYK:
|
||||||
|
case PSD.COLOR_MODE_MULTICHANNEL:
|
||||||
|
case PSD.COLOR_MODE_DUOTONE:
|
||||||
|
case PSD.COLOR_MODE_LAB:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(String.format("Unsupported color mode for PSD: %d", mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mode = mode;
|
||||||
|
|
||||||
|
this.largeFormat = largeFormat;
|
||||||
|
|
||||||
|
if (!hasValidDimensions()) {
|
||||||
|
throw new IllegalArgumentException(String.format("Dimensions exceed maximum allowed for %s: %dx%d (max %dx%d)",
|
||||||
|
largeFormat ? "PSB" : "PSD",
|
||||||
|
width, height, getMaxSize(), getMaxSize()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static PSDHeader read(final DataInput pInput) throws IOException {
|
||||||
int signature = pInput.readInt();
|
int signature = pInput.readInt();
|
||||||
if (signature != PSD.SIGNATURE_8BPS) {
|
if (signature != PSD.SIGNATURE_8BPS) {
|
||||||
throw new IIOException("Not a PSD document, expected signature \"8BPS\": \"" + PSDUtil.intToStr(signature) + "\" (0x" + Integer.toHexString(signature) + ")");
|
throw new IIOException("Not a PSD document, expected signature \"8BPS\": \"" + PSDUtil.intToStr(signature) + "\" (0x" + Integer.toHexString(signature) + ")");
|
||||||
@@ -75,6 +126,7 @@ final class PSDHeader {
|
|||||||
|
|
||||||
int version = pInput.readUnsignedShort();
|
int version = pInput.readUnsignedShort();
|
||||||
|
|
||||||
|
boolean largeFormat;
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case PSD.VERSION_PSD:
|
case PSD.VERSION_PSD:
|
||||||
largeFormat = false;
|
largeFormat = false;
|
||||||
@@ -89,15 +141,15 @@ final class PSDHeader {
|
|||||||
byte[] reserved = new byte[6];
|
byte[] reserved = new byte[6];
|
||||||
pInput.readFully(reserved); // We don't really care
|
pInput.readFully(reserved); // We don't really care
|
||||||
|
|
||||||
channels = pInput.readShort();
|
short channels = pInput.readShort();
|
||||||
if (channels < 1 || channels > 56) {
|
if (channels < 1 || channels > 56) {
|
||||||
throw new IIOException(String.format("Unsupported number of channels for PSD: %d", channels));
|
throw new IIOException(String.format("Unsupported number of channels for PSD: %d", channels));
|
||||||
}
|
}
|
||||||
|
|
||||||
height = pInput.readInt(); // Rows
|
int height = pInput.readInt(); // Rows
|
||||||
width = pInput.readInt(); // Columns
|
int width = pInput.readInt(); // Columns
|
||||||
|
|
||||||
bits = pInput.readShort();
|
short bits = pInput.readShort();
|
||||||
|
|
||||||
switch (bits) {
|
switch (bits) {
|
||||||
case 1:
|
case 1:
|
||||||
@@ -109,7 +161,7 @@ final class PSDHeader {
|
|||||||
throw new IIOException(String.format("Unsupported bit depth for PSD: %d bits", bits));
|
throw new IIOException(String.format("Unsupported bit depth for PSD: %d bits", bits));
|
||||||
}
|
}
|
||||||
|
|
||||||
mode = pInput.readShort();
|
short mode = pInput.readShort();
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case PSD.COLOR_MODE_BITMAP:
|
case PSD.COLOR_MODE_BITMAP:
|
||||||
@@ -124,6 +176,21 @@ final class PSDHeader {
|
|||||||
default:
|
default:
|
||||||
throw new IIOException(String.format("Unsupported color mode for PSD: %d", mode));
|
throw new IIOException(String.format("Unsupported color mode for PSD: %d", mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new PSDHeader(channels, width, height, bits, mode, largeFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(ImageOutputStream output) throws IOException {
|
||||||
|
output.writeInt(PSD.SIGNATURE_8BPS);
|
||||||
|
output.writeShort(largeFormat ? PSD.VERSION_PSB : PSD.VERSION_PSD);
|
||||||
|
|
||||||
|
output.write(new byte[6]); // Reserved
|
||||||
|
|
||||||
|
output.writeShort(channels);
|
||||||
|
output.writeInt(height); // Columns
|
||||||
|
output.writeInt(width); // Rows
|
||||||
|
output.writeShort(bits);
|
||||||
|
output.writeShort(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -177,4 +244,5 @@ final class PSDHeader {
|
|||||||
return "Unkown mode";
|
return "Unkown mode";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-5
@@ -331,7 +331,7 @@ public final class PSDImageReader extends ImageReaderBase {
|
|||||||
// Just stick to the raw type
|
// Just stick to the raw type
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally add the raw type
|
// Finally, add the raw type
|
||||||
types.add(rawType);
|
types.add(rawType);
|
||||||
|
|
||||||
return types.iterator();
|
return types.iterator();
|
||||||
@@ -842,7 +842,7 @@ public final class PSDImageReader extends ImageReaderBase {
|
|||||||
assertInput();
|
assertInput();
|
||||||
|
|
||||||
if (header == null) {
|
if (header == null) {
|
||||||
header = new PSDHeader(imageInput);
|
header = PSDHeader.read(imageInput);
|
||||||
|
|
||||||
if (!header.hasValidDimensions()) {
|
if (!header.hasValidDimensions()) {
|
||||||
processWarningOccurred(String.format("Dimensions exceed maximum allowed for %s: %dx%d (max %dx%d)",
|
processWarningOccurred(String.format("Dimensions exceed maximum allowed for %s: %dx%d (max %dx%d)",
|
||||||
@@ -930,13 +930,12 @@ public final class PSDImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
// NOTE: The spec says that if this section is empty, the length should be 0.
|
// NOTE: The spec says that if this section is empty, the length should be 0.
|
||||||
// Yet I have a PSB file that has size 12, and both contained lengths set to 0 (which
|
// Yet I have a PSB file that has size 12, and both contained lengths set to 0 (which
|
||||||
// is alo not as per spec, as layer count should be included if there's a layer info
|
// is also not as per spec, as layer count should be included if there's a layer info
|
||||||
// block, so minimum size should be either 0 or 14 (or 16 if multiple of 4 for PSB))...
|
// block, so minimum size should be either 0 or 14 (or 16 if multiple of 4 for PSB))...
|
||||||
|
|
||||||
if (layerAndMaskInfoLength > 0) {
|
if (layerAndMaskInfoLength > 0) {
|
||||||
long pos = imageInput.getStreamPosition();
|
long pos = imageInput.getStreamPosition();
|
||||||
|
|
||||||
//if (metadata.layerInfo == null) {
|
|
||||||
long layerInfoLength = header.largeFormat ? imageInput.readLong() : imageInput.readUnsignedInt();
|
long layerInfoLength = header.largeFormat ? imageInput.readLong() : imageInput.readUnsignedInt();
|
||||||
|
|
||||||
if (layerInfoLength > 0) {
|
if (layerInfoLength > 0) {
|
||||||
@@ -991,7 +990,6 @@ public final class PSDImageReader extends ImageReaderBase {
|
|||||||
System.out.println("layerInfo: " + metadata.layerInfo);
|
System.out.println("layerInfo: " + metadata.layerInfo);
|
||||||
System.out.println("globalLayerMask: " + (metadata.globalLayerMask != PSDGlobalLayerMask.NULL_MASK ? metadata.globalLayerMask : null));
|
System.out.println("globalLayerMask: " + (metadata.globalLayerMask != PSDGlobalLayerMask.NULL_MASK ? metadata.globalLayerMask : null));
|
||||||
}
|
}
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata.imageDataStart = metadata.layerAndMaskInfoStart + layerAndMaskInfoLength + (header.largeFormat ? 8 : 4);
|
metadata.imageDataStart = metadata.layerAndMaskInfoStart + layerAndMaskInfoLength + (header.largeFormat ? 8 : 4);
|
||||||
|
|||||||
+2
-4
@@ -69,12 +69,10 @@ final public class PSDImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
switch (version) {
|
switch (version) {
|
||||||
case PSD.VERSION_PSD:
|
case PSD.VERSION_PSD:
|
||||||
case PSD.VERSION_PSB:
|
case PSD.VERSION_PSB:
|
||||||
break;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
// Fall through
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+3
-3
@@ -43,8 +43,8 @@ final class PSDProviderInfo extends ReaderWriterProviderInfo {
|
|||||||
protected PSDProviderInfo() {
|
protected PSDProviderInfo() {
|
||||||
super(
|
super(
|
||||||
PSDProviderInfo.class,
|
PSDProviderInfo.class,
|
||||||
new String[] {"psd", "PSD"},
|
new String[] {"psd", "PSD", "psb", "PSB"},
|
||||||
new String[] {"psd"},
|
new String[] {"psd", "psb"},
|
||||||
new String[] {
|
new String[] {
|
||||||
"image/vnd.adobe.photoshop", // Official, IANA registered
|
"image/vnd.adobe.photoshop", // Official, IANA registered
|
||||||
"application/vnd.adobe.photoshop", // Used in XMP
|
"application/vnd.adobe.photoshop", // Used in XMP
|
||||||
@@ -55,7 +55,7 @@ final class PSDProviderInfo extends ReaderWriterProviderInfo {
|
|||||||
"com.twelvemonkeys.imageio.plugins.psd.PSDImageReader",
|
"com.twelvemonkeys.imageio.plugins.psd.PSDImageReader",
|
||||||
new String[] {"com.twelvemonkeys.imageio.plugins.psd.PSDImageReaderSpi"},
|
new String[] {"com.twelvemonkeys.imageio.plugins.psd.PSDImageReaderSpi"},
|
||||||
null,
|
null,
|
||||||
null, // new String[] {"com.twelvemonkeys.imageio.plugins.psd.PSDImageWriterSpi"},
|
null,
|
||||||
false, null, null, null, null,
|
false, null, null, null, null,
|
||||||
true, PSDMetadata.NATIVE_METADATA_FORMAT_NAME, PSDMetadata.NATIVE_METADATA_FORMAT_CLASS_NAME, null, null
|
true, PSDMetadata.NATIVE_METADATA_FORMAT_NAME, PSDMetadata.NATIVE_METADATA_FORMAT_CLASS_NAME, null, null
|
||||||
);
|
);
|
||||||
|
|||||||
+1
-1
@@ -67,7 +67,7 @@ final class PSDVersionInfo extends PSDImageResource {
|
|||||||
|
|
||||||
writer = PSDUtil.readUnicodeString(pInput);
|
writer = PSDUtil.readUnicodeString(pInput);
|
||||||
reader = PSDUtil.readUnicodeString(pInput);
|
reader = PSDUtil.readUnicodeString(pInput);
|
||||||
|
|
||||||
fileVersion = pInput.readInt();
|
fileVersion = pInput.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+39
-4
@@ -86,8 +86,6 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
|
|||||||
new TestData(getClassLoaderResource("/psd/test_gray16.psd"), new Dimension(710, 512)),
|
new TestData(getClassLoaderResource("/psd/test_gray16.psd"), new Dimension(710, 512)),
|
||||||
// 4 channel, CMYK, 16 bit samples
|
// 4 channel, CMYK, 16 bit samples
|
||||||
new TestData(getClassLoaderResource("/psd/cmyk_16bits.psd"), new Dimension(1000, 275)),
|
new TestData(getClassLoaderResource("/psd/cmyk_16bits.psd"), new Dimension(1000, 275)),
|
||||||
// 3 channel, RGB, 32 bit samples
|
|
||||||
new TestData(getClassLoaderResource("/psd/32bit5x5.psd"), new Dimension(5, 5)),
|
|
||||||
// 3 channel, RGB, 8 bit samples ("Large Document Format" aka PSB)
|
// 3 channel, RGB, 8 bit samples ("Large Document Format" aka PSB)
|
||||||
new TestData(getClassLoaderResource("/psb/test_original.psb"), new Dimension(710, 512)),
|
new TestData(getClassLoaderResource("/psb/test_original.psb"), new Dimension(710, 512)),
|
||||||
// From http://telegraphics.com.au/svn/psdparse/trunk/psd/
|
// From http://telegraphics.com.au/svn/psdparse/trunk/psd/
|
||||||
@@ -104,11 +102,48 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
|
|||||||
new TestData(getClassLoaderResource("/psd/rgb-multichannel-no-transparency.psd"), new Dimension(100, 100)),
|
new TestData(getClassLoaderResource("/psd/rgb-multichannel-no-transparency.psd"), new Dimension(100, 100)),
|
||||||
new TestData(getClassLoaderResource("/psb/rgb-multichannel-no-transparency.psb"), new Dimension(100, 100)),
|
new TestData(getClassLoaderResource("/psb/rgb-multichannel-no-transparency.psb"), new Dimension(100, 100)),
|
||||||
// CMYK, uncompressed + contains some uncommon MeSa (instead of 8BIM) resource blocks
|
// CMYK, uncompressed + contains some uncommon MeSa (instead of 8BIM) resource blocks
|
||||||
new TestData(getClassLoaderResource("/psd/fruit-cmyk-MeSa-resource.psd"), new Dimension(400, 191))
|
new TestData(getClassLoaderResource("/psd/fruit-cmyk-MeSa-resource.psd"), new Dimension(400, 191)),
|
||||||
|
// 3 channel, RGB, 32 bit samples
|
||||||
|
new TestData(getClassLoaderResource("/psd/32bit5x5.psd"), new Dimension(5, 5))
|
||||||
// TODO: Need more recent ZIP compressed PSD files from CS2/CS3+
|
// TODO: Need more recent ZIP compressed PSD files from CS2/CS3+
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<TestData> getTestDataForAffineTransformOpCompatibility() {
|
||||||
|
return Arrays.asList(
|
||||||
|
// 5 channel, RGB
|
||||||
|
new TestData(getClassLoaderResource("/psd/photoshopping.psd"), new Dimension(300, 225)),
|
||||||
|
// 1 channel, gray, 8 bit samples
|
||||||
|
new TestData(getClassLoaderResource("/psd/buttons.psd"), new Dimension(20, 20)),
|
||||||
|
// 3 channel RGB, "no composite layer"
|
||||||
|
new TestData(getClassLoaderResource("/psd/jugware-icon.psd"), new Dimension(128, 128)),
|
||||||
|
// 3 channel RGB, old data, no layer info/mask
|
||||||
|
new TestData(getClassLoaderResource("/psd/MARBLES.PSD"), new Dimension(1419, 1001)),
|
||||||
|
// 1 channel, indexed color
|
||||||
|
new TestData(getClassLoaderResource("/psd/coral_fish.psd"), new Dimension(800, 800)),
|
||||||
|
// 1 channel, bitmap, 1 bit samples
|
||||||
|
new TestData(getClassLoaderResource("/psd/test_bitmap.psd"), new Dimension(710, 512)),
|
||||||
|
// 1 channel, gray, 16 bit samples
|
||||||
|
new TestData(getClassLoaderResource("/psd/test_gray16.psd"), new Dimension(710, 512)),
|
||||||
|
// 3 channel, RGB, 8 bit samples ("Large Document Format" aka PSB)
|
||||||
|
new TestData(getClassLoaderResource("/psb/test_original.psb"), new Dimension(710, 512)),
|
||||||
|
// From http://telegraphics.com.au/svn/psdparse/trunk/psd/
|
||||||
|
new TestData(getClassLoaderResource("/psd/adobehq.psd"), new Dimension(341, 512)),
|
||||||
|
new TestData(getClassLoaderResource("/psd/adobehq_ind.psd"), new Dimension(341, 512)),
|
||||||
|
// Contains a shorter than normal PrintFlags chunk
|
||||||
|
new TestData(getClassLoaderResource("/psd/adobehq-2.5.psd"), new Dimension(341, 512)),
|
||||||
|
new TestData(getClassLoaderResource("/psd/adobehq-3.0.psd"), new Dimension(341, 512)),
|
||||||
|
new TestData(getClassLoaderResource("/psd/adobehq-5.5.psd"), new Dimension(341, 512)),
|
||||||
|
new TestData(getClassLoaderResource("/psd/adobehq-7.0.psd"), new Dimension(341, 512)),
|
||||||
|
// From https://github.com/kmike/psd-tools/tree/master/tests/psd_files
|
||||||
|
new TestData(getClassLoaderResource("/psd/masks2.psd"), new Dimension(640, 1136)),
|
||||||
|
// RGB, multiple alpha channels, no transparency
|
||||||
|
new TestData(getClassLoaderResource("/psd/rgb-multichannel-no-transparency.psd"), new Dimension(100, 100)),
|
||||||
|
new TestData(getClassLoaderResource("/psb/rgb-multichannel-no-transparency.psb"), new Dimension(100, 100))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Collections.singletonList("psd");
|
return Collections.singletonList("psd");
|
||||||
@@ -472,7 +507,7 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
|
|||||||
public void testMultiChannelNoTransparencyPSB() throws IOException {
|
public void testMultiChannelNoTransparencyPSB() throws IOException {
|
||||||
PSDImageReader imageReader = createReader();
|
PSDImageReader imageReader = createReader();
|
||||||
|
|
||||||
// The following PSB is RGB, has 4 channels (1 alpha/auxillary channel), but should be treated as opaque
|
// The following PSB is RGB, has 4 channels (1 alpha/auxiliary channel), but should be treated as opaque
|
||||||
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/psb/rgb-multichannel-no-transparency.psb"))) {
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/psb/rgb-multichannel-no-transparency.psb"))) {
|
||||||
imageReader.setInput(stream);
|
imageReader.setInput(stream);
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-reference</artifactId>
|
<artifactId>imageio-reference</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: JDK Reference Tests</name>
|
<name>TwelveMonkeys :: ImageIO :: JDK Reference Tests</name>
|
||||||
@@ -16,6 +16,18 @@
|
|||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.reference</project.jpms.module.name>
|
<project.jpms.module.name>com.twelvemonkeys.imageio.reference</project.jpms.module.name>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
+5
-12
@@ -46,6 +46,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.util.IIOUtil.lookupProviderByName;
|
import static com.twelvemonkeys.imageio.util.IIOUtil.lookupProviderByName;
|
||||||
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPEGImageReaderTest
|
* JPEGImageReaderTest
|
||||||
@@ -89,24 +90,16 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
@Override
|
@Override
|
||||||
public void testSetDestination() throws IOException {
|
public void testSetDestination() throws IOException {
|
||||||
// Known bug in Sun JPEGImageReader before Java 6
|
// Known bug in Sun JPEGImageReader before Java 6
|
||||||
if (IS_JAVA_6_OR_LATER) {
|
assumeTrue("Test skipped due to known bug in Java 1.5, please test again with Java 6 or later", IS_JAVA_6_OR_LATER);
|
||||||
super.testSetDestination();
|
super.testSetDestination();
|
||||||
}
|
|
||||||
else {
|
|
||||||
System.err.println("WARNING: Test skipped due to known bug in Java 1.5, please test again with Java 6 or later");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Override
|
@Override
|
||||||
public void testSetDestinationType() throws IOException {
|
public void testSetDestinationType() throws IOException {
|
||||||
// Known bug in Sun JPEGImageReader before Java 6
|
// Known bug in Sun JPEGImageReader before Java 6
|
||||||
if (IS_JAVA_6_OR_LATER) {
|
assumeTrue("Test skipped due to known bug in Java 1.5, please test again with Java 6 or later", IS_JAVA_6_OR_LATER);
|
||||||
super.testSetDestinationType();
|
super.testSetDestinationType();
|
||||||
}
|
|
||||||
else {
|
|
||||||
System.err.println("WARNING: Test skipped due to known bug in Java 1.5, please test again with Java 6 or later");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-sgi</artifactId>
|
<artifactId>imageio-sgi</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: SGI plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: SGI plugin</name>
|
||||||
|
|||||||
+25
-3
@@ -59,7 +59,7 @@ public final class SGIImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
private SGIHeader header;
|
private SGIHeader header;
|
||||||
|
|
||||||
protected SGIImageReader(final ImageReaderSpi provider) {
|
SGIImageReader(final ImageReaderSpi provider) {
|
||||||
super(provider);
|
super(provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,9 +88,31 @@ public final class SGIImageReader extends ImageReaderBase {
|
|||||||
public Iterator<ImageTypeSpecifier> getImageTypes(final int imageIndex) throws IOException {
|
public Iterator<ImageTypeSpecifier> getImageTypes(final int imageIndex) throws IOException {
|
||||||
ImageTypeSpecifier rawType = getRawImageType(imageIndex);
|
ImageTypeSpecifier rawType = getRawImageType(imageIndex);
|
||||||
|
|
||||||
List<ImageTypeSpecifier> specifiers = new ArrayList<ImageTypeSpecifier>();
|
List<ImageTypeSpecifier> specifiers = new ArrayList<>();
|
||||||
|
|
||||||
|
int channels = header.getChannels();
|
||||||
|
|
||||||
|
switch (header.getBytesPerPixel()) {
|
||||||
|
case 1:
|
||||||
|
if (channels == 1) {
|
||||||
|
specifiers.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY));
|
||||||
|
}
|
||||||
|
else if (channels == 3) {
|
||||||
|
specifiers.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR));
|
||||||
|
}
|
||||||
|
else if (channels == 4) {
|
||||||
|
specifiers.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (channels == 1) {
|
||||||
|
specifiers.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_GRAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Implement
|
|
||||||
specifiers.add(rawType);
|
specifiers.add(rawType);
|
||||||
|
|
||||||
return specifiers.iterator();
|
return specifiers.iterator();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-tga</artifactId>
|
<artifactId>imageio-tga</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: TGA plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: TGA plugin</name>
|
||||||
|
|||||||
+110
-47
@@ -96,10 +96,18 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
ImageTypeSpecifier rawType = getRawImageType(imageIndex);
|
ImageTypeSpecifier rawType = getRawImageType(imageIndex);
|
||||||
|
|
||||||
List<ImageTypeSpecifier> specifiers = new ArrayList<>();
|
List<ImageTypeSpecifier> specifiers = new ArrayList<>();
|
||||||
|
|
||||||
// TODO: Implement
|
|
||||||
specifiers.add(rawType);
|
specifiers.add(rawType);
|
||||||
|
|
||||||
|
if (rawType.getBufferedImageType() == BufferedImage.TYPE_INT_RGB) {
|
||||||
|
specifiers.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_BGR));
|
||||||
|
}
|
||||||
|
else if (rawType.getBufferedImageType() == BufferedImage.TYPE_INT_ARGB) {
|
||||||
|
specifiers.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB_PRE));
|
||||||
|
}
|
||||||
|
else if (rawType.getBufferedImageType() == BufferedImage.TYPE_INT_ARGB_PRE) {
|
||||||
|
specifiers.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB));
|
||||||
|
}
|
||||||
|
|
||||||
return specifiers.iterator();
|
return specifiers.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +124,14 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
return ImageTypeSpecifiers.createFromIndexColorModel(header.getColorMap());
|
return ImageTypeSpecifiers.createFromIndexColorModel(header.getColorMap());
|
||||||
case TGA.IMAGETYPE_MONOCHROME:
|
case TGA.IMAGETYPE_MONOCHROME:
|
||||||
case TGA.IMAGETYPE_MONOCHROME_RLE:
|
case TGA.IMAGETYPE_MONOCHROME_RLE:
|
||||||
return ImageTypeSpecifiers.createGrayscale(8, DataBuffer.TYPE_BYTE);
|
switch (header.getPixelDepth()) {
|
||||||
|
case 8:
|
||||||
|
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY);
|
||||||
|
case 16:
|
||||||
|
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_GRAY);
|
||||||
|
default:
|
||||||
|
throw new IIOException("Unknown pixel depth for monochrome: " + header.getPixelDepth());
|
||||||
|
}
|
||||||
case TGA.IMAGETYPE_TRUECOLOR:
|
case TGA.IMAGETYPE_TRUECOLOR:
|
||||||
case TGA.IMAGETYPE_TRUECOLOR_RLE:
|
case TGA.IMAGETYPE_TRUECOLOR_RLE:
|
||||||
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||||
@@ -135,12 +150,14 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
case 24:
|
case 24:
|
||||||
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
|
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
|
||||||
case 32:
|
case 32:
|
||||||
// 4BYTE_BGRX...
|
// NOTE: We'll read using little endian byte order, thus the file layout is BGRA/BGRx
|
||||||
// Can't mask out alpha (efficiently) for 4BYTE, so we'll ignore it while reading instead,
|
if (hasAlpha) {
|
||||||
// if hasAlpha is false
|
return ImageTypeSpecifier.createFromBufferedImageType(isAlphaPremultiplied ? BufferedImage.TYPE_INT_ARGB_PRE : BufferedImage.TYPE_INT_ARGB);
|
||||||
return ImageTypeSpecifiers.createInterleaved(sRGB, new int[] {2, 1, 0, 3}, DataBuffer.TYPE_BYTE, true, isAlphaPremultiplied);
|
}
|
||||||
|
|
||||||
|
return ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
|
||||||
default:
|
default:
|
||||||
throw new IIOException("Unknown pixel depth for truecolor: " + header.getPixelDepth());
|
throw new IIOException("Unknown pixel depth for true color: " + header.getPixelDepth());
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new IIOException("Unknown image type: " + header.getImageType());
|
throw new IIOException("Unknown image type: " + header.getImageType());
|
||||||
@@ -187,20 +204,26 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
input = imageInput;
|
input = imageInput;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int pixelDepth = header.getPixelDepth();
|
||||||
|
boolean flipped = isOriginLowerLeft(header.getOrigin());
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
switch (header.getPixelDepth()) {
|
switch (pixelDepth) {
|
||||||
case 8:
|
case 8:
|
||||||
case 24:
|
case 24:
|
||||||
case 32:
|
|
||||||
byte[] rowDataByte = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
byte[] rowDataByte = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
||||||
readRowByte(input, height, srcRegion, header.getOrigin(), xSub, ySub, rowDataByte, destRaster, clippedRow, y);
|
readRowByte(input, height, srcRegion, flipped, xSub, ySub, rowDataByte, destRaster, clippedRow, y);
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
short[] rowDataUShort = ((DataBufferUShort) rowRaster.getDataBuffer()).getData();
|
short[] rowDataUShort = ((DataBufferUShort) rowRaster.getDataBuffer()).getData();
|
||||||
readRowUShort(input, height, srcRegion, header.getOrigin(), xSub, ySub, rowDataUShort, destRaster, clippedRow, y);
|
readRowUShort(input, height, srcRegion, flipped, xSub, ySub, rowDataUShort, destRaster, clippedRow, y);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
int[] rowDataInt = ((DataBufferInt) rowRaster.getDataBuffer()).getData();
|
||||||
|
readRowInt(input, height, srcRegion, flipped, xSub, ySub, rowDataInt, destRaster, clippedRow, y);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new AssertionError("Unsupported pixel depth: " + header.getPixelDepth());
|
throw new AssertionError("Unsupported pixel depth: " + pixelDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
processImageProgress(100f * y / height);
|
processImageProgress(100f * y / height);
|
||||||
@@ -220,10 +243,26 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readRowByte(final DataInput input, int height, Rectangle srcRegion, int origin, int xSub, int ySub,
|
private boolean isOriginLowerLeft(final int origin) throws IIOException {
|
||||||
|
switch (origin) {
|
||||||
|
case TGA.ORIGIN_LOWER_LEFT:
|
||||||
|
return true;
|
||||||
|
case TGA.ORIGIN_UPPER_LEFT:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
// Other orientations are not supported
|
||||||
|
throw new IIOException("Unsupported origin: " + origin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readRowByte(final DataInput input, int height, Rectangle srcRegion, boolean flip, int xSub, int ySub,
|
||||||
byte[] rowDataByte, WritableRaster destChannel, Raster srcChannel, int y) throws IOException {
|
byte[] rowDataByte, WritableRaster destChannel, Raster srcChannel, int y) throws IOException {
|
||||||
|
// Flip into position?
|
||||||
|
int srcY = flip ? height - 1 - y : y;
|
||||||
|
int dstY = (srcY - srcRegion.y) / ySub;
|
||||||
|
|
||||||
// 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 || srcY < srcRegion.y || srcY >= srcRegion.y + srcRegion.height) {
|
||||||
input.skipBytes(rowDataByte.length);
|
input.skipBytes(rowDataByte.length);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -244,19 +283,7 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (origin) {
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
case TGA.ORIGIN_LOWER_LEFT:
|
|
||||||
// Flip into position
|
|
||||||
int dstY = (height - 1 - y - srcRegion.y) / ySub;
|
|
||||||
destChannel.setDataElements(0, dstY, srcChannel);
|
|
||||||
break;
|
|
||||||
case TGA.ORIGIN_UPPER_LEFT:
|
|
||||||
dstY = y / ySub;
|
|
||||||
destChannel.setDataElements(0, dstY, srcChannel);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IIOException("Unsupported origin: " + origin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeAlpha32(final byte[] rowData) {
|
private void removeAlpha32(final byte[] rowData) {
|
||||||
@@ -265,10 +292,14 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readRowUShort(final DataInput input, int height, Rectangle srcRegion, int origin, int xSub, int ySub,
|
private void readRowUShort(final DataInput input, int height, Rectangle srcRegion, boolean flip, int xSub, int ySub,
|
||||||
short[] rowDataUShort, WritableRaster destChannel, Raster srcChannel, int y) throws IOException {
|
short[] rowDataUShort, WritableRaster destChannel, Raster srcChannel, int y) throws IOException {
|
||||||
|
// Flip into position?
|
||||||
|
int srcY = flip ? height - 1 - y : y;
|
||||||
|
int dstY = (srcY - srcRegion.y) / ySub;
|
||||||
|
|
||||||
// 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 || srcY < srcRegion.y || srcY >= srcRegion.y + srcRegion.height) {
|
||||||
input.skipBytes(rowDataUShort.length * 2);
|
input.skipBytes(rowDataUShort.length * 2);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -283,19 +314,32 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (origin) {
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
case TGA.ORIGIN_LOWER_LEFT:
|
}
|
||||||
// Flip into position
|
|
||||||
int dstY = (height - 1 - y - srcRegion.y) / ySub;
|
private void readRowInt(final DataInput input, int height, Rectangle srcRegion, boolean flip, int xSub, int ySub,
|
||||||
destChannel.setDataElements(0, dstY, srcChannel);
|
int[] rowDataInt, WritableRaster destChannel, Raster srcChannel, int y) throws IOException {
|
||||||
break;
|
// Flip into position?
|
||||||
case TGA.ORIGIN_UPPER_LEFT:
|
int srcY = flip ? height - 1 - y : y;
|
||||||
dstY = y / ySub;
|
int dstY = (srcY - srcRegion.y) / ySub;
|
||||||
destChannel.setDataElements(0, dstY, srcChannel);
|
|
||||||
break;
|
// If subsampled or outside source region, skip entire row
|
||||||
default:
|
if (y % ySub != 0 || srcY < srcRegion.y || srcY >= srcRegion.y + srcRegion.height) {
|
||||||
throw new IIOException("Unsupported origin: " + origin);
|
input.skipBytes(rowDataInt.length * 4);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readFully(input, rowDataInt);
|
||||||
|
|
||||||
|
// Subsample horizontal
|
||||||
|
if (xSub != 1) {
|
||||||
|
for (int x = srcRegion.x / xSub; x < ((srcRegion.x + srcRegion.width) / xSub); x++) {
|
||||||
|
rowDataInt[x] = rowDataInt[x * xSub];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
destChannel.setDataElements(0, dstY, srcChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Candidate util method
|
// TODO: Candidate util method
|
||||||
@@ -311,6 +355,19 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Candidate util method
|
||||||
|
private static void readFully(final DataInput input, final int[] ints) throws IOException {
|
||||||
|
if (input instanceof ImageInputStream) {
|
||||||
|
// Optimization for ImageInputStreams, read all in one go
|
||||||
|
((ImageInputStream) input).readFully(ints, 0, ints.length);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < ints.length; i++) {
|
||||||
|
ints[i] = input.readInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Raster clipRowToRect(final Raster raster, final Rectangle rect, final int[] bands, final int xSub) {
|
private Raster clipRowToRect(final Raster raster, final Rectangle rect, final int[] bands, final int xSub) {
|
||||||
if (rect.contains(raster.getMinX(), 0, raster.getWidth(), 1)
|
if (rect.contains(raster.getMinX(), 0, raster.getWidth(), 1)
|
||||||
&& xSub == 1
|
&& xSub == 1
|
||||||
@@ -446,20 +503,26 @@ final class TGAImageReader extends ImageReaderBase {
|
|||||||
// Thumbnail is always stored non-compressed, no need for RLE support
|
// Thumbnail is always stored non-compressed, no need for RLE support
|
||||||
imageInput.seek(extensions.getThumbnailOffset() + 2);
|
imageInput.seek(extensions.getThumbnailOffset() + 2);
|
||||||
|
|
||||||
|
int pixelDepth = header.getPixelDepth();
|
||||||
|
boolean flipped = isOriginLowerLeft(header.getOrigin());
|
||||||
|
|
||||||
for (int y = 0; y < height; y++) {
|
for (int y = 0; y < height; y++) {
|
||||||
switch (header.getPixelDepth()) {
|
switch (pixelDepth) {
|
||||||
case 8:
|
case 8:
|
||||||
case 24:
|
case 24:
|
||||||
case 32:
|
|
||||||
byte[] rowDataByte = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
byte[] rowDataByte = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
||||||
readRowByte(imageInput, height, srcRegion, header.getOrigin(), 1, 1, rowDataByte, destRaster, rowRaster, y);
|
readRowByte(imageInput, height, srcRegion, flipped, 1, 1, rowDataByte, destRaster, rowRaster, y);
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
short[] rowDataUShort = ((DataBufferUShort) rowRaster.getDataBuffer()).getData();
|
short[] rowDataUShort = ((DataBufferUShort) rowRaster.getDataBuffer()).getData();
|
||||||
readRowUShort(imageInput, height, srcRegion, header.getOrigin(), 1, 1, rowDataUShort, destRaster, rowRaster, y);
|
readRowUShort(imageInput, height, srcRegion, flipped, 1, 1, rowDataUShort, destRaster, rowRaster, y);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
int[] rowDataInt = ((DataBufferInt) rowRaster.getDataBuffer()).getData();
|
||||||
|
readRowInt(imageInput, height, srcRegion, flipped, 1, 1, rowDataInt, destRaster, rowRaster, y);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new AssertionError("Unsupported pixel depth: " + header.getPixelDepth());
|
throw new AssertionError("Unsupported pixel depth: " + pixelDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
processThumbnailProgress(100f * y / height);
|
processThumbnailProgress(100f * y / height);
|
||||||
|
|||||||
+5
-2
@@ -193,10 +193,13 @@ 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, "8"));
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
if (header.getAttributeBits() > 0 && extensions != null && extensions.hasAlpha()) {
|
if (header.getImageType() == TGA.IMAGETYPE_MONOCHROME || header.getImageType() == TGA.IMAGETYPE_MONOCHROME_RLE) {
|
||||||
|
bitsPerSample.setAttribute("value", "16");
|
||||||
|
}
|
||||||
|
else if (header.getAttributeBits() > 0 && extensions != null && extensions.hasAlpha()) {
|
||||||
bitsPerSample.setAttribute("value", "5, 5, 5, 1");
|
bitsPerSample.setAttribute("value", "5, 5, 5, 1");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
+4
-1
@@ -91,7 +91,10 @@ public class TGAImageReaderTest extends ImageReaderAbstractTest<TGAImageReader>
|
|||||||
new TestData(getClassLoaderResource("/tga/XING_T24.TGA"), new Dimension(240, 164)), // Uncompressed 24 bit BGR top/down
|
new TestData(getClassLoaderResource("/tga/XING_T24.TGA"), new Dimension(240, 164)), // Uncompressed 24 bit BGR top/down
|
||||||
new TestData(getClassLoaderResource("/tga/XING_T32.TGA"), new Dimension(240, 164)), // Uncompressed 32 bit BGRA top/down
|
new TestData(getClassLoaderResource("/tga/XING_T32.TGA"), new Dimension(240, 164)), // Uncompressed 32 bit BGRA top/down
|
||||||
|
|
||||||
new TestData(getClassLoaderResource("/tga/autodesk-3dsmax-extsize494.tga"), new Dimension(440, 200)) // RLE compressed 32 bit BGRA bottom/up
|
new TestData(getClassLoaderResource("/tga/autodesk-3dsmax-extsize494.tga"), new Dimension(440, 200)), // RLE compressed 32 bit BGRA bottom/up
|
||||||
|
|
||||||
|
new TestData(getClassLoaderResource("/tga/monochrome16_top_left.tga"), new Dimension(64, 64)), // Uncompressed 16 bit monochrome
|
||||||
|
new TestData(getClassLoaderResource("/tga/monochrome16_top_left_rle.tga"), new Dimension(64, 64)) // RLE compressed 16 bit monochrome
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
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.7.0</version>
|
<version>3.7.2-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>
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>imageio</artifactId>
|
||||||
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>imageio-tiff-jai-interop</artifactId>
|
||||||
|
<name>TwelveMonkeys :: ImageIO :: TIFF/JAI Metadata Interop</name>
|
||||||
|
<description>
|
||||||
|
Test TIFF plugin and JAI TIFF plugin Metadata interoperability
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.jpms.module.name>com.twelvemonkeys.imageio.tiff.jaiinterop</project.jpms.module.name>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.jai-imageio</groupId>
|
||||||
|
<artifactId>jai-imageio-core</artifactId>
|
||||||
|
<version>1.4.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>imageio-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>imageio-core</artifactId>
|
||||||
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>imageio-metadata</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>imageio-tiff</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Harald Kuhr
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.twelvemonkeys.imageio.plugins.tiff.jaiinterop;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.metadata.tiff.Rational;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry;
|
||||||
|
import com.twelvemonkeys.imageio.plugins.tiff.TIFFImageMetadata;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import javax.imageio.ImageWriter;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||||
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests our TIFFImageMetadata works with JAI TIFFImageWriter.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: TIFFImageReaderJDKJPEGInteroperabilityTest.java,v 1.0 08.05.12 15:25 haraldk Exp$
|
||||||
|
*/
|
||||||
|
public class TIFFImageMetadataJAInteroperabilityTest {
|
||||||
|
private static final String JAI_TIFF_PROVIDER_CLASS_NAME = "com.github.jaiimageio.impl.plugins.tiff.TIFFImageWriterSpi";
|
||||||
|
|
||||||
|
private ImageWriter createImageWriter() {
|
||||||
|
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("TIFF");
|
||||||
|
|
||||||
|
while (writers.hasNext()) {
|
||||||
|
ImageWriter writer = writers.next();
|
||||||
|
|
||||||
|
if (JAI_TIFF_PROVIDER_CLASS_NAME.equals(writer.getOriginatingProvider().getClass().getName())) {
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new AssertionError("Expected Spi not found (dependency issue?): " + JAI_TIFF_PROVIDER_CLASS_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRationalNeedsDenominator() {
|
||||||
|
// Set the resolution to 200 dpi
|
||||||
|
IIOMetadata ourMetadata = new TIFFImageMetadata(Arrays.asList(new TIFFEntry(TIFF.TAG_RESOLUTION_UNIT, 2), // Unit DPI (default)
|
||||||
|
new TIFFEntry(TIFF.TAG_X_RESOLUTION, new Rational(200)),
|
||||||
|
new TIFFEntry(TIFF.TAG_Y_RESOLUTION, new Rational(200))));
|
||||||
|
|
||||||
|
ImageTypeSpecifier type = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY);
|
||||||
|
ImageWriter writer = createImageWriter();
|
||||||
|
IIOMetadata converted = writer.convertImageMetadata(ourMetadata, type, null);
|
||||||
|
|
||||||
|
assertNotNull(converted);
|
||||||
|
|
||||||
|
// Make sure we have x/y resolution in converted metadata
|
||||||
|
IIOMetadataNode standardTree = (IIOMetadataNode) converted.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
||||||
|
String horizontalPixelSize = ((IIOMetadataNode) standardTree.getElementsByTagName("HorizontalPixelSize").item(0)).getAttribute("value");
|
||||||
|
String verticalPixelSize = ((IIOMetadataNode) standardTree.getElementsByTagName("VerticalPixelSize").item(0)).getAttribute("value");
|
||||||
|
|
||||||
|
// For some reason this is *pixel size* in *mm*...
|
||||||
|
String expected = String.valueOf(2.54 / 200 * 10);
|
||||||
|
assertEquals(expected, horizontalPixelSize);
|
||||||
|
assertEquals(expected, verticalPixelSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-tiff-jdk-interop</artifactId>
|
<artifactId>imageio-tiff-jdk-interop</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: TIFF/JDK JPEG Interop</name>
|
<name>TwelveMonkeys :: ImageIO :: TIFF/JDK JPEG Interop</name>
|
||||||
@@ -13,9 +13,22 @@
|
|||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.jdkinterop</project.jpms.module.name>
|
<project.jpms.module.name>com.twelvemonkeys.imageio.tiff.jdkinterop</project.jpms.module.name>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-deploy-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skip>true</skip>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
+12
-11
@@ -28,25 +28,26 @@
|
|||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg.jdkinterop;
|
package com.twelvemonkeys.imageio.plugins.tiff.jdkinterop;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReader;
|
import static org.junit.Assert.fail;
|
||||||
import com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReaderSpi;
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
|
||||||
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.fail;
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReader;
|
||||||
|
import com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReaderSpi;
|
||||||
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests our TIFFImageReader delegating to the JDK JPEGImageReader.
|
* Tests our TIFFImageReader delegating to the JDK JPEGImageReader.
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.7.2-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-tiff</artifactId>
|
<artifactId>imageio-tiff</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: TIFF plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: TIFF plugin</name>
|
||||||
|
|||||||
+1
-1
@@ -53,7 +53,7 @@ final class BigTIFFProviderInfo extends ReaderWriterProviderInfo {
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
false, TIFFStreamMetadata.SUN_NATIVE_STREAM_METADATA_FORMAT_NAME, "com.twelvemonkeys.imageio.plugins.tiff.TIFFStreamMetadataFormat", null, null,
|
false, TIFFStreamMetadata.SUN_NATIVE_STREAM_METADATA_FORMAT_NAME, "com.twelvemonkeys.imageio.plugins.tiff.TIFFStreamMetadataFormat", null, null,
|
||||||
true, TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME, "com.twelvemonkeys.imageio.plugins.tiff.TIFFMedataFormat", null, null
|
true, TIFFImageMetadataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME, "com.twelvemonkeys.imageio.plugins.tiff.TIFFMedataFormat", null, null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-52
@@ -58,8 +58,6 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
|
|||||||
private final boolean optionUncompressed;
|
private final boolean optionUncompressed;
|
||||||
private final boolean optionByteAligned;
|
private final boolean optionByteAligned;
|
||||||
|
|
||||||
// Need to take fill order into account (?) (use flip table?)
|
|
||||||
private final int fillOrder;
|
|
||||||
private final int type;
|
private final int type;
|
||||||
|
|
||||||
private int decodedLength;
|
private int decodedLength;
|
||||||
@@ -81,12 +79,10 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
|
|||||||
* @param columns the number of columns in the stream.
|
* @param columns the number of columns in the stream.
|
||||||
* @param type the type of stream, must be one of {@code COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE},
|
* @param type the type of stream, must be one of {@code COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE},
|
||||||
* {@code COMPRESSION_CCITT_T4} or {@code COMPRESSION_CCITT_T6}.
|
* {@code COMPRESSION_CCITT_T4} or {@code COMPRESSION_CCITT_T6}.
|
||||||
* @param fillOrder fillOrder, must be {@code FILL_LEFT_TO_RIGHT} or
|
|
||||||
* {@code FILL_RIGHT_TO_LEFT}.
|
|
||||||
* @param options CCITT T.4 or T.6 options.
|
* @param options CCITT T.4 or T.6 options.
|
||||||
* @param byteAligned enable byte alignment used in PDF files (EncodedByteAlign).
|
* @param byteAligned enable byte alignment used in PDF files (EncodedByteAlign).
|
||||||
*/
|
*/
|
||||||
public CCITTFaxDecoderStream(final InputStream stream, final int columns, final int type, final int fillOrder,
|
public CCITTFaxDecoderStream(final InputStream stream, final int columns, final int type,
|
||||||
final long options, final boolean byteAligned) {
|
final long options, final boolean byteAligned) {
|
||||||
super(Validate.notNull(stream, "stream"));
|
super(Validate.notNull(stream, "stream"));
|
||||||
|
|
||||||
@@ -95,10 +91,6 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
|
|||||||
type == TIFFExtension.COMPRESSION_CCITT_T4 ||
|
type == TIFFExtension.COMPRESSION_CCITT_T4 ||
|
||||||
type == TIFFExtension.COMPRESSION_CCITT_T6,
|
type == TIFFExtension.COMPRESSION_CCITT_T6,
|
||||||
type, "Only CCITT Modified Huffman RLE compression (2), CCITT T4 (3) or CCITT T6 (4) supported: %s");
|
type, "Only CCITT Modified Huffman RLE compression (2), CCITT T4 (3) or CCITT T6 (4) supported: %s");
|
||||||
this.fillOrder = Validate.isTrue(
|
|
||||||
fillOrder == TIFFBaseline.FILL_LEFT_TO_RIGHT || fillOrder == TIFFExtension.FILL_RIGHT_TO_LEFT,
|
|
||||||
fillOrder, "Expected fill order 1 or 2: %s"
|
|
||||||
);
|
|
||||||
|
|
||||||
// We know this is only used for b/w (1 bit)
|
// We know this is only used for b/w (1 bit)
|
||||||
decodedRow = new byte[(columns + 7) / 8];
|
decodedRow = new byte[(columns + 7) / 8];
|
||||||
@@ -140,54 +132,63 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
|
|||||||
* @param columns the number of columns in the stream.
|
* @param columns the number of columns in the stream.
|
||||||
* @param type the type of stream, must be one of {@code COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE},
|
* @param type the type of stream, must be one of {@code COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE},
|
||||||
* {@code COMPRESSION_CCITT_T4} or {@code COMPRESSION_CCITT_T6}.
|
* {@code COMPRESSION_CCITT_T4} or {@code COMPRESSION_CCITT_T6}.
|
||||||
* @param fillOrder fillOrder, must be {@code FILL_LEFT_TO_RIGHT} or
|
|
||||||
* {@code FILL_RIGHT_TO_LEFT}.
|
|
||||||
* @param options CCITT T.4 or T.6 options.
|
* @param options CCITT T.4 or T.6 options.
|
||||||
*/
|
*/
|
||||||
public CCITTFaxDecoderStream(final InputStream stream, final int columns, final int type, final int fillOrder,
|
public CCITTFaxDecoderStream(final InputStream stream, final int columns, final int type,
|
||||||
final long options) {
|
final long options) {
|
||||||
this(stream, columns, type, fillOrder, options, type == TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE);
|
this(stream, columns, type, options, type == TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int findCompressionType(final int type, final InputStream in) throws IOException {
|
static int findCompressionType(final int encodedType, final InputStream stream) throws IOException {
|
||||||
// Discover possible incorrect type, revert to RLE
|
// Discover possible incorrect compression type, revert to RLE if no EOLs found
|
||||||
if (type == TIFFExtension.COMPRESSION_CCITT_T4 && in.markSupported()) {
|
if (encodedType == TIFFExtension.COMPRESSION_CCITT_T4 && stream.markSupported()) {
|
||||||
byte[] streamData = new byte[32];
|
int limit = 512;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
in.mark(streamData.length);
|
stream.mark(limit);
|
||||||
|
int first = stream.read();
|
||||||
|
int second = stream.read();
|
||||||
|
|
||||||
int offset = 0;
|
if (second == -1) {
|
||||||
while (offset < streamData.length) {
|
// stream to short
|
||||||
int read = in.read(streamData, offset, streamData.length - offset);
|
return encodedType;
|
||||||
if (read <= 0) {
|
}
|
||||||
break;
|
else if (first == 0 && (((byte) second) >> 4 == 1 || ((byte) second) == 1)) {
|
||||||
|
// correct, starts with EOL or byte aligned EOL
|
||||||
|
return encodedType;
|
||||||
|
}
|
||||||
|
|
||||||
|
short b = (short) (((((byte) first) << 8) + ((byte) second)) >> 4);
|
||||||
|
int limitBits = limit * 8;
|
||||||
|
int read = second;
|
||||||
|
byte streamByte = (byte) read;
|
||||||
|
|
||||||
|
for (int i = 12; i < limitBits; i++) {
|
||||||
|
if (i % 8 == 0) {
|
||||||
|
read = stream.read();
|
||||||
|
if (read == -1) {
|
||||||
|
// no EOL before stream end
|
||||||
|
return TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += read;
|
b = (short) ((b << 1) + ((streamByte >> (7 - (i % 8))) & 0x01));
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
in.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (streamData[0] != 0 || (streamData[1] >> 4 != 1 && streamData[1] != 1)) {
|
|
||||||
// Leading EOL (0b000000000001) not found, search further and try RLE if not found
|
|
||||||
int numBits = streamData.length * 8;
|
|
||||||
short b = (short) (((streamData[0] << 8) + streamData[1]) >> 4);
|
|
||||||
for (int i = 12; i < numBits; i++) {
|
|
||||||
b = (short) ((b << 1) + ((streamData[(i / 8)] >> (7 - (i % 8))) & 0x01));
|
|
||||||
|
|
||||||
if ((b & 0xFFF) == 1) {
|
if ((b & 0xFFF) == 1) {
|
||||||
|
// found EOL
|
||||||
return TIFFExtension.COMPRESSION_CCITT_T4;
|
return TIFFExtension.COMPRESSION_CCITT_T4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// no EOL till limit
|
||||||
return TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE;
|
return TIFFBaseline.COMPRESSION_CCITT_MODIFIED_HUFFMAN_RLE;
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
stream.reset();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return type;
|
return encodedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetch() throws IOException {
|
private void fetch() throws IOException {
|
||||||
@@ -197,13 +198,17 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
|
|||||||
try {
|
try {
|
||||||
decodeRow();
|
decodeRow();
|
||||||
}
|
}
|
||||||
|
catch (ArrayIndexOutOfBoundsException e) {
|
||||||
|
// Mask the AIOOBE as an IOException
|
||||||
|
throw new IOException("Malformed CCITT stream", e);
|
||||||
|
}
|
||||||
catch (EOFException e) {
|
catch (EOFException e) {
|
||||||
// TODO: Rewrite to avoid throw/catch for normal flow...
|
// TODO: Rewrite to avoid throw/catch for normal flow...
|
||||||
if (decodedLength != 0) {
|
if (decodedLength != 0) {
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ..otherwise, just let client code try to read past the
|
// ...otherwise, just let client code try to read past the
|
||||||
// end of stream
|
// end of stream
|
||||||
decodedLength = -1;
|
decodedLength = -1;
|
||||||
}
|
}
|
||||||
@@ -468,7 +473,7 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
|
|||||||
int bufferPos = -1;
|
int bufferPos = -1;
|
||||||
|
|
||||||
private boolean readBit() throws IOException {
|
private boolean readBit() throws IOException {
|
||||||
if (bufferPos < 0 || bufferPos > 7) {
|
if (bufferPos > 7 || bufferPos < 0) {
|
||||||
buffer = in.read();
|
buffer = in.read();
|
||||||
|
|
||||||
if (buffer == -1) {
|
if (buffer == -1) {
|
||||||
@@ -478,21 +483,10 @@ final class CCITTFaxDecoderStream extends FilterInputStream {
|
|||||||
bufferPos = 0;
|
bufferPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isSet;
|
boolean isSet = (buffer & 0x80) != 0;
|
||||||
|
buffer <<= 1;
|
||||||
if (fillOrder == TIFFBaseline.FILL_LEFT_TO_RIGHT) {
|
|
||||||
isSet = ((buffer >> (7 - bufferPos)) & 1) == 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
isSet = ((buffer >> (bufferPos)) & 1) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bufferPos++;
|
bufferPos++;
|
||||||
|
|
||||||
if (bufferPos > 7) {
|
|
||||||
bufferPos = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isSet;
|
return isSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user