mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-24 00:00:01 -04:00
Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 873420286d | |||
| 4993331a5d | |||
| af0a3889db | |||
| 6acdfd3be6 | |||
| cfb664a76a | |||
| 86d95e1f02 | |||
| 54dd9b6d7b | |||
| 4e10fc019e | |||
| 1295951ead | |||
| d5e664cdcc | |||
| efe5f3c34a | |||
| 2488f6f67c | |||
| 6a66d2e059 | |||
| ebd5533879 | |||
| e6e4e96309 | |||
| aadc62dde9 | |||
| 24cbe57240 | |||
| f7d8ae0cd2 | |||
| 5da934e11b | |||
| 51297ad496 | |||
| 80a534cd62 | |||
| 24130d466d | |||
| 7559686782 | |||
| b6988c37a7 | |||
| bbffb1d416 | |||
| c68de3bc92 | |||
| a12b6044c6 | |||
| 9a0e2d9659 | |||
| b904f8952f | |||
| 187c952b8e | |||
| ca86605923 | |||
| 8bc863298f | |||
| 3447d1782c | |||
| bf245fde5f | |||
| c0748dcfd7 | |||
| c293516201 | |||
| f6dae36b7e | |||
| a14b481e9e | |||
| d9c1a39c37 | |||
| e9d9f99bb0 | |||
| b9749b94b0 | |||
| 4996dff6e4 | |||
| b1a2244c7f | |||
| c6fe747ca3 | |||
| e1af4d7da9 | |||
| 33556cc0ec | |||
| eaf13b102f | |||
| 74718f1ffb | |||
| bd3700ea59 | |||
| 8fccd9445f | |||
| cf0ed8f95c | |||
| c12e4e5646 | |||
| 287b73c732 | |||
| 24271b8cad | |||
| 3e2f54ee7c | |||
| 2511b2d0cd | |||
| a15d54c92c | |||
| 47b7c4b16c | |||
| 9e1b01a7fd | |||
| 769acc8726 | |||
| 1ace3a6d5f | |||
| a06eb53cd2 | |||
| 1e1a640a6c | |||
| 2444bc5ad4 | |||
| 2e656a45f9 | |||
| 657928f4a5 | |||
| 08f7e070dc | |||
| b205226f0c | |||
| 821df11d90 | |||
| a62a838a0d | |||
| 75ff0f265f | |||
| 15c7cfe9a6 | |||
| 1286077b02 | |||
| 5757743db7 | |||
| fbaa13d48d | |||
| f12df442e9 | |||
| 0c0712ab30 | |||
| 9267842788 | |||
| bcffeb04ec | |||
| d1a1bab18c | |||
| 6b5e75a22b |
+8
-8
@@ -1,14 +1,14 @@
|
|||||||
dist: trusty
|
dist: trusty
|
||||||
language: java
|
language: java
|
||||||
jdk:
|
jdk:
|
||||||
- oraclejdk8 # Legacy
|
- oraclejdk8
|
||||||
- oraclejdk11 # LTS
|
# Oracle JDK 7 no longer supported, we use env matrix to test various CMM providers
|
||||||
- oraclejdk15 # Latest
|
# - oraclejdk7
|
||||||
jobs:
|
# Some JPEGImageReader tests fail on OpenJDK, need to investigate/fix before enabling
|
||||||
include:
|
# - openjdk7
|
||||||
# Extra job, testing legacy CMM option
|
env:
|
||||||
- jdk: oraclejdk8
|
- MAVEN_OPTS=-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider
|
||||||
env: MAVEN_OPTS=-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider
|
- MAVEN_OPTS=""
|
||||||
cache:
|
cache:
|
||||||
directories:
|
directories:
|
||||||
- $HOME/.m2
|
- $HOME/.m2
|
||||||
|
|||||||
@@ -23,32 +23,31 @@ The goal is to create a set of efficient and robust ImageIO plug-ins, that can b
|
|||||||
| ------ | -------- | ----------- |:----:|:-----:| -------- | ----- |
|
| ------ | -------- | ----------- |:----:|:-----:| -------- | ----- |
|
||||||
| Batik | **SVG** | Scalable Vector Graphics | âś” | - | - | Requires [Batik](https://xmlgraphics.apache.org/batik/)
|
| Batik | **SVG** | Scalable Vector Graphics | âś” | - | - | Requires [Batik](https://xmlgraphics.apache.org/batik/)
|
||||||
| | WMF | MS Windows Metafile | âś” | - | - | Requires [Batik](https://xmlgraphics.apache.org/batik/)
|
| | WMF | MS Windows Metafile | âś” | - | - | Requires [Batik](https://xmlgraphics.apache.org/batik/)
|
||||||
| [BMP](https://github.com/haraldk/TwelveMonkeys/wiki/BMP-Plugin) | **BMP** | MS Windows and IBM OS/2 Device Independent Bitmap | âś” | âś” | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/bmp_metadata.html) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [BMP](https://github.com/haraldk/TwelveMonkeys/wiki/BMP-Plugin) | **BMP** | MS Windows and IBM OS/2 Device Independent Bitmap | âś” | âś” | Native & Standard |
|
||||||
| | CUR | MS Windows Cursor Format | âś” | - | - |
|
| | CUR | MS Windows Cursor Format | âś” | - | - |
|
||||||
| | ICO | MS Windows Icon Format | âś” | âś” | - |
|
| | ICO | MS Windows Icon Format | âś” | âś” | - |
|
||||||
| [HDR](https://github.com/haraldk/TwelveMonkeys/wiki/HDR-Plugin) | HDR | Radiance High Dynamic Range RGBE Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [HDR](https://github.com/haraldk/TwelveMonkeys/wiki/HDR-Plugin) | HDR | Radiance High Dynamic Range RGBE Format | âś” | - | Standard |
|
||||||
| [ICNS](https://github.com/haraldk/TwelveMonkeys/wiki/ICNS-Plugin) | ICNS | Apple Icon Image | âś” | âś” | - |
|
| [ICNS](https://github.com/haraldk/TwelveMonkeys/wiki/ICNS-Plugin) | ICNS | Apple Icon Image | âś” | âś” | - |
|
||||||
| [IFF](https://github.com/haraldk/TwelveMonkeys/wiki/IFF-Plugin) | IFF | Commodore Amiga/Electronic Arts Interchange File Format | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [IFF](https://github.com/haraldk/TwelveMonkeys/wiki/IFF-Plugin) | IFF | Commodore Amiga/Electronic Arts Interchange File Format | âś” | âś” | Standard |
|
||||||
| [JPEG](https://github.com/haraldk/TwelveMonkeys/wiki/JPEG-Plugin) | **JPEG** | Joint Photographers Expert Group | âś” | âś” | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/jpeg_metadata.html#image) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [JPEG](https://github.com/haraldk/TwelveMonkeys/wiki/JPEG-Plugin) | **JPEG** | Joint Photographers Expert Group | âś” | âś” | Native & Standard |
|
||||||
| | JPEG Lossless | | âś” | - | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/jpeg_metadata.html#image) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| | **JPEG Lossless** | | âś” | - | Native & Standard |
|
||||||
| [PCX](https://github.com/haraldk/TwelveMonkeys/wiki/PCX-Plugin) | PCX | ZSoft Paintbrush Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [PCX](https://github.com/haraldk/TwelveMonkeys/wiki/PCX-Plugin) | PCX | ZSoft Paintbrush Format | âś” | - | Standard |
|
||||||
| | DCX | Multi-page PCX fax document | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| | DCX | Multi-page PCX fax document | âś” | - | Standard |
|
||||||
| [PICT](https://github.com/haraldk/TwelveMonkeys/wiki/PICT-Plugin) | PICT | Apple QuickTime Picture Format | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [PICT](https://github.com/haraldk/TwelveMonkeys/wiki/PICT-Plugin) | PICT | Apple Mac Paint Picture Format | âś” | - | - |
|
||||||
| | PNTG | Apple MacPaint Picture Format | âś” | | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [PNM](https://github.com/haraldk/TwelveMonkeys/wiki/PNM-Plugin) | PAM | NetPBM Portable Any Map | âś” | âś” | Standard |
|
||||||
| [PNM](https://github.com/haraldk/TwelveMonkeys/wiki/PNM-Plugin) | PAM | NetPBM Portable Any Map | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| | PBM | NetPBM Portable Bit Map | âś” | - | Standard |
|
||||||
| | PBM | NetPBM Portable Bit Map | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| | PGM | NetPBM Portable Grey Map | âś” | - | Standard |
|
||||||
| | PGM | NetPBM Portable Grey Map | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| | PPM | NetPBM Portable Pix Map | âś” | âś” | Standard |
|
||||||
| | PPM | NetPBM Portable Pix Map | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| | PFM | Portable Float Map | âś” | - | Standard |
|
||||||
| | PFM | Portable Float Map | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [PSD](https://github.com/haraldk/TwelveMonkeys/wiki/PSD-Plugin) | **PSD** | Adobe Photoshop Document | âś” | - | Native & Standard |
|
||||||
| [PSD](https://github.com/haraldk/TwelveMonkeys/wiki/PSD-Plugin) | **PSD** | Adobe Photoshop Document | âś” | - | Native & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| | PSB | Adobe Photoshop Large Document | âś” | - | Native & Standard |
|
||||||
| | PSB | Adobe Photoshop Large Document | âś” | - | Native & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [SGI](https://github.com/haraldk/TwelveMonkeys/wiki/SGI-Plugin) | SGI | Silicon Graphics Image Format | âś” | - | Standard |
|
||||||
| [SGI](https://github.com/haraldk/TwelveMonkeys/wiki/SGI-Plugin) | SGI | Silicon Graphics Image Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
| [TGA](https://github.com/haraldk/TwelveMonkeys/wiki/TGA-Plugin) | TGA | Truevision TGA Image Format | âś” | âś” | Standard |
|
||||||
| [TGA](https://github.com/haraldk/TwelveMonkeys/wiki/TGA-Plugin) | TGA | Truevision TGA Image Format | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
|
||||||
|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 & Standard |
|
||||||
| | 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 & Standard |
|
||||||
| [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 | In progress
|
||||||
| 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 |
|
||||||
|
|
||||||
|
|
||||||
**Important note on using Batik:** *Please read [The Apache™ XML Graphics Project - Security](http://xmlgraphics.apache.org/security.html),
|
**Important note on using Batik:** *Please read [The Apache™ XML Graphics Project - Security](http://xmlgraphics.apache.org/security.html),
|
||||||
@@ -274,12 +273,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.6.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-tiff</artifactId>
|
<artifactId>imageio-tiff</artifactId>
|
||||||
<version>3.6.4</version>
|
<version>3.6.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@@ -289,7 +288,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.6.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
```
|
```
|
||||||
@@ -298,13 +297,13 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
|||||||
|
|
||||||
To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path:
|
To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path:
|
||||||
|
|
||||||
twelvemonkeys-common-lang-3.6.4.jar
|
twelvemonkeys-common-lang-3.6.3.jar
|
||||||
twelvemonkeys-common-io-3.6.4.jar
|
twelvemonkeys-common-io-3.6.3.jar
|
||||||
twelvemonkeys-common-image-3.6.4.jar
|
twelvemonkeys-common-image-3.6.3.jar
|
||||||
twelvemonkeys-imageio-core-3.6.4.jar
|
twelvemonkeys-imageio-core-3.6.3.jar
|
||||||
twelvemonkeys-imageio-metadata-3.6.4.jar
|
twelvemonkeys-imageio-metadata-3.6.3.jar
|
||||||
twelvemonkeys-imageio-jpeg-3.6.4.jar
|
twelvemonkeys-imageio-jpeg-3.6.3.jar
|
||||||
twelvemonkeys-imageio-tiff-3.6.4.jar
|
twelvemonkeys-imageio-tiff-3.6.3.jar
|
||||||
|
|
||||||
#### Deploying the plugins in a web app
|
#### Deploying the plugins in a web app
|
||||||
|
|
||||||
@@ -370,42 +369,42 @@ Other "fat" JAR bundlers will probably have similar mechanisms to merge entries
|
|||||||
|
|
||||||
### Links to prebuilt binaries
|
### Links to prebuilt binaries
|
||||||
|
|
||||||
##### Latest version (3.6.4)
|
##### Latest version (3.6.3)
|
||||||
|
|
||||||
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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.6.3/common-lang-3.6.3.jar)
|
||||||
* [common-io-3.6.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.6.3/common-io-3.6.3.jar)
|
||||||
* [common-image-3.6.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.6.3/common-image-3.6.3.jar)
|
||||||
|
|
||||||
ImageIO dependencies
|
ImageIO dependencies
|
||||||
* [imageio-core-3.6.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.6.3/imageio-core-3.6.3.jar)
|
||||||
* [imageio-metadata-3.6.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.6.3/imageio-metadata-3.6.3.jar)
|
||||||
|
|
||||||
ImageIO plugins
|
ImageIO plugins
|
||||||
* [imageio-bmp-3.6.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.6.3/imageio-bmp-3.6.3.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.6.3/imageio-hdr-3.6.3.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.6.3/imageio-icns-3.6.3.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.6.3/imageio-iff-3.6.3.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.6.3/imageio-jpeg-3.6.3.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.6.3/imageio-pcx-3.6.3.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.6.3/imageio-pict-3.6.3.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.6.3/imageio-pnm-3.6.3.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.6.3/imageio-psd-3.6.3.jar)
|
||||||
* [imageio-sgi-3.6.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.6.3/imageio-sgi-3.6.3.jar)
|
||||||
* [imageio-tga-3.6.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.6.3/imageio-tga-3.6.3.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.6.3/imageio-thumbsdb-3.6.3.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.6.3/imageio-tiff-3.6.3.jar)
|
||||||
|
|
||||||
ImageIO plugins requiring 3rd party libs
|
ImageIO plugins requiring 3rd party libs
|
||||||
* [imageio-batik-3.6.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.6.3/imageio-batik-3.6.3.jar)
|
||||||
|
|
||||||
Photoshop Path support for ImageIO
|
Photoshop Path support for ImageIO
|
||||||
* [imageio-clippath-3.6.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.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.6.3/imageio-clippath-3.6.3.jar)
|
||||||
|
|
||||||
Servlet support
|
Servlet support
|
||||||
* [servlet-3.6.4.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.6.4/servlet-3.6.4.jar)
|
* [servlet-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.6.3/servlet-3.6.3.jar)
|
||||||
|
|
||||||
##### Old version (3.0.x)
|
##### Old version (3.0.x)
|
||||||
|
|
||||||
|
|||||||
+1
-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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>com.twelvemonkeys.bom</groupId>
|
<groupId>com.twelvemonkeys.bom</groupId>
|
||||||
|
|||||||
@@ -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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-image</artifactId>
|
<artifactId>common-image</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
@@ -13,10 +13,6 @@
|
|||||||
The TwelveMonkeys Common Image support
|
The TwelveMonkeys Common Image support
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.common.image</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
|
|||||||
@@ -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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-io</artifactId>
|
<artifactId>common-io</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
@@ -13,10 +13,6 @@
|
|||||||
The TwelveMonkeys Common IO support
|
The TwelveMonkeys Common IO support
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.common.io</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
|
|||||||
@@ -346,7 +346,7 @@ public final class FileUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the file (type) extension of the given file.
|
* Gets the file (type) extension of the given file.
|
||||||
* A file extension is the part of the filename, after the last occurrence
|
* A file extension is the part of the filename, after the last occurence
|
||||||
* of a period {@code '.'}.
|
* of a period {@code '.'}.
|
||||||
* If the filename contains no period, {@code null} is returned.
|
* If the filename contains no period, {@code null} is returned.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -32,13 +32,13 @@ package com.twelvemonkeys.io.enc;
|
|||||||
|
|
||||||
import com.twelvemonkeys.io.FileUtil;
|
import com.twelvemonkeys.io.FileUtil;
|
||||||
import com.twelvemonkeys.lang.ObjectAbstractTest;
|
import com.twelvemonkeys.lang.ObjectAbstractTest;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -73,7 +73,7 @@ public abstract class EncoderAbstractTest extends ObjectAbstractTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createData(final int pLength) {
|
private byte[] createData(final int pLength) throws Exception {
|
||||||
byte[] bytes = new byte[pLength];
|
byte[] bytes = new byte[pLength];
|
||||||
RANDOM.nextBytes(bytes);
|
RANDOM.nextBytes(bytes);
|
||||||
return bytes;
|
return bytes;
|
||||||
@@ -82,8 +82,9 @@ public abstract class EncoderAbstractTest extends ObjectAbstractTest {
|
|||||||
private void runStreamTest(final int pLength) throws Exception {
|
private void runStreamTest(final int pLength) throws Exception {
|
||||||
byte[] data = createData(pLength);
|
byte[] data = createData(pLength);
|
||||||
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
|
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
|
||||||
|
OutputStream out = new EncoderStream(outBytes, createEncoder(), true);
|
||||||
|
|
||||||
try (OutputStream out = new EncoderStream(outBytes, createEncoder(), true)) {
|
try {
|
||||||
// Provoke failure for encoders that doesn't take array offset properly into account
|
// Provoke failure for encoders that doesn't take array offset properly into account
|
||||||
int off = (data.length + 1) / 2;
|
int off = (data.length + 1) / 2;
|
||||||
out.write(data, 0, off);
|
out.write(data, 0, off);
|
||||||
@@ -91,6 +92,9 @@ public abstract class EncoderAbstractTest extends ObjectAbstractTest {
|
|||||||
out.write(data, off, data.length - off);
|
out.write(data, off, data.length - off);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
byte[] encoded = outBytes.toByteArray();
|
byte[] encoded = outBytes.toByteArray();
|
||||||
|
|
||||||
@@ -98,7 +102,7 @@ public abstract class EncoderAbstractTest extends ObjectAbstractTest {
|
|||||||
// System.err.println("encoded: " + Arrays.toString(encoded));
|
// System.err.println("encoded: " + Arrays.toString(encoded));
|
||||||
|
|
||||||
byte[] decoded = FileUtil.read(new DecoderStream(new ByteArrayInputStream(encoded), createCompatibleDecoder()));
|
byte[] decoded = FileUtil.read(new DecoderStream(new ByteArrayInputStream(encoded), createCompatibleDecoder()));
|
||||||
assertArrayEquals(data, decoded);
|
assertTrue(Arrays.equals(data, decoded));
|
||||||
|
|
||||||
InputStream in = new DecoderStream(new ByteArrayInputStream(encoded), createCompatibleDecoder());
|
InputStream in = new DecoderStream(new ByteArrayInputStream(encoded), createCompatibleDecoder());
|
||||||
outBytes = new ByteArrayOutputStream();
|
outBytes = new ByteArrayOutputStream();
|
||||||
@@ -112,7 +116,7 @@ public abstract class EncoderAbstractTest extends ObjectAbstractTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
decoded = outBytes.toByteArray();
|
decoded = outBytes.toByteArray();
|
||||||
assertArrayEquals(data, decoded);
|
assertTrue(Arrays.equals(data, decoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -125,6 +129,10 @@ public abstract class EncoderAbstractTest extends ObjectAbstractTest {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
fail(e.getMessage() + ": " + i);
|
fail(e.getMessage() + ": " + i);
|
||||||
}
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail(e.getMessage() + ": " + i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 100; i < 2000; i += 250) {
|
for (int i = 100; i < 2000; i += 250) {
|
||||||
@@ -135,6 +143,10 @@ public abstract class EncoderAbstractTest extends ObjectAbstractTest {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
fail(e.getMessage() + ": " + i);
|
fail(e.getMessage() + ": " + i);
|
||||||
}
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail(e.getMessage() + ": " + i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 2000; i < 80000; i += 1000) {
|
for (int i = 2000; i < 80000; i += 1000) {
|
||||||
@@ -145,8 +157,14 @@ public abstract class EncoderAbstractTest extends ObjectAbstractTest {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
fail(e.getMessage() + ": " + i);
|
fail(e.getMessage() + ": " + i);
|
||||||
}
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail(e.getMessage() + ": " + i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Test that the transition from byte[] to ByteBuffer didn't introduce bugs when writing to a wrapped array with offset.
|
// TODO: Test that the transition from byte[]Â to ByteBuffer didn't introduce bugs when writing to a wrapped array with offset.
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-lang</artifactId>
|
<artifactId>common-lang</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
@@ -13,8 +13,4 @@
|
|||||||
The TwelveMonkeys Common Language support
|
The TwelveMonkeys Common Language support
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.common.lang</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -330,7 +330,7 @@ abstract class AbstractDecoratedMap<K, V> extends AbstractMap<K, V> implements M
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple Map.Entry implementation.
|
* A simple Map.Entry implementaton.
|
||||||
*/
|
*/
|
||||||
static class BasicEntry<K, V> implements Entry<K, V>, Serializable {
|
static class BasicEntry<K, V> implements Entry<K, V>, Serializable {
|
||||||
K mKey;
|
K mKey;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import java.io.Serializable;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@code Map} implementation that removes (expires) its elements after
|
* A {@code Map} implementation that removes (exipres) its elements after
|
||||||
* a given period. The map is by default backed by a {@link java.util.HashMap},
|
* a given period. The map is by default backed by a {@link java.util.HashMap},
|
||||||
* or can be instantiated with any given {@code Map} as backing.
|
* or can be instantiated with any given {@code Map} as backing.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -67,7 +67,7 @@ public class TimeoutMap<K, V> extends AbstractDecoratedMap<K, V> implements Expi
|
|||||||
protected long expiryTime = 60000L; // 1 minute
|
protected long expiryTime = 60000L; // 1 minute
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
private volatile long nextExpiryTime = Long.MAX_VALUE;
|
private volatile long nextExpiryTime;
|
||||||
//////////////////////
|
//////////////////////
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -178,7 +178,7 @@ public class TimeoutMap<K, V> extends AbstractDecoratedMap<K, V> implements Expi
|
|||||||
* @return {@code true} if this map contains no key-value mappings.
|
* @return {@code true} if this map contains no key-value mappings.
|
||||||
*/
|
*/
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return size() <= 0;
|
return (size() <= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -208,7 +208,7 @@ public class TimeoutMap<K, V> extends AbstractDecoratedMap<K, V> implements Expi
|
|||||||
* @see #containsKey(java.lang.Object)
|
* @see #containsKey(java.lang.Object)
|
||||||
*/
|
*/
|
||||||
public V get(Object pKey) {
|
public V get(Object pKey) {
|
||||||
TimedEntry entry = (TimedEntry) entries.get(pKey);
|
TimedEntry<K, V> entry = (TimedEntry<K, V>) entries.get(pKey);
|
||||||
|
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -236,7 +236,7 @@ public class TimeoutMap<K, V> extends AbstractDecoratedMap<K, V> implements Expi
|
|||||||
* {@code null} values.
|
* {@code null} values.
|
||||||
*/
|
*/
|
||||||
public V put(K pKey, V pValue) {
|
public V put(K pKey, V pValue) {
|
||||||
TimedEntry entry = (TimedEntry) entries.get(pKey);
|
TimedEntry<K, V> entry = (TimedEntry<K, V>) entries.get(pKey);
|
||||||
V oldValue;
|
V oldValue;
|
||||||
|
|
||||||
if (entry == null) {
|
if (entry == null) {
|
||||||
@@ -272,7 +272,7 @@ public class TimeoutMap<K, V> extends AbstractDecoratedMap<K, V> implements Expi
|
|||||||
* {@code null} values.
|
* {@code null} values.
|
||||||
*/
|
*/
|
||||||
public V remove(Object pKey) {
|
public V remove(Object pKey) {
|
||||||
TimedEntry entry = (TimedEntry) entries.remove(pKey);
|
TimedEntry<K, V> entry = (TimedEntry<K, V>) entries.remove(pKey);
|
||||||
return (entry != null) ? entry.getValue() : null;
|
return (entry != null) ? entry.getValue() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,12 +284,13 @@ public class TimeoutMap<K, V> extends AbstractDecoratedMap<K, V> implements Expi
|
|||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*protected*/ TimedEntry createEntry(K pKey, V pValue) {
|
/*protected*/ TimedEntry<K, V> createEntry(K pKey, V pValue) {
|
||||||
return new TimedEntry(pKey, pValue);
|
return new TimedEntry<K, V>(pKey, pValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes any expired mappings.
|
* Removes any expired mappings.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
protected void removeExpiredEntries() {
|
protected void removeExpiredEntries() {
|
||||||
// Remove any expired elements
|
// Remove any expired elements
|
||||||
@@ -311,7 +312,7 @@ public class TimeoutMap<K, V> extends AbstractDecoratedMap<K, V> implements Expi
|
|||||||
long next = Long.MAX_VALUE;
|
long next = Long.MAX_VALUE;
|
||||||
nextExpiryTime = next; // Avoid multiple runs...
|
nextExpiryTime = next; // Avoid multiple runs...
|
||||||
for (Iterator<Entry<K, V>> iterator = new EntryIterator(); iterator.hasNext();) {
|
for (Iterator<Entry<K, V>> iterator = new EntryIterator(); iterator.hasNext();) {
|
||||||
TimedEntry entry = (TimedEntry) iterator.next();
|
TimedEntry<K, V> entry = (TimedEntry<K, V>) iterator.next();
|
||||||
////
|
////
|
||||||
long expires = entry.expires();
|
long expires = entry.expires();
|
||||||
if (expires < next) {
|
if (expires < next) {
|
||||||
@@ -375,7 +376,7 @@ public class TimeoutMap<K, V> extends AbstractDecoratedMap<K, V> implements Expi
|
|||||||
|
|
||||||
while (mNext == null && mIterator.hasNext()) {
|
while (mNext == null && mIterator.hasNext()) {
|
||||||
Entry<K, Entry<K, V>> entry = mIterator.next();
|
Entry<K, Entry<K, V>> entry = mIterator.next();
|
||||||
TimedEntry timed = (TimedEntry) entry.getValue();
|
TimedEntry<K, V> timed = (TimedEntry<K, V>) entry.getValue();
|
||||||
|
|
||||||
if (timed.isExpiredBy(mNow)) {
|
if (timed.isExpiredBy(mNow)) {
|
||||||
// Remove from map, and continue
|
// Remove from map, and continue
|
||||||
@@ -424,26 +425,17 @@ public class TimeoutMap<K, V> extends AbstractDecoratedMap<K, V> implements Expi
|
|||||||
/**
|
/**
|
||||||
* Keeps track of timed objects
|
* Keeps track of timed objects
|
||||||
*/
|
*/
|
||||||
private class TimedEntry extends BasicEntry<K, V> {
|
private class TimedEntry<K, V> extends BasicEntry<K, V> {
|
||||||
private long mTimestamp;
|
private long mTimestamp;
|
||||||
|
|
||||||
TimedEntry(K pKey, V pValue) {
|
TimedEntry(K pKey, V pValue) {
|
||||||
super(pKey, pValue);
|
super(pKey, pValue);
|
||||||
updateTimestamp();
|
mTimestamp = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
public V setValue(V pValue) {
|
public V setValue(V pValue) {
|
||||||
updateTimestamp();
|
|
||||||
return super.setValue(pValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTimestamp() {
|
|
||||||
mTimestamp = System.currentTimeMillis();
|
mTimestamp = System.currentTimeMillis();
|
||||||
|
return super.setValue(pValue);
|
||||||
long expires = expires();
|
|
||||||
if (expires < nextExpiryTime) {
|
|
||||||
nextExpiryTime = expires;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean isExpired() {
|
final boolean isExpired() {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.lang;
|
package com.twelvemonkeys.lang;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
@@ -41,7 +41,7 @@ import java.util.Date;
|
|||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.junit.Test;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* StringUtilTestCase
|
* StringUtilTestCase
|
||||||
@@ -76,24 +76,24 @@ public class StringUtilTest {
|
|||||||
assertNull(StringUtil.valueOf(null));
|
assertNull(StringUtil.valueOf(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Test
|
@Test
|
||||||
public void testToUpperCase() {
|
public void testToUpperCase() {
|
||||||
String str = StringUtil.toUpperCase(TEST_STRING);
|
String str = StringUtil.toUpperCase(TEST_STRING);
|
||||||
assertNotNull(str);
|
assertNotNull(str);
|
||||||
assertEquals(TEST_STRING.toUpperCase(), str);
|
assertEquals(TEST_STRING.toUpperCase(), str);
|
||||||
|
|
||||||
assertNull(StringUtil.toUpperCase(null));
|
str = StringUtil.toUpperCase(null);
|
||||||
|
assertNull(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Test
|
@Test
|
||||||
public void testToLowerCase() {
|
public void testToLowerCase() {
|
||||||
String str = StringUtil.toLowerCase(TEST_STRING);
|
String str = StringUtil.toLowerCase(TEST_STRING);
|
||||||
assertNotNull(str);
|
assertNotNull(str);
|
||||||
assertEquals(TEST_STRING.toLowerCase(), str);
|
assertEquals(TEST_STRING.toLowerCase(), str);
|
||||||
|
|
||||||
assertNull(StringUtil.toLowerCase(null));
|
str = StringUtil.toLowerCase(null);
|
||||||
|
assertNull(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -113,7 +113,6 @@ public class StringUtilTest {
|
|||||||
assertFalse(StringUtil.isEmpty(new String[]{WHITESPACE_STRING, TEST_STRING}));
|
assertFalse(StringUtil.isEmpty(new String[]{WHITESPACE_STRING, TEST_STRING}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Test
|
@Test
|
||||||
public void testContains() {
|
public void testContains() {
|
||||||
assertTrue(StringUtil.contains(TEST_STRING, TEST_STRING));
|
assertTrue(StringUtil.contains(TEST_STRING, TEST_STRING));
|
||||||
@@ -146,7 +145,6 @@ public class StringUtilTest {
|
|||||||
assertFalse(StringUtil.containsIgnoreCase(null, null));
|
assertFalse(StringUtil.containsIgnoreCase(null, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Test
|
@Test
|
||||||
public void testContainsChar() {
|
public void testContainsChar() {
|
||||||
for (int i = 0; i < TEST_STRING.length(); i++) {
|
for (int i = 0; i < TEST_STRING.length(); i++) {
|
||||||
@@ -468,7 +466,7 @@ public class StringUtilTest {
|
|||||||
assertEquals(TEST_STRING, StringUtil.ltrim(TEST_STRING));
|
assertEquals(TEST_STRING, StringUtil.ltrim(TEST_STRING));
|
||||||
assertEquals(TEST_STRING, StringUtil.ltrim(" " + TEST_STRING));
|
assertEquals(TEST_STRING, StringUtil.ltrim(" " + TEST_STRING));
|
||||||
assertEquals(TEST_STRING, StringUtil.ltrim(WHITESPACE_STRING + TEST_STRING));
|
assertEquals(TEST_STRING, StringUtil.ltrim(WHITESPACE_STRING + TEST_STRING));
|
||||||
assertNotEquals(TEST_STRING, StringUtil.ltrim(TEST_STRING + WHITESPACE_STRING));
|
assertFalse(TEST_STRING.equals(StringUtil.ltrim(TEST_STRING + WHITESPACE_STRING)));
|
||||||
// TODO: Test is not complete
|
// TODO: Test is not complete
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -477,7 +475,7 @@ public class StringUtilTest {
|
|||||||
assertEquals(TEST_STRING, StringUtil.rtrim(TEST_STRING));
|
assertEquals(TEST_STRING, StringUtil.rtrim(TEST_STRING));
|
||||||
assertEquals(TEST_STRING, StringUtil.rtrim(TEST_STRING + " "));
|
assertEquals(TEST_STRING, StringUtil.rtrim(TEST_STRING + " "));
|
||||||
assertEquals(TEST_STRING, StringUtil.rtrim(TEST_STRING + WHITESPACE_STRING));
|
assertEquals(TEST_STRING, StringUtil.rtrim(TEST_STRING + WHITESPACE_STRING));
|
||||||
assertNotEquals(TEST_STRING, StringUtil.rtrim(WHITESPACE_STRING + TEST_STRING));
|
assertFalse(TEST_STRING.equals(StringUtil.rtrim(WHITESPACE_STRING + TEST_STRING)));
|
||||||
// TODO: Test is not complete
|
// TODO: Test is not complete
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,7 +516,7 @@ public class StringUtilTest {
|
|||||||
public void testCaptialize() {
|
public void testCaptialize() {
|
||||||
assertNull(StringUtil.capitalize(null));
|
assertNull(StringUtil.capitalize(null));
|
||||||
assertEquals(TEST_STRING.toUpperCase(), StringUtil.capitalize(TEST_STRING.toUpperCase()));
|
assertEquals(TEST_STRING.toUpperCase(), StringUtil.capitalize(TEST_STRING.toUpperCase()));
|
||||||
assertEquals('A', StringUtil.capitalize("abc").charAt(0));
|
assertTrue(StringUtil.capitalize("abc").charAt(0) == 'A');
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -554,13 +552,13 @@ public class StringUtilTest {
|
|||||||
public void testToDateWithFormatString() {
|
public void testToDateWithFormatString() {
|
||||||
Calendar cal = new GregorianCalendar();
|
Calendar cal = new GregorianCalendar();
|
||||||
cal.clear();
|
cal.clear();
|
||||||
cal.set(1976, Calendar.MARCH, 16); // Month is 0-based
|
cal.set(1976, 2, 16); // Month is 0-based
|
||||||
Date date = StringUtil.toDate("16.03.1976", "dd.MM.yyyy");
|
Date date = StringUtil.toDate("16.03.1976", "dd.MM.yyyy");
|
||||||
assertNotNull(date);
|
assertNotNull(date);
|
||||||
assertEquals(cal.getTime(), date);
|
assertEquals(cal.getTime(), date);
|
||||||
|
|
||||||
cal.clear();
|
cal.clear();
|
||||||
cal.set(2004, Calendar.MAY, 13, 23, 51, 3);
|
cal.set(2004, 4, 13, 23, 51, 3);
|
||||||
date = StringUtil.toDate("2004-5-13 23:51 (03)", "yyyy-MM-dd hh:mm (ss)");
|
date = StringUtil.toDate("2004-5-13 23:51 (03)", "yyyy-MM-dd hh:mm (ss)");
|
||||||
assertNotNull(date);
|
assertNotNull(date);
|
||||||
assertEquals(cal.getTime(), date);
|
assertEquals(cal.getTime(), date);
|
||||||
@@ -578,15 +576,15 @@ public class StringUtilTest {
|
|||||||
public void testToDateWithFormat() {
|
public void testToDateWithFormat() {
|
||||||
Calendar cal = new GregorianCalendar();
|
Calendar cal = new GregorianCalendar();
|
||||||
cal.clear();
|
cal.clear();
|
||||||
cal.set(1976, Calendar.MARCH, 16); // Month is 0-based
|
cal.set(1976, 2, 16); // Month is 0-based
|
||||||
Date date = StringUtil.toDate("16.03.1976", new SimpleDateFormat("dd.MM.yyyy"));
|
Date date = StringUtil.toDate("16.03.1976", new SimpleDateFormat("dd.MM.yyyy"));
|
||||||
assertNotNull(date);
|
assertNotNull(date);
|
||||||
assertEquals(cal.getTime(), date);
|
assertEquals(cal.getTime(), date);
|
||||||
|
|
||||||
cal.clear();
|
cal.clear();
|
||||||
cal.set(2004, Calendar.MAY, 13, 23, 51);
|
cal.set(2004, 4, 13, 23, 51);
|
||||||
DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, new Locale("no", "NO"));
|
date = StringUtil.toDate("13.5.04 23:51",
|
||||||
date = StringUtil.toDate(format.format(cal.getTime()), format);
|
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, new Locale("no", "NO")));
|
||||||
assertNotNull(date);
|
assertNotNull(date);
|
||||||
assertEquals(cal.getTime(), date);
|
assertEquals(cal.getTime(), date);
|
||||||
|
|
||||||
@@ -603,9 +601,10 @@ public class StringUtilTest {
|
|||||||
public void testToTimestamp() {
|
public void testToTimestamp() {
|
||||||
Calendar cal = new GregorianCalendar();
|
Calendar cal = new GregorianCalendar();
|
||||||
cal.clear();
|
cal.clear();
|
||||||
cal.set(1976, Calendar.MARCH, 16, 21, 28, 4); // Month is 0-based
|
cal.set(1976, 2, 16, 21, 28, 4); // Month is 0-based
|
||||||
Timestamp date = StringUtil.toTimestamp("1976-03-16 21:28:04");
|
Date date = StringUtil.toTimestamp("1976-03-16 21:28:04");
|
||||||
assertNotNull(date);
|
assertNotNull(date);
|
||||||
|
assertTrue(date instanceof Timestamp);
|
||||||
assertEquals(cal.getTime(), date);
|
assertEquals(cal.getTime(), date);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -822,7 +821,7 @@ public class StringUtilTest {
|
|||||||
assertTrue(StringUtil.isNumber("12345"));
|
assertTrue(StringUtil.isNumber("12345"));
|
||||||
assertTrue(StringUtil.isNumber(TEST_INTEGER.toString()));
|
assertTrue(StringUtil.isNumber(TEST_INTEGER.toString()));
|
||||||
assertTrue(StringUtil.isNumber("1234567890123456789012345678901234567890"));
|
assertTrue(StringUtil.isNumber("1234567890123456789012345678901234567890"));
|
||||||
assertTrue(StringUtil.isNumber(String.valueOf(Long.MAX_VALUE) + Long.MAX_VALUE));
|
assertTrue(StringUtil.isNumber(String.valueOf(Long.MAX_VALUE) + String.valueOf(Long.MAX_VALUE)));
|
||||||
assertFalse(StringUtil.isNumber("abc"));
|
assertFalse(StringUtil.isNumber("abc"));
|
||||||
assertFalse(StringUtil.isNumber(TEST_STRING));
|
assertFalse(StringUtil.isNumber(TEST_STRING));
|
||||||
}
|
}
|
||||||
@@ -832,7 +831,7 @@ public class StringUtilTest {
|
|||||||
assertTrue(StringUtil.isNumber("-12345"));
|
assertTrue(StringUtil.isNumber("-12345"));
|
||||||
assertTrue(StringUtil.isNumber('-' + TEST_INTEGER.toString()));
|
assertTrue(StringUtil.isNumber('-' + TEST_INTEGER.toString()));
|
||||||
assertTrue(StringUtil.isNumber("-1234567890123456789012345678901234567890"));
|
assertTrue(StringUtil.isNumber("-1234567890123456789012345678901234567890"));
|
||||||
assertTrue(StringUtil.isNumber('-' + String.valueOf(Long.MAX_VALUE) + Long.MAX_VALUE));
|
assertTrue(StringUtil.isNumber('-' + String.valueOf(Long.MAX_VALUE) + String.valueOf(Long.MAX_VALUE)));
|
||||||
assertFalse(StringUtil.isNumber("-abc"));
|
assertFalse(StringUtil.isNumber("-abc"));
|
||||||
assertFalse(StringUtil.isNumber('-' + TEST_STRING));
|
assertFalse(StringUtil.isNumber('-' + TEST_STRING));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -557,7 +557,7 @@ public class TimeoutMapTest extends MapAbstractTest {
|
|||||||
// NOTE: Only wait fist time, to avoid slooow tests
|
// NOTE: Only wait fist time, to avoid slooow tests
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
try {
|
try {
|
||||||
wait(60L);
|
wait(60l);
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
}
|
}
|
||||||
@@ -591,7 +591,7 @@ public class TimeoutMapTest extends MapAbstractTest {
|
|||||||
try {
|
try {
|
||||||
wait(60l);
|
wait(60l);
|
||||||
}
|
}
|
||||||
catch (InterruptedException ignore) {
|
catch (InterruptedException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -651,24 +651,5 @@ public class TimeoutMapTest extends MapAbstractTest {
|
|||||||
assertTrue("Wrong entry removed, keySet().iterator() is broken.", !map.containsKey(removedKey));
|
assertTrue("Wrong entry removed, keySet().iterator() is broken.", !map.containsKey(removedKey));
|
||||||
assertTrue("Wrong entry removed, keySet().iterator() is broken.", map.containsKey(otherKey));
|
assertTrue("Wrong entry removed, keySet().iterator() is broken.", map.containsKey(otherKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testContainsKeyOnEmptyMap() {
|
|
||||||
// See #600
|
|
||||||
Map<String, String> timeoutMap = new TimeoutMap<>(30);
|
|
||||||
assertFalse(timeoutMap.containsKey("xyz"));
|
|
||||||
timeoutMap.put("xyz", "xyz");
|
|
||||||
assertTrue(timeoutMap.containsKey("xyz"));
|
|
||||||
|
|
||||||
try {
|
|
||||||
Thread.sleep(50); // Let the item expire
|
|
||||||
}
|
|
||||||
catch (InterruptedException ignore) {
|
|
||||||
}
|
|
||||||
|
|
||||||
assertFalse(timeoutMap.containsKey("xyz"));
|
|
||||||
assertNull(timeoutMap.get("xyz"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.7.0</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>com.twelvemonkeys.contrib</groupId>
|
<groupId>com.twelvemonkeys.contrib</groupId>
|
||||||
<artifactId>contrib</artifactId>
|
<artifactId>contrib</artifactId>
|
||||||
|
|||||||
@@ -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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-batik</artifactId>
|
<artifactId>imageio-batik</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
|
||||||
@@ -14,12 +14,6 @@
|
|||||||
See the <a href="http://xmlgraphics.apache.org/batik/">Batik Home page</a>
|
See the <a href="http://xmlgraphics.apache.org/batik/">Batik Home page</a>
|
||||||
for more information.]]>
|
for more information.]]>
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.batik</project.jpms.module.name>
|
|
||||||
<batik.version>1.14</batik.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
@@ -108,4 +102,8 @@
|
|||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<batik.version>1.14</batik.version>
|
||||||
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
+1
-1
@@ -655,7 +655,7 @@ public class SVGImageReader extends ImageReaderBase {
|
|||||||
if (allowExternalResources) {
|
if (allowExternalResources) {
|
||||||
return super.getExternalResourceSecurity(resourceURL, docURL);
|
return super.getExternalResourceSecurity(resourceURL, docURL);
|
||||||
}
|
}
|
||||||
return new EmbededExternalResourceSecurity(resourceURL);
|
return new NoLoadExternalResourceSecurity();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-19
@@ -297,25 +297,6 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadEmbeddedWithDisallowExternalResources() throws IOException{
|
|
||||||
// File using "data:" URLs for embedded resources
|
|
||||||
URL resource = getClassLoaderResource("/svg/embedded-data-resource.svg");
|
|
||||||
SVGImageReader reader = createReader();
|
|
||||||
|
|
||||||
TestData data = new TestData(resource, (Dimension) null);
|
|
||||||
try (ImageInputStream stream = data.getInputStream()) {
|
|
||||||
reader.setInput(stream);
|
|
||||||
|
|
||||||
SVGReadParam param = reader.getDefaultReadParam();
|
|
||||||
param.setAllowExternalResources(false);
|
|
||||||
reader.read(0, param);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = SecurityException.class)
|
@Test(expected = SecurityException.class)
|
||||||
public void testDisallowedExternalResources() throws URISyntaxException, IOException {
|
public void testDisallowedExternalResources() throws URISyntaxException, IOException {
|
||||||
// system-property set to true in surefire-plugin-settings in the pom
|
// system-property set to true in surefire-plugin-settings in the pom
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 92 KiB |
@@ -4,16 +4,12 @@
|
|||||||
<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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-bmp</artifactId>
|
<artifactId>imageio-bmp</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
|
||||||
<description>ImageIO plugin for Microsoft Device Independent Bitmap (BMP/DIB) format.</description>
|
<description>ImageIO plugin for Microsoft Device Independent Bitmap (BMP/DIB) format.</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.bmp</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
+10
-12
@@ -37,7 +37,7 @@ import java.io.DataInput;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.Collections;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
@@ -205,7 +205,7 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
checkBounds(pImageIndex);
|
checkBounds(pImageIndex);
|
||||||
|
|
||||||
// TODO: Better implementation, include INT_RGB types for 3BYTE_BGR and 4BYTE_ABGR for INT_ARGB
|
// TODO: Better implementation, include INT_RGB types for 3BYTE_BGR and 4BYTE_ABGR for INT_ARGB
|
||||||
return Collections.singletonList(getRawImageType(pImageIndex)).iterator();
|
return Arrays.asList(getRawImageType(pImageIndex)).iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -410,13 +410,6 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
private ImageReader initReaderDelegate(int compression) throws IOException {
|
private ImageReader initReaderDelegate(int compression) throws IOException {
|
||||||
ImageReader reader = getImageReaderDelegate(compression);
|
ImageReader reader = getImageReaderDelegate(compression);
|
||||||
reader.reset();
|
|
||||||
|
|
||||||
// Install listener
|
|
||||||
ListenerDelegator listenerDelegator = new ListenerDelegator();
|
|
||||||
reader.addIIOReadWarningListener(listenerDelegator);
|
|
||||||
reader.addIIOReadProgressListener(listenerDelegator);
|
|
||||||
reader.addIIOReadUpdateListener(listenerDelegator);
|
|
||||||
|
|
||||||
imageInput.seek(pixelOffset);
|
imageInput.seek(pixelOffset);
|
||||||
reader.setInput(new SubImageInputStream(imageInput, header.getImageSize()));
|
reader.setInput(new SubImageInputStream(imageInput, header.getImageSize()));
|
||||||
@@ -457,6 +450,12 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
ImageReader reader = readers.next();
|
ImageReader reader = readers.next();
|
||||||
|
|
||||||
|
// Install listener
|
||||||
|
ListenerDelegator listenerDelegator = new ListenerDelegator();
|
||||||
|
reader.addIIOReadWarningListener(listenerDelegator);
|
||||||
|
reader.addIIOReadProgressListener(listenerDelegator);
|
||||||
|
reader.addIIOReadUpdateListener(listenerDelegator);
|
||||||
|
|
||||||
// Cache for later use
|
// Cache for later use
|
||||||
switch (compression) {
|
switch (compression) {
|
||||||
case DIB.COMPRESSION_JPEG:
|
case DIB.COMPRESSION_JPEG:
|
||||||
@@ -634,8 +633,7 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
return new BMPMetadata(header, colors);
|
return new BMPMetadata(header, colors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
public static void main(String[] args) throws IOException {
|
||||||
public static void main(String[] args) {
|
|
||||||
BMPImageReaderSpi provider = new BMPImageReaderSpi();
|
BMPImageReaderSpi provider = new BMPImageReaderSpi();
|
||||||
BMPImageReader reader = new BMPImageReader(provider);
|
BMPImageReader reader = new BMPImageReader(provider);
|
||||||
|
|
||||||
@@ -688,7 +686,7 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "UnusedDeclaration", "SameParameterValue" })
|
@SuppressWarnings({"unchecked", "UnusedDeclaration"})
|
||||||
static <T extends Throwable> void throwAs(final Class<T> pType, final Throwable pThrowable) throws T {
|
static <T extends Throwable> void throwAs(final Class<T> pType, final Throwable pThrowable) throws T {
|
||||||
throw (T) pThrowable;
|
throw (T) pThrowable;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-5
@@ -364,11 +364,7 @@ abstract class DIBHeader {
|
|||||||
|
|
||||||
public String getBMPVersion() {
|
public String getBMPVersion() {
|
||||||
// This is to be compatible with the native metadata of the original com.sun....BMPMetadata
|
// This is to be compatible with the native metadata of the original com.sun....BMPMetadata
|
||||||
return size > DIB.BITMAP_INFO_HEADER_SIZE
|
return compression == DIB.COMPRESSION_BITFIELDS ? "BMP v. 3.x NT" : "BMP v. 3.x";
|
||||||
? "BMP V2/V3 INFO"
|
|
||||||
: compression == DIB.COMPRESSION_BITFIELDS || compression == DIB.COMPRESSION_ALPHA_BITFIELDS
|
|
||||||
? "BMP v. 3.x NT"
|
|
||||||
: "BMP v. 3.x";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-4
@@ -342,7 +342,6 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
|
|
||||||
for (TestData data : getTestData()) {
|
for (TestData data : getTestData()) {
|
||||||
if (data.getInput().toString().contains("pal8offs")) {
|
if (data.getInput().toString().contains("pal8offs")) {
|
||||||
// Skip: Contains extra bogus PaletteEntry nodes
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +358,6 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
System.err.println("WARNING: Reading " + data + " caused exception: " + e.getMessage());
|
System.err.println("WARNING: Reading " + data + " caused exception: " + e.getMessage());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
IIOMetadata jreMetadata = jreReader.getImageMetadata(0);
|
IIOMetadata jreMetadata = jreReader.getImageMetadata(0);
|
||||||
|
|
||||||
assertTrue(metadata.isStandardMetadataFormatSupported());
|
assertTrue(metadata.isStandardMetadataFormatSupported());
|
||||||
@@ -372,7 +370,6 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
String absolutePath = data.toString();
|
String absolutePath = data.toString();
|
||||||
String localPath = absolutePath.substring(absolutePath.lastIndexOf("test-classes") + 12);
|
String localPath = absolutePath.substring(absolutePath.lastIndexOf("test-classes") + 12);
|
||||||
|
|
||||||
// TODO: blauesglas_16_bitmask444 fails BMP Version for 11+
|
|
||||||
Node expectedTree = jreMetadata.getAsTree(format);
|
Node expectedTree = jreMetadata.getAsTree(format);
|
||||||
Node actualTree = metadata.getAsTree(format);
|
Node actualTree = metadata.getAsTree(format);
|
||||||
|
|
||||||
@@ -431,7 +428,6 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("RedundantIfStatement")
|
|
||||||
private boolean excludeEqualValueTest(final Node expected) {
|
private boolean excludeEqualValueTest(final Node expected) {
|
||||||
if (expected.getLocalName().equals("ImageSize")) {
|
if (expected.getLocalName().equals("ImageSize")) {
|
||||||
// JRE metadata returns 0, even if known in reader...
|
// JRE metadata returns 0, even if known in 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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-clippath</artifactId>
|
<artifactId>imageio-clippath</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
|
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
|
||||||
@@ -12,10 +12,6 @@
|
|||||||
Photoshop Clipping Path Support.
|
Photoshop Clipping Path Support.
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.clippath</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
@@ -4,15 +4,11 @@
|
|||||||
<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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: Core</name>
|
<name>TwelveMonkeys :: ImageIO :: Core</name>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.core</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
|
|||||||
@@ -265,9 +265,8 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
// - transferType is ok
|
// - transferType is ok
|
||||||
// - bands are ok
|
// - bands are ok
|
||||||
// TODO: Test if color model is ok?
|
// TODO: Test if color model is ok?
|
||||||
if (specifier.getSampleModel().getTransferType() == dest.getSampleModel().getTransferType()
|
if (specifier.getSampleModel().getTransferType() == dest.getSampleModel().getTransferType() &&
|
||||||
&& Arrays.equals(specifier.getSampleModel().getSampleSize(), dest.getSampleModel().getSampleSize())
|
specifier.getNumBands() <= dest.getSampleModel().getNumBands()) {
|
||||||
&& specifier.getNumBands() <= dest.getSampleModel().getNumBands()) {
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ public final class UInt32ColorModel extends ComponentColorModel {
|
|||||||
// This class only supports DataBuffer.TYPE_INT, cast is safe
|
// This class only supports DataBuffer.TYPE_INT, cast is safe
|
||||||
int[] ipixel = (int[]) pixel;
|
int[] ipixel = (int[]) pixel;
|
||||||
for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) {
|
for (int c = 0, nc = normOffset; c < numComponents; c++, nc++) {
|
||||||
normComponents[nc] = ((float) (ipixel[c] & 0xFFFFFFFFL)) / ((float) ((1L << getComponentSize(c)) - 1));
|
normComponents[nc] = ((float) (ipixel[c] & 0xffffffffl)) / ((float) ((1l << getComponentSize(c)) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
int numColorComponents = getNumColorComponents();
|
int numColorComponents = getNumColorComponents();
|
||||||
|
|||||||
+4
-4
@@ -49,10 +49,10 @@ public abstract class ReaderWriterProviderInfo extends ProviderInfo {
|
|||||||
private final String[] mimeTypes;
|
private final String[] mimeTypes;
|
||||||
private final String readerClassName;
|
private final String readerClassName;
|
||||||
private final String[] readerSpiClassNames;
|
private final String[] readerSpiClassNames;
|
||||||
private final Class<?>[] inputTypes = new Class<?>[] {ImageInputStream.class};
|
private final Class[] inputTypes = new Class[] {ImageInputStream.class};
|
||||||
private final String writerClassName;
|
private final String writerClassName;
|
||||||
private final String[] writerSpiClassNames;
|
private final String[] writerSpiClassNames;
|
||||||
private final Class<?>[] outputTypes = new Class<?>[] {ImageOutputStream.class};
|
private final Class[] outputTypes = new Class[] {ImageOutputStream.class};
|
||||||
private final boolean supportsStandardStreamMetadata;
|
private final boolean supportsStandardStreamMetadata;
|
||||||
private final String nativeStreamMetadataFormatName;
|
private final String nativeStreamMetadataFormatName;
|
||||||
private final String nativeStreamMetadataFormatClassName;
|
private final String nativeStreamMetadataFormatClassName;
|
||||||
@@ -80,7 +80,7 @@ public abstract class ReaderWriterProviderInfo extends ProviderInfo {
|
|||||||
final String writerClassName,
|
final String writerClassName,
|
||||||
final String[] writerSpiClassNames,
|
final String[] writerSpiClassNames,
|
||||||
final boolean supportsStandardStreamMetadata,
|
final boolean supportsStandardStreamMetadata,
|
||||||
final String nativeStreamMetadataFormatName,
|
final String nativeStreameMetadataFormatName,
|
||||||
final String nativeStreamMetadataFormatClassName,
|
final String nativeStreamMetadataFormatClassName,
|
||||||
final String[] extraStreamMetadataFormatNames,
|
final String[] extraStreamMetadataFormatNames,
|
||||||
final String[] extraStreamMetadataFormatClassNames,
|
final String[] extraStreamMetadataFormatClassNames,
|
||||||
@@ -99,7 +99,7 @@ public abstract class ReaderWriterProviderInfo extends ProviderInfo {
|
|||||||
this.writerClassName = writerClassName;
|
this.writerClassName = writerClassName;
|
||||||
this.writerSpiClassNames = writerSpiClassNames;
|
this.writerSpiClassNames = writerSpiClassNames;
|
||||||
this.supportsStandardStreamMetadata = supportsStandardStreamMetadata;
|
this.supportsStandardStreamMetadata = supportsStandardStreamMetadata;
|
||||||
this.nativeStreamMetadataFormatName = nativeStreamMetadataFormatName;
|
this.nativeStreamMetadataFormatName = nativeStreameMetadataFormatName;
|
||||||
this.nativeStreamMetadataFormatClassName = nativeStreamMetadataFormatClassName;
|
this.nativeStreamMetadataFormatClassName = nativeStreamMetadataFormatClassName;
|
||||||
this.extraStreamMetadataFormatNames = extraStreamMetadataFormatNames;
|
this.extraStreamMetadataFormatNames = extraStreamMetadataFormatNames;
|
||||||
this.extraStreamMetadataFormatClassNames = extraStreamMetadataFormatClassNames;
|
this.extraStreamMetadataFormatClassNames = extraStreamMetadataFormatClassNames;
|
||||||
|
|||||||
-251
@@ -1,251 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.stream;
|
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStreamImpl;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
|
|
||||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
|
||||||
import static java.lang.Math.max;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A buffered replacement for {@link javax.imageio.stream.FileImageInputStream}
|
|
||||||
* that provides greatly improved performance for shorter reads, like single
|
|
||||||
* byte or bit reads.
|
|
||||||
* As with {@code javax.imageio.stream.FileImageInputStream}, either
|
|
||||||
* {@link File} or {@link RandomAccessFile} can be used as input.
|
|
||||||
*
|
|
||||||
* @see javax.imageio.stream.FileImageInputStream
|
|
||||||
*/
|
|
||||||
// TODO: Create a memory-mapped version?
|
|
||||||
// Or not... From java.nio.channels.FileChannel.map:
|
|
||||||
// For most operating systems, mapping a file into memory is more
|
|
||||||
// expensive than reading or writing a few tens of kilobytes of data via
|
|
||||||
// the usual {@link #read read} and {@link #write write} methods. From the
|
|
||||||
// standpoint of performance it is generally only worth mapping relatively
|
|
||||||
// large files into memory.
|
|
||||||
public final class BufferedFileImageInputStream extends ImageInputStreamImpl {
|
|
||||||
static final int DEFAULT_BUFFER_SIZE = 8192;
|
|
||||||
|
|
||||||
private byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
|
|
||||||
private int bufferPos;
|
|
||||||
private int bufferLimit;
|
|
||||||
|
|
||||||
private final ByteBuffer integralCache = ByteBuffer.allocate(8);
|
|
||||||
private final byte[] integralCacheArray = integralCache.array();
|
|
||||||
|
|
||||||
private RandomAccessFile raf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a <code>BufferedFileImageInputStream</code> that will read from a given <code>File</code>.
|
|
||||||
*
|
|
||||||
* @param file a <code>File</code> to read from.
|
|
||||||
* @throws IllegalArgumentException if <code>file</code> is <code>null</code>.
|
|
||||||
* @throws FileNotFoundException if <code>file</code> is a directory or cannot be opened for reading
|
|
||||||
* for any reason.
|
|
||||||
*/
|
|
||||||
public BufferedFileImageInputStream(final File file) throws FileNotFoundException {
|
|
||||||
this(new RandomAccessFile(notNull(file, "file"), "r"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a <code>BufferedFileImageInputStream</code> that will read from a given <code>RandomAccessFile</code>.
|
|
||||||
*
|
|
||||||
* @param raf a <code>RandomAccessFile</code> to read from.
|
|
||||||
* @throws IllegalArgumentException if <code>raf</code> is <code>null</code>.
|
|
||||||
*/
|
|
||||||
public BufferedFileImageInputStream(final RandomAccessFile raf) {
|
|
||||||
this.raf = notNull(raf, "raf");
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
|
||||||
private boolean fillBuffer() throws IOException {
|
|
||||||
bufferPos = 0;
|
|
||||||
int length = raf.read(buffer, 0, buffer.length);
|
|
||||||
bufferLimit = max(length, 0);
|
|
||||||
|
|
||||||
return bufferLimit > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean bufferEmpty() {
|
|
||||||
return bufferPos >= bufferLimit;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setByteOrder(ByteOrder byteOrder) {
|
|
||||||
super.setByteOrder(byteOrder);
|
|
||||||
integralCache.order(byteOrder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read() throws IOException {
|
|
||||||
checkClosed();
|
|
||||||
|
|
||||||
if (bufferEmpty() && !fillBuffer()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bitOffset = 0;
|
|
||||||
streamPos++;
|
|
||||||
|
|
||||||
return buffer[bufferPos++] & 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
|
|
||||||
checkClosed();
|
|
||||||
bitOffset = 0;
|
|
||||||
|
|
||||||
if (bufferEmpty()) {
|
|
||||||
// Bypass buffer if buffer is empty for reads longer than buffer
|
|
||||||
if (pLength >= buffer.length) {
|
|
||||||
return readDirect(pBuffer, pOffset, pLength);
|
|
||||||
}
|
|
||||||
else if (!fillBuffer()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return readBuffered(pBuffer, pOffset, pLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int readDirect(final byte[] pBuffer, final int pOffset, final int pLength) throws IOException {
|
|
||||||
// Invalidate the buffer, as its contents is no longer in sync with the stream's position.
|
|
||||||
bufferLimit = 0;
|
|
||||||
int read = raf.read(pBuffer, pOffset, pLength);
|
|
||||||
|
|
||||||
if (read > 0) {
|
|
||||||
streamPos += read;
|
|
||||||
}
|
|
||||||
|
|
||||||
return read;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int readBuffered(final byte[] pBuffer, final int pOffset, final int pLength) {
|
|
||||||
// Read as much as possible from buffer
|
|
||||||
int length = Math.min(bufferLimit - bufferPos, pLength);
|
|
||||||
|
|
||||||
if (length > 0) {
|
|
||||||
System.arraycopy(buffer, bufferPos, pBuffer, pOffset, length);
|
|
||||||
bufferPos += length;
|
|
||||||
streamPos += length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long length() {
|
|
||||||
// WTF?! This method is allowed to throw IOException in the interface...
|
|
||||||
try {
|
|
||||||
checkClosed();
|
|
||||||
return raf.length();
|
|
||||||
}
|
|
||||||
catch (IOException ignore) {
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void close() throws IOException {
|
|
||||||
super.close();
|
|
||||||
|
|
||||||
raf.close();
|
|
||||||
|
|
||||||
raf = null;
|
|
||||||
buffer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to override the readShort(), readInt() and readLong() methods,
|
|
||||||
// because the implementations in ImageInputStreamImpl expects the
|
|
||||||
// read(byte[], int, int) to always read the expected number of bytes,
|
|
||||||
// causing uninitialized values, alignment issues and EOFExceptions at
|
|
||||||
// random places...
|
|
||||||
// Notes:
|
|
||||||
// * readUnsignedXx() is covered by their signed counterparts
|
|
||||||
// * readChar() is covered by readShort()
|
|
||||||
// * readFloat() and readDouble() is covered by readInt() and readLong()
|
|
||||||
// respectively.
|
|
||||||
// * readLong() may be covered by two readInt()s, we'll override to be safe
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public short readShort() throws IOException {
|
|
||||||
readFully(integralCacheArray, 0, 2);
|
|
||||||
|
|
||||||
return integralCache.getShort(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int readInt() throws IOException {
|
|
||||||
readFully(integralCacheArray, 0, 4);
|
|
||||||
|
|
||||||
return integralCache.getInt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long readLong() throws IOException {
|
|
||||||
readFully(integralCacheArray, 0, 8);
|
|
||||||
|
|
||||||
return integralCache.getLong(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seek(long position) throws IOException {
|
|
||||||
checkClosed();
|
|
||||||
|
|
||||||
if (position < flushedPos) {
|
|
||||||
throw new IndexOutOfBoundsException("position < flushedPos!");
|
|
||||||
}
|
|
||||||
|
|
||||||
bitOffset = 0;
|
|
||||||
|
|
||||||
if (streamPos == position) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimized to not invalidate buffer if new position is within current buffer
|
|
||||||
long newBufferPos = bufferPos + position - streamPos;
|
|
||||||
if (newBufferPos >= 0 && newBufferPos <= bufferLimit) {
|
|
||||||
bufferPos = (int) newBufferPos;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Will invalidate buffer
|
|
||||||
bufferLimit = 0;
|
|
||||||
raf.seek(position);
|
|
||||||
}
|
|
||||||
|
|
||||||
streamPos = position;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-104
@@ -1,104 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.stream;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.spi.ProviderInfo;
|
|
||||||
|
|
||||||
import javax.imageio.spi.ImageInputStreamSpi;
|
|
||||||
import javax.imageio.spi.ServiceRegistry;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BufferedFileImageInputStreamSpi
|
|
||||||
* Experimental
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
* @author last modified by $Author: haraldk$
|
|
||||||
* @version $Id: BufferedFileImageInputStreamSpi.java,v 1.0 May 15, 2008 2:14:59 PM haraldk Exp$
|
|
||||||
*/
|
|
||||||
public class BufferedFileImageInputStreamSpi extends ImageInputStreamSpi {
|
|
||||||
public BufferedFileImageInputStreamSpi() {
|
|
||||||
this(new StreamProviderInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
private BufferedFileImageInputStreamSpi(ProviderInfo providerInfo) {
|
|
||||||
super(providerInfo.getVendorName(), providerInfo.getVersion(), File.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRegistration(final ServiceRegistry registry, final Class<?> category) {
|
|
||||||
Iterator<ImageInputStreamSpi> providers = registry.getServiceProviders(ImageInputStreamSpi.class, new FileInputFilter(), true);
|
|
||||||
|
|
||||||
while (providers.hasNext()) {
|
|
||||||
ImageInputStreamSpi provider = providers.next();
|
|
||||||
if (provider != this) {
|
|
||||||
registry.setOrdering(ImageInputStreamSpi.class, this, provider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageInputStream createInputStreamInstance(final Object input, final boolean pUseCache, final File pCacheDir) {
|
|
||||||
if (input instanceof File) {
|
|
||||||
try {
|
|
||||||
return new BufferedFileImageInputStream((File) input);
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException e) {
|
|
||||||
// For consistency with the JRE bundled SPIs, we'll return null here,
|
|
||||||
// even though the spec does not say that's allowed.
|
|
||||||
// The problem is that the SPIs can only declare that they support an input type like a File,
|
|
||||||
// instead they should be allowed to inspect the instance, to see that the file does exist...
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Expected input of type File: " + input);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canUseCacheFile() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription(final Locale pLocale) {
|
|
||||||
return "Service provider that instantiates an ImageInputStream from a File";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class FileInputFilter implements ServiceRegistry.Filter {
|
|
||||||
@Override
|
|
||||||
public boolean filter(final Object provider) {
|
|
||||||
return ((ImageInputStreamSpi) provider).getInputClass() == File.class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+3
-7
@@ -43,19 +43,15 @@ import static com.twelvemonkeys.lang.Validate.notNull;
|
|||||||
* A buffered {@code ImageInputStream}.
|
* A buffered {@code ImageInputStream}.
|
||||||
* Experimental - seems to be effective for {@link javax.imageio.stream.FileImageInputStream}
|
* Experimental - seems to be effective for {@link javax.imageio.stream.FileImageInputStream}
|
||||||
* and {@link javax.imageio.stream.FileCacheImageInputStream} when doing a lot of single-byte reads
|
* and {@link javax.imageio.stream.FileCacheImageInputStream} when doing a lot of single-byte reads
|
||||||
* (or short byte-array reads).
|
* (or short byte-array reads) on OS X at least.
|
||||||
* Code that uses the {@code readFully} methods are not affected by the issue.
|
* Code that uses the {@code readFully} methods are not affected by the issue.
|
||||||
* <p>
|
|
||||||
* NOTE: Invoking {@code close()} will <em>NOT</em> close the wrapped stream.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @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: BufferedFileImageInputStream.java,v 1.0 May 15, 2008 4:36:49 PM haraldk Exp$
|
* @version $Id: BufferedFileImageInputStream.java,v 1.0 May 15, 2008 4:36:49 PM haraldk Exp$
|
||||||
*
|
|
||||||
* @deprecated Use {@link BufferedFileImageInputStream} instead.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
// TODO: Create a provider for this (wrapping the FileIIS and FileCacheIIS classes), and disable the Sun built-in spis?
|
||||||
|
// TODO: Test on other platforms, might be just an OS X issue
|
||||||
public final class BufferedImageInputStream extends ImageInputStreamImpl implements ImageInputStream {
|
public final class BufferedImageInputStream extends ImageInputStreamImpl implements ImageInputStream {
|
||||||
static final int DEFAULT_BUFFER_SIZE = 8192;
|
static final int DEFAULT_BUFFER_SIZE = 8192;
|
||||||
|
|
||||||
|
|||||||
-95
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.stream;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.spi.ProviderInfo;
|
|
||||||
|
|
||||||
import javax.imageio.spi.ImageInputStreamSpi;
|
|
||||||
import javax.imageio.spi.ServiceRegistry;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BufferedRAFImageInputStreamSpi
|
|
||||||
* Experimental
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
* @author last modified by $Author: haraldk$
|
|
||||||
* @version $Id: BufferedRAFImageInputStreamSpi.java,v 1.0 May 15, 2008 2:14:59 PM haraldk Exp$
|
|
||||||
*/
|
|
||||||
public class BufferedRAFImageInputStreamSpi extends ImageInputStreamSpi {
|
|
||||||
public BufferedRAFImageInputStreamSpi() {
|
|
||||||
this(new StreamProviderInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
private BufferedRAFImageInputStreamSpi(ProviderInfo providerInfo) {
|
|
||||||
super(providerInfo.getVendorName(), providerInfo.getVersion(), RandomAccessFile.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRegistration(final ServiceRegistry registry, final Class<?> category) {
|
|
||||||
Iterator<ImageInputStreamSpi> providers = registry.getServiceProviders(ImageInputStreamSpi.class, new RAFInputFilter(), true);
|
|
||||||
|
|
||||||
while (providers.hasNext()) {
|
|
||||||
ImageInputStreamSpi provider = providers.next();
|
|
||||||
if (provider != this) {
|
|
||||||
registry.setOrdering(ImageInputStreamSpi.class, this, provider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageInputStream createInputStreamInstance(final Object input, final boolean pUseCache, final File pCacheDir) {
|
|
||||||
if (input instanceof RandomAccessFile) {
|
|
||||||
return new BufferedFileImageInputStream((RandomAccessFile) input);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Expected input of type RandomAccessFile: " + input);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canUseCacheFile() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription(final Locale pLocale) {
|
|
||||||
return "Service provider that instantiates an ImageInputStream from a RandomAccessFile";
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class RAFInputFilter implements ServiceRegistry.Filter {
|
|
||||||
@Override
|
|
||||||
public boolean filter(final Object provider) {
|
|
||||||
return ((ImageInputStreamSpi) provider).getInputClass() == RandomAccessFile.class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+9
-8
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Harald Kuhr
|
* Copyright (c) 2008, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -34,6 +34,7 @@ import com.twelvemonkeys.imageio.spi.ProviderInfo;
|
|||||||
|
|
||||||
import javax.imageio.spi.ImageInputStreamSpi;
|
import javax.imageio.spi.ImageInputStreamSpi;
|
||||||
import javax.imageio.stream.FileCacheImageInputStream;
|
import javax.imageio.stream.FileCacheImageInputStream;
|
||||||
|
import javax.imageio.stream.FileImageInputStream;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -71,7 +72,7 @@ public class URLImageInputStreamSpi extends ImageInputStreamSpi {
|
|||||||
// Special case for file protocol, a lot faster than FileCacheImageInputStream
|
// Special case for file protocol, a lot faster than FileCacheImageInputStream
|
||||||
if ("file".equals(url.getProtocol())) {
|
if ("file".equals(url.getProtocol())) {
|
||||||
try {
|
try {
|
||||||
return new BufferedFileImageInputStream(new File(url.toURI()));
|
return new BufferedImageInputStream(new FileImageInputStream(new File(url.toURI())));
|
||||||
}
|
}
|
||||||
catch (URISyntaxException ignore) {
|
catch (URISyntaxException ignore) {
|
||||||
// This should never happen, but if it does, we'll fall back to using the stream
|
// This should never happen, but if it does, we'll fall back to using the stream
|
||||||
@@ -80,29 +81,29 @@ public class URLImageInputStreamSpi extends ImageInputStreamSpi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise revert to cached
|
// Otherwise revert to cached
|
||||||
final InputStream urlStream = url.openStream();
|
final InputStream stream = url.openStream();
|
||||||
if (pUseCache) {
|
if (pUseCache) {
|
||||||
return new FileCacheImageInputStream(urlStream, pCacheDir) {
|
return new BufferedImageInputStream(new FileCacheImageInputStream(stream, pCacheDir) {
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
try {
|
try {
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
urlStream.close(); // NOTE: If this line throws IOE, it will shadow the original..
|
stream.close(); // NOTE: If this line throws IOE, it will shadow the original..
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new MemoryCacheImageInputStream(urlStream) {
|
return new MemoryCacheImageInputStream(stream) {
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
try {
|
try {
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
urlStream.close(); // NOTE: If this line throws IOE, it will shadow the original..
|
stream.close(); // NOTE: If this line throws IOE, it will shadow the original..
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -223,12 +223,7 @@ public final class IIOUtil {
|
|||||||
public static void subsampleRow(byte[] srcRow, int srcPos, int srcWidth,
|
public static void subsampleRow(byte[] srcRow, int srcPos, int srcWidth,
|
||||||
byte[] destRow, int destPos,
|
byte[] destRow, int destPos,
|
||||||
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
||||||
// Period == 1 is a no-op...
|
Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); // Period == 1 could be a no-op...
|
||||||
if (samplePeriod == 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1");
|
|
||||||
Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 8 && (bitsPerSample == 1 || bitsPerSample % 2 == 0),
|
Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 8 && (bitsPerSample == 1 || bitsPerSample % 2 == 0),
|
||||||
"bitsPerSample must be > 0 and <= 8 and a power of 2");
|
"bitsPerSample must be > 0 and <= 8 and a power of 2");
|
||||||
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
||||||
@@ -266,12 +261,7 @@ public final class IIOUtil {
|
|||||||
public static void subsampleRow(short[] srcRow, int srcPos, int srcWidth,
|
public static void subsampleRow(short[] srcRow, int srcPos, int srcWidth,
|
||||||
short[] destRow, int destPos,
|
short[] destRow, int destPos,
|
||||||
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
||||||
// Period == 1 is a no-op...
|
Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); // Period == 1 could be a no-op...
|
||||||
if (samplePeriod == 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1");
|
|
||||||
Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 16 && (bitsPerSample == 1 || bitsPerSample % 2 == 0),
|
Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 16 && (bitsPerSample == 1 || bitsPerSample % 2 == 0),
|
||||||
"bitsPerSample must be > 0 and <= 16 and a power of 2");
|
"bitsPerSample must be > 0 and <= 16 and a power of 2");
|
||||||
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
||||||
@@ -288,12 +278,7 @@ public final class IIOUtil {
|
|||||||
public static void subsampleRow(int[] srcRow, int srcPos, int srcWidth,
|
public static void subsampleRow(int[] srcRow, int srcPos, int srcWidth,
|
||||||
int[] destRow, int destPos,
|
int[] destRow, int destPos,
|
||||||
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
||||||
// Period == 1 is a no-op...
|
Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); // Period == 1 could be a no-op...
|
||||||
if (samplePeriod == 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1");
|
|
||||||
Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 32 && (bitsPerSample == 1 || bitsPerSample % 2 == 0),
|
Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 32 && (bitsPerSample == 1 || bitsPerSample % 2 == 0),
|
||||||
"bitsPerSample must be > 0 and <= 32 and a power of 2");
|
"bitsPerSample must be > 0 and <= 32 and a power of 2");
|
||||||
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
||||||
|
|||||||
+17
-39
@@ -30,21 +30,14 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.util;
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
import static com.twelvemonkeys.lang.Validate.isTrue;
|
import com.twelvemonkeys.imageio.color.DiscreteAlphaIndexColorModel;
|
||||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
|
||||||
|
|
||||||
import java.awt.color.ColorSpace;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.awt.image.ColorModel;
|
|
||||||
import java.awt.image.DataBuffer;
|
|
||||||
import java.awt.image.DirectColorModel;
|
|
||||||
import java.awt.image.IndexColorModel;
|
|
||||||
import java.awt.image.MultiPixelPackedSampleModel;
|
|
||||||
import java.awt.image.SampleModel;
|
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import java.awt.color.ColorSpace;
|
||||||
|
import java.awt.image.*;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.color.DiscreteAlphaIndexColorModel;
|
import static com.twelvemonkeys.lang.Validate.isTrue;
|
||||||
|
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory class for creating {@code ImageTypeSpecifier}s.
|
* Factory class for creating {@code ImageTypeSpecifier}s.
|
||||||
@@ -176,36 +169,21 @@ public final class ImageTypeSpecifiers {
|
|||||||
|
|
||||||
int numEntries = 1 << bits;
|
int numEntries = 1 << bits;
|
||||||
|
|
||||||
ColorModel colorModel;
|
byte[] r = new byte[numEntries];
|
||||||
|
byte[] g = new byte[numEntries];
|
||||||
|
byte[] b = new byte[numEntries];
|
||||||
|
|
||||||
if (ColorSpace.getInstance(ColorSpace.CS_GRAY).equals(colorSpace)) {
|
// Scale array values according to color profile..
|
||||||
// For default gray, use linear response
|
for (int i = 0; i < numEntries; i++) {
|
||||||
byte[] gray = new byte[numEntries];
|
float[] gray = new float[]{i / (float) (numEntries - 1)};
|
||||||
|
float[] rgb = colorSpace.toRGB(gray);
|
||||||
|
|
||||||
for (int i = 0; i < numEntries; i++) {
|
r[i] = (byte) (rgb[0] * 255);
|
||||||
gray[i] = (byte) ((i * 255) / (numEntries - 1));
|
g[i] = (byte) (rgb[1] * 255);
|
||||||
}
|
b[i] = (byte) (rgb[2] * 255);
|
||||||
|
|
||||||
colorModel = new IndexColorModel(bits, numEntries, gray, gray, gray);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
byte[] r = new byte[numEntries];
|
|
||||||
byte[] g = new byte[numEntries];
|
|
||||||
byte[] b = new byte[numEntries];
|
|
||||||
|
|
||||||
// Scale array values according to color profile..
|
|
||||||
for (int i = 0; i < numEntries; i++) {
|
|
||||||
float[] gray = new float[] { i / (float) (numEntries - 1) };
|
|
||||||
float[] rgb = colorSpace.toRGB(gray);
|
|
||||||
|
|
||||||
r[i] = (byte) Math.round(rgb[0] * 255);
|
|
||||||
g[i] = (byte) Math.round(rgb[1] * 255);
|
|
||||||
b[i] = (byte) Math.round(rgb[2] * 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
colorModel = new IndexColorModel(bits, numEntries, r, g, b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColorModel colorModel = new IndexColorModel(bits, numEntries, r, g, b);
|
||||||
SampleModel sampleModel = new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
|
SampleModel sampleModel = new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
|
||||||
|
|
||||||
return new ImageTypeSpecifier(colorModel, sampleModel);
|
return new ImageTypeSpecifier(colorModel, sampleModel);
|
||||||
@@ -223,7 +201,7 @@ public final class ImageTypeSpecifiers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ImageTypeSpecifier createFromIndexColorModel(final IndexColorModel pColorModel) {
|
public static ImageTypeSpecifier createFromIndexColorModel(final IndexColorModel pColorModel) {
|
||||||
return new IndexedImageTypeSpecifier(pColorModel);
|
return IndexedImageTypeSpecifier.createFromIndexColorModel(pColorModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ImageTypeSpecifier createDiscreteAlphaIndexedFromIndexColorModel(final IndexColorModel pColorModel) {
|
public static ImageTypeSpecifier createDiscreteAlphaIndexedFromIndexColorModel(final IndexColorModel pColorModel) {
|
||||||
|
|||||||
+27
-24
@@ -30,13 +30,13 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.util;
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.awt.image.ColorModel;
|
|
||||||
import java.awt.image.WritableRaster;
|
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.IndexColorModel;
|
||||||
|
import java.awt.image.WritableRaster;
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IndexedImageTypeSpecifier
|
* IndexedImageTypeSpecifier
|
||||||
@@ -45,24 +45,27 @@ import javax.imageio.ImageTypeSpecifier;
|
|||||||
* @author last modified by $Author: haraldk$
|
* @author last modified by $Author: haraldk$
|
||||||
* @version $Id: IndexedImageTypeSpecifier.java,v 1.0 May 19, 2008 11:04:28 AM haraldk Exp$
|
* @version $Id: IndexedImageTypeSpecifier.java,v 1.0 May 19, 2008 11:04:28 AM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
final class IndexedImageTypeSpecifier extends ImageTypeSpecifier {
|
final class IndexedImageTypeSpecifier {
|
||||||
IndexedImageTypeSpecifier(final ColorModel colorModel) {
|
private IndexedImageTypeSpecifier() {}
|
||||||
// For some reason, we need a sample model, even though we won't use it
|
|
||||||
super(notNull(colorModel, "colorModel"), colorModel.createCompatibleSampleModel(1, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
static ImageTypeSpecifier createFromIndexColorModel(final IndexColorModel pColorModel) {
|
||||||
public final BufferedImage createBufferedImage(final int pWidth, final int pHeight) {
|
// For some reason, we need a sample model
|
||||||
try {
|
return new ImageTypeSpecifier(notNull(pColorModel, "colorModel"), pColorModel.createCompatibleSampleModel(1, 1)) {
|
||||||
// This is a fix for the super-method, that first creates a sample model, and then
|
|
||||||
// creates a raster from it, using Raster.createWritableRaster. The problem with
|
@Override
|
||||||
// that approach, is that it always creates a TYPE_CUSTOM BufferedImage for indexed images.
|
public final BufferedImage createBufferedImage(final int pWidth, final int pHeight) {
|
||||||
WritableRaster raster = colorModel.createCompatibleWritableRaster(pWidth, pHeight);
|
try {
|
||||||
return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
|
// This is a fix for the super-method, that first creates a sample model, and then
|
||||||
}
|
// creates a raster from it, using Raster.createWritableRaster. The problem with
|
||||||
catch (NegativeArraySizeException e) {
|
// that approach, is that it always creates a TYPE_CUSTOM BufferedImage for indexed images.
|
||||||
// Exception most likely thrown from a DataBuffer constructor
|
WritableRaster raster = colorModel.createCompatibleWritableRaster(pWidth, pHeight);
|
||||||
throw new IllegalArgumentException("Array size > Integer.MAX_VALUE!");
|
return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), new Hashtable());
|
||||||
}
|
}
|
||||||
|
catch (NegativeArraySizeException e) {
|
||||||
|
// Exception most likely thrown from a DataBuffer constructor
|
||||||
|
throw new IllegalArgumentException("Array size > Integer.MAX_VALUE!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-18
@@ -30,16 +30,15 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.util;
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.color.UInt32ColorModel;
|
||||||
|
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.image.BandedSampleModel;
|
import java.awt.image.BandedSampleModel;
|
||||||
import java.awt.image.DataBuffer;
|
import java.awt.image.DataBuffer;
|
||||||
import java.awt.image.PixelInterleavedSampleModel;
|
import java.awt.image.PixelInterleavedSampleModel;
|
||||||
import java.awt.image.SampleModel;
|
import java.awt.image.SampleModel;
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.color.UInt32ColorModel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageTypeSpecifier for interleaved 32 bit unsigned integral samples.
|
* ImageTypeSpecifier for interleaved 32 bit unsigned integral samples.
|
||||||
*
|
*
|
||||||
@@ -48,13 +47,11 @@ import com.twelvemonkeys.imageio.color.UInt32ColorModel;
|
|||||||
* @author last modified by $Author: haraldk$
|
* @author last modified by $Author: haraldk$
|
||||||
* @version $Id: UInt32ImageTypeSpecifier.java,v 1.0 24.01.11 17.51 haraldk Exp$
|
* @version $Id: UInt32ImageTypeSpecifier.java,v 1.0 24.01.11 17.51 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
final class UInt32ImageTypeSpecifier extends ImageTypeSpecifier {
|
final class UInt32ImageTypeSpecifier {
|
||||||
private UInt32ImageTypeSpecifier(final ColorSpace cs, final boolean hasAlpha, final boolean isAlphaPremultiplied, final SampleModel sampleModel) {
|
private UInt32ImageTypeSpecifier() {}
|
||||||
super(new UInt32ColorModel(cs, hasAlpha, isAlphaPremultiplied), sampleModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ImageTypeSpecifier createInterleaved(final ColorSpace cs, final int[] bandOffsets, final boolean hasAlpha, final boolean isAlphaPremultiplied) {
|
static ImageTypeSpecifier createInterleaved(final ColorSpace cs, final int[] bandOffsets, final boolean hasAlpha, final boolean isAlphaPremultiplied) {
|
||||||
return new UInt32ImageTypeSpecifier(
|
return create(
|
||||||
cs, hasAlpha, isAlphaPremultiplied,
|
cs, hasAlpha, isAlphaPremultiplied,
|
||||||
new PixelInterleavedSampleModel(
|
new PixelInterleavedSampleModel(
|
||||||
DataBuffer.TYPE_INT, 1, 1,
|
DataBuffer.TYPE_INT, 1, 1,
|
||||||
@@ -66,7 +63,7 @@ final class UInt32ImageTypeSpecifier extends ImageTypeSpecifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ImageTypeSpecifier createBanded(final ColorSpace cs, final int[] bandIndices, final int[] bandOffsets, final boolean hasAlpha, final boolean isAlphaPremultiplied) {
|
static ImageTypeSpecifier createBanded(final ColorSpace cs, final int[] bandIndices, final int[] bandOffsets, final boolean hasAlpha, final boolean isAlphaPremultiplied) {
|
||||||
return new UInt32ImageTypeSpecifier(
|
return create(
|
||||||
cs, hasAlpha, isAlphaPremultiplied,
|
cs, hasAlpha, isAlphaPremultiplied,
|
||||||
new BandedSampleModel(
|
new BandedSampleModel(
|
||||||
DataBuffer.TYPE_INT, 1, 1, 1,
|
DataBuffer.TYPE_INT, 1, 1, 1,
|
||||||
@@ -75,13 +72,7 @@ final class UInt32ImageTypeSpecifier extends ImageTypeSpecifier {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static ImageTypeSpecifier create(final ColorSpace cs, final boolean hasAlpha, final boolean isAlphaPremultiplied, final SampleModel sampleModel) {
|
||||||
public boolean equals(final Object other) {
|
return new ImageTypeSpecifier(new UInt32ColorModel(cs, hasAlpha, isAlphaPremultiplied), sampleModel);
|
||||||
if (!(other instanceof UInt32ImageTypeSpecifier)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt32ImageTypeSpecifier that = (UInt32ImageTypeSpecifier) other;
|
|
||||||
return colorModel.equals(that.colorModel) && sampleModel.equals(that.sampleModel);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-2
@@ -1,2 +0,0 @@
|
|||||||
com.twelvemonkeys.imageio.stream.BufferedFileImageInputStreamSpi
|
|
||||||
com.twelvemonkeys.imageio.stream.BufferedRAFImageInputStreamSpi
|
|
||||||
-30
@@ -1,30 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.stream;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import javax.imageio.spi.ImageInputStreamSpi;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assume.assumeFalse;
|
|
||||||
|
|
||||||
public class BufferedFileImageInputStreamSpiTest extends ImageInputStreamSpiTest<File> {
|
|
||||||
@Override
|
|
||||||
protected ImageInputStreamSpi createProvider() {
|
|
||||||
return new BufferedFileImageInputStreamSpi();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected File createInput() throws IOException {
|
|
||||||
return File.createTempFile("test-", ".tst");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReturnNullWhenFileDoesNotExist() throws IOException {
|
|
||||||
// This is really stupid behavior, but it is consistent with the JRE bundled SPIs.
|
|
||||||
File input = new File("a-file-that-should-not-exist-ever.fnf");
|
|
||||||
assumeFalse("File should not exist: " + input.getPath(), input.exists());
|
|
||||||
assertNull(provider.createInputStreamInstance(input));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-386
@@ -1,386 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2020, 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.stream;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.function.ThrowingRunnable;
|
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.stream.BufferedImageInputStreamTest.rangeEquals;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BufferedFileImageInputStreamTestCase
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
* @author last modified by $Author: haraldk$
|
|
||||||
* @version $Id: BufferedFileImageInputStreamTestCase.java,v 1.0 Apr 21, 2009 10:58:48 AM haraldk Exp$
|
|
||||||
*/
|
|
||||||
public class BufferedFileImageInputStreamTest {
|
|
||||||
private final Random random = new Random(170984354357234566L);
|
|
||||||
|
|
||||||
private File randomDataToFile(byte[] data) throws IOException {
|
|
||||||
random.nextBytes(data);
|
|
||||||
|
|
||||||
File file = File.createTempFile("read", ".tmp");
|
|
||||||
Files.write(file.toPath(), data);
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreate() throws IOException {
|
|
||||||
BufferedFileImageInputStream stream = new BufferedFileImageInputStream(File.createTempFile("empty", ".tmp"));
|
|
||||||
assertEquals("Data length should be same as stream length", 0, stream.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateNullFile() throws IOException {
|
|
||||||
try {
|
|
||||||
new BufferedFileImageInputStream((File) null);
|
|
||||||
fail("Expected IllegalArgumentException");
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException expected) {
|
|
||||||
assertNotNull("Null exception message", expected.getMessage());
|
|
||||||
String message = expected.getMessage().toLowerCase();
|
|
||||||
assertTrue("Exception message does not contain parameter name", message.contains("file"));
|
|
||||||
assertTrue("Exception message does not contain null", message.contains("null"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateNullRAF() {
|
|
||||||
try {
|
|
||||||
new BufferedFileImageInputStream((RandomAccessFile) null);
|
|
||||||
fail("Expected IllegalArgumentException");
|
|
||||||
}
|
|
||||||
catch (IllegalArgumentException expected) {
|
|
||||||
assertNotNull("Null exception message", expected.getMessage());
|
|
||||||
String message = expected.getMessage().toLowerCase();
|
|
||||||
assertTrue("Exception message does not contain parameter name", message.contains("raf"));
|
|
||||||
assertTrue("Exception message does not contain null", message.contains("null"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRead() throws IOException {
|
|
||||||
byte[] data = new byte[1024 * 1024];
|
|
||||||
File file = randomDataToFile(data);
|
|
||||||
|
|
||||||
BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadArray() throws IOException {
|
|
||||||
byte[] data = new byte[1024 * 1024];
|
|
||||||
File file = randomDataToFile(data);
|
|
||||||
|
|
||||||
BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
|
|
||||||
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
|
||||||
|
|
||||||
byte[] result = new byte[1024];
|
|
||||||
|
|
||||||
for (int i = 0; i < data.length / result.length; i++) {
|
|
||||||
stream.readFully(result);
|
|
||||||
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadSkip() throws IOException {
|
|
||||||
byte[] data = new byte[1024 * 14];
|
|
||||||
File file = randomDataToFile(data);
|
|
||||||
|
|
||||||
BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
|
|
||||||
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
|
||||||
|
|
||||||
byte[] result = new byte[7];
|
|
||||||
|
|
||||||
for (int i = 0; i < data.length / result.length; i += 2) {
|
|
||||||
stream.readFully(result);
|
|
||||||
stream.skipBytes(result.length);
|
|
||||||
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadSeek() throws IOException {
|
|
||||||
byte[] data = new byte[1024 * 18];
|
|
||||||
File file = randomDataToFile(data);
|
|
||||||
|
|
||||||
BufferedFileImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
|
|
||||||
assertEquals("File length should be same as stream length", file.length(), stream.length());
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadBitRandom() throws IOException {
|
|
||||||
byte[] bytes = new byte[8];
|
|
||||||
File file = randomDataToFile(bytes);
|
|
||||||
long value = ByteBuffer.wrap(bytes).getLong();
|
|
||||||
|
|
||||||
// Create stream
|
|
||||||
ImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
|
|
||||||
for (int i = 1; i <= 64; i++) {
|
|
||||||
assertEquals(String.format("bit %d differ", i), (value << (i - 1L)) >>> 63L, stream.readBit());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadBitsRandom() throws IOException {
|
|
||||||
byte[] bytes = new byte[8];
|
|
||||||
File file = randomDataToFile(bytes);
|
|
||||||
long value = ByteBuffer.wrap(bytes).getLong();
|
|
||||||
|
|
||||||
// Create stream
|
|
||||||
ImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
|
|
||||||
for (int i = 1; i <= 64; i++) {
|
|
||||||
stream.seek(0);
|
|
||||||
assertEquals(String.format("bit %d differ", i), value >>> (64L - i), stream.readBits(i));
|
|
||||||
assertEquals(i % 8, stream.getBitOffset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadBitsRandomOffset() throws IOException {
|
|
||||||
byte[] bytes = new byte[8];
|
|
||||||
File file = randomDataToFile(bytes);
|
|
||||||
long value = ByteBuffer.wrap(bytes).getLong();
|
|
||||||
|
|
||||||
// Create stream
|
|
||||||
ImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
|
|
||||||
for (int i = 1; i <= 60; i++) {
|
|
||||||
stream.seek(0);
|
|
||||||
stream.setBitOffset(i % 8);
|
|
||||||
assertEquals(String.format("bit %d differ", i), (value << (i % 8)) >>> (64L - i), stream.readBits(i));
|
|
||||||
assertEquals(i * 2 % 8, stream.getBitOffset());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadShort() throws IOException {
|
|
||||||
byte[] bytes = new byte[8743]; // Slightly more than one buffer size
|
|
||||||
File file = randomDataToFile(bytes);
|
|
||||||
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++) {
|
|
||||||
assertEquals(buffer.getShort(), stream.readShort());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readShort();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
stream.seek(0);
|
|
||||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
buffer.position(0);
|
|
||||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length / 2; i++) {
|
|
||||||
assertEquals(buffer.getShort(), stream.readShort());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readShort();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadInt() throws IOException {
|
|
||||||
byte[] bytes = new byte[8743]; // Slightly more than one buffer size
|
|
||||||
File file = randomDataToFile(bytes);
|
|
||||||
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++) {
|
|
||||||
assertEquals(buffer.getInt(), stream.readInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readInt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
stream.seek(0);
|
|
||||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
buffer.position(0);
|
|
||||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length / 4; i++) {
|
|
||||||
assertEquals(buffer.getInt(), stream.readInt());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readInt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadLong() throws IOException {
|
|
||||||
byte[] bytes = new byte[8743]; // Slightly more than one buffer size
|
|
||||||
File file = randomDataToFile(bytes);
|
|
||||||
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++) {
|
|
||||||
assertEquals(buffer.getLong(), stream.readLong());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readLong();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
stream.seek(0);
|
|
||||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
buffer.position(0);
|
|
||||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
|
|
||||||
for (int i = 0; i < bytes.length / 8; i++) {
|
|
||||||
assertEquals(buffer.getLong(), stream.readLong());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readLong();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSeekPastEOF() throws IOException {
|
|
||||||
byte[] bytes = new byte[9];
|
|
||||||
File file = randomDataToFile(bytes);
|
|
||||||
|
|
||||||
final ImageInputStream stream = new BufferedFileImageInputStream(file);
|
|
||||||
stream.seek(1000);
|
|
||||||
|
|
||||||
assertEquals(-1, stream.read());
|
|
||||||
assertEquals(-1, stream.read(new byte[1], 0, 1));
|
|
||||||
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readFully(new byte[1]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readByte();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readShort();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readInt();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
stream.readLong();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
stream.seek(0);
|
|
||||||
for (byte value : bytes) {
|
|
||||||
assertEquals(value, stream.readByte());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(-1, stream.read());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testClose() throws IOException {
|
|
||||||
// Create wrapper stream
|
|
||||||
RandomAccessFile mock = mock(RandomAccessFile.class);
|
|
||||||
ImageInputStream stream = new BufferedFileImageInputStream(mock);
|
|
||||||
|
|
||||||
stream.close();
|
|
||||||
verify(mock, only()).close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-18
@@ -1,18 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.stream;
|
|
||||||
|
|
||||||
import javax.imageio.spi.ImageInputStreamSpi;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
|
|
||||||
public class BufferedRAFImageInputStreamSpiTest extends ImageInputStreamSpiTest<RandomAccessFile> {
|
|
||||||
@Override
|
|
||||||
protected ImageInputStreamSpi createProvider() {
|
|
||||||
return new BufferedRAFImageInputStreamSpi();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected RandomAccessFile createInput() throws IOException {
|
|
||||||
return new RandomAccessFile(File.createTempFile("test-", ".tst"), "r");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-2
@@ -39,11 +39,11 @@ import static com.twelvemonkeys.imageio.stream.BufferedImageInputStreamTest.rang
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ByteArrayImageInputStreamTest
|
* ByteArrayImageInputStreamTestCase
|
||||||
*
|
*
|
||||||
* @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: ByteArrayImageInputStreamTest.java,v 1.0 Apr 21, 2009 10:58:48 AM haraldk Exp$
|
* @version $Id: ByteArrayImageInputStreamTestCase.java,v 1.0 Apr 21, 2009 10:58:48 AM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class ByteArrayImageInputStreamTest {
|
public class ByteArrayImageInputStreamTest {
|
||||||
private final Random random = new Random(1709843507234566L);
|
private final Random random = new Random(1709843507234566L);
|
||||||
|
|||||||
+3
-3
@@ -11,14 +11,14 @@ import java.util.Locale;
|
|||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
abstract class ImageInputStreamSpiTest<T> {
|
abstract class ImageInputStreamSpiTest<T> {
|
||||||
protected final ImageInputStreamSpi provider = createProvider();
|
private final ImageInputStreamSpi provider = createProvider();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected final Class<T> inputClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
private final Class<T> inputClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||||
|
|
||||||
protected abstract ImageInputStreamSpi createProvider();
|
protected abstract ImageInputStreamSpi createProvider();
|
||||||
|
|
||||||
protected abstract T createInput() throws IOException;
|
protected abstract T createInput();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInputClass() {
|
public void testInputClass() {
|
||||||
|
|||||||
+57
-94
@@ -97,6 +97,10 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
|
|
||||||
protected abstract List<String> getMIMETypes();
|
protected abstract List<String> getMIMETypes();
|
||||||
|
|
||||||
|
protected boolean allowsNullRawImageType() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected static void failBecause(String message, Throwable exception) {
|
protected static void failBecause(String message, Throwable exception) {
|
||||||
throw new AssertionError(message, exception);
|
throw new AssertionError(message, exception);
|
||||||
}
|
}
|
||||||
@@ -217,7 +221,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
image = reader.read(i);
|
image = reader.read(i);
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
e.printStackTrace();
|
|
||||||
failBecause(String.format("Image %s index %s could not be read: %s", data.getInput(), i, e), e);
|
failBecause(String.format("Image %s index %s could not be read: %s", data.getInput(), i, e), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -280,6 +283,26 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadNoInput() throws IOException {
|
||||||
|
ImageReader reader = createReader();
|
||||||
|
// Do not set input
|
||||||
|
|
||||||
|
BufferedImage image = null;
|
||||||
|
try {
|
||||||
|
image = reader.read(0);
|
||||||
|
fail("Read image with no input");
|
||||||
|
}
|
||||||
|
catch (IllegalStateException ignore) {
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
failBecause("Image could not be read", e);
|
||||||
|
}
|
||||||
|
assertNull(image);
|
||||||
|
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReRead() throws IOException {
|
public void testReRead() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
@@ -300,71 +323,69 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test
|
||||||
public void testReadNoInput() throws IOException {
|
|
||||||
ImageReader reader = createReader();
|
|
||||||
// Do not set input
|
|
||||||
|
|
||||||
try {
|
|
||||||
reader.read(0);
|
|
||||||
fail("Read image with no input");
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
failBecause("Image could not be read", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IndexOutOfBoundsException.class)
|
|
||||||
public void testReadIndexNegativeWithParam() throws IOException {
|
public void testReadIndexNegativeWithParam() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
TestData data = getTestData().get(0);
|
TestData data = getTestData().get(0);
|
||||||
reader.setInput(data.getInputStream());
|
reader.setInput(data.getInputStream());
|
||||||
|
|
||||||
|
BufferedImage image = null;
|
||||||
try {
|
try {
|
||||||
reader.read(-1, reader.getDefaultReadParam());
|
image = reader.read(-1, reader.getDefaultReadParam());
|
||||||
fail("Read image with illegal index");
|
fail("Read image with illegal index");
|
||||||
}
|
}
|
||||||
|
catch (IndexOutOfBoundsException ignore) {
|
||||||
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
failBecause("Image could not be read", e);
|
failBecause("Image could not be read", e);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
reader.dispose();
|
assertNull(image);
|
||||||
}
|
|
||||||
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IndexOutOfBoundsException.class)
|
@Test
|
||||||
public void testReadIndexOutOfBoundsWithParam() throws IOException {
|
public void testReadIndexOutOfBoundsWithParam() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
TestData data = getTestData().get(0);
|
TestData data = getTestData().get(0);
|
||||||
reader.setInput(data.getInputStream());
|
reader.setInput(data.getInputStream());
|
||||||
|
|
||||||
|
BufferedImage image = null;
|
||||||
try {
|
try {
|
||||||
reader.read(Short.MAX_VALUE, reader.getDefaultReadParam());
|
image = reader.read(Short.MAX_VALUE, reader.getDefaultReadParam());
|
||||||
fail("Read image with index out of bounds");
|
fail("Read image with index out of bounds");
|
||||||
}
|
}
|
||||||
|
catch (IndexOutOfBoundsException ignore) {
|
||||||
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
failBecause("Image could not be read", e);
|
failBecause("Image could not be read", e);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
reader.dispose();
|
assertNull(image);
|
||||||
}
|
|
||||||
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test
|
||||||
public void testReadNoInputWithParam() throws IOException {
|
public void testReadNoInputWithParam() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
// Do not set input
|
// Do not set input
|
||||||
|
|
||||||
|
BufferedImage image = null;
|
||||||
try {
|
try {
|
||||||
reader.read(0, reader.getDefaultReadParam());
|
image = reader.read(0, reader.getDefaultReadParam());
|
||||||
fail("Read image with no input");
|
fail("Read image with no input");
|
||||||
}
|
}
|
||||||
|
catch (IllegalStateException ignore) {
|
||||||
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
failBecause("Image could not be read", e);
|
failBecause("Image could not be read", e);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
reader.dispose();
|
assertNull(image);
|
||||||
}
|
|
||||||
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1356,6 +1377,9 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
reader.setInput(data.getInputStream());
|
reader.setInput(data.getInputStream());
|
||||||
|
|
||||||
ImageTypeSpecifier rawType = reader.getRawImageType(0);
|
ImageTypeSpecifier rawType = reader.getRawImageType(0);
|
||||||
|
if (rawType == null && allowsNullRawImageType()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
assertNotNull(rawType);
|
assertNotNull(rawType);
|
||||||
|
|
||||||
Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
|
Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
|
||||||
@@ -1377,7 +1401,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
|
|
||||||
assertTrue("ImageTypeSpecifier from getRawImageType should be in the iterator from getImageTypes", rawFound);
|
assertTrue("ImageTypeSpecifier from getRawImageType should be in the iterator from getImageTypes", rawFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1626,72 +1649,12 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
BufferedImage one = reader.read(0);
|
BufferedImage one = reader.read(0);
|
||||||
BufferedImage two = reader.read(0);
|
BufferedImage two = reader.read(0);
|
||||||
|
|
||||||
// Test for same BufferedImage instance
|
|
||||||
assertNotSame("Multiple reads return same (mutable) image", one, two);
|
assertNotSame("Multiple reads return same (mutable) image", one, two);
|
||||||
|
|
||||||
// Test for same backing storage (array)
|
one.setRGB(0, 0, Color.BLUE.getRGB());
|
||||||
one.setRGB(0, 0, Color.BLACK.getRGB());
|
two.setRGB(0, 0, Color.RED.getRGB());
|
||||||
two.setRGB(0, 0, Color.WHITE.getRGB());
|
|
||||||
assertTrue(one.getRGB(0, 0) != two.getRGB(0, 0));
|
assertTrue(one.getRGB(0, 0) != two.getRGB(0, 0));
|
||||||
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadThumbnails() throws IOException {
|
|
||||||
T reader = createReader();
|
|
||||||
|
|
||||||
if (reader.readerSupportsThumbnails()) {
|
|
||||||
for (TestData testData : getTestData()) {
|
|
||||||
try (ImageInputStream inputStream = testData.getInputStream()) {
|
|
||||||
reader.setInput(inputStream);
|
|
||||||
|
|
||||||
int numImages = reader.getNumImages(true);
|
|
||||||
|
|
||||||
for (int i = 0; i < numImages; i++) {
|
|
||||||
int numThumbnails = reader.getNumThumbnails(0);
|
|
||||||
|
|
||||||
for (int t = 0; t < numThumbnails; t++) {
|
|
||||||
BufferedImage thumbnail = reader.readThumbnail(0, t);
|
|
||||||
|
|
||||||
assertNotNull(thumbnail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testThumbnailProgress() throws IOException {
|
|
||||||
T reader = createReader();
|
|
||||||
|
|
||||||
IIOReadProgressListener listener = mock(IIOReadProgressListener.class);
|
|
||||||
reader.addIIOReadProgressListener(listener);
|
|
||||||
|
|
||||||
if (reader.readerSupportsThumbnails()) {
|
|
||||||
for (TestData testData : getTestData()) {
|
|
||||||
try (ImageInputStream inputStream = testData.getInputStream()) {
|
|
||||||
|
|
||||||
reader.setInput(inputStream);
|
|
||||||
|
|
||||||
int numThumbnails = reader.getNumThumbnails(0);
|
|
||||||
for (int i = 0; i < numThumbnails; i++) {
|
|
||||||
reset(listener);
|
|
||||||
|
|
||||||
reader.readThumbnail(0, i);
|
|
||||||
|
|
||||||
InOrder order = inOrder(listener);
|
|
||||||
order.verify(listener).thumbnailStarted(reader, 0, i);
|
|
||||||
order.verify(listener, atLeastOnce()).thumbnailProgress(reader, 100f);
|
|
||||||
order.verify(listener).thumbnailComplete(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-21
@@ -30,20 +30,14 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.util;
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import java.awt.color.ColorSpace;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.awt.image.ColorModel;
|
|
||||||
import java.awt.image.DataBuffer;
|
|
||||||
import java.awt.image.DirectColorModel;
|
|
||||||
import java.awt.image.IndexColorModel;
|
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import java.awt.color.ColorSpace;
|
||||||
|
import java.awt.image.*;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
public class ImageTypeSpecifiersTest {
|
public class ImageTypeSpecifiersTest {
|
||||||
|
|
||||||
@@ -547,7 +541,8 @@ public class ImageTypeSpecifiersTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreatePackedGrayscale1BPP() {
|
public void testCreatePackedGrayscale1() {
|
||||||
|
// TODO: Fails on Java 11, because IndexColorModel now has an overloaded equals that actually tests the color entries
|
||||||
assertEquals(
|
assertEquals(
|
||||||
ImageTypeSpecifier.createGrayscale(1, DataBuffer.TYPE_BYTE, false),
|
ImageTypeSpecifier.createGrayscale(1, DataBuffer.TYPE_BYTE, false),
|
||||||
ImageTypeSpecifiers.createPackedGrayscale(GRAY, 1, DataBuffer.TYPE_BYTE)
|
ImageTypeSpecifiers.createPackedGrayscale(GRAY, 1, DataBuffer.TYPE_BYTE)
|
||||||
@@ -555,8 +550,8 @@ public class ImageTypeSpecifiersTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreatePackedGrayscale2BPP() {
|
public void testCreatePackedGrayscale2() {
|
||||||
// TODO: Fails on Java 11+, because IndexColorModel now has an overloaded equals that actually tests the color entries
|
// TODO: Fails on Java 11, because IndexColorModel now has an overloaded equals that actually tests the color entries
|
||||||
assertEquals(
|
assertEquals(
|
||||||
ImageTypeSpecifier.createGrayscale(2, DataBuffer.TYPE_BYTE, false),
|
ImageTypeSpecifier.createGrayscale(2, DataBuffer.TYPE_BYTE, false),
|
||||||
ImageTypeSpecifiers.createPackedGrayscale(GRAY, 2, DataBuffer.TYPE_BYTE)
|
ImageTypeSpecifiers.createPackedGrayscale(GRAY, 2, DataBuffer.TYPE_BYTE)
|
||||||
@@ -564,8 +559,8 @@ public class ImageTypeSpecifiersTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreatePackedGrayscale4BPP() {
|
public void testCreatePackedGrayscale4() throws Exception {
|
||||||
// TODO: Fails on Java 11+, because IndexColorModel now has an overloaded equals that actually tests the color entries
|
// TODO: Fails on Java 11, because IndexColorModel now has an overloaded equals that actually tests the color entries
|
||||||
assertEquals(
|
assertEquals(
|
||||||
ImageTypeSpecifier.createGrayscale(4, DataBuffer.TYPE_BYTE, false),
|
ImageTypeSpecifier.createGrayscale(4, DataBuffer.TYPE_BYTE, false),
|
||||||
ImageTypeSpecifiers.createPackedGrayscale(GRAY, 4, DataBuffer.TYPE_BYTE)
|
ImageTypeSpecifiers.createPackedGrayscale(GRAY, 4, DataBuffer.TYPE_BYTE)
|
||||||
@@ -658,7 +653,7 @@ public class ImageTypeSpecifiersTest {
|
|||||||
for (int bits = 1; bits <= 8; bits <<= 1) {
|
for (int bits = 1; bits <= 8; bits <<= 1) {
|
||||||
int[] colors = createIntLut(1 << bits);
|
int[] colors = createIntLut(1 << bits);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
new IndexedImageTypeSpecifier(new IndexColorModel(bits, colors.length, colors, 0, false, -1, DataBuffer.TYPE_BYTE)),
|
IndexedImageTypeSpecifier.createFromIndexColorModel(new IndexColorModel(bits, colors.length, colors, 0, false, -1, DataBuffer.TYPE_BYTE)),
|
||||||
ImageTypeSpecifiers.createIndexed(colors, false, -1, bits, DataBuffer.TYPE_BYTE)
|
ImageTypeSpecifiers.createIndexed(colors, false, -1, bits, DataBuffer.TYPE_BYTE)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -668,7 +663,7 @@ public class ImageTypeSpecifiersTest {
|
|||||||
public void testCreateIndexedIntArray16() {
|
public void testCreateIndexedIntArray16() {
|
||||||
int[] colors = createIntLut(1 << 16);
|
int[] colors = createIntLut(1 << 16);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
new IndexedImageTypeSpecifier(new IndexColorModel(16, colors.length, colors, 0, false, -1, DataBuffer.TYPE_USHORT)),
|
IndexedImageTypeSpecifier.createFromIndexColorModel(new IndexColorModel(16, colors.length, colors, 0, false, -1, DataBuffer.TYPE_USHORT)),
|
||||||
ImageTypeSpecifiers.createIndexed(colors, false, -1, 16, DataBuffer.TYPE_USHORT)
|
ImageTypeSpecifiers.createIndexed(colors, false, -1, 16, DataBuffer.TYPE_USHORT)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -680,7 +675,7 @@ public class ImageTypeSpecifiersTest {
|
|||||||
int[] colors = createIntLut(1 << bits);
|
int[] colors = createIntLut(1 << bits);
|
||||||
IndexColorModel colorModel = new IndexColorModel(bits, colors.length, colors, 0, false, -1, DataBuffer.TYPE_BYTE);
|
IndexColorModel colorModel = new IndexColorModel(bits, colors.length, colors, 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
new IndexedImageTypeSpecifier(colorModel),
|
IndexedImageTypeSpecifier.createFromIndexColorModel(colorModel),
|
||||||
ImageTypeSpecifiers.createFromIndexColorModel(colorModel)
|
ImageTypeSpecifiers.createFromIndexColorModel(colorModel)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -691,7 +686,7 @@ public class ImageTypeSpecifiersTest {
|
|||||||
int[] colors = createIntLut(1 << 16);
|
int[] colors = createIntLut(1 << 16);
|
||||||
IndexColorModel colorModel = new IndexColorModel(16, colors.length, colors, 0, false, -1, DataBuffer.TYPE_USHORT);
|
IndexColorModel colorModel = new IndexColorModel(16, colors.length, colors, 0, false, -1, DataBuffer.TYPE_USHORT);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
new IndexedImageTypeSpecifier(colorModel),
|
IndexedImageTypeSpecifier.createFromIndexColorModel(colorModel),
|
||||||
ImageTypeSpecifiers.createFromIndexColorModel(colorModel)
|
ImageTypeSpecifiers.createFromIndexColorModel(colorModel)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-17
@@ -30,17 +30,14 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.util;
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import org.junit.Test;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
|
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.DataBuffer;
|
import java.awt.image.DataBuffer;
|
||||||
import java.awt.image.IndexColorModel;
|
import java.awt.image.IndexColorModel;
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IndexedImageTypeSpecifierTestCase
|
* IndexedImageTypeSpecifierTestCase
|
||||||
@@ -54,43 +51,46 @@ public class IndexedImageTypeSpecifierTest {
|
|||||||
public void testEquals() {
|
public void testEquals() {
|
||||||
IndexColorModel cm = new IndexColorModel(1, 2, new int[]{0xffffff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE);
|
IndexColorModel cm = new IndexColorModel(1, 2, new int[]{0xffffff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||||
|
|
||||||
ImageTypeSpecifier spec = new IndexedImageTypeSpecifier(cm);
|
ImageTypeSpecifier spec = IndexedImageTypeSpecifier.createFromIndexColorModel(cm);
|
||||||
ImageTypeSpecifier other = new IndexedImageTypeSpecifier(cm);
|
ImageTypeSpecifier other = IndexedImageTypeSpecifier.createFromIndexColorModel(cm);
|
||||||
ImageTypeSpecifier different = new IndexedImageTypeSpecifier(new IndexColorModel(2, 2, new int[]{0xff00ff, 0x00, 0xff00ff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE));
|
ImageTypeSpecifier different = IndexedImageTypeSpecifier.createFromIndexColorModel(new IndexColorModel(2, 2, new int[]{0xff00ff, 0x00, 0xff00ff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE));
|
||||||
|
|
||||||
assertEquals(spec, other);
|
assertEquals(spec, other);
|
||||||
assertEquals(other, spec);
|
assertEquals(other, spec);
|
||||||
|
|
||||||
assertEquals(spec.hashCode(), other.hashCode());
|
assertEquals(spec.hashCode(), other.hashCode());
|
||||||
|
|
||||||
|
assertTrue(spec.equals(other));
|
||||||
|
assertTrue(other.equals(spec));
|
||||||
|
|
||||||
// TODO: There is still a problem that IndexColorModel does not override equals,
|
// TODO: There is still a problem that IndexColorModel does not override equals,
|
||||||
// so any model with the same number of bits, transparency, and transfer type will be treated as equal
|
// so any model with the same number of bits, transparency, and transfer type will be treated as equal
|
||||||
assertNotEquals(other, different);
|
assertFalse(other.equals(different));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHashCode() {
|
public void testHashCode() {
|
||||||
IndexColorModel cm = new IndexColorModel(1, 2, new int[]{0xffffff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE);
|
IndexColorModel cm = new IndexColorModel(1, 2, new int[]{0xffffff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||||
|
|
||||||
ImageTypeSpecifier spec = new IndexedImageTypeSpecifier(cm);
|
ImageTypeSpecifier spec = IndexedImageTypeSpecifier.createFromIndexColorModel(cm);
|
||||||
ImageTypeSpecifier other = new IndexedImageTypeSpecifier(cm);
|
ImageTypeSpecifier other = IndexedImageTypeSpecifier.createFromIndexColorModel(cm);
|
||||||
ImageTypeSpecifier different = new IndexedImageTypeSpecifier(new IndexColorModel(2, 2, new int[]{0xff00ff, 0x00, 0xff00ff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE));
|
ImageTypeSpecifier different = IndexedImageTypeSpecifier.createFromIndexColorModel(new IndexColorModel(2, 2, new int[]{0xff00ff, 0x00, 0xff00ff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE));
|
||||||
|
|
||||||
// TODO: There is still a problem that IndexColorModel does not override hashCode,
|
// TODO: There is still a problem that IndexColorModel does not override hashCode,
|
||||||
// so any model with the same number of bits, transparency, and transfer type will have same hash
|
// so any model with the same number of bits, transparency, and transfer type will have same hash
|
||||||
assertEquals(spec.hashCode(), other.hashCode());
|
assertEquals(spec.hashCode(), other.hashCode());
|
||||||
assertNotEquals(spec.hashCode(), different.hashCode());
|
assertFalse(spec.hashCode() == different.hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testCreateNull() {
|
public void testCreateNull() {
|
||||||
new IndexedImageTypeSpecifier(null);
|
IndexedImageTypeSpecifier.createFromIndexColorModel(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateBufferedImageBinary() {
|
public void testCreateBufferedImageBinary() {
|
||||||
IndexColorModel cm = new IndexColorModel(1, 2, new int[]{0xffffff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE);
|
IndexColorModel cm = new IndexColorModel(1, 2, new int[]{0xffffff, 0x00}, 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||||
ImageTypeSpecifier spec = new IndexedImageTypeSpecifier(cm);
|
ImageTypeSpecifier spec = IndexedImageTypeSpecifier.createFromIndexColorModel(cm);
|
||||||
|
|
||||||
BufferedImage image = spec.createBufferedImage(2, 2);
|
BufferedImage image = spec.createBufferedImage(2, 2);
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ public class IndexedImageTypeSpecifierTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testCreateBufferedImageIndexed() {
|
public void testCreateBufferedImageIndexed() {
|
||||||
IndexColorModel cm = new IndexColorModel(8, 256, new int[256], 0, false, -1, DataBuffer.TYPE_BYTE);
|
IndexColorModel cm = new IndexColorModel(8, 256, new int[256], 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||||
ImageTypeSpecifier spec = new IndexedImageTypeSpecifier(cm);
|
ImageTypeSpecifier spec = IndexedImageTypeSpecifier.createFromIndexColorModel(cm);
|
||||||
|
|
||||||
BufferedImage image = spec.createBufferedImage(2, 2);
|
BufferedImage image = spec.createBufferedImage(2, 2);
|
||||||
|
|
||||||
|
|||||||
@@ -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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-hdr</artifactId>
|
<artifactId>imageio-hdr</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
|
||||||
@@ -12,10 +12,6 @@
|
|||||||
ImageIO plugin for Radiance RGBE High Dynaimc Range format (HDR).
|
ImageIO plugin for Radiance RGBE High Dynaimc Range format (HDR).
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.hdr</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
@@ -4,16 +4,12 @@
|
|||||||
<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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-icns</artifactId>
|
<artifactId>imageio-icns</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
|
||||||
<description>ImageIO plugin for Apple Icon Image (ICNS) format.</description>
|
<description>ImageIO plugin for Apple Icon Image (ICNS) format.</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.icns</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
@@ -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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-iff</artifactId>
|
<artifactId>imageio-iff</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
|
||||||
@@ -13,10 +13,6 @@
|
|||||||
type ILBM and PBM format.
|
type ILBM and PBM format.
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.iff</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
+2
-3
@@ -102,15 +102,14 @@ abstract class AbstractMultiPaletteChunk extends IFFChunk implements MultiPalett
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void writeChunk(DataOutput pOutput) {
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
throw new UnsupportedOperationException("Method writeChunk not implemented");
|
throw new UnsupportedOperationException("Method writeChunk not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ColorModel getColorModel(final IndexColorModel colorModel, final int rowIndex, final boolean laced) {
|
public ColorModel getColorModel(final IndexColorModel colorModel, final int rowIndex, final boolean laced) {
|
||||||
if (rowIndex < lastRow || mutablePalette == null || originalPalette != null && originalPalette.get() != colorModel) {
|
if (rowIndex < lastRow || mutablePalette == null || originalPalette != null && originalPalette.get() != colorModel) {
|
||||||
originalPalette = new WeakReference<>(colorModel);
|
originalPalette = new WeakReference<IndexColorModel>(colorModel);
|
||||||
mutablePalette = new MutableIndexColorModel(colorModel);
|
mutablePalette = new MutableIndexColorModel(colorModel);
|
||||||
|
|
||||||
if (initialChanges != null) {
|
if (initialChanges != null) {
|
||||||
|
|||||||
+3
-7
@@ -30,12 +30,11 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.iff;
|
package com.twelvemonkeys.imageio.plugins.iff;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BMHDChunk
|
* BMHDChunk
|
||||||
*
|
*
|
||||||
@@ -130,8 +129,7 @@ final class BMHDChunk extends IFFChunk {
|
|||||||
pageHeight = Math.min(pHeight, Short.MAX_VALUE);
|
pageHeight = Math.min(pHeight, Short.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void readChunk(DataInput pInput) throws IOException {
|
||||||
void readChunk(final DataInput pInput) throws IOException {
|
|
||||||
if (chunkLength != 20) {
|
if (chunkLength != 20) {
|
||||||
throw new IIOException("Unknown BMHD chunk length: " + chunkLength);
|
throw new IIOException("Unknown BMHD chunk length: " + chunkLength);
|
||||||
}
|
}
|
||||||
@@ -150,8 +148,7 @@ final class BMHDChunk extends IFFChunk {
|
|||||||
pageHeight = pInput.readShort();
|
pageHeight = pInput.readShort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
void writeChunk(final DataOutput pOutput) throws IOException {
|
|
||||||
pOutput.writeInt(chunkId);
|
pOutput.writeInt(chunkId);
|
||||||
pOutput.writeInt(chunkLength);
|
pOutput.writeInt(chunkLength);
|
||||||
|
|
||||||
@@ -170,7 +167,6 @@ final class BMHDChunk extends IFFChunk {
|
|||||||
pOutput.writeShort(pageHeight);
|
pOutput.writeShort(pageHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return super.toString()
|
return super.toString()
|
||||||
+ " {w=" + width + ", h=" + height
|
+ " {w=" + width + ", h=" + height
|
||||||
|
|||||||
+3
-4
@@ -32,6 +32,7 @@ package com.twelvemonkeys.imageio.plugins.iff;
|
|||||||
|
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BODYChunk
|
* BODYChunk
|
||||||
@@ -44,13 +45,11 @@ final class BODYChunk extends IFFChunk {
|
|||||||
super(IFF.CHUNK_BODY, pChunkLength);
|
super(IFF.CHUNK_BODY, pChunkLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void readChunk(DataInput pInput) throws IOException {
|
||||||
void readChunk(final DataInput pInput) {
|
|
||||||
throw new InternalError("BODY chunk should only be read from IFFImageReader");
|
throw new InternalError("BODY chunk should only be read from IFFImageReader");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
void writeChunk(final DataOutput pOutput) {
|
|
||||||
throw new InternalError("BODY chunk should only be written from IFFImageWriter");
|
throw new InternalError("BODY chunk should only be written from IFFImageWriter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-8
@@ -30,12 +30,11 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.iff;
|
package com.twelvemonkeys.imageio.plugins.iff;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CAMGChunk
|
* CAMGChunk
|
||||||
*
|
*
|
||||||
@@ -47,14 +46,13 @@ final class CAMGChunk extends IFFChunk {
|
|||||||
// #define CAMG_HAM 0x800 /* hold and modify */
|
// #define CAMG_HAM 0x800 /* hold and modify */
|
||||||
// #define CAMG_EHB 0x80 /* extra halfbrite */
|
// #define CAMG_EHB 0x80 /* extra halfbrite */
|
||||||
|
|
||||||
int camg;
|
private int camg;
|
||||||
|
|
||||||
public CAMGChunk(int pLength) {
|
public CAMGChunk(int pLength) {
|
||||||
super(IFF.CHUNK_CAMG, pLength);
|
super(IFF.CHUNK_CAMG, pLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void readChunk(DataInput pInput) throws IOException {
|
||||||
void readChunk(final DataInput pInput) throws IOException {
|
|
||||||
if (chunkLength != 4) {
|
if (chunkLength != 4) {
|
||||||
throw new IIOException("Unknown CAMG chunk length: " + chunkLength);
|
throw new IIOException("Unknown CAMG chunk length: " + chunkLength);
|
||||||
}
|
}
|
||||||
@@ -62,8 +60,7 @@ final class CAMGChunk extends IFFChunk {
|
|||||||
camg = pInput.readInt();
|
camg = pInput.readInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
void writeChunk(final DataOutput pOutput) {
|
|
||||||
throw new InternalError("Not implemented: writeChunk()");
|
throw new InternalError("Not implemented: writeChunk()");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +80,6 @@ final class CAMGChunk extends IFFChunk {
|
|||||||
return (camg & 0x80) != 0;
|
return (camg & 0x80) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return super.toString() + " {mode=" + (isHAM() ? "HAM" : isEHB() ? "EHB" : "Normal") + "}";
|
return super.toString() + " {mode=" + (isHAM() ? "HAM" : isEHB() ? "EHB" : "Normal") + "}";
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-5
@@ -30,6 +30,7 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.iff;
|
package com.twelvemonkeys.imageio.plugins.iff;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.IndexColorModel;
|
import java.awt.image.IndexColorModel;
|
||||||
import java.awt.image.WritableRaster;
|
import java.awt.image.WritableRaster;
|
||||||
@@ -38,8 +39,6 @@ import java.io.DataOutput;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CMAPChunk
|
* CMAPChunk
|
||||||
*
|
*
|
||||||
@@ -69,7 +68,6 @@ final class CMAPChunk extends IFFChunk {
|
|||||||
model = pModel;
|
model = pModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
void readChunk(final DataInput pInput) throws IOException {
|
void readChunk(final DataInput pInput) throws IOException {
|
||||||
int numColors = chunkLength / 3;
|
int numColors = chunkLength / 3;
|
||||||
|
|
||||||
@@ -97,7 +95,6 @@ final class CMAPChunk extends IFFChunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
void writeChunk(final DataOutput pOutput) throws IOException {
|
void writeChunk(final DataOutput pOutput) throws IOException {
|
||||||
pOutput.writeInt(chunkId);
|
pOutput.writeInt(chunkId);
|
||||||
pOutput.writeInt(chunkLength);
|
pOutput.writeInt(chunkLength);
|
||||||
@@ -115,7 +112,6 @@ final class CMAPChunk extends IFFChunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return super.toString() + " {colorMap=" + model + "}";
|
return super.toString() + " {colorMap=" + model + "}";
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-8
@@ -35,10 +35,10 @@ import java.io.DataOutput;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GenericChunk
|
* UnknownChunk
|
||||||
*
|
*
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
* @version $Id: GenericChunk.java,v 1.0 28.feb.2006 00:53:47 haku Exp$
|
* @version $Id: UnknownChunk.java,v 1.0 28.feb.2006 00:53:47 haku Exp$
|
||||||
*/
|
*/
|
||||||
final class GenericChunk extends IFFChunk {
|
final class GenericChunk extends IFFChunk {
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ final class GenericChunk extends IFFChunk {
|
|||||||
|
|
||||||
protected GenericChunk(int pChunkId, int pChunkLength) {
|
protected GenericChunk(int pChunkId, int pChunkLength) {
|
||||||
super(pChunkId, pChunkLength);
|
super(pChunkId, pChunkLength);
|
||||||
data = new byte[chunkLength];
|
data = new byte[pChunkLength <= 50 ? pChunkLength : 47];
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GenericChunk(int pChunkId, byte[] pChunkData) {
|
protected GenericChunk(int pChunkId, byte[] pChunkData) {
|
||||||
@@ -54,15 +54,13 @@ final class GenericChunk extends IFFChunk {
|
|||||||
data = pChunkData;
|
data = pChunkData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void readChunk(DataInput pInput) throws IOException {
|
||||||
void readChunk(final DataInput pInput) throws IOException {
|
|
||||||
pInput.readFully(data, 0, data.length);
|
pInput.readFully(data, 0, data.length);
|
||||||
|
|
||||||
skipData(pInput, chunkLength, data.length);
|
skipData(pInput, chunkLength, data.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
void writeChunk(DataOutput pOutput) throws IOException {
|
||||||
void writeChunk(final DataOutput pOutput) throws IOException {
|
|
||||||
pOutput.writeInt(chunkId);
|
pOutput.writeInt(chunkId);
|
||||||
pOutput.writeInt(chunkLength);
|
pOutput.writeInt(chunkLength);
|
||||||
pOutput.write(data, 0, data.length);
|
pOutput.write(data, 0, data.length);
|
||||||
@@ -72,7 +70,6 @@ final class GenericChunk extends IFFChunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return super.toString() + " {value=\""
|
return super.toString() + " {value=\""
|
||||||
+ new String(data, 0, data.length <= 50 ? data.length : 47)
|
+ new String(data, 0, data.length <= 50 ? data.length : 47)
|
||||||
|
|||||||
@@ -91,12 +91,6 @@ interface IFF {
|
|||||||
/** EA IFF 85 Generic Copyright text chunk */
|
/** EA IFF 85 Generic Copyright text chunk */
|
||||||
int CHUNK_COPY = ('(' << 24) + ('c' << 16) + (')' << 8) + ' ';
|
int CHUNK_COPY = ('(' << 24) + ('c' << 16) + (')' << 8) + ' ';
|
||||||
|
|
||||||
/** EA IFF 85 Generic annotation chunk (usually used for Software) */
|
|
||||||
int CHUNK_ANNO = ('A' << 24) + ('N' << 16) + ('N' << 8) + 'O';;
|
|
||||||
|
|
||||||
/** Third-party defined UTF-8 text. */
|
|
||||||
int CHUNK_UTF8 = ('U' << 24) + ('T' << 16) + ('F' << 8) + '8';
|
|
||||||
|
|
||||||
/** color cycling */
|
/** color cycling */
|
||||||
int CHUNK_CRNG = ('C' << 24) + ('R' << 16) + ('N' << 8) + 'G';
|
int CHUNK_CRNG = ('C' << 24) + ('R' << 16) + ('N' << 8) + 'G';
|
||||||
/** color cycling */
|
/** color cycling */
|
||||||
|
|||||||
-269
@@ -1,269 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.iff;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.AbstractMetadata;
|
|
||||||
|
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.image.IndexColorModel;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.iff.IFF.*;
|
|
||||||
import static com.twelvemonkeys.lang.Validate.isTrue;
|
|
||||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
|
||||||
|
|
||||||
final class IFFImageMetadata extends AbstractMetadata {
|
|
||||||
private final int formType;
|
|
||||||
private final BMHDChunk header;
|
|
||||||
private final IndexColorModel colorMap;
|
|
||||||
private final CAMGChunk viewPort;
|
|
||||||
private final List<GenericChunk> meta;
|
|
||||||
|
|
||||||
IFFImageMetadata(int formType, BMHDChunk header, IndexColorModel colorMap, CAMGChunk viewPort, List<GenericChunk> meta) {
|
|
||||||
this.formType = isTrue(validFormType(formType), formType, "Unknown IFF Form type: %s");
|
|
||||||
this.header = notNull(header, "header");
|
|
||||||
this.colorMap = colorMap;
|
|
||||||
this.viewPort = viewPort;
|
|
||||||
this.meta = meta;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean validFormType(int formType) {
|
|
||||||
switch (formType) {
|
|
||||||
case TYPE_ACBM:
|
|
||||||
case TYPE_DEEP:
|
|
||||||
case TYPE_ILBM:
|
|
||||||
case TYPE_PBM:
|
|
||||||
case TYPE_RGB8:
|
|
||||||
case TYPE_RGBN:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IIOMetadataNode getStandardChromaNode() {
|
|
||||||
IIOMetadataNode chroma = new IIOMetadataNode("Chroma");
|
|
||||||
|
|
||||||
IIOMetadataNode csType = new IIOMetadataNode("ColorSpaceType");
|
|
||||||
chroma.appendChild(csType);
|
|
||||||
|
|
||||||
switch (header.bitplanes) {
|
|
||||||
case 8:
|
|
||||||
if (colorMap == null) {
|
|
||||||
csType.setAttribute("name", "GRAY");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
case 5:
|
|
||||||
case 6:
|
|
||||||
case 7:
|
|
||||||
case 24:
|
|
||||||
case 32:
|
|
||||||
csType.setAttribute("name", "RGB");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
csType.setAttribute("name", "Unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: Channels in chroma node reflects channels in color model (see data node, for channels in data)
|
|
||||||
IIOMetadataNode numChannels = new IIOMetadataNode("NumChannels");
|
|
||||||
chroma.appendChild(numChannels);
|
|
||||||
if (colorMap == null && header.bitplanes == 8) {
|
|
||||||
numChannels.setAttribute("value", Integer.toString(1));
|
|
||||||
}
|
|
||||||
else if (header.bitplanes == 32) {
|
|
||||||
numChannels.setAttribute("value", Integer.toString(4));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
numChannels.setAttribute("value", Integer.toString(3));
|
|
||||||
}
|
|
||||||
|
|
||||||
IIOMetadataNode blackIsZero = new IIOMetadataNode("BlackIsZero");
|
|
||||||
chroma.appendChild(blackIsZero);
|
|
||||||
blackIsZero.setAttribute("value", "TRUE");
|
|
||||||
|
|
||||||
// NOTE: TGA files may contain a color map, even if true color...
|
|
||||||
// Not sure if this is a good idea to expose to the meta data,
|
|
||||||
// as it might be unexpected... Then again...
|
|
||||||
if (colorMap != null) {
|
|
||||||
IIOMetadataNode palette = new IIOMetadataNode("Palette");
|
|
||||||
chroma.appendChild(palette);
|
|
||||||
|
|
||||||
for (int i = 0; i < colorMap.getMapSize(); i++) {
|
|
||||||
IIOMetadataNode paletteEntry = new IIOMetadataNode("PaletteEntry");
|
|
||||||
palette.appendChild(paletteEntry);
|
|
||||||
paletteEntry.setAttribute("index", Integer.toString(i));
|
|
||||||
|
|
||||||
paletteEntry.setAttribute("red", Integer.toString(colorMap.getRed(i)));
|
|
||||||
paletteEntry.setAttribute("green", Integer.toString(colorMap.getGreen(i)));
|
|
||||||
paletteEntry.setAttribute("blue", Integer.toString(colorMap.getBlue(i)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Background color is the color of the transparent index in the color model?
|
|
||||||
// if (extensions != null && extensions.getBackgroundColor() != 0) {
|
|
||||||
// Color background = new Color(extensions.getBackgroundColor(), true);
|
|
||||||
//
|
|
||||||
// IIOMetadataNode backgroundColor = new IIOMetadataNode("BackgroundColor");
|
|
||||||
// chroma.appendChild(backgroundColor);
|
|
||||||
//
|
|
||||||
// backgroundColor.setAttribute("red", Integer.toString(background.getRed()));
|
|
||||||
// backgroundColor.setAttribute("green", Integer.toString(background.getGreen()));
|
|
||||||
// backgroundColor.setAttribute("blue", Integer.toString(background.getBlue()));
|
|
||||||
// }
|
|
||||||
|
|
||||||
return chroma;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IIOMetadataNode getStandardCompressionNode() {
|
|
||||||
if (header.compressionType == BMHDChunk.COMPRESSION_NONE) {
|
|
||||||
return null; // All defaults
|
|
||||||
}
|
|
||||||
|
|
||||||
IIOMetadataNode node = new IIOMetadataNode("Compression");
|
|
||||||
|
|
||||||
IIOMetadataNode compressionTypeName = new IIOMetadataNode("CompressionTypeName");
|
|
||||||
compressionTypeName.setAttribute("value", "RLE");
|
|
||||||
node.appendChild(compressionTypeName);
|
|
||||||
|
|
||||||
IIOMetadataNode lossless = new IIOMetadataNode("Lossless");
|
|
||||||
lossless.setAttribute("value", "TRUE");
|
|
||||||
node.appendChild(lossless);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IIOMetadataNode getStandardDataNode() {
|
|
||||||
IIOMetadataNode data = new IIOMetadataNode("Data");
|
|
||||||
|
|
||||||
// PlanarConfiguration
|
|
||||||
IIOMetadataNode planarConfiguration = new IIOMetadataNode("PlanarConfiguration");
|
|
||||||
switch (formType) {
|
|
||||||
case TYPE_PBM:
|
|
||||||
planarConfiguration.setAttribute("value", "PixelInterleaved");
|
|
||||||
break;
|
|
||||||
case TYPE_ILBM:
|
|
||||||
planarConfiguration.setAttribute("value", "PlaneInterleaved");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
planarConfiguration.setAttribute("value", "Unknown " + IFFUtil.toChunkStr(formType));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data.appendChild(planarConfiguration);
|
|
||||||
|
|
||||||
IIOMetadataNode sampleFormat = new IIOMetadataNode("SampleFormat");
|
|
||||||
sampleFormat.setAttribute("value", colorMap != null ? "Index" : "UnsignedIntegral");
|
|
||||||
data.appendChild(sampleFormat);
|
|
||||||
|
|
||||||
// BitsPerSample
|
|
||||||
IIOMetadataNode bitsPerSample = new IIOMetadataNode("BitsPerSample");
|
|
||||||
String value = bitsPerSampleValue(header.bitplanes);
|
|
||||||
bitsPerSample.setAttribute("value", value);
|
|
||||||
data.appendChild(bitsPerSample);
|
|
||||||
|
|
||||||
// SignificantBitsPerSample not in format
|
|
||||||
// SampleMSB not in format
|
|
||||||
|
|
||||||
return data;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private String bitsPerSampleValue(int bitplanes) {
|
|
||||||
switch (bitplanes) {
|
|
||||||
case 1:
|
|
||||||
case 2:
|
|
||||||
case 3:
|
|
||||||
case 4:
|
|
||||||
case 5:
|
|
||||||
case 6:
|
|
||||||
case 7:
|
|
||||||
case 8:
|
|
||||||
return Integer.toString(bitplanes);
|
|
||||||
case 24:
|
|
||||||
return "8 8 8";
|
|
||||||
case 32:
|
|
||||||
return "8 8 8 8";
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Ubknown bit count: " + bitplanes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IIOMetadataNode getStandardDimensionNode() {
|
|
||||||
if (viewPort == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
IIOMetadataNode dimension = new IIOMetadataNode("Dimension");
|
|
||||||
|
|
||||||
// PixelAspectRatio
|
|
||||||
IIOMetadataNode pixelAspectRatio = new IIOMetadataNode("PixelAspectRatio");
|
|
||||||
pixelAspectRatio.setAttribute("value", String.valueOf((viewPort.isHires() ? 2f : 1f) / (viewPort.isLaced() ? 2f : 1f)));
|
|
||||||
dimension.appendChild(pixelAspectRatio);
|
|
||||||
|
|
||||||
// TODO: HorizontalScreenSize?
|
|
||||||
// TODO: VerticalScreenSize?
|
|
||||||
|
|
||||||
return dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IIOMetadataNode getStandardDocumentNode() {
|
|
||||||
IIOMetadataNode document = new IIOMetadataNode("Document");
|
|
||||||
|
|
||||||
IIOMetadataNode formatVersion = new IIOMetadataNode("FormatVersion");
|
|
||||||
document.appendChild(formatVersion);
|
|
||||||
formatVersion.setAttribute("value", "1.0");
|
|
||||||
|
|
||||||
return document;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IIOMetadataNode getStandardTextNode() {
|
|
||||||
if (meta.isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
IIOMetadataNode text = new IIOMetadataNode("Text");
|
|
||||||
|
|
||||||
// /Text/TextEntry@keyword = field name, /Text/TextEntry@value = field value.
|
|
||||||
for (GenericChunk chunk : meta) {
|
|
||||||
IIOMetadataNode node = new IIOMetadataNode("TextEntry");
|
|
||||||
node.setAttribute("keyword", IFFUtil.toChunkStr(chunk.chunkId));
|
|
||||||
node.setAttribute("value", new String(chunk.data, chunk.chunkId == IFF.CHUNK_UTF8 ? StandardCharsets.UTF_8 : StandardCharsets.US_ASCII));
|
|
||||||
text.appendChild(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
return text;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected IIOMetadataNode getStandardTransparencyNode() {
|
|
||||||
if ((colorMap == null || !colorMap.hasAlpha()) && header.bitplanes != 32) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
IIOMetadataNode transparency = new IIOMetadataNode("Transparency");
|
|
||||||
|
|
||||||
if (header.bitplanes == 32) {
|
|
||||||
IIOMetadataNode alpha = new IIOMetadataNode("Alpha");
|
|
||||||
alpha.setAttribute("value", "nonpremultiplied");
|
|
||||||
transparency.appendChild(alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colorMap != null && colorMap.getTransparency() == Transparency.BITMASK) {
|
|
||||||
IIOMetadataNode transparentIndex = new IIOMetadataNode("TransparentIndex");
|
|
||||||
transparentIndex.setAttribute("value", Integer.toString(colorMap.getTransparentPixel()));
|
|
||||||
transparency.appendChild(transparentIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return transparency;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+21
-38
@@ -32,13 +32,13 @@ package com.twelvemonkeys.imageio.plugins.iff;
|
|||||||
|
|
||||||
import com.twelvemonkeys.image.ResampleOp;
|
import com.twelvemonkeys.image.ResampleOp;
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
|
import com.twelvemonkeys.imageio.stream.BufferedImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||||
import com.twelvemonkeys.io.enc.PackBitsDecoder;
|
import com.twelvemonkeys.io.enc.PackBitsDecoder;
|
||||||
|
|
||||||
import javax.imageio.*;
|
import javax.imageio.*;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
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.*;
|
||||||
@@ -47,7 +47,6 @@ import java.awt.image.*;
|
|||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -97,7 +96,7 @@ import java.util.List;
|
|||||||
* @see <a href="http://en.wikipedia.org/wiki/Interchange_File_Format">Wikipedia: IFF</a>
|
* @see <a href="http://en.wikipedia.org/wiki/Interchange_File_Format">Wikipedia: IFF</a>
|
||||||
* @see <a href="http://en.wikipedia.org/wiki/ILBM">Wikipedia: IFF ILBM</a>
|
* @see <a href="http://en.wikipedia.org/wiki/ILBM">Wikipedia: IFF ILBM</a>
|
||||||
*/
|
*/
|
||||||
public final class IFFImageReader extends ImageReaderBase {
|
public class IFFImageReader extends ImageReaderBase {
|
||||||
// http://home.comcast.net/~erniew/lwsdk/docs/filefmts/ilbm.html
|
// http://home.comcast.net/~erniew/lwsdk/docs/filefmts/ilbm.html
|
||||||
// http://www.fileformat.info/format/iff/spec/7866a9f0e53c42309af667c5da3bd426/view.htm
|
// http://www.fileformat.info/format/iff/spec/7866a9f0e53c42309af667c5da3bd426/view.htm
|
||||||
// - Contains definitions of some "new" chunks, as well as alternative FORM types
|
// - Contains definitions of some "new" chunks, as well as alternative FORM types
|
||||||
@@ -112,14 +111,17 @@ public final class IFFImageReader extends ImageReaderBase {
|
|||||||
private GRABChunk grab;
|
private GRABChunk grab;
|
||||||
private CAMGChunk viewPort;
|
private CAMGChunk viewPort;
|
||||||
private MultiPalette paletteChange;
|
private MultiPalette paletteChange;
|
||||||
private final List<GenericChunk> meta = new ArrayList<>();
|
|
||||||
private int formType;
|
private int formType;
|
||||||
private long bodyStart;
|
private long bodyStart;
|
||||||
|
|
||||||
private BufferedImage image;
|
private BufferedImage image;
|
||||||
private DataInputStream byteRunStream;
|
private DataInputStream byteRunStream;
|
||||||
|
|
||||||
IFFImageReader(ImageReaderSpi pProvider) {
|
public IFFImageReader() {
|
||||||
|
super(new IFFImageReaderSpi());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IFFImageReader(ImageReaderSpi pProvider) {
|
||||||
super(pProvider);
|
super(pProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +133,6 @@ public final class IFFImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void resetMembers() {
|
protected void resetMembers() {
|
||||||
header = null;
|
header = null;
|
||||||
colorMap = null;
|
colorMap = null;
|
||||||
@@ -139,7 +140,6 @@ public final class IFFImageReader extends ImageReaderBase {
|
|||||||
body = null;
|
body = null;
|
||||||
viewPort = null;
|
viewPort = null;
|
||||||
formType = 0;
|
formType = 0;
|
||||||
meta.clear();
|
|
||||||
|
|
||||||
image = null;
|
image = null;
|
||||||
byteRunStream = null;
|
byteRunStream = null;
|
||||||
@@ -258,6 +258,11 @@ public final class IFFImageReader extends ImageReaderBase {
|
|||||||
// System.out.println(ctbl);
|
// System.out.println(ctbl);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IFF.CHUNK_JUNK:
|
||||||
|
// Always skip junk chunks
|
||||||
|
IFFChunk.skipData(imageInput, length, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
case IFF.CHUNK_BODY:
|
case IFF.CHUNK_BODY:
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
throw new IIOException("Multiple BODY chunks not allowed");
|
throw new IIOException("Multiple BODY chunks not allowed");
|
||||||
@@ -269,32 +274,18 @@ public final class IFFImageReader extends ImageReaderBase {
|
|||||||
// NOTE: We don't read the body here, it's done later in the read(int, ImageReadParam) method
|
// NOTE: We don't read the body here, it's done later in the read(int, ImageReadParam) method
|
||||||
// Done reading meta
|
// Done reading meta
|
||||||
return;
|
return;
|
||||||
|
default:
|
||||||
case IFF.CHUNK_ANNO:
|
// TODO: We probably want to store ANNO, TEXT, AUTH, COPY etc chunks as Metadata
|
||||||
case IFF.CHUNK_AUTH:
|
// SHAM, ANNO, DEST, SPRT and more
|
||||||
case IFF.CHUNK_COPY:
|
IFFChunk generic = new GenericChunk(chunkId, length);
|
||||||
case IFF.CHUNK_NAME:
|
|
||||||
case IFF.CHUNK_TEXT:
|
|
||||||
case IFF.CHUNK_UTF8:
|
|
||||||
GenericChunk generic = new GenericChunk(chunkId, length);
|
|
||||||
generic.readChunk(imageInput);
|
generic.readChunk(imageInput);
|
||||||
meta.add(generic);
|
|
||||||
|
|
||||||
// System.out.println(generic);
|
// System.out.println(generic);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IFF.CHUNK_JUNK:
|
|
||||||
// Always skip junk chunks
|
|
||||||
default:
|
|
||||||
// TODO: SHAM, DEST, SPRT and more
|
|
||||||
// Everything else, we'll just skip
|
|
||||||
IFFChunk.skipData(imageInput, length, 0);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
|
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
|
||||||
init(pIndex);
|
init(pIndex);
|
||||||
|
|
||||||
@@ -323,26 +314,16 @@ public final class IFFImageReader extends ImageReaderBase {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWidth(int pIndex) throws IOException {
|
public int getWidth(int pIndex) throws IOException {
|
||||||
init(pIndex);
|
init(pIndex);
|
||||||
return header.width;
|
return header.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight(int pIndex) throws IOException {
|
public int getHeight(int pIndex) throws IOException {
|
||||||
init(pIndex);
|
init(pIndex);
|
||||||
return header.height;
|
return header.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
|
||||||
init(imageIndex);
|
|
||||||
|
|
||||||
return new IFFImageMetadata(formType, header, colorMap != null ? colorMap.getIndexColorModel(header, isEHB()) : null, viewPort, meta);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<ImageTypeSpecifier> getImageTypes(int pIndex) throws IOException {
|
public Iterator<ImageTypeSpecifier> getImageTypes(int pIndex) throws IOException {
|
||||||
init(pIndex);
|
init(pIndex);
|
||||||
|
|
||||||
@@ -382,11 +363,12 @@ public final class IFFImageReader extends ImageReaderBase {
|
|||||||
if (colorMap != null) {
|
if (colorMap != null) {
|
||||||
IndexColorModel cm = colorMap.getIndexColorModel(header, isEHB());
|
IndexColorModel cm = colorMap.getIndexColorModel(header, isEHB());
|
||||||
specifier = ImageTypeSpecifiers.createFromIndexColorModel(cm);
|
specifier = ImageTypeSpecifiers.createFromIndexColorModel(cm);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
specifier = ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY);
|
specifier = ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
// NOTE: HAM modes falls through, as they are converted to RGB
|
// NOTE: HAM modes falls through, as they are converted to RGB
|
||||||
case 24:
|
case 24:
|
||||||
@@ -804,7 +786,7 @@ public final class IFFImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] pArgs) throws IOException {
|
public static void main(String[] pArgs) throws IOException {
|
||||||
ImageReader reader = new IFFImageReader(new IFFImageReaderSpi());
|
ImageReader reader = new IFFImageReader();
|
||||||
|
|
||||||
boolean scale = false;
|
boolean scale = false;
|
||||||
for (String arg : pArgs) {
|
for (String arg : pArgs) {
|
||||||
@@ -818,7 +800,8 @@ public final class IFFImageReader extends ImageReaderBase {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try (ImageInputStream input = ImageIO.createImageInputStream(file)) {
|
try {
|
||||||
|
ImageInputStream input = new BufferedImageInputStream(ImageIO.createImageInputStream(file));
|
||||||
boolean canRead = reader.getOriginatingProvider().canDecodeInput(input);
|
boolean canRead = reader.getOriginatingProvider().canDecodeInput(input);
|
||||||
|
|
||||||
if (canRead) {
|
if (canRead) {
|
||||||
|
|||||||
+3
-7
@@ -30,13 +30,12 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.iff;
|
package com.twelvemonkeys.imageio.plugins.iff;
|
||||||
|
|
||||||
import java.io.IOException;
|
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import javax.imageio.ImageReader;
|
import javax.imageio.ImageReader;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IFFImageReaderSpi
|
* IFFImageReaderSpi
|
||||||
@@ -53,7 +52,6 @@ public final class IFFImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
super(new IFFProviderInfo());
|
super(new IFFProviderInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canDecodeInput(Object pSource) throws IOException {
|
public boolean canDecodeInput(Object pSource) throws IOException {
|
||||||
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource);
|
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource);
|
||||||
}
|
}
|
||||||
@@ -82,12 +80,10 @@ public final class IFFImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ImageReader createReaderInstance(Object pExtension) throws IOException {
|
public ImageReader createReaderInstance(Object pExtension) throws IOException {
|
||||||
return new IFFImageReader(this);
|
return new IFFImageReader(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription(Locale pLocale) {
|
public String getDescription(Locale pLocale) {
|
||||||
return "Commodore Amiga/Electronic Arts Image Interchange Format (IFF) image reader";
|
return "Commodore Amiga/Electronic Arts Image Interchange Format (IFF) image reader";
|
||||||
}
|
}
|
||||||
|
|||||||
+22
-26
@@ -30,31 +30,22 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.iff;
|
package com.twelvemonkeys.imageio.plugins.iff;
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.awt.image.ColorModel;
|
|
||||||
import java.awt.image.IndexColorModel;
|
|
||||||
import java.awt.image.Raster;
|
|
||||||
import java.awt.image.RenderedImage;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
import javax.imageio.IIOImage;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
import javax.imageio.ImageWriter;
|
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
import javax.imageio.spi.ImageWriterSpi;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.ImageWriterBase;
|
import com.twelvemonkeys.imageio.ImageWriterBase;
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||||
import com.twelvemonkeys.io.enc.EncoderStream;
|
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||||
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
||||||
|
|
||||||
|
import javax.imageio.*;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writer for Commodore Amiga (Electronic Arts) IFF ILBM (InterLeaved BitMap) format.
|
* Writer for Commodore Amiga (Electronic Arts) IFF ILBM (InterLeaved BitMap) format.
|
||||||
* The IFF format (Interchange File Format) is the standard file format
|
* The IFF format (Interchange File Format) is the standard file format
|
||||||
@@ -66,23 +57,24 @@ import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
|||||||
* @see <a href="http://en.wikipedia.org/wiki/Interchange_File_Format">Wikipedia: IFF</a>
|
* @see <a href="http://en.wikipedia.org/wiki/Interchange_File_Format">Wikipedia: IFF</a>
|
||||||
* @see <a href="http://en.wikipedia.org/wiki/ILBM">Wikipedia: IFF ILBM</a>
|
* @see <a href="http://en.wikipedia.org/wiki/ILBM">Wikipedia: IFF ILBM</a>
|
||||||
*/
|
*/
|
||||||
public final class IFFImageWriter extends ImageWriterBase {
|
public class IFFImageWriter extends ImageWriterBase {
|
||||||
|
|
||||||
IFFImageWriter(ImageWriterSpi pProvider) {
|
public IFFImageWriter() {
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IFFImageWriter(ImageWriterSpi pProvider) {
|
||||||
super(pProvider);
|
super(pProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) {
|
public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) {
|
||||||
throw new UnsupportedOperationException("Method getDefaultImageMetadata not implemented");// TODO: Implement
|
throw new UnsupportedOperationException("Method getDefaultImageMetadata not implemented");// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) {
|
public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) {
|
||||||
throw new UnsupportedOperationException("Method convertImageMetadata not implemented");// TODO: Implement
|
throw new UnsupportedOperationException("Method convertImageMetadata not implemented");// TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(IIOMetadata pStreamMetadata, IIOImage pImage, ImageWriteParam pParam) throws IOException {
|
public void write(IIOMetadata pStreamMetadata, IIOImage pImage, ImageWriteParam pParam) throws IOException {
|
||||||
assertOutput();
|
assertOutput();
|
||||||
|
|
||||||
@@ -113,9 +105,13 @@ public final class IFFImageWriter extends ImageWriterBase {
|
|||||||
|
|
||||||
// NOTE: This is much faster than imageOutput.write(pImageData.toByteArray())
|
// NOTE: This is much faster than imageOutput.write(pImageData.toByteArray())
|
||||||
// as the data array is not duplicated
|
// as the data array is not duplicated
|
||||||
try (OutputStream adapter = IIOUtil.createStreamAdapter(imageOutput)) {
|
OutputStream adapter = IIOUtil.createStreamAdapter(imageOutput);
|
||||||
|
try {
|
||||||
pImageData.writeTo(adapter);
|
pImageData.writeTo(adapter);
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
adapter.close();
|
||||||
|
}
|
||||||
|
|
||||||
if (pImageData.size() % 2 == 0) {
|
if (pImageData.size() % 2 == 0) {
|
||||||
imageOutput.writeByte(0); // PAD
|
imageOutput.writeByte(0); // PAD
|
||||||
@@ -184,7 +180,7 @@ public final class IFFImageWriter extends ImageWriterBase {
|
|||||||
|
|
||||||
private void writeMeta(RenderedImage pImage, int pBodyLength) throws IOException {
|
private void writeMeta(RenderedImage pImage, int pBodyLength) throws IOException {
|
||||||
// Annotation ANNO chunk, 8 + annoData.length bytes
|
// Annotation ANNO chunk, 8 + annoData.length bytes
|
||||||
String annotation = String.format("Written by %s IFFImageWriter %s", getOriginatingProvider().getVendorName(), getOriginatingProvider().getVersion());
|
String annotation = "Written by " + getOriginatingProvider().getDescription(null) + " by " + getOriginatingProvider().getVendorName();
|
||||||
GenericChunk anno = new GenericChunk(IFFUtil.toInt("ANNO".getBytes()), annotation.getBytes());
|
GenericChunk anno = new GenericChunk(IFFUtil.toInt("ANNO".getBytes()), annotation.getBytes());
|
||||||
|
|
||||||
ColorModel cm = pImage.getColorModel();
|
ColorModel cm = pImage.getColorModel();
|
||||||
|
|||||||
+3
-6
@@ -30,13 +30,12 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.iff;
|
package com.twelvemonkeys.imageio.plugins.iff;
|
||||||
|
|
||||||
import java.io.IOException;
|
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
import javax.imageio.ImageWriter;
|
import javax.imageio.ImageWriter;
|
||||||
|
import java.io.IOException;
|
||||||
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IFFImageWriterSpi
|
* IFFImageWriterSpi
|
||||||
@@ -59,12 +58,10 @@ public class IFFImageWriterSpi extends ImageWriterSpiBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ImageWriter createWriterInstance(Object pExtension) throws IOException {
|
public ImageWriter createWriterInstance(Object pExtension) throws IOException {
|
||||||
return new IFFImageWriter(this);
|
return new IFFImageWriter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription(Locale pLocale) {
|
public String getDescription(Locale pLocale) {
|
||||||
return "Commodore Amiga/Electronic Arts Image Interchange Format (IFF) image writer";
|
return "Commodore Amiga/Electronic Arts Image Interchange Format (IFF) image writer";
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ package com.twelvemonkeys.imageio.plugins.iff;
|
|||||||
* @author Harald Kuhr (Java port)
|
* @author Harald Kuhr (Java port)
|
||||||
* @version $Id: IFFUtil.java,v 1.0 06.mar.2006 13:31:35 haku Exp$
|
* @version $Id: IFFUtil.java,v 1.0 06.mar.2006 13:31:35 haku Exp$
|
||||||
*/
|
*/
|
||||||
final class IFFUtil {
|
class IFFUtil {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a rotation table
|
* Creates a rotation table
|
||||||
|
|||||||
-511
@@ -1,511 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.iff;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import java.awt.image.IndexColorModel;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.function.ThrowingRunnable;
|
|
||||||
import org.w3c.dom.Node;
|
|
||||||
|
|
||||||
public class IFFImageMetadataTest {
|
|
||||||
@Test
|
|
||||||
public void testStandardFeatures() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
final IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
// Standard metadata format
|
|
||||||
assertTrue(metadata.isStandardMetadataFormatSupported());
|
|
||||||
Node root = metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
|
||||||
assertNotNull(root);
|
|
||||||
assertTrue(root instanceof IIOMetadataNode);
|
|
||||||
|
|
||||||
// Other formats
|
|
||||||
assertNull(metadata.getNativeMetadataFormatName());
|
|
||||||
assertNull(metadata.getExtraMetadataFormatNames());
|
|
||||||
assertThrows(IllegalArgumentException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
metadata.getAsTree("com_foo_bar_1.0");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Read-only
|
|
||||||
assertTrue(metadata.isReadOnly());
|
|
||||||
assertThrows(IllegalStateException.class, new ThrowingRunnable() {
|
|
||||||
@Override
|
|
||||||
public void run() throws Throwable {
|
|
||||||
metadata.mergeTree(IIOMetadataFormatImpl.standardMetadataFormatName, new IIOMetadataNode(IIOMetadataFormatImpl.standardMetadataFormatName));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardChromaGray() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode chroma = metadata.getStandardChromaNode();
|
|
||||||
assertNotNull(chroma);
|
|
||||||
assertEquals("Chroma", chroma.getNodeName());
|
|
||||||
assertEquals(3, chroma.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode colorSpaceType = (IIOMetadataNode) chroma.getFirstChild();
|
|
||||||
assertEquals("ColorSpaceType", colorSpaceType.getNodeName());
|
|
||||||
assertEquals("GRAY", colorSpaceType.getAttribute("name"));
|
|
||||||
|
|
||||||
IIOMetadataNode numChannels = (IIOMetadataNode) colorSpaceType.getNextSibling();
|
|
||||||
assertEquals("NumChannels", numChannels.getNodeName());
|
|
||||||
assertEquals("1", numChannels.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode blackIsZero = (IIOMetadataNode) numChannels.getNextSibling();
|
|
||||||
assertEquals("BlackIsZero", blackIsZero.getNodeName());
|
|
||||||
assertEquals("TRUE", blackIsZero.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(blackIsZero.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardChromaRGB() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode chroma = metadata.getStandardChromaNode();
|
|
||||||
assertNotNull(chroma);
|
|
||||||
assertEquals("Chroma", chroma.getNodeName());
|
|
||||||
assertEquals(3, chroma.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode colorSpaceType = (IIOMetadataNode) chroma.getFirstChild();
|
|
||||||
assertEquals("ColorSpaceType", colorSpaceType.getNodeName());
|
|
||||||
assertEquals("RGB", colorSpaceType.getAttribute("name"));
|
|
||||||
|
|
||||||
IIOMetadataNode numChannels = (IIOMetadataNode) colorSpaceType.getNextSibling();
|
|
||||||
assertEquals("NumChannels", numChannels.getNodeName());
|
|
||||||
assertEquals("3", numChannels.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode blackIsZero = (IIOMetadataNode) numChannels.getNextSibling();
|
|
||||||
assertEquals("BlackIsZero", blackIsZero.getNodeName());
|
|
||||||
assertEquals("TRUE", blackIsZero.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(blackIsZero.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardChromaPalette() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 1, BMHDChunk.MASK_TRANSPARENT_COLOR, BMHDChunk.COMPRESSION_BYTE_RUN, 1);
|
|
||||||
|
|
||||||
byte[] bw = {0, (byte) 0xff};
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, new IndexColorModel(header.bitplanes, bw.length, bw, bw, bw, header.transparentIndex), null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode chroma = metadata.getStandardChromaNode();
|
|
||||||
assertNotNull(chroma);
|
|
||||||
assertEquals("Chroma", chroma.getNodeName());
|
|
||||||
assertEquals(4, chroma.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode colorSpaceType = (IIOMetadataNode) chroma.getFirstChild();
|
|
||||||
assertEquals("ColorSpaceType", colorSpaceType.getNodeName());
|
|
||||||
assertEquals("RGB", colorSpaceType.getAttribute("name"));
|
|
||||||
|
|
||||||
IIOMetadataNode numChannels = (IIOMetadataNode) colorSpaceType.getNextSibling();
|
|
||||||
assertEquals("NumChannels", numChannels.getNodeName());
|
|
||||||
assertEquals("3", numChannels.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode blackIsZero = (IIOMetadataNode) numChannels.getNextSibling();
|
|
||||||
assertEquals("BlackIsZero", blackIsZero.getNodeName());
|
|
||||||
assertEquals("TRUE", blackIsZero.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode palette = (IIOMetadataNode) blackIsZero.getNextSibling();
|
|
||||||
assertEquals("Palette", palette.getNodeName());
|
|
||||||
assertEquals(bw.length, palette.getLength());
|
|
||||||
|
|
||||||
for (int i = 0; i < palette.getLength(); i++) {
|
|
||||||
IIOMetadataNode item0 = (IIOMetadataNode) palette.item(i);
|
|
||||||
assertEquals("PaletteEntry", item0.getNodeName());
|
|
||||||
assertEquals(String.valueOf(i), item0.getAttribute("index"));
|
|
||||||
String rgb = String.valueOf(bw[i] & 0xff);
|
|
||||||
assertEquals(rgb, item0.getAttribute("red"));
|
|
||||||
assertEquals(rgb, item0.getAttribute("green"));
|
|
||||||
assertEquals(rgb, item0.getAttribute("blue"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: BackgroundIndex == 1??
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardCompressionRLE() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode compression = metadata.getStandardCompressionNode();
|
|
||||||
assertNotNull(compression);
|
|
||||||
assertEquals("Compression", compression.getNodeName());
|
|
||||||
assertEquals(2, compression.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode compressionTypeName = (IIOMetadataNode) compression.getFirstChild();
|
|
||||||
assertEquals("CompressionTypeName", compressionTypeName.getNodeName());
|
|
||||||
assertEquals("RLE", compressionTypeName.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode lossless = (IIOMetadataNode) compressionTypeName.getNextSibling();
|
|
||||||
assertEquals("Lossless", lossless.getNodeName());
|
|
||||||
assertEquals("TRUE", lossless.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(lossless.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardCompressionNone() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_NONE, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
assertNull(metadata.getStandardCompressionNode()); // No compression, all default...
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDataILBM_Gray() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
|
||||||
assertNotNull(data);
|
|
||||||
assertEquals("Data", data.getNodeName());
|
|
||||||
assertEquals(3, data.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode planarConfiguration = (IIOMetadataNode) data.getFirstChild();
|
|
||||||
assertEquals("PlanarConfiguration", planarConfiguration.getNodeName());
|
|
||||||
assertEquals("PlaneInterleaved", planarConfiguration.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode sampleFomat = (IIOMetadataNode) planarConfiguration.getNextSibling();
|
|
||||||
assertEquals("SampleFormat", sampleFomat.getNodeName());
|
|
||||||
assertEquals("UnsignedIntegral", sampleFomat.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) sampleFomat.getNextSibling();
|
|
||||||
assertEquals("BitsPerSample", bitsPerSample.getNodeName());
|
|
||||||
assertEquals("8", bitsPerSample.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(bitsPerSample.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDataILBM_RGB() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
|
||||||
assertNotNull(data);
|
|
||||||
assertEquals("Data", data.getNodeName());
|
|
||||||
assertEquals(3, data.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode planarConfiguration = (IIOMetadataNode) data.getFirstChild();
|
|
||||||
assertEquals("PlanarConfiguration", planarConfiguration.getNodeName());
|
|
||||||
assertEquals("PlaneInterleaved", planarConfiguration.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode sampleFomat = (IIOMetadataNode) planarConfiguration.getNextSibling();
|
|
||||||
assertEquals("SampleFormat", sampleFomat.getNodeName());
|
|
||||||
assertEquals("UnsignedIntegral", sampleFomat.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) sampleFomat.getNextSibling();
|
|
||||||
assertEquals("BitsPerSample", bitsPerSample.getNodeName());
|
|
||||||
assertEquals("8 8 8", bitsPerSample.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(bitsPerSample.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDataILBM_RGBA() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 32, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
|
||||||
assertNotNull(data);
|
|
||||||
assertEquals("Data", data.getNodeName());
|
|
||||||
assertEquals(3, data.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode planarConfiguration = (IIOMetadataNode) data.getFirstChild();
|
|
||||||
assertEquals("PlanarConfiguration", planarConfiguration.getNodeName());
|
|
||||||
assertEquals("PlaneInterleaved", planarConfiguration.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode sampleFomat = (IIOMetadataNode) planarConfiguration.getNextSibling();
|
|
||||||
assertEquals("SampleFormat", sampleFomat.getNodeName());
|
|
||||||
assertEquals("UnsignedIntegral", sampleFomat.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) sampleFomat.getNextSibling();
|
|
||||||
assertEquals("BitsPerSample", bitsPerSample.getNodeName());
|
|
||||||
assertEquals("8 8 8 8", bitsPerSample.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(bitsPerSample.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDataILBM_Palette() {
|
|
||||||
for (int i = 1; i <= 8; i++) {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, i, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
byte[] rgb = new byte[2 << i]; // Colors doesn't really matter here
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, new IndexColorModel(header.bitplanes, rgb.length, rgb, rgb, rgb, 0), null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
|
||||||
assertNotNull(data);
|
|
||||||
assertEquals("Data", data.getNodeName());
|
|
||||||
assertEquals(3, data.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode planarConfiguration = (IIOMetadataNode) data.getFirstChild();
|
|
||||||
assertEquals("PlanarConfiguration", planarConfiguration.getNodeName());
|
|
||||||
assertEquals("PlaneInterleaved", planarConfiguration.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode sampleFomat = (IIOMetadataNode) planarConfiguration.getNextSibling();
|
|
||||||
assertEquals("SampleFormat", sampleFomat.getNodeName());
|
|
||||||
assertEquals("Index", sampleFomat.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) sampleFomat.getNextSibling();
|
|
||||||
assertEquals("BitsPerSample", bitsPerSample.getNodeName());
|
|
||||||
assertEquals(String.valueOf(i), bitsPerSample.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(bitsPerSample.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDataPBM_Gray() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_PBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
|
||||||
assertNotNull(data);
|
|
||||||
assertEquals("Data", data.getNodeName());
|
|
||||||
assertEquals(3, data.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode planarConfiguration = (IIOMetadataNode) data.getFirstChild();
|
|
||||||
assertEquals("PlanarConfiguration", planarConfiguration.getNodeName());
|
|
||||||
assertEquals("PixelInterleaved", planarConfiguration.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode sampleFomat = (IIOMetadataNode) planarConfiguration.getNextSibling();
|
|
||||||
assertEquals("SampleFormat", sampleFomat.getNodeName());
|
|
||||||
assertEquals("UnsignedIntegral", sampleFomat.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) sampleFomat.getNextSibling();
|
|
||||||
assertEquals("BitsPerSample", bitsPerSample.getNodeName());
|
|
||||||
assertEquals("8", bitsPerSample.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(bitsPerSample.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDataPBM_RGB() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_PBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
|
||||||
assertNotNull(data);
|
|
||||||
assertEquals("Data", data.getNodeName());
|
|
||||||
assertEquals(3, data.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode planarConfiguration = (IIOMetadataNode) data.getFirstChild();
|
|
||||||
assertEquals("PlanarConfiguration", planarConfiguration.getNodeName());
|
|
||||||
assertEquals("PixelInterleaved", planarConfiguration.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode sampleFomat = (IIOMetadataNode) planarConfiguration.getNextSibling();
|
|
||||||
assertEquals("SampleFormat", sampleFomat.getNodeName());
|
|
||||||
assertEquals("UnsignedIntegral", sampleFomat.getAttribute("value"));
|
|
||||||
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) sampleFomat.getNextSibling();
|
|
||||||
assertEquals("BitsPerSample", bitsPerSample.getNodeName());
|
|
||||||
assertEquals("8 8 8", bitsPerSample.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(bitsPerSample.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDimensionNoViewport() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode dimension = metadata.getStandardDimensionNode();
|
|
||||||
assertNull(dimension);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDimensionNormal() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, new CAMGChunk(4), Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode dimension = metadata.getStandardDimensionNode();
|
|
||||||
assertNotNull(dimension);
|
|
||||||
assertEquals("Dimension", dimension.getNodeName());
|
|
||||||
assertEquals(1, dimension.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode pixelAspectRatio = (IIOMetadataNode) dimension.getFirstChild();
|
|
||||||
assertEquals("PixelAspectRatio", pixelAspectRatio.getNodeName());
|
|
||||||
assertEquals("1.0", pixelAspectRatio.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(pixelAspectRatio.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDimensionHires() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
CAMGChunk viewPort = new CAMGChunk(4);
|
|
||||||
viewPort.camg = 0x8000;
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, viewPort, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode dimension = metadata.getStandardDimensionNode();
|
|
||||||
assertNotNull(dimension);
|
|
||||||
assertEquals("Dimension", dimension.getNodeName());
|
|
||||||
assertEquals(1, dimension.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode pixelAspectRatio = (IIOMetadataNode) dimension.getFirstChild();
|
|
||||||
assertEquals("PixelAspectRatio", pixelAspectRatio.getNodeName());
|
|
||||||
assertEquals("2.0", pixelAspectRatio.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(pixelAspectRatio.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDimensionInterlaced() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
CAMGChunk viewPort = new CAMGChunk(4);
|
|
||||||
viewPort.camg = 0x4;
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, viewPort, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode dimension = metadata.getStandardDimensionNode();
|
|
||||||
assertNotNull(dimension);
|
|
||||||
assertEquals("Dimension", dimension.getNodeName());
|
|
||||||
assertEquals(1, dimension.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode pixelAspectRatio = (IIOMetadataNode) dimension.getFirstChild();
|
|
||||||
assertEquals("PixelAspectRatio", pixelAspectRatio.getNodeName());
|
|
||||||
assertEquals("0.5", pixelAspectRatio.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(pixelAspectRatio.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDimensionHiresInterlaced() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
CAMGChunk viewPort = new CAMGChunk(4);
|
|
||||||
viewPort.camg = 0x8004;
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, viewPort, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode dimension = metadata.getStandardDimensionNode();
|
|
||||||
assertNotNull(dimension);
|
|
||||||
assertEquals("Dimension", dimension.getNodeName());
|
|
||||||
assertEquals(1, dimension.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode pixelAspectRatio = (IIOMetadataNode) dimension.getFirstChild();
|
|
||||||
assertEquals("PixelAspectRatio", pixelAspectRatio.getNodeName());
|
|
||||||
assertEquals("1.0", pixelAspectRatio.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(pixelAspectRatio.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardDocument() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode document = metadata.getStandardDocumentNode();
|
|
||||||
assertNotNull(document);
|
|
||||||
assertEquals("Document", document.getNodeName());
|
|
||||||
assertEquals(1, document.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode pixelAspectRatio = (IIOMetadataNode) document.getFirstChild();
|
|
||||||
assertEquals("FormatVersion", pixelAspectRatio.getNodeName());
|
|
||||||
assertEquals("1.0", pixelAspectRatio.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(pixelAspectRatio.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardText() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
String[] texts = {"annotation", "äñnótâtïøñ"};
|
|
||||||
List<GenericChunk> meta = Arrays.asList(new GenericChunk(IFF.CHUNK_ANNO, texts[0].getBytes(StandardCharsets.US_ASCII)),
|
|
||||||
new GenericChunk(IFF.CHUNK_UTF8, texts[1].getBytes(StandardCharsets.UTF_8)));
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, meta);
|
|
||||||
|
|
||||||
IIOMetadataNode text = metadata.getStandardTextNode();
|
|
||||||
assertNotNull(text);
|
|
||||||
assertEquals("Text", text.getNodeName());
|
|
||||||
assertEquals(texts.length, text.getLength());
|
|
||||||
|
|
||||||
for (int i = 0; i < texts.length; i++) {
|
|
||||||
IIOMetadataNode textEntry = (IIOMetadataNode) text.item(i);
|
|
||||||
assertEquals("TextEntry", textEntry.getNodeName());
|
|
||||||
assertEquals(IFFUtil.toChunkStr(meta.get(i).chunkId), textEntry.getAttribute("keyword"));
|
|
||||||
assertEquals(texts[i], textEntry.getAttribute("value"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardTransparencyRGB() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode transparency = metadata.getStandardTransparencyNode();
|
|
||||||
assertNull(transparency); // No transparency, just defaults
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardTransparencyRGBA() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 32, BMHDChunk.MASK_HAS_MASK, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
|
||||||
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode transparency = metadata.getStandardTransparencyNode();
|
|
||||||
assertNotNull(transparency);
|
|
||||||
assertEquals("Transparency", transparency.getNodeName());
|
|
||||||
assertEquals(1, transparency.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode pixelAspectRatio = (IIOMetadataNode) transparency.getFirstChild();
|
|
||||||
assertEquals("Alpha", pixelAspectRatio.getNodeName());
|
|
||||||
assertEquals("nonpremultiplied", pixelAspectRatio.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(pixelAspectRatio.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testStandardTransparencyPalette() {
|
|
||||||
BMHDChunk header = new BMHDChunk(300, 200, 1, BMHDChunk.MASK_TRANSPARENT_COLOR, BMHDChunk.COMPRESSION_BYTE_RUN, 1);
|
|
||||||
|
|
||||||
byte[] bw = {0, (byte) 0xff};
|
|
||||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, new IndexColorModel(header.bitplanes, bw.length, bw, bw, bw, header.transparentIndex), null, Collections.<GenericChunk>emptyList());
|
|
||||||
|
|
||||||
IIOMetadataNode transparency = metadata.getStandardTransparencyNode();
|
|
||||||
assertNotNull(transparency);
|
|
||||||
assertEquals("Transparency", transparency.getNodeName());
|
|
||||||
assertEquals(1, transparency.getLength());
|
|
||||||
|
|
||||||
IIOMetadataNode pixelAspectRatio = (IIOMetadataNode) transparency.getFirstChild();
|
|
||||||
assertEquals("TransparentIndex", pixelAspectRatio.getNodeName());
|
|
||||||
assertEquals("1", pixelAspectRatio.getAttribute("value"));
|
|
||||||
|
|
||||||
assertNull(pixelAspectRatio.getNextSibling()); // No more children
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<?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.0</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>imageio-jpeg-jai-interop</artifactId>
|
|
||||||
<name>TwelveMonkeys :: ImageIO :: JPEG/JAI TIFF Interop</name>
|
|
||||||
<description>
|
|
||||||
Test JPEG plugin and JAI TIFF plugin interoperability
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.jaiinterop</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.jai-imageio</groupId>
|
|
||||||
<artifactId>jai-imageio-core</artifactId>
|
|
||||||
<version>1.3.0</version>
|
|
||||||
</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-jpeg</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
||||||
-121
@@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.jpeg.jaiinterop;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReaderSpi;
|
|
||||||
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.IIORegistry;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
|
||||||
import javax.imageio.spi.ServiceRegistry;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the JAI TIFFImageReader delegating to our JPEGImageReader.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
* @author last modified by $Author: haraldk$
|
|
||||||
* @version $Id: JAITIFFImageReaderInteroperabilityTest.java,v 1.0 08.05.12 15:25 haraldk Exp$
|
|
||||||
*/
|
|
||||||
public class JAITIFFImageReaderInteroperabilityTest extends ImageReaderAbstractTest<ImageReader> {
|
|
||||||
private static final String JAI_TIFF_PROVIDER_CLASS_NAME = "com.github.jaiimageio.impl.plugins.tiff.TIFFImageReaderSpi";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ImageReaderSpi createProvider() {
|
|
||||||
Iterator<ImageReaderSpi> providers = IIORegistry.getDefaultInstance().getServiceProviders(ImageReaderSpi.class, new ServiceRegistry.Filter() {
|
|
||||||
@Override
|
|
||||||
public boolean filter(final Object provider) {
|
|
||||||
return JAI_TIFF_PROVIDER_CLASS_NAME.equals(provider.getClass().getName());
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
if (providers.hasNext()) {
|
|
||||||
return providers.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<TestData> getTestData() {
|
|
||||||
return Arrays.asList(
|
|
||||||
new TestData(getClassLoaderResource("/tiff/foto_0001.tif"), new Dimension(1663, 2338)), // 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/jpeg-lossless-8bit-gray.tif"), new Dimension(512, 512)) // Lossless JPEG Gray, 8 bit/sample
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<String> getFormatNames() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<String> getSuffixes() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<String> getMIMETypes() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Fails in TIFFImageReader")
|
|
||||||
@Override
|
|
||||||
public void testSetDestinationIllegal() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReallyUsingOurJPEGImageReader() {
|
|
||||||
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JPEG");
|
|
||||||
|
|
||||||
if (readers.hasNext()) {
|
|
||||||
ImageReader reader = readers.next();
|
|
||||||
|
|
||||||
if ((reader.getOriginatingProvider() instanceof JPEGImageReaderSpi)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fail("Expected Spi not registered (dependency issue?): " + JPEGImageReaderSpi.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,39 +0,0 @@
|
|||||||
<?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.0</version>
|
|
||||||
</parent>
|
|
||||||
<artifactId>imageio-jpeg-jep262-interop</artifactId>
|
|
||||||
<name>TwelveMonkeys :: ImageIO :: JPEG/JEP-262 Interop</name>
|
|
||||||
<description>
|
|
||||||
Test JPEG plugin and JEP-262 (JDK TIFF plugin) interoperability
|
|
||||||
</description>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.jep262interop</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<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-jpeg</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
</project>
|
|
||||||
-125
@@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.jpeg.jep262interop;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReaderSpi;
|
|
||||||
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.IIORegistry;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
|
||||||
import javax.imageio.spi.ServiceRegistry;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
import static org.junit.Assume.assumeTrue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the JEP 262 TIFFImageReader delegating to our JPEGImageReader.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
* @author last modified by $Author: haraldk$
|
|
||||||
* @version $Id: TIFFImageReaderTest.java,v 1.0 08.05.12 15:25 haraldk Exp$
|
|
||||||
*/
|
|
||||||
public class JEP262TIFFImageReaderInteroperabilityTest extends ImageReaderAbstractTest<ImageReader> {
|
|
||||||
private static final String JEP_262_PROVIDER_CLASS_NAME = "com.sun.imageio.plugins.tiff.TIFFImageReaderSpi";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ImageReaderSpi createProvider() {
|
|
||||||
Iterator<ImageReaderSpi> providers = IIORegistry.getDefaultInstance().getServiceProviders(ImageReaderSpi.class, new ServiceRegistry.Filter() {
|
|
||||||
@Override
|
|
||||||
public boolean filter(final Object provider) {
|
|
||||||
return JEP_262_PROVIDER_CLASS_NAME.equals(provider.getClass().getName()) && ((ImageReaderSpi) provider).getVendorName().startsWith("Oracle");
|
|
||||||
}
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
if (providers.hasNext()) {
|
|
||||||
return providers.next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip tests if we have no Spi (ie. pre JDK 9)
|
|
||||||
assumeTrue("Provider " + JEP_262_PROVIDER_CLASS_NAME + " not found", false);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<TestData> getTestData() {
|
|
||||||
return Arrays.asList(
|
|
||||||
new TestData(getClassLoaderResource("/tiff/foto_0001.tif"), new Dimension(1663, 2338)), // 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/jpeg-lossless-8bit-gray.tif"), new Dimension(512, 512)) // Lossless JPEG Gray, 8 bit/sample
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<String> getFormatNames() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<String> getSuffixes() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<String> getMIMETypes() {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Ignore("Fails in TIFFImageReader")
|
|
||||||
@Override
|
|
||||||
public void testSetDestinationIllegal() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReallyUsingOurJPEGImageReader() {
|
|
||||||
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JPEG");
|
|
||||||
|
|
||||||
if (readers.hasNext()) {
|
|
||||||
ImageReader reader = readers.next();
|
|
||||||
|
|
||||||
if ((reader.getOriginatingProvider() instanceof JPEGImageReaderSpi)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fail("Expected Spi not registered (dependency issue?): " + JPEGImageReaderSpi.class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
BIN
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.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-jpeg</artifactId>
|
<artifactId>imageio-jpeg</artifactId>
|
||||||
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
|
||||||
@@ -12,10 +12,6 @@
|
|||||||
ImageIO plugin for Joint Photographer Expert Group images (JPEG/JFIF).
|
ImageIO plugin for Joint Photographer Expert Group images (JPEG/JFIF).
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.jpms.module.name>com.twelvemonkeys.imageio.jpeg</project.jpms.module.name>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
+2
-4
@@ -38,7 +38,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An application (APPn) segment in the JPEG stream.
|
* Application.
|
||||||
*
|
*
|
||||||
* @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: harald.kuhr$
|
* @author last modified by $Author: harald.kuhr$
|
||||||
@@ -78,9 +78,7 @@ class Application extends Segment {
|
|||||||
if ("JFXX".equals(identifier)) {
|
if ("JFXX".equals(identifier)) {
|
||||||
return JFXX.read(data, length);
|
return JFXX.read(data, length);
|
||||||
}
|
}
|
||||||
if ("Exif".equals(identifier)) {
|
// TODO: Exif?
|
||||||
return EXIF.read(data, length);
|
|
||||||
}
|
|
||||||
case JPEG.APP2:
|
case JPEG.APP2:
|
||||||
// ICC_PROFILE
|
// ICC_PROFILE
|
||||||
if ("ICC_PROFILE".equals(identifier)) {
|
if ("ICC_PROFILE".equals(identifier)) {
|
||||||
|
|||||||
-158
@@ -1,158 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012, 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.jpeg;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.color.YCbCrConverter;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
|
||||||
import com.twelvemonkeys.imageio.plugins.jpeg.ThumbnailReader.JPEGThumbnailReader;
|
|
||||||
import com.twelvemonkeys.imageio.plugins.jpeg.ThumbnailReader.UncompressedThumbnailReader;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EXIFThumbnail
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
* @author last modified by $Author: haraldk$
|
|
||||||
* @version $Id: EXIFThumbnail.java,v 1.0 18.04.12 12:19 haraldk Exp$
|
|
||||||
*/
|
|
||||||
final class EXIFThumbnail {
|
|
||||||
private EXIFThumbnail() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static ThumbnailReader from(final EXIF segment, final CompoundDirectory exif, final ImageReader jpegThumbnailReader) throws IOException {
|
|
||||||
if (segment != null && exif != null && exif.directoryCount() >= 2) {
|
|
||||||
ImageInputStream stream = segment.exifData(); // NOTE This is an in-memory stream and must not be closed...
|
|
||||||
|
|
||||||
Directory ifd1 = exif.getDirectory(1);
|
|
||||||
|
|
||||||
// Compression: 1 = no compression, 6 = JPEG compression (default)
|
|
||||||
Entry compressionEntry = ifd1.getEntryById(TIFF.TAG_COMPRESSION);
|
|
||||||
int compression = compressionEntry == null ? 6 : ((Number) compressionEntry.getValue()).intValue();
|
|
||||||
|
|
||||||
switch (compression) {
|
|
||||||
case 1:
|
|
||||||
return createUncompressedThumbnailReader(stream, ifd1);
|
|
||||||
case 6:
|
|
||||||
return createJPEGThumbnailReader(segment, jpegThumbnailReader, stream, ifd1);
|
|
||||||
default:
|
|
||||||
throw new IIOException("EXIF IFD with unknown thumbnail compression (expected 1 or 6): " + compression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static UncompressedThumbnailReader createUncompressedThumbnailReader(ImageInputStream stream, Directory ifd1) throws IOException {
|
|
||||||
Entry stripOffEntry = ifd1.getEntryById(TIFF.TAG_STRIP_OFFSETS);
|
|
||||||
Entry width = ifd1.getEntryById(TIFF.TAG_IMAGE_WIDTH);
|
|
||||||
Entry height = ifd1.getEntryById(TIFF.TAG_IMAGE_HEIGHT);
|
|
||||||
|
|
||||||
if (stripOffEntry != null && width != null && height != null) {
|
|
||||||
Entry bitsPerSample = ifd1.getEntryById(TIFF.TAG_BITS_PER_SAMPLE);
|
|
||||||
Entry samplesPerPixel = ifd1.getEntryById(TIFF.TAG_SAMPLES_PER_PIXEL);
|
|
||||||
Entry photometricInterpretation = ifd1.getEntryById(TIFF.TAG_PHOTOMETRIC_INTERPRETATION);
|
|
||||||
|
|
||||||
// Required
|
|
||||||
int w = ((Number) width.getValue()).intValue();
|
|
||||||
int h = ((Number) height.getValue()).intValue();
|
|
||||||
|
|
||||||
if (bitsPerSample != null && !Arrays.equals((int[]) bitsPerSample.getValue(), new int[] {8, 8, 8})) {
|
|
||||||
throw new IIOException("Unknown BitsPerSample value for uncompressed EXIF thumbnail (expected [8, 8, 8]): " + bitsPerSample.getValueAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (samplesPerPixel != null && ((Number) samplesPerPixel.getValue()).intValue() != 3) {
|
|
||||||
throw new IIOException("Unknown SamplesPerPixel value for uncompressed EXIF thumbnail (expected 3): " + samplesPerPixel.getValueAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
int interpretation = photometricInterpretation != null ? ((Number) photometricInterpretation.getValue()).intValue() : 2;
|
|
||||||
long stripOffset = ((Number) stripOffEntry.getValue()).longValue();
|
|
||||||
|
|
||||||
int thumbLength = w * h * 3;
|
|
||||||
if (stripOffset >= 0 && stripOffset + thumbLength <= stream.length()) {
|
|
||||||
// Read raw image data, either RGB or YCbCr
|
|
||||||
stream.seek(stripOffset);
|
|
||||||
byte[] thumbData = new byte[thumbLength];
|
|
||||||
stream.readFully(thumbData);
|
|
||||||
|
|
||||||
switch (interpretation) {
|
|
||||||
case 2:
|
|
||||||
// RGB
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
// YCbCr
|
|
||||||
for (int i = 0; i < thumbLength; i += 3) {
|
|
||||||
YCbCrConverter.convertYCbCr2RGB(thumbData, thumbData, i);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IIOException("Unknown PhotometricInterpretation value for uncompressed EXIF thumbnail (expected 2 or 6): " + interpretation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new UncompressedThumbnailReader(w, h, thumbData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IIOException("EXIF IFD with empty or incomplete uncompressed thumbnail");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static JPEGThumbnailReader createJPEGThumbnailReader(EXIF exif, ImageReader jpegThumbnailReader, ImageInputStream stream, Directory ifd1) throws IOException {
|
|
||||||
Entry jpegOffEntry = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
|
||||||
if (jpegOffEntry != null) {
|
|
||||||
Entry jpegLenEntry = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
|
||||||
|
|
||||||
// Test if Exif thumbnail is contained within the Exif segment (offset + length <= segment.length)
|
|
||||||
long jpegOffset = ((Number) jpegOffEntry.getValue()).longValue();
|
|
||||||
long jpegLength = jpegLenEntry != null ? ((Number) jpegLenEntry.getValue()).longValue() : -1;
|
|
||||||
|
|
||||||
if (jpegLength > 0 && jpegOffset + jpegLength <= exif.data.length) {
|
|
||||||
// Verify first bytes are FFD8
|
|
||||||
stream.seek(jpegOffset);
|
|
||||||
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
|
||||||
|
|
||||||
if (stream.readUnsignedShort() == JPEG.SOI) {
|
|
||||||
return new JPEGThumbnailReader(jpegThumbnailReader, stream, jpegOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IIOException("EXIF IFD with empty or incomplete JPEG thumbnail");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+248
@@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012, 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.jpeg;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.color.YCbCrConverter;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
||||||
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.SequenceInputStream;
|
||||||
|
import java.lang.ref.SoftReference;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EXIFThumbnail
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: EXIFThumbnail.java,v 1.0 18.04.12 12:19 haraldk Exp$
|
||||||
|
*/
|
||||||
|
final class EXIFThumbnailReader extends ThumbnailReader {
|
||||||
|
private final ImageReader reader;
|
||||||
|
private final Directory ifd;
|
||||||
|
private final ImageInputStream stream;
|
||||||
|
private final int compression;
|
||||||
|
|
||||||
|
private transient SoftReference<BufferedImage> cachedThumbnail;
|
||||||
|
|
||||||
|
EXIFThumbnailReader(final ThumbnailReadProgressListener progressListener, final ImageReader jpegReader, final int imageIndex, final int thumbnailIndex, final Directory ifd, final ImageInputStream stream) {
|
||||||
|
super(progressListener, imageIndex, thumbnailIndex);
|
||||||
|
this.reader = Validate.notNull(jpegReader);
|
||||||
|
this.ifd = ifd;
|
||||||
|
this.stream = stream;
|
||||||
|
|
||||||
|
Entry compression = ifd.getEntryById(TIFF.TAG_COMPRESSION);
|
||||||
|
|
||||||
|
this.compression = compression != null ? ((Number) compression.getValue()).intValue() : 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BufferedImage read() throws IOException {
|
||||||
|
if (compression == 1) { // 1 = no compression
|
||||||
|
processThumbnailStarted();
|
||||||
|
BufferedImage thumbnail = readUncompressed();
|
||||||
|
processThumbnailProgress(100f);
|
||||||
|
processThumbnailComplete();
|
||||||
|
|
||||||
|
return thumbnail;
|
||||||
|
}
|
||||||
|
else if (compression == 6) { // 6 = JPEG compression
|
||||||
|
processThumbnailStarted();
|
||||||
|
BufferedImage thumbnail = readJPEGCached(true);
|
||||||
|
processThumbnailProgress(100f);
|
||||||
|
processThumbnailComplete();
|
||||||
|
|
||||||
|
return thumbnail;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IIOException("Unsupported EXIF thumbnail compression: " + compression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage readJPEGCached(final boolean pixelsExposed) throws IOException {
|
||||||
|
BufferedImage thumbnail = cachedThumbnail != null ? cachedThumbnail.get() : null;
|
||||||
|
|
||||||
|
if (thumbnail == null) {
|
||||||
|
thumbnail = readJPEG();
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedThumbnail = pixelsExposed ? null : new SoftReference<>(thumbnail);
|
||||||
|
|
||||||
|
return thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage readJPEG() throws IOException {
|
||||||
|
// IFD1 should contain JPEG offset for JPEG thumbnail
|
||||||
|
Entry jpegOffset = ifd.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||||
|
|
||||||
|
if (jpegOffset != null) {
|
||||||
|
stream.seek(((Number) jpegOffset.getValue()).longValue());
|
||||||
|
InputStream input = IIOUtil.createStreamAdapter(stream);
|
||||||
|
|
||||||
|
// For certain EXIF files (encoded with TIFF.TAG_YCBCR_POSITIONING = 2?), we need
|
||||||
|
// EXIF information to read the thumbnail correctly (otherwise the colors are messed up).
|
||||||
|
// Probably related to: http://bugs.sun.com/view_bug.do?bug_id=4881314
|
||||||
|
|
||||||
|
// HACK: Splice empty EXIF information into the thumbnail stream
|
||||||
|
byte[] fakeEmptyExif = {
|
||||||
|
// SOI (from original data)
|
||||||
|
(byte) input.read(), (byte) input.read(),
|
||||||
|
// APP1 + len (016) + 'Exif' + 0-term + pad
|
||||||
|
(byte) 0xFF, (byte) 0xE1, 0, 16, 'E', 'x', 'i', 'f', 0, 0,
|
||||||
|
// Big-endian BOM (MM), TIFF magic (042), offset (0000)
|
||||||
|
'M', 'M', 0, 42, 0, 0, 0, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
input = new SequenceInputStream(new ByteArrayInputStream(fakeEmptyExif), input);
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
try (MemoryCacheImageInputStream stream = new MemoryCacheImageInputStream(input)) {
|
||||||
|
return readJPEGThumbnail(reader, stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IIOException("Missing JPEGInterchangeFormat tag for JPEG compressed EXIF thumbnail");
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage readUncompressed() throws IOException {
|
||||||
|
// Read ImageWidth, ImageLength (height) and BitsPerSample (=8 8 8, always)
|
||||||
|
// PhotometricInterpretation (2=RGB, 6=YCbCr), SamplesPerPixel (=3, always),
|
||||||
|
Entry width = ifd.getEntryById(TIFF.TAG_IMAGE_WIDTH);
|
||||||
|
Entry height = ifd.getEntryById(TIFF.TAG_IMAGE_HEIGHT);
|
||||||
|
|
||||||
|
if (width == null || height == null) {
|
||||||
|
throw new IIOException("Missing dimensions for uncompressed EXIF thumbnail");
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry bitsPerSample = ifd.getEntryById(TIFF.TAG_BITS_PER_SAMPLE);
|
||||||
|
Entry samplesPerPixel = ifd.getEntryById(TIFF.TAG_SAMPLES_PER_PIXEL);
|
||||||
|
Entry photometricInterpretation = ifd.getEntryById(TIFF.TAG_PHOTOMETRIC_INTERPRETATION);
|
||||||
|
|
||||||
|
// Required
|
||||||
|
int w = ((Number) width.getValue()).intValue();
|
||||||
|
int h = ((Number) height.getValue()).intValue();
|
||||||
|
|
||||||
|
if (bitsPerSample != null) {
|
||||||
|
int[] bpp = (int[]) bitsPerSample.getValue();
|
||||||
|
if (!Arrays.equals(bpp, new int[] {8, 8, 8})) {
|
||||||
|
throw new IIOException("Unknown BitsPerSample value for uncompressed EXIF thumbnail (expected [8, 8, 8]): " + bitsPerSample.getValueAsString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (samplesPerPixel != null && (Integer) samplesPerPixel.getValue() != 3) {
|
||||||
|
throw new IIOException("Unknown SamplesPerPixel value for uncompressed EXIF thumbnail (expected 3): " + samplesPerPixel.getValueAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
int interpretation = photometricInterpretation != null ? ((Number) photometricInterpretation.getValue()).intValue() : 2;
|
||||||
|
|
||||||
|
// IFD1 should contain strip offsets for uncompressed images
|
||||||
|
Entry offset = ifd.getEntryById(TIFF.TAG_STRIP_OFFSETS);
|
||||||
|
if (offset != null) {
|
||||||
|
stream.seek(((Number) offset.getValue()).longValue());
|
||||||
|
|
||||||
|
// Read raw image data, either RGB or YCbCr
|
||||||
|
int thumbSize = w * h * 3;
|
||||||
|
byte[] thumbData = JPEGImageReader.readFully(stream, thumbSize);
|
||||||
|
|
||||||
|
switch (interpretation) {
|
||||||
|
case 2:
|
||||||
|
// RGB
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
// YCbCr
|
||||||
|
for (int i = 0; i < thumbSize; i += 3) {
|
||||||
|
YCbCrConverter.convertYCbCr2RGB(thumbData, thumbData, i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IIOException("Unknown PhotometricInterpretation value for uncompressed EXIF thumbnail (expected 2 or 6): " + interpretation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ThumbnailReader.readRawThumbnail(thumbData, thumbSize, 0, w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IIOException("Missing StripOffsets tag for uncompressed EXIF thumbnail");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() throws IOException {
|
||||||
|
if (compression == 1) { // 1 = no compression
|
||||||
|
Entry width = ifd.getEntryById(TIFF.TAG_IMAGE_WIDTH);
|
||||||
|
|
||||||
|
if (width == null) {
|
||||||
|
throw new IIOException("Missing dimensions for uncompressed EXIF thumbnail");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((Number) width.getValue()).intValue();
|
||||||
|
}
|
||||||
|
else if (compression == 6) { // 6 = JPEG compression
|
||||||
|
return readJPEGCached(false).getWidth();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IIOException("Unsupported EXIF thumbnail compression (expected 1 or 6): " + compression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() throws IOException {
|
||||||
|
if (compression == 1) { // 1 = no compression
|
||||||
|
Entry height = ifd.getEntryById(TIFF.TAG_IMAGE_HEIGHT);
|
||||||
|
|
||||||
|
if (height == null) {
|
||||||
|
throw new IIOException("Missing dimensions for uncompressed EXIF thumbnail");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((Number) height.getValue()).intValue();
|
||||||
|
}
|
||||||
|
else if (compression == 6) { // 6 = JPEG compression
|
||||||
|
return readJPEGCached(false).getHeight();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IIOException("Unsupported EXIF thumbnail compression (expected 1 or 6): " + compression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-7
@@ -62,7 +62,6 @@ class FastCMYKToRGB implements /*BufferedImageOp,*/ RasterOp {
|
|||||||
* @return {@code dest}, or a new {@link WritableRaster} if {@code dest} is {@code null}.
|
* @return {@code dest}, or a new {@link WritableRaster} if {@code dest} is {@code null}.
|
||||||
* @throws IllegalArgumentException if {@code src} and {@code dest} refer to the same object
|
* @throws IllegalArgumentException if {@code src} and {@code dest} refer to the same object
|
||||||
*/
|
*/
|
||||||
@Override
|
|
||||||
public WritableRaster filter(Raster src, WritableRaster dest) {
|
public WritableRaster filter(Raster src, WritableRaster dest) {
|
||||||
Validate.notNull(src, "src may not be null");
|
Validate.notNull(src, "src may not be null");
|
||||||
// TODO: Why not allow same raster, if converting to 4 byte ABGR?
|
// TODO: Why not allow same raster, if converting to 4 byte ABGR?
|
||||||
@@ -143,12 +142,10 @@ class FastCMYKToRGB implements /*BufferedImageOp,*/ RasterOp {
|
|||||||
rgb[2] = (byte) (255 - (((cmyk[2] & 0xFF) * (255 - k) / 255) + k));
|
rgb[2] = (byte) (255 - (((cmyk[2] & 0xFF) * (255 - k) / 255) + k));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Rectangle2D getBounds2D(Raster src) {
|
public Rectangle2D getBounds2D(Raster src) {
|
||||||
return src.getBounds();
|
return src.getBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public WritableRaster createCompatibleDestRaster(final Raster src) {
|
public WritableRaster createCompatibleDestRaster(final Raster src) {
|
||||||
// WHAT?? This code no longer work for JRE 7u45+... JRE bug?!
|
// WHAT?? This code no longer work for JRE 7u45+... JRE bug?!
|
||||||
// Raster child = src.createChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, new int[] {0, 1, 2});
|
// Raster child = src.createChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, new int[] {0, 1, 2});
|
||||||
@@ -156,11 +153,10 @@ class FastCMYKToRGB implements /*BufferedImageOp,*/ RasterOp {
|
|||||||
|
|
||||||
// This is a workaround for the above code that no longer works.
|
// This is a workaround for the above code that no longer works.
|
||||||
// It wil use 25% more memory, but it seems to work...
|
// It wil use 25% more memory, but it seems to work...
|
||||||
return src.createCompatibleWritableRaster()
|
WritableRaster raster = src.createCompatibleWritableRaster();
|
||||||
.createWritableChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, new int[] {0, 1, 2});
|
return raster.createWritableChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, new int[] {0, 1, 2});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
|
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
|
||||||
if (dstPt == null) {
|
if (dstPt == null) {
|
||||||
dstPt = new Point2D.Double(srcPt.getX(), srcPt.getY());
|
dstPt = new Point2D.Double(srcPt.getX(), srcPt.getY());
|
||||||
@@ -172,7 +168,6 @@ class FastCMYKToRGB implements /*BufferedImageOp,*/ RasterOp {
|
|||||||
return dstPt;
|
return dstPt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public RenderingHints getRenderingHints() {
|
public RenderingHints getRenderingHints() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import java.io.IOException;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JFIF segment.
|
* JFIFSegment
|
||||||
*
|
*
|
||||||
* @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$
|
||||||
@@ -54,8 +54,8 @@ final class JFIF extends Application {
|
|||||||
final int yThumbnail;
|
final int yThumbnail;
|
||||||
final byte[] thumbnail;
|
final byte[] thumbnail;
|
||||||
|
|
||||||
JFIF(int majorVersion, int minorVersion, int units, int xDensity, int yDensity, int xThumbnail, int yThumbnail, byte[] thumbnail) {
|
private JFIF(int majorVersion, int minorVersion, int units, int xDensity, int yDensity, int xThumbnail, int yThumbnail, byte[] thumbnail, byte[] data) {
|
||||||
super(JPEG.APP0, "JFIF", new byte[5 + 9 + (thumbnail != null ? thumbnail.length : 0)]);
|
super(JPEG.APP0, "JFIF", data);
|
||||||
|
|
||||||
this.majorVersion = majorVersion;
|
this.majorVersion = majorVersion;
|
||||||
this.minorVersion = minorVersion;
|
this.minorVersion = minorVersion;
|
||||||
@@ -98,7 +98,7 @@ final class JFIF extends Application {
|
|||||||
throw new EOFException();
|
throw new EOFException();
|
||||||
}
|
}
|
||||||
|
|
||||||
data.readFully(new byte[5]); // Skip "JFIF\0"
|
data.readFully(new byte[5]);
|
||||||
|
|
||||||
byte[] bytes = new byte[length - 2 - 5];
|
byte[] bytes = new byte[length - 2 - 5];
|
||||||
data.readFully(bytes);
|
data.readFully(bytes);
|
||||||
@@ -115,7 +115,8 @@ final class JFIF extends Application {
|
|||||||
buffer.getShort() & 0xffff,
|
buffer.getShort() & 0xffff,
|
||||||
x = buffer.get() & 0xff,
|
x = buffer.get() & 0xff,
|
||||||
y = buffer.get() & 0xff,
|
y = buffer.get() & 0xff,
|
||||||
getBytes(buffer, Math.min(buffer.remaining(), x * y * 3))
|
getBytes(buffer, Math.min(buffer.remaining(), x * y * 3)),
|
||||||
|
bytes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+23
-27
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Harald Kuhr
|
* Copyright (c) 2012, Harald Kuhr
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@@ -30,45 +30,41 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import java.awt.image.BufferedImage;
|
||||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.DataInput;
|
|
||||||
import java.io.EOFException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An EXIF segment.
|
* JFIFThumbnailReader
|
||||||
*
|
*
|
||||||
* @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: JFIFSegment.java,v 1.0 23.04.12 16:52 haraldk Exp$
|
* @version $Id: JFIFThumbnailReader.java,v 1.0 18.04.12 12:19 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
final class EXIF extends Application {
|
final class JFIFThumbnailReader extends ThumbnailReader {
|
||||||
EXIF(byte[] data) {
|
private final JFIF segment;
|
||||||
super(JPEG.APP1, "Exif", data);
|
|
||||||
|
JFIFThumbnailReader(final ThumbnailReadProgressListener progressListener, final int imageIndex, final int thumbnailIndex, final JFIF segment) {
|
||||||
|
super(progressListener, imageIndex, thumbnailIndex);
|
||||||
|
this.segment = segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public BufferedImage read() {
|
||||||
return String.format("APP1/Exif, length: %d", data.length);
|
processThumbnailStarted();
|
||||||
|
BufferedImage thumbnail = readRawThumbnail(segment.thumbnail, segment.thumbnail.length, 0, segment.xThumbnail, segment.yThumbnail);
|
||||||
|
processThumbnailProgress(100f);
|
||||||
|
processThumbnailComplete();
|
||||||
|
|
||||||
|
return thumbnail;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageInputStream exifData() {
|
@Override
|
||||||
// Identifier is "Exif\0" + 1 byte pad
|
public int getWidth() throws IOException {
|
||||||
int offset = identifier.length() + 2;
|
return segment.xThumbnail;
|
||||||
return new ByteArrayImageInputStream(data, offset, data.length - offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EXIF read(final DataInput data, int length) throws IOException {
|
@Override
|
||||||
if (length < 2 + 6) {
|
public int getHeight() throws IOException {
|
||||||
throw new EOFException();
|
return segment.yThumbnail;
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bytes = new byte[length - 2];
|
|
||||||
data.readFully(bytes);
|
|
||||||
|
|
||||||
return new EXIF(bytes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ import java.io.IOException;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JFXX segment (aka JFIF extension segment).
|
* JFXXSegment
|
||||||
*
|
*
|
||||||
* @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$
|
||||||
@@ -49,8 +49,8 @@ final class JFXX extends Application {
|
|||||||
final int extensionCode;
|
final int extensionCode;
|
||||||
final byte[] thumbnail;
|
final byte[] thumbnail;
|
||||||
|
|
||||||
JFXX(final int extensionCode, final byte[] thumbnail) {
|
private JFXX(final int extensionCode, final byte[] thumbnail, final byte[] data) {
|
||||||
super(com.twelvemonkeys.imageio.metadata.jpeg.JPEG.APP0, "JFXX", new byte[1 + (thumbnail != null ? thumbnail.length : 0)]);
|
super(com.twelvemonkeys.imageio.metadata.jpeg.JPEG.APP0, "JFXX", data);
|
||||||
|
|
||||||
this.extensionCode = extensionCode;
|
this.extensionCode = extensionCode;
|
||||||
this.thumbnail = thumbnail;
|
this.thumbnail = thumbnail;
|
||||||
@@ -82,7 +82,8 @@ final class JFXX extends Application {
|
|||||||
|
|
||||||
return new JFXX(
|
return new JFXX(
|
||||||
bytes[0] & 0xff,
|
bytes[0] & 0xff,
|
||||||
bytes.length - 1 > 0 ? Arrays.copyOfRange(bytes, 1, bytes.length - 1) : null
|
bytes.length - 1 > 0 ? Arrays.copyOfRange(bytes, 1, bytes.length - 1) : null,
|
||||||
|
bytes
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-96
@@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2012, 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.jpeg;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
|
||||||
import com.twelvemonkeys.imageio.plugins.jpeg.ThumbnailReader.IndexedThumbnailReader;
|
|
||||||
import com.twelvemonkeys.imageio.plugins.jpeg.ThumbnailReader.JPEGThumbnailReader;
|
|
||||||
import com.twelvemonkeys.imageio.plugins.jpeg.ThumbnailReader.UncompressedThumbnailReader;
|
|
||||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JFXXThumbnailReader
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
* @author last modified by $Author: haraldk$
|
|
||||||
* @version $Id: JFXXThumbnailReader.java,v 1.0 18.04.12 12:19 haraldk Exp$
|
|
||||||
*/
|
|
||||||
final class JFXXThumbnail {
|
|
||||||
|
|
||||||
private JFXXThumbnail() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static ThumbnailReader from(final JFXX segment, final ImageReader thumbnailReader) throws IOException {
|
|
||||||
if (segment != null) {
|
|
||||||
if (segment.thumbnail != null && segment.thumbnail.length > 2) {
|
|
||||||
switch (segment.extensionCode) {
|
|
||||||
case JFXX.JPEG:
|
|
||||||
if (((segment.thumbnail[0] & 0xff) << 8 | segment.thumbnail[1] & 0xff) == JPEG.SOI) {
|
|
||||||
return new JPEGThumbnailReader(thumbnailReader, new ByteArrayImageInputStream(segment.thumbnail), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JFXX.INDEXED:
|
|
||||||
int w = segment.thumbnail[0] & 0xff;
|
|
||||||
int h = segment.thumbnail[1] & 0xff;
|
|
||||||
|
|
||||||
if (segment.thumbnail.length >= 2 + 768 + w * h) {
|
|
||||||
return new IndexedThumbnailReader(w, h, segment.thumbnail, 2, segment.thumbnail, 2 + 768);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JFXX.RGB:
|
|
||||||
w = segment.thumbnail[0] & 0xff;
|
|
||||||
h = segment.thumbnail[1] & 0xff;
|
|
||||||
|
|
||||||
if (segment.thumbnail.length >= 2 + w * h * 3) {
|
|
||||||
return new UncompressedThumbnailReader(w, h, segment.thumbnail, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IIOException(String.format("Unknown JFXX extension code: %d, ignoring thumbnail", segment.extensionCode));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IIOException("JFXX segment truncated, ignoring thumbnail");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+178
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2012, 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.jpeg;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.image.InverseColorMapIndexColorModel;
|
||||||
|
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||||
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.awt.image.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.SoftReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JFXXThumbnailReader
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: JFXXThumbnailReader.java,v 1.0 18.04.12 12:19 haraldk Exp$
|
||||||
|
*/
|
||||||
|
final class JFXXThumbnailReader extends ThumbnailReader {
|
||||||
|
|
||||||
|
private final ImageReader reader;
|
||||||
|
private final JFXX segment;
|
||||||
|
|
||||||
|
private transient SoftReference<BufferedImage> cachedThumbnail;
|
||||||
|
|
||||||
|
JFXXThumbnailReader(final ThumbnailReadProgressListener progressListener, final ImageReader jpegReader, final int imageIndex, final int thumbnailIndex, final JFXX segment) {
|
||||||
|
super(progressListener, imageIndex, thumbnailIndex);
|
||||||
|
this.reader = Validate.notNull(jpegReader);
|
||||||
|
this.segment = segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BufferedImage read() throws IOException {
|
||||||
|
processThumbnailStarted();
|
||||||
|
|
||||||
|
BufferedImage thumbnail;
|
||||||
|
switch (segment.extensionCode) {
|
||||||
|
case JFXX.JPEG:
|
||||||
|
thumbnail = readJPEGCached(true);
|
||||||
|
break;
|
||||||
|
case JFXX.INDEXED:
|
||||||
|
thumbnail = readIndexed();
|
||||||
|
break;
|
||||||
|
case JFXX.RGB:
|
||||||
|
thumbnail = readRGB();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IIOException(String.format("Unsupported JFXX extension code: %d", segment.extensionCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
processThumbnailProgress(100f);
|
||||||
|
processThumbnailComplete();
|
||||||
|
|
||||||
|
return thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
|
IIOMetadata readMetadata() throws IOException {
|
||||||
|
ImageInputStream input = new ByteArrayImageInputStream(segment.thumbnail);
|
||||||
|
|
||||||
|
try {
|
||||||
|
reader.setInput(input);
|
||||||
|
|
||||||
|
return reader.getImageMetadata(0);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage readJPEGCached(boolean pixelsExposed) throws IOException {
|
||||||
|
BufferedImage thumbnail = cachedThumbnail != null ? cachedThumbnail.get() : null;
|
||||||
|
|
||||||
|
if (thumbnail == null) {
|
||||||
|
ImageInputStream stream = new ByteArrayImageInputStream(segment.thumbnail);
|
||||||
|
try {
|
||||||
|
thumbnail = readJPEGThumbnail(reader, stream);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedThumbnail = pixelsExposed ? null : new SoftReference<>(thumbnail);
|
||||||
|
|
||||||
|
return thumbnail;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth() throws IOException {
|
||||||
|
switch (segment.extensionCode) {
|
||||||
|
case JFXX.RGB:
|
||||||
|
case JFXX.INDEXED:
|
||||||
|
return segment.thumbnail[0] & 0xff;
|
||||||
|
case JFXX.JPEG:
|
||||||
|
return readJPEGCached(false).getWidth();
|
||||||
|
default:
|
||||||
|
throw new IIOException(String.format("Unsupported JFXX extension code: %d", segment.extensionCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() throws IOException {
|
||||||
|
switch (segment.extensionCode) {
|
||||||
|
case JFXX.RGB:
|
||||||
|
case JFXX.INDEXED:
|
||||||
|
return segment.thumbnail[1] & 0xff;
|
||||||
|
case JFXX.JPEG:
|
||||||
|
return readJPEGCached(false).getHeight();
|
||||||
|
default:
|
||||||
|
throw new IIOException(String.format("Unsupported JFXX extension code: %d", segment.extensionCode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage readIndexed() {
|
||||||
|
// 1 byte: xThumb
|
||||||
|
// 1 byte: yThumb
|
||||||
|
// 768 bytes: palette
|
||||||
|
// x * y bytes: 8 bit indexed pixels
|
||||||
|
int w = segment.thumbnail[0] & 0xff;
|
||||||
|
int h = segment.thumbnail[1] & 0xff;
|
||||||
|
|
||||||
|
int[] rgbs = new int[256];
|
||||||
|
for (int i = 0; i < rgbs.length; i++) {
|
||||||
|
rgbs[i] = (segment.thumbnail[3 * i + 2] & 0xff) << 16
|
||||||
|
| (segment.thumbnail[3 * i + 3] & 0xff) << 8
|
||||||
|
| (segment.thumbnail[3 * i + 4] & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexColorModel icm = new InverseColorMapIndexColorModel(8, rgbs.length, rgbs, 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||||
|
DataBufferByte buffer = new DataBufferByte(segment.thumbnail, segment.thumbnail.length - 770, 770);
|
||||||
|
WritableRaster raster = Raster.createPackedRaster(buffer, w, h, 8, null);
|
||||||
|
|
||||||
|
return new BufferedImage(icm, raster, icm.isAlphaPremultiplied(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BufferedImage readRGB() {
|
||||||
|
// 1 byte: xThumb
|
||||||
|
// 1 byte: yThumb
|
||||||
|
// 3 * x * y bytes: 24 bit RGB pixels
|
||||||
|
int w = segment.thumbnail[0] & 0xff;
|
||||||
|
int h = segment.thumbnail[1] & 0xff;
|
||||||
|
|
||||||
|
return ThumbnailReader.readRawThumbnail(segment.thumbnail, segment.thumbnail.length - 2, 2, w, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-2
@@ -32,7 +32,6 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
|
|||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
import com.twelvemonkeys.xml.XMLSerializer;
|
import com.twelvemonkeys.xml.XMLSerializer;
|
||||||
|
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
@@ -133,7 +132,7 @@ final class JPEGImage10MetadataCleaner {
|
|||||||
IIOMetadataNode app0JFXX = new IIOMetadataNode("app0JFXX");
|
IIOMetadataNode app0JFXX = new IIOMetadataNode("app0JFXX");
|
||||||
app0JFXX.setAttribute("extensionCode", String.valueOf(jfxx.extensionCode));
|
app0JFXX.setAttribute("extensionCode", String.valueOf(jfxx.extensionCode));
|
||||||
|
|
||||||
ThumbnailReader thumbnailReader = JFXXThumbnail.from(jfxx, reader.getThumbnailReader());
|
JFXXThumbnailReader thumbnailReader = new JFXXThumbnailReader(null, reader.getThumbnailReader(), 0, 0, jfxx);
|
||||||
IIOMetadataNode jfifThumb;
|
IIOMetadataNode jfifThumb;
|
||||||
|
|
||||||
switch (jfxx.extensionCode) {
|
switch (jfxx.extensionCode) {
|
||||||
|
|||||||
+255
-182
@@ -34,10 +34,14 @@ import com.twelvemonkeys.imageio.ImageReaderBase;
|
|||||||
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||||
import com.twelvemonkeys.imageio.color.YCbCrConverter;
|
import com.twelvemonkeys.imageio.color.YCbCrConverter;
|
||||||
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
||||||
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
||||||
|
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
@@ -58,6 +62,7 @@ import java.awt.color.ICC_ColorSpace;
|
|||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -194,38 +199,73 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
|
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
|
||||||
ImageTypeSpecifier rawImageType = getRawImageType(imageIndex);
|
checkBounds(imageIndex);
|
||||||
ColorModel rawColorModel = rawImageType.getColorModel();
|
initHeader(imageIndex);
|
||||||
JPEGColorSpace sourceCSType = getSourceCSType(getJFIF(), getAdobeDCT(), getSOF());
|
|
||||||
|
|
||||||
Set<ImageTypeSpecifier> types = new LinkedHashSet<>();
|
Iterator<ImageTypeSpecifier> types;
|
||||||
|
try {
|
||||||
if (rawColorModel.getColorSpace().getType() != ColorSpace.TYPE_GRAY) {
|
types = delegate.getImageTypes(0);
|
||||||
// Add the standard types, we can always convert to these, except for gray
|
}
|
||||||
if (rawColorModel.hasAlpha()) {
|
catch (IndexOutOfBoundsException | NegativeArraySizeException ignore) {
|
||||||
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB));
|
types = null;
|
||||||
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR));
|
|
||||||
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB_PRE));
|
|
||||||
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR_PRE));
|
|
||||||
}
|
|
||||||
|
|
||||||
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR));
|
|
||||||
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB));
|
|
||||||
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_BGR));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
types.add(rawImageType);
|
JPEGColorSpace csType = getSourceCSType(getJFIF(), getAdobeDCT(), getSOF());
|
||||||
|
|
||||||
// If the source type has a luminance (Y) component, we can also convert to gray
|
if (types == null || !types.hasNext() || csType == JPEGColorSpace.CMYK || csType == JPEGColorSpace.YCCK) {
|
||||||
if (sourceCSType != JPEGColorSpace.RGB && sourceCSType != JPEGColorSpace.RGBA && sourceCSType != JPEGColorSpace.CMYK) {
|
ArrayList<ImageTypeSpecifier> typeList = new ArrayList<>();
|
||||||
if (rawColorModel.hasAlpha()) {
|
// Add the standard types, we can always convert to these
|
||||||
types.add(ImageTypeSpecifiers.createGrayscale(8, DataBuffer.TYPE_BYTE, false));
|
typeList.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR));
|
||||||
|
typeList.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB));
|
||||||
|
typeList.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_BGR));
|
||||||
|
|
||||||
|
// We also read and return CMYK if the source image is CMYK/YCCK + original color profile if present
|
||||||
|
ICC_Profile profile = getEmbeddedICCProfile(false);
|
||||||
|
|
||||||
|
if (csType == JPEGColorSpace.CMYK || csType == JPEGColorSpace.YCCK) {
|
||||||
|
if (profile != null && profile.getNumComponents() == 4) {
|
||||||
|
typeList.add(ImageTypeSpecifiers.createInterleaved(ColorSpaces.createColorSpace(profile), new int[] {3, 2, 1, 0}, DataBuffer.TYPE_BYTE, false, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
typeList.add(ImageTypeSpecifiers.createInterleaved(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), new int[] {3, 2, 1, 0}, DataBuffer.TYPE_BYTE, false, false));
|
||||||
|
}
|
||||||
|
else if (csType == JPEGColorSpace.YCbCr || csType == JPEGColorSpace.RGB) {
|
||||||
|
if (profile != null && profile.getNumComponents() == 3) {
|
||||||
|
typeList.add(ImageTypeSpecifiers.createInterleaved(ColorSpaces.createColorSpace(profile), new int[] {0, 1, 2}, DataBuffer.TYPE_BYTE, false, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (csType == JPEGColorSpace.YCbCrA || csType == JPEGColorSpace.RGBA) {
|
||||||
|
// Prepend ARGB types
|
||||||
|
typeList.addAll(0, Arrays.asList(
|
||||||
|
ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB),
|
||||||
|
ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR),
|
||||||
|
ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB_PRE),
|
||||||
|
ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR_PRE)
|
||||||
|
));
|
||||||
|
|
||||||
|
if (profile != null && profile.getNumComponents() == 3) {
|
||||||
|
typeList.add(ImageTypeSpecifiers.createInterleaved(ColorSpaces.createColorSpace(profile), new int[] {0, 1, 2, 3}, DataBuffer.TYPE_BYTE, true, false));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
types.add(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY));
|
return typeList.iterator();
|
||||||
|
}
|
||||||
|
else if (csType == JPEGColorSpace.RGB) {
|
||||||
|
// Bug in com.sun...JPEGImageReader: returns gray as acceptable type, but refuses to convert
|
||||||
|
ArrayList<ImageTypeSpecifier> typeList = new ArrayList<>();
|
||||||
|
|
||||||
|
// Filter out the gray type
|
||||||
|
while (types.hasNext()) {
|
||||||
|
ImageTypeSpecifier type = types.next();
|
||||||
|
if (type.getBufferedImageType() != BufferedImage.TYPE_BYTE_GRAY) {
|
||||||
|
typeList.add(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeList.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
return types.iterator();
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -233,55 +273,34 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
checkBounds(imageIndex);
|
checkBounds(imageIndex);
|
||||||
initHeader(imageIndex);
|
initHeader(imageIndex);
|
||||||
|
|
||||||
// Consult the image metadata
|
// If delegate can determine the spec, we'll just go with that
|
||||||
JPEGColorSpace csType = getSourceCSType(getJFIF(), getAdobeDCT(), getSOF());
|
try {
|
||||||
ICC_Profile profile = getEmbeddedICCProfile(false);
|
ImageTypeSpecifier rawType = delegate.getRawImageType(0);
|
||||||
|
|
||||||
ColorSpace cs;
|
if (rawType != null) {
|
||||||
boolean hasAlpha = false;
|
return rawType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IIOException | NullPointerException | ArrayIndexOutOfBoundsException | NegativeArraySizeException ignore) {
|
||||||
|
// Fall through
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, consult the image metadata
|
||||||
|
JPEGColorSpace csType = getSourceCSType(getJFIF(), getAdobeDCT(), getSOF());
|
||||||
|
|
||||||
switch (csType) {
|
switch (csType) {
|
||||||
case GrayA:
|
|
||||||
hasAlpha = true;
|
|
||||||
case Gray:
|
|
||||||
// Create based on embedded profile if exists, otherwise create from Gray
|
|
||||||
cs = profile != null && profile.getNumComponents() == 1
|
|
||||||
? ColorSpaces.createColorSpace(profile)
|
|
||||||
: ColorSpaces.getColorSpace(ColorSpace.CS_GRAY);
|
|
||||||
return ImageTypeSpecifiers.createInterleaved(cs, hasAlpha ? new int[] {1, 0} : new int[] {0}, DataBuffer.TYPE_BYTE, hasAlpha, false);
|
|
||||||
|
|
||||||
case YCbCrA:
|
|
||||||
case RGBA:
|
|
||||||
case PhotoYCCA:
|
|
||||||
hasAlpha = true;
|
|
||||||
case YCbCr:
|
|
||||||
case RGB:
|
|
||||||
case PhotoYCC:
|
|
||||||
// Create based on PhotoYCC profile...
|
|
||||||
if (csType == JPEGColorSpace.PhotoYCC || csType == JPEGColorSpace.PhotoYCCA) {
|
|
||||||
cs = ColorSpaces.getColorSpace(ColorSpace.CS_PYCC);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// ...or create based on embedded profile if exists, otherwise create from sRGB
|
|
||||||
cs = profile != null && profile.getNumComponents() == 3
|
|
||||||
? ColorSpaces.createColorSpace(profile)
|
|
||||||
: ColorSpaces.getColorSpace(ColorSpace.CS_sRGB);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ImageTypeSpecifiers.createInterleaved(cs, hasAlpha ? new int[] {3, 2, 1, 0} : new int[] {2, 1, 0}, DataBuffer.TYPE_BYTE, hasAlpha, false);
|
|
||||||
|
|
||||||
case YCCK:
|
|
||||||
case CMYK:
|
case CMYK:
|
||||||
// Create based on embedded profile if exists, otherwise create from "Generic CMYK"
|
// Create based on embedded profile if exists, or create from "Generic CMYK"
|
||||||
cs = profile != null && profile.getNumComponents() == 4
|
ICC_Profile profile = getEmbeddedICCProfile(false);
|
||||||
? ColorSpaces.createColorSpace(profile)
|
|
||||||
: ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK);
|
|
||||||
|
|
||||||
return ImageTypeSpecifiers.createInterleaved(cs, new int[] {3, 2, 1, 0}, DataBuffer.TYPE_BYTE, false, false);
|
if (profile != null && profile.getNumComponents() == 4) {
|
||||||
|
return ImageTypeSpecifiers.createInterleaved(ColorSpaces.createColorSpace(profile), new int[]{3, 2, 1, 0}, DataBuffer.TYPE_BYTE, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ImageTypeSpecifiers.createInterleaved(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), new int[] {3, 2, 1, 0}, DataBuffer.TYPE_BYTE, false, false);
|
||||||
default:
|
default:
|
||||||
// For other types, we probably can't give a proper type
|
// For other types, we probably can't give a proper type, return null
|
||||||
throw new IIOException("Could not determine JPEG source color space");
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,8 +327,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
adobeDCT = null;
|
adobeDCT = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
JFIF jfif = getJFIF();
|
JPEGColorSpace sourceCSType = getSourceCSType(getJFIF(), adobeDCT, sof);
|
||||||
JPEGColorSpace sourceCSType = getSourceCSType(jfif, adobeDCT, sof);
|
|
||||||
|
|
||||||
if (sof.marker == JPEG.SOF3) {
|
if (sof.marker == JPEG.SOF3) {
|
||||||
// Read image as lossless
|
// Read image as lossless
|
||||||
@@ -334,15 +352,20 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
|
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
|
||||||
// - or only filter out the bad ICC profiles in the JPEGSegmentImageInputStream.
|
// - or only filter out the bad ICC profiles in the JPEGSegmentImageInputStream.
|
||||||
else if (bogusAdobeDCT
|
else if (delegate.canReadRaster() && (
|
||||||
|| profile != null && !ColorSpaces.isCS_sRGB(profile)
|
bogusAdobeDCT ||
|
||||||
|| (long) sof.lines * sof.samplesPerLine > Integer.MAX_VALUE
|
sourceCSType == JPEGColorSpace.CMYK ||
|
||||||
|| delegateCSTypeMismatch(jfif, adobeDCT, sof, sourceCSType)) {
|
sourceCSType == JPEGColorSpace.YCCK ||
|
||||||
|
profile != null && !ColorSpaces.isCS_sRGB(profile) ||
|
||||||
|
(long) sof.lines * sof.samplesPerLine > Integer.MAX_VALUE ||
|
||||||
|
!delegate.getImageTypes(0).hasNext() ||
|
||||||
|
sourceCSType == JPEGColorSpace.YCbCr && getRawImageType(imageIndex) != null)) { // TODO: Issue warning?
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.println("Reading using raster and extra conversion");
|
System.out.println("Reading using raster and extra conversion");
|
||||||
System.out.println("ICC color profile: " + profile);
|
System.out.println("ICC color profile: " + profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Possible to optimize slightly, to avoid readAsRaster for non-CMYK and other good types?
|
||||||
return readImageAsRasterAndReplaceColorProfile(imageIndex, param, sof, sourceCSType, profile);
|
return readImageAsRasterAndReplaceColorProfile(imageIndex, param, sof, sourceCSType, profile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -353,56 +376,6 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
return delegate.read(0, param);
|
return delegate.read(0, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean delegateCSTypeMismatch(final JFIF jfif, final AdobeDCT adobeDCT, final Frame startOfFrame, final JPEGColorSpace sourceCSType) throws IOException {
|
|
||||||
switch (sourceCSType) {
|
|
||||||
case GrayA:
|
|
||||||
case RGBA:
|
|
||||||
case YCbCrA:
|
|
||||||
case PhotoYCC:
|
|
||||||
case PhotoYCCA:
|
|
||||||
case CMYK:
|
|
||||||
case YCCK:
|
|
||||||
// These are no longer supported by the delegate, we'll handle ourselves
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
ImageTypeSpecifier rawImageType = delegate.getRawImageType(0);
|
|
||||||
|
|
||||||
switch (sourceCSType) {
|
|
||||||
case Gray:
|
|
||||||
return rawImageType == null || rawImageType.getColorModel().getColorSpace().getType() != ColorSpace.TYPE_GRAY;
|
|
||||||
case YCbCr:
|
|
||||||
// NOTE: For backwards compatibility, null is allowed for YCbCr
|
|
||||||
if (rawImageType == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If We have a JFIF, but with non-standard component Ids, the standard reader mistakes it for RGB
|
|
||||||
if (jfif != null && (startOfFrame.components[0].id != 1 || startOfFrame.components[1].id != 2 || startOfFrame.components[2].id != 3)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Else, if we have no Adobe marker and no subsampling, the standard reader mistakes it for RGB
|
|
||||||
else if (adobeDCT == null
|
|
||||||
&& (startOfFrame.components[0].id != 1 || startOfFrame.components[1].id != 2 || startOfFrame.components[2].id != 3)
|
|
||||||
&& (startOfFrame.components[0].hSub == 1 || startOfFrame.components[0].vSub == 1
|
|
||||||
|| startOfFrame.components[1].hSub == 1 || startOfFrame.components[1].vSub == 1
|
|
||||||
|| startOfFrame.components[2].hSub == 1 || startOfFrame.components[2].vSub == 1)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case RGB:
|
|
||||||
return rawImageType == null || rawImageType.getColorModel().getColorSpace().getType() != ColorSpace.TYPE_RGB;
|
|
||||||
default:
|
|
||||||
// Probably needs special handling, but we don't know what to do...
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IIOException | NullPointerException | ArrayIndexOutOfBoundsException | NegativeArraySizeException ignore) {
|
|
||||||
// An exception here is a clear indicator we need to handle conversion
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private BufferedImage readImageAsRasterAndReplaceColorProfile(int imageIndex, ImageReadParam param, Frame startOfFrame, JPEGColorSpace csType, ICC_Profile profile) throws IOException {
|
private BufferedImage readImageAsRasterAndReplaceColorProfile(int imageIndex, ImageReadParam param, Frame startOfFrame, JPEGColorSpace csType, ICC_Profile profile) throws IOException {
|
||||||
int origWidth = getWidth(imageIndex);
|
int origWidth = getWidth(imageIndex);
|
||||||
int origHeight = getHeight(imageIndex);
|
int origHeight = getHeight(imageIndex);
|
||||||
@@ -420,10 +393,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
RasterOp convert = null;
|
RasterOp convert = null;
|
||||||
ICC_ColorSpace intendedCS = profile != null ? ColorSpaces.createColorSpace(profile) : null;
|
ICC_ColorSpace intendedCS = profile != null ? ColorSpaces.createColorSpace(profile) : null;
|
||||||
|
|
||||||
if (destination.getNumBands() <= 2 && (csType != JPEGColorSpace.Gray && csType != JPEGColorSpace.GrayA)) {
|
if (profile != null && (csType == JPEGColorSpace.Gray || csType == JPEGColorSpace.GrayA)) {
|
||||||
convert = new LuminanceToGray();
|
|
||||||
}
|
|
||||||
else if (profile != null && (csType == JPEGColorSpace.Gray || csType == JPEGColorSpace.GrayA)) {
|
|
||||||
// com.sun. reader does not do ColorConvertOp for CS_GRAY, even if embedded ICC profile,
|
// com.sun. reader does not do ColorConvertOp for CS_GRAY, even if embedded ICC profile,
|
||||||
// probably because IJG native part does it already...? If applied, color looks wrong (too dark)...
|
// probably because IJG native part does it already...? If applied, color looks wrong (too dark)...
|
||||||
// convert = new ColorConvertOp(intendedCS, image.getColorModel().getColorSpace(), null);
|
// convert = new ColorConvertOp(intendedCS, image.getColorModel().getColorSpace(), null);
|
||||||
@@ -432,7 +402,8 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
// Handle inconsistencies
|
// Handle inconsistencies
|
||||||
if (startOfFrame.componentsInFrame() != intendedCS.getNumComponents()) {
|
if (startOfFrame.componentsInFrame() != intendedCS.getNumComponents()) {
|
||||||
// If ICC profile number of components and startOfFrame does not match, ignore ICC profile
|
// If ICC profile number of components and startOfFrame does not match, ignore ICC profile
|
||||||
processWarningOccurred(String.format("Embedded ICC color profile is incompatible with image data. " +
|
processWarningOccurred(String.format(
|
||||||
|
"Embedded ICC color profile is incompatible with image data. " +
|
||||||
"Profile indicates %d components, but SOF%d has %d color components. " +
|
"Profile indicates %d components, but SOF%d has %d color components. " +
|
||||||
"Ignoring ICC profile, assuming source color space %s.",
|
"Ignoring ICC profile, assuming source color space %s.",
|
||||||
intendedCS.getNumComponents(), startOfFrame.marker & 0xf, startOfFrame.componentsInFrame(), csType
|
intendedCS.getNumComponents(), startOfFrame.marker & 0xf, startOfFrame.componentsInFrame(), csType
|
||||||
@@ -456,7 +427,10 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
ColorSpace cmykCS = ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK);
|
ColorSpace cmykCS = ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK);
|
||||||
|
|
||||||
if (cmykCS instanceof ICC_ColorSpace) {
|
if (cmykCS instanceof ICC_ColorSpace) {
|
||||||
processWarningOccurred("No embedded ICC color profile, defaulting to \"generic\" CMYK ICC profile. Colors may look incorrect.");
|
processWarningOccurred(
|
||||||
|
"No embedded ICC color profile, defaulting to \"generic\" CMYK ICC profile. " +
|
||||||
|
"Colors may look incorrect."
|
||||||
|
);
|
||||||
|
|
||||||
// NOTE: Avoid using CCOp if same color space, as it's more compatible that way
|
// NOTE: Avoid using CCOp if same color space, as it's more compatible that way
|
||||||
if (cmykCS != image.getColorModel().getColorSpace()) {
|
if (cmykCS != image.getColorModel().getColorSpace()) {
|
||||||
@@ -465,11 +439,17 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// ColorConvertOp using non-ICC CS is deadly slow, fall back to fast conversion instead
|
// ColorConvertOp using non-ICC CS is deadly slow, fall back to fast conversion instead
|
||||||
processWarningOccurred("No embedded ICC color profile, will convert using inaccurate CMYK to RGB conversion. Colors may look incorrect.");
|
processWarningOccurred(
|
||||||
|
"No embedded ICC color profile, will convert using inaccurate CMYK to RGB conversion. " +
|
||||||
|
"Colors may look incorrect."
|
||||||
|
);
|
||||||
|
|
||||||
convert = new FastCMYKToRGB();
|
convert = new FastCMYKToRGB();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (profile != null) {
|
||||||
|
processWarningOccurred("Embedded ICC color profile is incompatible with Java 2D, color profile will be ignored.");
|
||||||
|
}
|
||||||
|
|
||||||
// We'll need a read param
|
// We'll need a read param
|
||||||
if (param == null) {
|
if (param == null) {
|
||||||
@@ -548,9 +528,10 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
switch (adobeDCT.transform) {
|
switch (adobeDCT.transform) {
|
||||||
case AdobeDCT.Unknown:
|
case AdobeDCT.Unknown:
|
||||||
return JPEGColorSpace.RGB;
|
return JPEGColorSpace.RGB;
|
||||||
|
case AdobeDCT.YCC:
|
||||||
|
return JPEGColorSpace.YCbCr;
|
||||||
default:
|
default:
|
||||||
// TODO: Warning!
|
// TODO: Warning!
|
||||||
case AdobeDCT.YCC:
|
|
||||||
return JPEGColorSpace.YCbCr; // assume it's YCbCr
|
return JPEGColorSpace.YCbCr; // assume it's YCbCr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -580,9 +561,10 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
switch (adobeDCT.transform) {
|
switch (adobeDCT.transform) {
|
||||||
case AdobeDCT.Unknown:
|
case AdobeDCT.Unknown:
|
||||||
return JPEGColorSpace.CMYK;
|
return JPEGColorSpace.CMYK;
|
||||||
|
case AdobeDCT.YCCK:
|
||||||
|
return JPEGColorSpace.YCCK;
|
||||||
default:
|
default:
|
||||||
// TODO: Warning!
|
// TODO: Warning!
|
||||||
case AdobeDCT.YCCK:
|
|
||||||
return JPEGColorSpace.YCCK; // assume it's YCCK
|
return JPEGColorSpace.YCCK; // assume it's YCCK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -659,12 +641,6 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (imageInput != null) {
|
if (imageInput != null) {
|
||||||
// Need to wrap stream to avoid messing with the byte order of the underlying stream
|
|
||||||
// in the case we are operating as a delegate for ie. TIFFImageReader.
|
|
||||||
if (!(imageInput instanceof SubImageInputStream)) {
|
|
||||||
imageInput = new SubImageInputStream(imageInput, Long.MAX_VALUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
streamOffsets.add(imageInput.getStreamPosition());
|
streamOffsets.add(imageInput.getStreamPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,7 +655,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
private void initDelegate(boolean seekForwardOnly, boolean ignoreMetadata) throws IOException {
|
private void initDelegate(boolean seekForwardOnly, boolean ignoreMetadata) throws IOException {
|
||||||
// JPEGSegmentImageInputStream that filters out/skips bad/unnecessary segments
|
// JPEGSegmentImageInputStream that filters out/skips bad/unnecessary segments
|
||||||
delegate.setInput(imageInput != null
|
delegate.setInput(imageInput != null
|
||||||
? new JPEGSegmentImageInputStream(imageInput, new JPEGSegmentWarningDelegate())
|
? new JPEGSegmentImageInputStream(new SubImageInputStream(imageInput, Long.MAX_VALUE), new JPEGSegmentStreamWarningDelegate())
|
||||||
: null, seekForwardOnly, ignoreMetadata);
|
: null, seekForwardOnly, ignoreMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,7 +693,6 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initHeader(final int imageIndex) throws IOException {
|
private void initHeader(final int imageIndex) throws IOException {
|
||||||
assertInput();
|
|
||||||
if (imageIndex < 0) {
|
if (imageIndex < 0) {
|
||||||
throw new IndexOutOfBoundsException("imageIndex < 0: " + imageIndex);
|
throw new IndexOutOfBoundsException("imageIndex < 0: " + imageIndex);
|
||||||
}
|
}
|
||||||
@@ -734,6 +709,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
thumbnails = null;
|
thumbnails = null;
|
||||||
|
|
||||||
initDelegate(seekForwardOnly, ignoreMetadata);
|
initDelegate(seekForwardOnly, ignoreMetadata);
|
||||||
|
|
||||||
initHeader();
|
initHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -817,14 +793,13 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
// TODO: We should probably optimize this
|
// TODO: We should probably optimize this
|
||||||
try {
|
try {
|
||||||
segments = null;
|
|
||||||
getSOF(); // No SOF, no image
|
getSOF(); // No SOF, no image
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
catch (IIOException ignore) {}
|
catch (IIOException ignore) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
imageInput.seek(streamOffsets.get(currentStreamIndex));
|
currentStreamIndex = -1;
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@@ -902,30 +877,41 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
return jfxx.isEmpty() ? null : (JFXX) jfxx.get(0);
|
return jfxx.isEmpty() ? null : (JFXX) jfxx.get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private EXIF getExif() throws IOException {
|
private CompoundDirectory getExif() throws IOException {
|
||||||
List<Application> exif = getAppSegments(JPEG.APP1, "Exif");
|
List<Application> exifSegments = getAppSegments(JPEG.APP1, "Exif");
|
||||||
return exif.isEmpty() ? null : (EXIF) exif.get(0); // TODO: Can there actually be more Exif segments?
|
|
||||||
}
|
|
||||||
|
|
||||||
private CompoundDirectory parseExif(final EXIF exif) throws IOException {
|
if (!exifSegments.isEmpty()) {
|
||||||
if (exif != null) {
|
Application exif = exifSegments.get(0);
|
||||||
// Identifier is "Exif\0" + 1 byte pad
|
int offset = exif.identifier.length() + 2; // Incl. pad
|
||||||
if (exif.data.length > exif.identifier.length() + 2) {
|
|
||||||
try (ImageInputStream stream = exif.exifData()) {
|
if (exif.data.length <= offset) {
|
||||||
|
processWarningOccurred("Exif chunk has no data.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TODO: Consider returning ByteArrayImageInputStream from Segment.data()
|
||||||
|
try (ImageInputStream stream = new ByteArrayImageInputStream(exif.data, offset, exif.data.length - offset)) {
|
||||||
return (CompoundDirectory) new TIFFReader().read(stream);
|
return (CompoundDirectory) new TIFFReader().read(stream);
|
||||||
}
|
}
|
||||||
catch (IIOException e) {
|
catch (IIOException e) {
|
||||||
processWarningOccurred("Exif chunk is present, but can't be read: " + e.getMessage());
|
processWarningOccurred("Exif chunk is present, but can't be read: " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
processWarningOccurred("Exif chunk has no data.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Util method?
|
||||||
|
static byte[] readFully(DataInput stream, int len) throws IOException {
|
||||||
|
if (len == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = new byte[len];
|
||||||
|
stream.readFully(data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
ICC_Profile getEmbeddedICCProfile(final boolean allowBadIndexes) throws IOException {
|
ICC_Profile getEmbeddedICCProfile(final boolean allowBadIndexes) throws IOException {
|
||||||
// ICC v 1.42 (2006) annex B:
|
// ICC v 1.42 (2006) annex B:
|
||||||
// APP2 marker (0xFFE2) + 2 byte length + ASCII 'ICC_PROFILE' + 0 (termination)
|
// APP2 marker (0xFFE2) + 2 byte length + ASCII 'ICC_PROFILE' + 0 (termination)
|
||||||
@@ -1091,39 +1077,109 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
if (thumbnails == null) {
|
if (thumbnails == null) {
|
||||||
thumbnails = new ArrayList<>();
|
thumbnails = new ArrayList<>();
|
||||||
|
ThumbnailReadProgressListener thumbnailProgressDelegator = new ThumbnailProgressDelegate();
|
||||||
|
|
||||||
// Read JFIF thumbnails if present
|
// Read JFIF thumbnails if present
|
||||||
try {
|
JFIF jfif = getJFIF();
|
||||||
ThumbnailReader thumbnail = JFIFThumbnail.from(getJFIF());
|
if (jfif != null && jfif.thumbnail != null) {
|
||||||
if (thumbnail != null) {
|
// TODO: Check if the JFIF segment really has room for this thumbnail?
|
||||||
thumbnails.add(thumbnail);
|
thumbnails.add(new JFIFThumbnailReader(thumbnailProgressDelegator, imageIndex, thumbnails.size(), jfif));
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
processWarningOccurred(e.getMessage());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read JFXX thumbnails if present
|
// Read JFXX thumbnails if present
|
||||||
try {
|
JFXX jfxx = getJFXX();
|
||||||
ThumbnailReader thumbnail = JFXXThumbnail.from(getJFXX(), getThumbnailReader());
|
if (jfxx != null && jfxx.thumbnail != null) {
|
||||||
if (thumbnail != null) {
|
switch (jfxx.extensionCode) {
|
||||||
thumbnails.add(thumbnail);
|
case JFXX.JPEG:
|
||||||
|
case JFXX.INDEXED:
|
||||||
|
case JFXX.RGB:
|
||||||
|
// TODO: Check if the JFXX segment really has room for this thumbnail?
|
||||||
|
thumbnails.add(new JFXXThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), imageIndex, thumbnails.size(), jfxx));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
processWarningOccurred("Unknown JFXX extension code: " + jfxx.extensionCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
|
||||||
processWarningOccurred(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read Exif thumbnails if present
|
// Read Exif thumbnails if present
|
||||||
try {
|
List<Application> exifSegments = getAppSegments(JPEG.APP1, "Exif");
|
||||||
EXIF exif = getExif();
|
if (!exifSegments.isEmpty()) {
|
||||||
ThumbnailReader thumbnailReader = EXIFThumbnail.from(exif, parseExif(exif), getThumbnailReader());
|
Application exif = exifSegments.get(0);
|
||||||
if (thumbnailReader != null) {
|
|
||||||
thumbnails.add(thumbnailReader);
|
// Identifier is "Exif\0" + 1 byte pad
|
||||||
|
int dataOffset = exif.identifier.length() + 2;
|
||||||
|
|
||||||
|
if (exif.data.length <= dataOffset) {
|
||||||
|
processWarningOccurred("Exif chunk has no data.");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ImageInputStream stream = new ByteArrayImageInputStream(exif.data, dataOffset, exif.data.length - dataOffset);
|
||||||
|
try {
|
||||||
|
CompoundDirectory exifMetadata = (CompoundDirectory) new TIFFReader().read(stream);
|
||||||
|
|
||||||
|
if (exifMetadata.directoryCount() == 2) {
|
||||||
|
Directory ifd1 = exifMetadata.getDirectory(1);
|
||||||
|
|
||||||
|
// Compression: 1 = no compression, 6 = JPEG compression (default)
|
||||||
|
Entry compressionEntry = ifd1.getEntryById(TIFF.TAG_COMPRESSION);
|
||||||
|
int compression = compressionEntry == null ? 6 : ((Number) compressionEntry.getValue()).intValue();
|
||||||
|
|
||||||
|
if (compression == 6) {
|
||||||
|
Entry jpegOffEntry = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||||
|
if (jpegOffEntry != null) {
|
||||||
|
Entry jpegLenEntry = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||||
|
|
||||||
|
// Test if Exif thumbnail is contained within the Exif segment (offset + length <= segment.length)
|
||||||
|
long jpegOffset = ((Number) jpegOffEntry.getValue()).longValue();
|
||||||
|
long jpegLength = jpegLenEntry != null ? ((Number) jpegLenEntry.getValue()).longValue() : -1;
|
||||||
|
if (jpegLength > 0 && jpegOffset + jpegLength <= stream.length()) {
|
||||||
|
// Verify first bytes are FFD8
|
||||||
|
stream.seek(jpegOffset);
|
||||||
|
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||||
|
if (stream.readUnsignedShort() == JPEG.SOI) {
|
||||||
|
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
||||||
|
}
|
||||||
|
// TODO: Simplify this warning fallback stuff...
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with empty or incomplete JPEG thumbnail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with empty or incomplete JPEG thumbnail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with JPEG thumbnail missing JPEGInterchangeFormat tag");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (compression == 1) {
|
||||||
|
Entry stripOffEntry = ifd1.getEntryById(TIFF.TAG_STRIP_OFFSETS);
|
||||||
|
if (stripOffEntry != null) {
|
||||||
|
long stripOffset = ((Number) stripOffEntry.getValue()).longValue();
|
||||||
|
|
||||||
|
if (stripOffset < stream.length()) {
|
||||||
|
// TODO: Verify length of Exif thumbnail vs length of segment like in JPEG
|
||||||
|
// ...but this requires so many extra values... Instead move this logic to the
|
||||||
|
// EXIFThumbnailReader?
|
||||||
|
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with empty or incomplete uncompressed thumbnail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with uncompressed thumbnail missing StripOffsets tag");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with unknown compression (expected 1 or 6): " + compression);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IIOException e) {
|
||||||
|
processWarningOccurred("Exif chunk present, but can't be read: " + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
processWarningOccurred(e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1166,13 +1222,13 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
|
public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
|
||||||
checkThumbnailBounds(imageIndex, thumbnailIndex);
|
checkThumbnailBounds(imageIndex, thumbnailIndex);
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
return thumbnail;
|
return thumbnail;
|
||||||
}
|
}
|
||||||
@@ -1183,7 +1239,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
||||||
initHeader(imageIndex);
|
initHeader(imageIndex);
|
||||||
|
|
||||||
return new JPEGImage10Metadata(segments, getSOF(), getJFIF(), getJFXX(), getEmbeddedICCProfile(true), getAdobeDCT(), parseExif(getExif()));
|
return new JPEGImage10Metadata(segments, getSOF(), getJFIF(), getJFXX(), getEmbeddedICCProfile(true), getAdobeDCT(), getExif());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1308,7 +1364,24 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class JPEGSegmentWarningDelegate implements JPEGSegmentWarningListener {
|
private class ThumbnailProgressDelegate implements ThumbnailReadProgressListener {
|
||||||
|
@Override
|
||||||
|
public void thumbnailStarted(int imageIndex, int thumbnailIndex) {
|
||||||
|
processThumbnailStarted(imageIndex, thumbnailIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void thumbnailProgress(float percentageDone) {
|
||||||
|
processThumbnailProgress(percentageDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void thumbnailComplete() {
|
||||||
|
processThumbnailComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class JPEGSegmentStreamWarningDelegate implements JPEGSegmentStreamWarningListener {
|
||||||
@Override
|
@Override
|
||||||
public void warningOccurred(String warning) {
|
public void warningOccurred(String warning) {
|
||||||
processWarningOccurred(warning);
|
processWarningOccurred(warning);
|
||||||
|
|||||||
+7
-1
@@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.stream.BufferedImageInputStream;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
@@ -75,7 +77,7 @@ final class JPEGLosslessDecoderWrapper {
|
|||||||
* @throws IOException is thrown if the decoder failed or a conversion is not supported
|
* @throws IOException is thrown if the decoder failed or a conversion is not supported
|
||||||
*/
|
*/
|
||||||
BufferedImage readImage(final List<Segment> segments, final ImageInputStream input) throws IOException {
|
BufferedImage readImage(final List<Segment> segments, final ImageInputStream input) throws IOException {
|
||||||
JPEGLosslessDecoder decoder = new JPEGLosslessDecoder(segments, input, listenerDelegate);
|
JPEGLosslessDecoder decoder = new JPEGLosslessDecoder(segments, createBufferedInput(input), listenerDelegate);
|
||||||
|
|
||||||
// TODO: Allow 10/12/14 bit (using a ComponentColorModel with correct bits, as in TIFF)
|
// TODO: Allow 10/12/14 bit (using a ComponentColorModel with correct bits, as in TIFF)
|
||||||
// TODO: Rewrite this to pass a pre-allocated buffer of correct type (byte/short)/correct bands
|
// TODO: Rewrite this to pass a pre-allocated buffer of correct type (byte/short)/correct bands
|
||||||
@@ -109,6 +111,10 @@ final class JPEGLosslessDecoderWrapper {
|
|||||||
throw new IIOException("JPEG Lossless with " + decoder.getPrecision() + " bit precision and " + decoder.getNumComponents() + " component(s) not supported");
|
throw new IIOException("JPEG Lossless with " + decoder.getPrecision() + " bit precision and " + decoder.getNumComponents() + " component(s) not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ImageInputStream createBufferedInput(final ImageInputStream input) throws IOException {
|
||||||
|
return input instanceof BufferedImageInputStream ? input : new BufferedImageInputStream(input);
|
||||||
|
}
|
||||||
|
|
||||||
Raster readRaster(final List<Segment> segments, final ImageInputStream input) throws IOException {
|
Raster readRaster(final List<Segment> segments, final ImageInputStream input) throws IOException {
|
||||||
// TODO: Can perhaps be implemented faster
|
// TODO: Can perhaps be implemented faster
|
||||||
return readImage(segments, input).getRaster();
|
return readImage(segments, input).getRaster();
|
||||||
|
|||||||
+2
-2
@@ -50,8 +50,8 @@ final class JPEGProviderInfo extends ReaderWriterProviderInfo {
|
|||||||
new String[] {"com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReaderSpi"},
|
new String[] {"com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageReaderSpi"},
|
||||||
"com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageWriter",
|
"com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageWriter",
|
||||||
new String[] {"com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageWriterSpi"},
|
new String[] {"com.twelvemonkeys.imageio.plugins.jpeg.JPEGImageWriterSpi"},
|
||||||
false, "javax_imageio_jpeg_stream_1.0", null, null, null,
|
false, null, null, null, null,
|
||||||
true, "javax_imageio_jpeg_image_1.0", null, null, null
|
true, null, null, null, null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-7
@@ -59,7 +59,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
|
|||||||
// TODO: Support multiple JPEG streams (SOI...EOI, SOI...EOI, ...) in a single file
|
// TODO: Support multiple JPEG streams (SOI...EOI, SOI...EOI, ...) in a single file
|
||||||
|
|
||||||
private final ImageInputStream stream;
|
private final ImageInputStream stream;
|
||||||
private final JPEGSegmentWarningListener warningListener;
|
private final JPEGSegmentStreamWarningListener warningListener;
|
||||||
|
|
||||||
private final ComponentIdSet componentIds = new ComponentIdSet();
|
private final ComponentIdSet componentIds = new ComponentIdSet();
|
||||||
|
|
||||||
@@ -67,13 +67,14 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
|
|||||||
private int currentSegment = -1;
|
private int currentSegment = -1;
|
||||||
private Segment segment;
|
private Segment segment;
|
||||||
|
|
||||||
JPEGSegmentImageInputStream(final ImageInputStream stream, final JPEGSegmentWarningListener warningListener) {
|
|
||||||
|
JPEGSegmentImageInputStream(final ImageInputStream stream, final JPEGSegmentStreamWarningListener warningListener) {
|
||||||
this.stream = notNull(stream, "stream");
|
this.stream = notNull(stream, "stream");
|
||||||
this.warningListener = notNull(warningListener, "warningListener");
|
this.warningListener = notNull(warningListener, "warningListener");
|
||||||
}
|
}
|
||||||
|
|
||||||
JPEGSegmentImageInputStream(final ImageInputStream stream) {
|
JPEGSegmentImageInputStream(final ImageInputStream stream) {
|
||||||
this(stream, JPEGSegmentWarningListener.NULL_LISTENER);
|
this(stream, JPEGSegmentStreamWarningListener.NULL_LISTENER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processWarningOccured(final String warning) {
|
private void processWarningOccured(final String warning) {
|
||||||
@@ -149,6 +150,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
|
|||||||
else {
|
else {
|
||||||
if (marker == JPEG.EOI) {
|
if (marker == JPEG.EOI) {
|
||||||
segment = new Segment(marker, realPosition, segment.end(), 2);
|
segment = new Segment(marker, realPosition, segment.end(), 2);
|
||||||
|
segments.add(segment);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Length including length field itself
|
// Length including length field itself
|
||||||
@@ -163,7 +165,6 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
|
|||||||
// Inspect segment, see if we have 16 bit precision (assuming segments will not contain
|
// Inspect segment, see if we have 16 bit precision (assuming segments will not contain
|
||||||
// multiple quality tables with varying precision)
|
// multiple quality tables with varying precision)
|
||||||
int qtInfo = stream.read();
|
int qtInfo = stream.read();
|
||||||
|
|
||||||
if ((qtInfo & 0x10) == 0x10) {
|
if ((qtInfo & 0x10) == 0x10) {
|
||||||
processWarningOccured("16 bit DQT encountered");
|
processWarningOccured("16 bit DQT encountered");
|
||||||
segment = new DownsampledDQTReplacement(realPosition, segment.end(), length, qtInfo, stream);
|
segment = new DownsampledDQTReplacement(realPosition, segment.end(), length, qtInfo, stream);
|
||||||
@@ -187,9 +188,10 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
|
|||||||
else {
|
else {
|
||||||
segment = new Segment(marker, realPosition, segment.end(), length);
|
segment = new Segment(marker, realPosition, segment.end(), length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
segments.add(segment);
|
||||||
}
|
}
|
||||||
|
|
||||||
segments.add(segment);
|
|
||||||
currentSegment = segments.size() - 1;
|
currentSegment = segments.size() - 1;
|
||||||
|
|
||||||
if (marker == JPEG.SOS) {
|
if (marker == JPEG.SOS) {
|
||||||
@@ -332,7 +334,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void streamInit() throws IOException {
|
private void streamInit() throws IOException {
|
||||||
long position = stream.getStreamPosition();
|
stream.seek(0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int soi = stream.readUnsignedShort();
|
int soi = stream.readUnsignedShort();
|
||||||
@@ -341,7 +343,7 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
|
|||||||
throw new IIOException(String.format("Not a JPEG stream (starts with: 0x%04x, expected SOI: 0x%04x)", soi, JPEG.SOI));
|
throw new IIOException(String.format("Not a JPEG stream (starts with: 0x%04x, expected SOI: 0x%04x)", soi, JPEG.SOI));
|
||||||
}
|
}
|
||||||
|
|
||||||
segment = new Segment(soi, position, 0, 2);
|
segment = new Segment(soi, 0, 0, 2);
|
||||||
|
|
||||||
segments.add(segment);
|
segments.add(segment);
|
||||||
currentSegment = segments.size() - 1; // 0
|
currentSegment = segments.size() - 1; // 0
|
||||||
|
|||||||
+2
-2
@@ -33,10 +33,10 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
|
|||||||
/**
|
/**
|
||||||
* JPEGSegmentStreamWarningListener
|
* JPEGSegmentStreamWarningListener
|
||||||
*/
|
*/
|
||||||
interface JPEGSegmentWarningListener {
|
interface JPEGSegmentStreamWarningListener {
|
||||||
void warningOccurred(String warning);
|
void warningOccurred(String warning);
|
||||||
|
|
||||||
JPEGSegmentWarningListener NULL_LISTENER = new JPEGSegmentWarningListener() {
|
JPEGSegmentStreamWarningListener NULL_LISTENER = new JPEGSegmentStreamWarningListener() {
|
||||||
@Override
|
@Override
|
||||||
public void warningOccurred(final String warning) {}
|
public void warningOccurred(final String warning) {}
|
||||||
};
|
};
|
||||||
-95
@@ -1,95 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.jpeg;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.Validate;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.geom.Point2D;
|
|
||||||
import java.awt.geom.Rectangle2D;
|
|
||||||
import java.awt.image.Raster;
|
|
||||||
import java.awt.image.RasterOp;
|
|
||||||
import java.awt.image.WritableRaster;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LuminanceToGray.
|
|
||||||
*
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
* @author last modified by $Author: haraldk$
|
|
||||||
* @version $Id: LuminanceToGray.java,v 1.0 10/04/2021 haraldk Exp$
|
|
||||||
*/
|
|
||||||
final class LuminanceToGray implements RasterOp {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WritableRaster filter(final Raster src, WritableRaster dest) {
|
|
||||||
Validate.notNull(src, "src may not be null");
|
|
||||||
Validate.isTrue(src != dest, "src and dest raster may not be same");
|
|
||||||
Validate.isTrue(src.getNumDataElements() >= 3, src.getNumDataElements(), "luminance raster must have at least 3 data elements: %s");
|
|
||||||
|
|
||||||
if (dest == null) {
|
|
||||||
dest = createCompatibleDestRaster(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If src and dest have alpha component, keep it, otherwise extract luminance only
|
|
||||||
int[] bandList = src.getNumBands() > 3 && dest.getNumBands() > 1 ? new int[] {0, 3} : new int[] {0};
|
|
||||||
dest.setRect(0, 0, src.createChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, bandList));
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Rectangle2D getBounds2D(final Raster src) {
|
|
||||||
return src.getBounds();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public WritableRaster createCompatibleDestRaster(final Raster src) {
|
|
||||||
return src.createCompatibleWritableRaster()
|
|
||||||
.createWritableChild(0, 0, src.getWidth(), src.getHeight(), 0, 0, new int[] {0});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Point2D getPoint2D(final Point2D srcPt, Point2D dstPt) {
|
|
||||||
if (dstPt == null) {
|
|
||||||
dstPt = new Point2D.Double(srcPt.getX(), srcPt.getY());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dstPt.setLocation(srcPt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dstPt;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RenderingHints getRenderingHints() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+6
-20
@@ -30,31 +30,17 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.plugins.jpeg.ThumbnailReader.UncompressedThumbnailReader;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JFIFThumbnail
|
* ThumbnailReadProgressListener
|
||||||
*
|
*
|
||||||
* @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: JFIFThumbnail.java,v 1.0 18.04.12 12:19 haraldk Exp$
|
* @version $Id: ThumbnailReadProgressListener.java,v 1.0 07.05.12 10:15 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
final class JFIFThumbnail {
|
interface ThumbnailReadProgressListener {
|
||||||
private JFIFThumbnail() {
|
void thumbnailStarted(int imageIndex, int thumbnailIndex);
|
||||||
}
|
|
||||||
|
|
||||||
static ThumbnailReader from(final JFIF segment) throws IOException {
|
void thumbnailProgress(float percentageDone);
|
||||||
if (segment != null && segment.xThumbnail > 0 && segment.yThumbnail > 0) {
|
|
||||||
if (segment.thumbnail == null || segment.thumbnail.length < segment.xThumbnail * segment.yThumbnail) {
|
|
||||||
throw new IIOException("Truncated JFIF thumbnail");
|
|
||||||
}
|
|
||||||
|
|
||||||
return new UncompressedThumbnailReader(segment.xThumbnail, segment.yThumbnail, segment.thumbnail);
|
void thumbnailComplete();
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+50
-142
@@ -31,16 +31,12 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import javax.imageio.ImageReader;
|
import javax.imageio.ImageReader;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
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.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import static com.twelvemonkeys.lang.Validate.isTrue;
|
|
||||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ThumbnailReader
|
* ThumbnailReader
|
||||||
*
|
*
|
||||||
@@ -50,156 +46,68 @@ import static com.twelvemonkeys.lang.Validate.notNull;
|
|||||||
*/
|
*/
|
||||||
abstract class ThumbnailReader {
|
abstract class ThumbnailReader {
|
||||||
|
|
||||||
|
private final ThumbnailReadProgressListener progressListener;
|
||||||
|
protected final int imageIndex;
|
||||||
|
protected final int thumbnailIndex;
|
||||||
|
|
||||||
|
protected ThumbnailReader(final ThumbnailReadProgressListener progressListener, final int imageIndex, final int thumbnailIndex) {
|
||||||
|
this.progressListener = progressListener != null ? progressListener : new NullProgressListener();
|
||||||
|
this.imageIndex = imageIndex;
|
||||||
|
this.thumbnailIndex = thumbnailIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void processThumbnailStarted() {
|
||||||
|
progressListener.thumbnailStarted(imageIndex, thumbnailIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void processThumbnailProgress(float percentageDone) {
|
||||||
|
progressListener.thumbnailProgress(percentageDone);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void processThumbnailComplete() {
|
||||||
|
progressListener.thumbnailComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected BufferedImage readJPEGThumbnail(final ImageReader reader, final ImageInputStream stream) throws IOException {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
|
return reader.read(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static protected BufferedImage readRawThumbnail(final byte[] thumbnail, final int size, final int offset, int w, int h) {
|
||||||
|
DataBufferByte buffer = new DataBufferByte(thumbnail, size, offset);
|
||||||
|
WritableRaster raster;
|
||||||
|
ColorModel cm;
|
||||||
|
|
||||||
|
if (thumbnail.length == w * h) {
|
||||||
|
raster = Raster.createInterleavedRaster(buffer, w, h, w, 1, new int[] {0}, null);
|
||||||
|
cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
raster = Raster.createInterleavedRaster(buffer, w, h, w * 3, 3, new int[] {0, 1, 2}, null);
|
||||||
|
cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||||
|
}
|
||||||
|
|
||||||
public abstract BufferedImage read() throws IOException;
|
public abstract BufferedImage read() throws IOException;
|
||||||
|
|
||||||
public abstract int getWidth() throws IOException;
|
public abstract int getWidth() throws IOException;
|
||||||
|
|
||||||
public abstract int getHeight() throws IOException;
|
public abstract int getHeight() throws IOException;
|
||||||
|
|
||||||
public IIOMetadata readMetadata() throws IOException {
|
private static class NullProgressListener implements ThumbnailReadProgressListener {
|
||||||
return null;
|
@Override
|
||||||
}
|
public void thumbnailStarted(int imageIndex, int thumbnailIndex) {
|
||||||
|
|
||||||
static class UncompressedThumbnailReader extends ThumbnailReader {
|
|
||||||
private final int width;
|
|
||||||
private final int height;
|
|
||||||
private final byte[] data;
|
|
||||||
private final int offset;
|
|
||||||
|
|
||||||
public UncompressedThumbnailReader(int width, int height, byte[] data) {
|
|
||||||
this(width, height, data, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UncompressedThumbnailReader(int width, int height, byte[] data, int offset) {
|
|
||||||
this.width = isTrue(width > 0, width, "width");
|
|
||||||
this.height = isTrue(height > 0, height, "height");;
|
|
||||||
this.data = notNull(data, "data");
|
|
||||||
this.offset = isTrue(offset >= 0 && offset < data.length, offset, "offset");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BufferedImage read() throws IOException {
|
public void thumbnailProgress(float percentageDone) {
|
||||||
DataBufferByte buffer = new DataBufferByte(data, data.length, offset);
|
|
||||||
WritableRaster raster;
|
|
||||||
ColorModel cm;
|
|
||||||
|
|
||||||
if (data.length == width * height) {
|
|
||||||
raster = Raster.createInterleavedRaster(buffer, width, height, width, 1, new int[] {0}, null);
|
|
||||||
cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
raster = Raster.createInterleavedRaster(buffer, width, height, width * 3, 3, new int[] {0, 1, 2}, null);
|
|
||||||
cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getWidth() throws IOException {
|
public void thumbnailComplete() {
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() throws IOException {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class IndexedThumbnailReader extends ThumbnailReader {
|
|
||||||
private final int width;
|
|
||||||
private final int height;
|
|
||||||
private final byte[] palette;
|
|
||||||
private final int paletteOff;
|
|
||||||
private final byte[] data;
|
|
||||||
private final int dataOff;
|
|
||||||
|
|
||||||
public IndexedThumbnailReader(final int width, int height, final byte[] palette, final int paletteOff, final byte[] data, final int dataOff) {
|
|
||||||
this.width = isTrue(width > 0, width, "width");
|
|
||||||
this.height = isTrue(height > 0, height, "height");;
|
|
||||||
this.palette = notNull(palette, "palette");
|
|
||||||
this.paletteOff = isTrue(paletteOff >= 0 && paletteOff < palette.length, paletteOff, "paletteOff");
|
|
||||||
this.data = notNull(data, "data");
|
|
||||||
this.dataOff = isTrue(dataOff >= 0 && dataOff < data.length, dataOff, "dataOff");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BufferedImage read() throws IOException {
|
|
||||||
// 256 RGB triplets
|
|
||||||
int[] rgbs = new int[256];
|
|
||||||
for (int i = 0; i < rgbs.length; i++) {
|
|
||||||
rgbs[i] = (palette[paletteOff + 3 * i ] & 0xff) << 16
|
|
||||||
| (palette[paletteOff + 3 * i + 1] & 0xff) << 8
|
|
||||||
| (palette[paletteOff + 3 * i + 2] & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
IndexColorModel icm = new IndexColorModel(8, rgbs.length, rgbs, 0, false, -1, DataBuffer.TYPE_BYTE);
|
|
||||||
DataBufferByte buffer = new DataBufferByte(data, data.length - dataOff, dataOff);
|
|
||||||
WritableRaster raster = Raster.createPackedRaster(buffer, width, height, 8, null);
|
|
||||||
|
|
||||||
return new BufferedImage(icm, raster, icm.isAlphaPremultiplied(), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWidth() throws IOException {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() throws IOException {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class JPEGThumbnailReader extends ThumbnailReader {
|
|
||||||
private final ImageReader reader;
|
|
||||||
private final ImageInputStream input;
|
|
||||||
private final long offset;
|
|
||||||
|
|
||||||
private Dimension dimension;
|
|
||||||
|
|
||||||
public JPEGThumbnailReader(final ImageReader reader, final ImageInputStream input, final long offset) {
|
|
||||||
this.reader = notNull(reader, "reader");
|
|
||||||
this.input = notNull(input, "input");
|
|
||||||
this.offset = isTrue(offset >= 0, offset, "offset");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initReader() throws IOException {
|
|
||||||
if (reader.getInput() != input) {
|
|
||||||
input.seek(offset);
|
|
||||||
reader.setInput(input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BufferedImage read() throws IOException {
|
|
||||||
initReader();
|
|
||||||
return reader.read(0, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Dimension readDimensions() throws IOException {
|
|
||||||
if (dimension == null) {
|
|
||||||
initReader();
|
|
||||||
dimension = new Dimension(reader.getWidth(0), reader.getHeight(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
return dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getWidth() throws IOException {
|
|
||||||
return readDimensions().width;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getHeight() throws IOException {
|
|
||||||
return readDimensions().height;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IIOMetadata readMetadata() throws IOException {
|
|
||||||
initReader();
|
|
||||||
return reader.getImageMetadata(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -52,7 +52,9 @@ public abstract class AbstractThumbnailReaderTest {
|
|||||||
IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi());
|
IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract ThumbnailReader createReader(ImageInputStream stream) throws IOException;
|
protected abstract ThumbnailReader createReader(
|
||||||
|
ThumbnailReadProgressListener progressListener, int imageIndex, int thumbnailIndex, ImageInputStream stream
|
||||||
|
) throws IOException;
|
||||||
|
|
||||||
protected final ImageInputStream createStream(final String name) throws IOException {
|
protected final ImageInputStream createStream(final String name) throws IOException {
|
||||||
URL resource = getClass().getResource(name);
|
URL resource = getClass().getResource(name);
|
||||||
|
|||||||
+38
-174
@@ -30,33 +30,23 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.AbstractCompoundDirectory;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
||||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.IFD;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.DataInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Arrays;
|
|
||||||
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.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EXIFThumbnailReaderTest
|
* EXIFThumbnailReaderTest
|
||||||
@@ -67,175 +57,31 @@ import static org.junit.Assert.*;
|
|||||||
*/
|
*/
|
||||||
public class EXIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
public class EXIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
||||||
|
|
||||||
private final ImageReader thumbnailReader = ImageIO.getImageReadersByFormatName("jpeg").next();
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
thumbnailReader.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFromNullSegment() throws IOException {
|
|
||||||
assertNull(EXIFThumbnail.from(null, null, thumbnailReader));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFromNullIFD() throws IOException {
|
|
||||||
assertNull(EXIFThumbnail.from(new EXIF(new byte[0]), null, thumbnailReader));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFromEmptyIFD() throws IOException {
|
|
||||||
assertNull(EXIFThumbnail.from(new EXIF(new byte[0]), new EXIFDirectory(), thumbnailReader));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFromSingleIFD() throws IOException {
|
|
||||||
assertNull(EXIFThumbnail.from(new EXIF(new byte[42]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList())), thumbnailReader));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromMissingThumbnail() throws IOException {
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[42]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(Collections.<Entry>emptyList())), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromUnsupportedThumbnailCompression() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Collections.singletonList(new TIFFEntry(TIFF.TAG_COMPRESSION, 42));
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[42]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromMissingOffsetUncompressed() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Arrays.asList(
|
|
||||||
new TIFFEntry(TIFF.TAG_COMPRESSION, 1),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, 16),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_HEIGHT, 9)
|
|
||||||
);
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[6 + 16 * 9 * 3]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromMissingWidthUncompressed() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Arrays.asList(
|
|
||||||
new TIFFEntry(TIFF.TAG_COMPRESSION, 1),
|
|
||||||
new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, 0),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_HEIGHT, 9)
|
|
||||||
);
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[6 + 16 * 9 * 3]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromMissingHeightUncompressed() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Arrays.asList(
|
|
||||||
new TIFFEntry(TIFF.TAG_COMPRESSION, 1),
|
|
||||||
new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, 0),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, 16)
|
|
||||||
);
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[6 + 16 * 9 * 3]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromUnsupportedPhotometricUncompressed() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Arrays.asList(
|
|
||||||
new TIFFEntry(TIFF.TAG_COMPRESSION, 1),
|
|
||||||
new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, 0),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, 16),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_HEIGHT, 9),
|
|
||||||
new TIFFEntry(TIFF.TAG_PHOTOMETRIC_INTERPRETATION, 42)
|
|
||||||
);
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[6 + 16 * 9 * 3]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromUnsupportedBitsPerSampleUncompressed() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Arrays.asList(
|
|
||||||
new TIFFEntry(TIFF.TAG_COMPRESSION, 1),
|
|
||||||
new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, 0),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, 16),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_HEIGHT, 9),
|
|
||||||
new TIFFEntry(TIFF.TAG_BITS_PER_SAMPLE, new int[]{5, 6, 5})
|
|
||||||
);
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[6 + 16 * 9 * 3]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromUnsupportedSamplesPerPixelUncompressed() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Arrays.asList(
|
|
||||||
new TIFFEntry(TIFF.TAG_COMPRESSION, 1),
|
|
||||||
new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, 0),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, 160),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_HEIGHT, 90),
|
|
||||||
new TIFFEntry(TIFF.TAG_SAMPLES_PER_PIXEL, 1)
|
|
||||||
);
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[6 + 16 * 9]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromTruncatedUncompressed() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Arrays.asList(
|
|
||||||
new TIFFEntry(TIFF.TAG_COMPRESSION, 1),
|
|
||||||
new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, 0),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, 160),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_HEIGHT, 90)
|
|
||||||
);
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[42]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testValidUncompressed() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Arrays.asList(
|
|
||||||
new TIFFEntry(TIFF.TAG_COMPRESSION, 1),
|
|
||||||
new TIFFEntry(TIFF.TAG_STRIP_OFFSETS, 0),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, 16),
|
|
||||||
new TIFFEntry(TIFF.TAG_IMAGE_HEIGHT, 9)
|
|
||||||
);
|
|
||||||
|
|
||||||
ThumbnailReader reader = EXIFThumbnail.from(new EXIF(new byte[6 + 16 * 9 * 3]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
assertNotNull(reader);
|
|
||||||
|
|
||||||
// Sanity check below
|
|
||||||
assertEquals(16, reader.getWidth());
|
|
||||||
assertEquals(9, reader.getHeight());
|
|
||||||
assertNotNull(reader.read());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromMissingOffsetJPEG() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Collections.singletonList(new TIFFEntry(TIFF.TAG_COMPRESSION, 6));
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[42]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromTruncatedJPEG() throws IOException {
|
|
||||||
List<TIFFEntry> entries = Arrays.asList(
|
|
||||||
new TIFFEntry(TIFF.TAG_COMPRESSION, 6),
|
|
||||||
new TIFFEntry(TIFF.TAG_JPEG_INTERCHANGE_FORMAT, 0)
|
|
||||||
);
|
|
||||||
EXIFThumbnail.from(new EXIF(new byte[42]), new EXIFDirectory(new IFD(Collections.<Entry>emptyList()), new IFD(entries)), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ThumbnailReader createReader(final ImageInputStream stream) throws IOException {
|
protected EXIFThumbnailReader createReader(final ThumbnailReadProgressListener progressListener, final int imageIndex, final int thumbnailIndex, final ImageInputStream stream) throws IOException {
|
||||||
List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(stream, JPEG.APP1, "Exif");
|
List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(stream, JPEG.APP1, "Exif");
|
||||||
stream.close();
|
stream.close();
|
||||||
|
|
||||||
assertNotNull(segments);
|
assertNotNull(segments);
|
||||||
assertFalse(segments.isEmpty());
|
assertFalse(segments.isEmpty());
|
||||||
|
|
||||||
JPEGSegment exifSegment = segments.get(0);
|
TIFFReader reader = new TIFFReader();
|
||||||
InputStream data = exifSegment.segmentData();
|
InputStream data = segments.get(0).data();
|
||||||
byte[] exifData = new byte[exifSegment.segmentLength() - 2];
|
if (data.read() < 0) {
|
||||||
new DataInputStream(data).readFully(exifData);
|
throw new AssertionError("EOF!");
|
||||||
|
}
|
||||||
|
|
||||||
EXIF exif = new EXIF(exifData);
|
ImageInputStream exifStream = ImageIO.createImageInputStream(data);
|
||||||
return EXIFThumbnail.from(exif, (CompoundDirectory) new TIFFReader().read(exif.exifData()), thumbnailReader);
|
CompoundDirectory ifds = (CompoundDirectory) reader.read(exifStream);
|
||||||
|
|
||||||
|
assertEquals(2, ifds.directoryCount());
|
||||||
|
|
||||||
|
return new EXIFThumbnailReader(progressListener, ImageIO.getImageReadersByFormatName("JPEG").next(), imageIndex, thumbnailIndex, ifds.getDirectory(1), exifStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadJPEG() throws IOException {
|
public void testReadJPEG() throws IOException {
|
||||||
ThumbnailReader reader = createReader(createStream("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"));
|
ThumbnailReader reader = createReader(mock(ThumbnailReadProgressListener.class), 0, 0, createStream("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"));
|
||||||
|
|
||||||
assertEquals(114, reader.getWidth());
|
assertEquals(114, reader.getWidth());
|
||||||
assertEquals(160, reader.getHeight());
|
assertEquals(160, reader.getHeight());
|
||||||
@@ -248,7 +94,7 @@ public class EXIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadRaw() throws IOException {
|
public void testReadRaw() throws IOException {
|
||||||
ThumbnailReader reader = createReader(createStream("/jpeg/exif-rgb-thumbnail-sony-d700.jpg"));
|
ThumbnailReader reader = createReader(mock(ThumbnailReadProgressListener.class), 0, 0, createStream("/jpeg/exif-rgb-thumbnail-sony-d700.jpg"));
|
||||||
|
|
||||||
assertEquals(80, reader.getWidth());
|
assertEquals(80, reader.getWidth());
|
||||||
assertEquals(60, reader.getHeight());
|
assertEquals(60, reader.getHeight());
|
||||||
@@ -259,9 +105,27 @@ public class EXIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
|||||||
assertEquals(60, thumbnail.getHeight());
|
assertEquals(60, thumbnail.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class EXIFDirectory extends AbstractCompoundDirectory {
|
@Test
|
||||||
public EXIFDirectory(IFD... ifds) {
|
public void testProgressListenerJPEG() throws IOException {
|
||||||
super(Arrays.asList(ifds));
|
ThumbnailReadProgressListener listener = mock(ThumbnailReadProgressListener.class);
|
||||||
}
|
|
||||||
|
createReader(listener, 42, 43, createStream("/jpeg/cmyk-sample-multiple-chunk-icc.jpg")).read();
|
||||||
|
|
||||||
|
InOrder order = inOrder(listener);
|
||||||
|
order.verify(listener).thumbnailStarted(42, 43);
|
||||||
|
order.verify(listener, atLeastOnce()).thumbnailProgress(100f);
|
||||||
|
order.verify(listener).thumbnailComplete();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProgressListenerRaw() throws IOException {
|
||||||
|
ThumbnailReadProgressListener listener = mock(ThumbnailReadProgressListener.class);
|
||||||
|
|
||||||
|
createReader(listener, 0, 99, createStream("/jpeg/exif-rgb-thumbnail-sony-d700.jpg")).read();
|
||||||
|
|
||||||
|
InOrder order = inOrder(listener);
|
||||||
|
order.verify(listener).thumbnailStarted(0, 99);
|
||||||
|
order.verify(listener, atLeastOnce()).thumbnailProgress(100f);
|
||||||
|
order.verify(listener).thumbnailComplete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -63,7 +63,7 @@ public class FastCMYKToRGBTest {
|
|||||||
assertNotNull(pixel);
|
assertNotNull(pixel);
|
||||||
assertEquals(3, pixel.length);
|
assertEquals(3, pixel.length);
|
||||||
byte[] expected = {(byte) 255, (byte) 255, (byte) 255};
|
byte[] expected = {(byte) 255, (byte) 255, (byte) 255};
|
||||||
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
assertTrue(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), Arrays.equals(expected, pixel));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -95,7 +95,7 @@ public class FastCMYKToRGBTest {
|
|||||||
assertNotNull(pixel);
|
assertNotNull(pixel);
|
||||||
assertEquals(3, pixel.length);
|
assertEquals(3, pixel.length);
|
||||||
byte[] expected = {(byte) 0, (byte) 0, (byte) 0};
|
byte[] expected = {(byte) 0, (byte) 0, (byte) 0};
|
||||||
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
assertTrue(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), Arrays.equals(expected, pixel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ public class FastCMYKToRGBTest {
|
|||||||
assertNotNull(pixel);
|
assertNotNull(pixel);
|
||||||
assertEquals(3, pixel.length);
|
assertEquals(3, pixel.length);
|
||||||
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i)};
|
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i)};
|
||||||
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
assertTrue(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), Arrays.equals(expected, pixel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ public class FastCMYKToRGBTest {
|
|||||||
assertNotNull(pixel);
|
assertNotNull(pixel);
|
||||||
assertEquals(3, pixel.length);
|
assertEquals(3, pixel.length);
|
||||||
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i)};
|
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i)};
|
||||||
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
assertTrue(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), Arrays.equals(expected, pixel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ public class FastCMYKToRGBTest {
|
|||||||
assertNotNull(pixel);
|
assertNotNull(pixel);
|
||||||
assertEquals(4, pixel.length);
|
assertEquals(4, pixel.length);
|
||||||
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i), (byte) 0xff};
|
byte[] expected = {(byte) (255 - i), (byte) i, (byte) (127 - i), (byte) 0xff};
|
||||||
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
assertTrue(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), Arrays.equals(expected, pixel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+18
-39
@@ -33,10 +33,9 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
|
|||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
@@ -44,6 +43,7 @@ import java.io.IOException;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JFIFThumbnailReaderTest
|
* JFIFThumbnailReaderTest
|
||||||
@@ -53,9 +53,8 @@ import static org.junit.Assert.*;
|
|||||||
* @version $Id: JFIFThumbnailReaderTest.java,v 1.0 04.05.12 15:56 haraldk Exp$
|
* @version $Id: JFIFThumbnailReaderTest.java,v 1.0 04.05.12 15:56 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class JFIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
public class JFIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ThumbnailReader createReader(ImageInputStream stream) throws IOException {
|
protected JFIFThumbnailReader createReader(ThumbnailReadProgressListener progressListener, int imageIndex, int thumbnailIndex, ImageInputStream stream) throws IOException {
|
||||||
List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(stream, JPEG.APP0, "JFIF");
|
List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(stream, JPEG.APP0, "JFIF");
|
||||||
stream.close();
|
stream.close();
|
||||||
|
|
||||||
@@ -63,44 +62,12 @@ public class JFIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
|||||||
assertFalse(segments.isEmpty());
|
assertFalse(segments.isEmpty());
|
||||||
|
|
||||||
JPEGSegment segment = segments.get(0);
|
JPEGSegment segment = segments.get(0);
|
||||||
|
return new JFIFThumbnailReader(progressListener, imageIndex, thumbnailIndex, JFIF.read(new DataInputStream(segment.segmentData()), segment.segmentLength()));
|
||||||
return JFIFThumbnail.from(JFIF.read(new DataInputStream(segment.segmentData()), segment.segmentLength()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFromNull() throws IOException {
|
|
||||||
assertNull(JFIFThumbnail.from(null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFromNullThumbnail() throws IOException {
|
|
||||||
assertNull(JFIFThumbnail.from(new JFIF(1, 1, 0, 1, 1, 0, 0, null)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFromEmpty() throws IOException {
|
|
||||||
assertNull(JFIFThumbnail.from(new JFIF(1, 1, 0, 1, 1, 0, 0, new byte[0])));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromTruncated() throws IOException {
|
|
||||||
JFIFThumbnail.from(new JFIF(1, 1, 0, 1, 1, 255, 170, new byte[99]));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFromValid() throws IOException {
|
|
||||||
ThumbnailReader reader = JFIFThumbnail.from(new JFIF(1, 1, 0, 1, 1, 30, 20, new byte[30 * 20 * 3]));
|
|
||||||
assertNotNull(reader);
|
|
||||||
|
|
||||||
// Sanity check below
|
|
||||||
assertEquals(30, reader.getWidth());
|
|
||||||
assertEquals(20, reader.getHeight());
|
|
||||||
assertNotNull(reader.read());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadRaw() throws IOException {
|
public void testReadRaw() throws IOException {
|
||||||
ThumbnailReader reader = createReader(createStream("/jpeg/jfif-jfif-and-exif-thumbnail-sharpshot-iphone.jpg"));
|
ThumbnailReader reader = createReader(mock(ThumbnailReadProgressListener.class), 0, 0, createStream("/jpeg/jfif-jfif-and-exif-thumbnail-sharpshot-iphone.jpg"));
|
||||||
|
|
||||||
assertEquals(131, reader.getWidth());
|
assertEquals(131, reader.getWidth());
|
||||||
assertEquals(122, reader.getHeight());
|
assertEquals(122, reader.getHeight());
|
||||||
@@ -113,7 +80,7 @@ public class JFIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadNonSpecGray() throws IOException {
|
public void testReadNonSpecGray() throws IOException {
|
||||||
ThumbnailReader reader = createReader(createStream("/jpeg/jfif-grayscale-thumbnail.jpg"));
|
ThumbnailReader reader = createReader(mock(ThumbnailReadProgressListener.class), 0, 0, createStream("/jpeg/jfif-grayscale-thumbnail.jpg"));
|
||||||
|
|
||||||
assertEquals(127, reader.getWidth());
|
assertEquals(127, reader.getWidth());
|
||||||
assertEquals(76, reader.getHeight());
|
assertEquals(76, reader.getHeight());
|
||||||
@@ -124,4 +91,16 @@ public class JFIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
|||||||
assertEquals(127, thumbnail.getWidth());
|
assertEquals(127, thumbnail.getWidth());
|
||||||
assertEquals(76, thumbnail.getHeight());
|
assertEquals(76, thumbnail.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProgressListenerRaw() throws IOException {
|
||||||
|
ThumbnailReadProgressListener listener = mock(ThumbnailReadProgressListener.class);
|
||||||
|
|
||||||
|
createReader(listener, 0, 99, createStream("/jpeg/jfif-jfif-and-exif-thumbnail-sharpshot-iphone.jpg")).read();
|
||||||
|
|
||||||
|
InOrder order = inOrder(listener);
|
||||||
|
order.verify(listener).thumbnailStarted(0, 99);
|
||||||
|
order.verify(listener, atLeastOnce()).thumbnailProgress(100f);
|
||||||
|
order.verify(listener).thumbnailComplete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-66
@@ -33,13 +33,10 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
|
|||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
||||||
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.InOrder;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
@@ -47,6 +44,7 @@ import java.io.IOException;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JFXXThumbnailReaderTest
|
* JFXXThumbnailReaderTest
|
||||||
@@ -56,10 +54,8 @@ import static org.junit.Assert.*;
|
|||||||
* @version $Id: JFXXThumbnailReaderTest.java,v 1.0 04.05.12 15:56 haraldk Exp$
|
* @version $Id: JFXXThumbnailReaderTest.java,v 1.0 04.05.12 15:56 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class JFXXThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
public class JFXXThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
||||||
private final ImageReader thumbnailReader = ImageIO.getImageReadersByFormatName("jpeg").next();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ThumbnailReader createReader(final ImageInputStream stream) throws IOException {
|
protected JFXXThumbnailReader createReader(ThumbnailReadProgressListener progressListener, int imageIndex, int thumbnailIndex, ImageInputStream stream) throws IOException {
|
||||||
List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(stream, JPEG.APP0, "JFXX");
|
List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(stream, JPEG.APP0, "JFXX");
|
||||||
stream.close();
|
stream.close();
|
||||||
|
|
||||||
@@ -67,69 +63,12 @@ public class JFXXThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
|||||||
assertFalse(segments.isEmpty());
|
assertFalse(segments.isEmpty());
|
||||||
|
|
||||||
JPEGSegment jfxx = segments.get(0);
|
JPEGSegment jfxx = segments.get(0);
|
||||||
return JFXXThumbnail.from(JFXX.read(new DataInputStream(jfxx.segmentData()), jfxx.length()), thumbnailReader);
|
return new JFXXThumbnailReader(progressListener, ImageIO.getImageReadersByFormatName("jpeg").next(), imageIndex, thumbnailIndex, JFXX.read(new DataInputStream(jfxx.segmentData()), jfxx.length()));
|
||||||
}
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void tearDown() {
|
|
||||||
thumbnailReader.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFromNull() throws IOException {
|
|
||||||
assertNull(JFXXThumbnail.from(null, thumbnailReader));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromNullThumbnail() throws IOException {
|
|
||||||
JFXXThumbnail.from(new JFXX(JFXX.JPEG, null), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromEmpty() throws IOException {
|
|
||||||
JFXXThumbnail.from(new JFXX(JFXX.JPEG, new byte[0]), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromTruncatedJPEG() throws IOException {
|
|
||||||
JFXXThumbnail.from(new JFXX(JFXX.JPEG, new byte[99]), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromTruncatedRGB() throws IOException {
|
|
||||||
byte[] thumbnail = new byte[765];
|
|
||||||
thumbnail[0] = (byte) 160;
|
|
||||||
thumbnail[1] = 90;
|
|
||||||
|
|
||||||
JFXXThumbnail.from(new JFXX(JFXX.RGB, thumbnail), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IIOException.class)
|
|
||||||
public void testFromTruncatedIndexed() throws IOException {
|
|
||||||
byte[] thumbnail = new byte[365];
|
|
||||||
thumbnail[0] = (byte) 160;
|
|
||||||
thumbnail[1] = 90;
|
|
||||||
|
|
||||||
JFXXThumbnail.from(new JFXX(JFXX.INDEXED, thumbnail), thumbnailReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFromValid() throws IOException {
|
|
||||||
byte[] thumbnail = new byte[14];
|
|
||||||
thumbnail[0] = 2;
|
|
||||||
thumbnail[1] = 2;
|
|
||||||
ThumbnailReader reader = JFXXThumbnail.from(new JFXX(JFXX.RGB, thumbnail), thumbnailReader);
|
|
||||||
assertNotNull(reader);
|
|
||||||
|
|
||||||
// Sanity check below
|
|
||||||
assertEquals(2, reader.getWidth());
|
|
||||||
assertEquals(2, reader.getHeight());
|
|
||||||
assertNotNull(reader.read());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadJPEG() throws IOException {
|
public void testReadJPEG() throws IOException {
|
||||||
ThumbnailReader reader = createReader(createStream("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg"));
|
ThumbnailReader reader = createReader(mock(ThumbnailReadProgressListener.class), 0, 0, createStream("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg"));
|
||||||
|
|
||||||
assertEquals(80, reader.getWidth());
|
assertEquals(80, reader.getWidth());
|
||||||
assertEquals(60, reader.getHeight());
|
assertEquals(60, reader.getHeight());
|
||||||
@@ -142,4 +81,16 @@ public class JFXXThumbnailReaderTest extends AbstractThumbnailReaderTest {
|
|||||||
|
|
||||||
// TODO: Test JFXX indexed thumbnail
|
// TODO: Test JFXX indexed thumbnail
|
||||||
// TODO: Test JFXX RGB thumbnail
|
// TODO: Test JFXX RGB thumbnail
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProgressListenerRaw() throws IOException {
|
||||||
|
ThumbnailReadProgressListener listener = mock(ThumbnailReadProgressListener.class);
|
||||||
|
|
||||||
|
createReader(listener, 0, 99, createStream("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg")).read();
|
||||||
|
|
||||||
|
InOrder order = inOrder(listener);
|
||||||
|
order.verify(listener).thumbnailStarted(0, 99);
|
||||||
|
order.verify(listener, atLeastOnce()).thumbnailProgress(100f);
|
||||||
|
order.verify(listener).thumbnailComplete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-56
@@ -31,7 +31,6 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import org.hamcrest.core.IsInstanceOf;
|
import org.hamcrest.core.IsInstanceOf;
|
||||||
@@ -56,7 +55,6 @@ import java.awt.*;
|
|||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.DataBuffer;
|
|
||||||
import java.awt.image.DataBufferByte;
|
import java.awt.image.DataBufferByte;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -142,6 +140,11 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
// More test data in specific tests below
|
// More test data in specific tests below
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean allowsNullRawImageType() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Arrays.asList("JPEG", "jpeg", "JPG", "jpg",
|
return Arrays.asList("JPEG", "jpeg", "JPG", "jpg",
|
||||||
@@ -419,8 +422,8 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testYCbCrNotSubsampledNonstandardComponentIds() throws IOException {
|
public void testYCbCrNotSubsampledNonstandardChannelIndexes() throws IOException {
|
||||||
// Regression: Make sure 3 channel, non-subsampled JFIF, defaults to YCbCr, even if nonstandard component ids
|
// Regression: Make sure 3 channel, non-subsampled JFIF, defaults to YCbCr, even if unstandard channel indexes
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/jfif-ycbcr-no-subsampling-intel.jpg"))) {
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/jfif-ycbcr-no-subsampling-intel.jpg"))) {
|
||||||
reader.setInput(stream);
|
reader.setInput(stream);
|
||||||
@@ -1232,56 +1235,6 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRGBANoGrayImageTypes() throws IOException {
|
|
||||||
JPEGImageReader reader = createReader();
|
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/adobe-unknown-rgb-ids.jpg")));
|
|
||||||
|
|
||||||
Iterator<ImageTypeSpecifier> imageTypes = reader.getImageTypes(0);
|
|
||||||
|
|
||||||
while (imageTypes.hasNext()) {
|
|
||||||
ImageTypeSpecifier specifier = imageTypes.next();
|
|
||||||
assertNotEquals("RGB JPEGs can't be decoded as Gray as it has no luminance (Y) component", ColorSpace.TYPE_GRAY, specifier.getColorModel().getColorSpace().getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = Exception.class)
|
|
||||||
public void testRGBAsGray() throws IOException {
|
|
||||||
final JPEGImageReader reader = createReader();
|
|
||||||
try {
|
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/adobe-unknown-rgb-ids.jpg")));
|
|
||||||
|
|
||||||
assertEquals(225, reader.getWidth(0));
|
|
||||||
assertEquals(156, reader.getHeight(0));
|
|
||||||
|
|
||||||
final ImageReadParam param = reader.getDefaultReadParam();
|
|
||||||
param.setSourceRegion(new Rectangle(0, 0, 225, 8));
|
|
||||||
param.setDestinationType(ImageTypeSpecifiers.createGrayscale(8, DataBuffer.TYPE_BYTE));
|
|
||||||
|
|
||||||
// Should ideally throw IIOException due to destination type mismatch, but throws IllegalArgumentException...
|
|
||||||
reader.read(0, param);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testYCbCrAsGray() throws IOException {
|
|
||||||
JPEGImageReader reader = createReader();
|
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/jfif-ycbcr-no-subsampling-intel.jpg")));
|
|
||||||
|
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
|
||||||
param.setDestinationType(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY));
|
|
||||||
|
|
||||||
BufferedImage image = reader.read(0, param);
|
|
||||||
|
|
||||||
assertNotNull(image);
|
|
||||||
assertEquals(BufferedImage.TYPE_BYTE_GRAY, image.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Slightly fuzzy RGB equals method. Tolerance +/-5 steps.
|
* Slightly fuzzy RGB equals method. Tolerance +/-5 steps.
|
||||||
*/
|
*/
|
||||||
@@ -1464,7 +1417,7 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
assertNotNull(unknown.getUserObject()); // All unknowns must have user object (data array)
|
assertNotNull(unknown.getUserObject()); // All unknowns must have user object (data array)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IIOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
fail(String.format("Reading metadata failed for %s image %s: %s", testData, i, e.getMessage()));
|
fail(String.format("Reading metadata failed for %s image %s: %s", testData, i, e.getMessage()));
|
||||||
}
|
}
|
||||||
@@ -1865,7 +1818,7 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/exif-jfif-app13-app14ycck-3channel.jpg")));
|
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/exif-jfif-app13-app14ycck-3channel.jpg")));
|
||||||
|
|
||||||
ImageTypeSpecifier rawType = reader.getRawImageType(0);
|
ImageTypeSpecifier rawType = reader.getRawImageType(0);
|
||||||
assertNotNull(rawType); // As of Java 9, use RGB for YCC and CMYK for YCCK
|
assertNull(rawType); // But no exception, please...
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
|
|||||||
+22
-34
@@ -30,16 +30,26 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
import static org.mockito.Mockito.mock;
|
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import javax.imageio.*;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||||
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
|
import javax.imageio.spi.IIORegistry;
|
||||||
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
|
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.ColorModel;
|
|
||||||
import java.awt.image.ComponentColorModel;
|
import java.awt.image.ComponentColorModel;
|
||||||
import java.awt.image.DataBuffer;
|
import java.awt.image.DataBuffer;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
@@ -51,29 +61,10 @@ import java.util.Arrays;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.imageio.IIOImage;
|
import static org.junit.Assert.assertEquals;
|
||||||
import javax.imageio.ImageIO;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import javax.imageio.ImageReadParam;
|
import static org.mockito.Mockito.mock;
|
||||||
import javax.imageio.ImageReader;
|
import static org.mockito.Mockito.when;
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
import javax.imageio.ImageWriter;
|
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
|
||||||
import javax.imageio.spi.IIORegistry;
|
|
||||||
import javax.imageio.spi.ImageWriterSpi;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
|
||||||
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
|
||||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPEGImageWriterTest
|
* JPEGImageWriterTest
|
||||||
@@ -94,16 +85,13 @@ public class JPEGImageWriterTest extends ImageWriterAbstractTest<JPEGImageWriter
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<? extends RenderedImage> getTestData() {
|
protected List<? extends RenderedImage> getTestData() {
|
||||||
ColorModel cmyk = new ComponentColorModel(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
new BufferedImage(320, 200, BufferedImage.TYPE_3BYTE_BGR),
|
new BufferedImage(320, 200, BufferedImage.TYPE_3BYTE_BGR),
|
||||||
new BufferedImage(32, 20, BufferedImage.TYPE_INT_RGB),
|
new BufferedImage(32, 20, BufferedImage.TYPE_INT_RGB),
|
||||||
new BufferedImage(32, 20, BufferedImage.TYPE_INT_BGR),
|
new BufferedImage(32, 20, BufferedImage.TYPE_INT_BGR),
|
||||||
// Java 11+ no longer supports RGBA JPEG
|
new BufferedImage(32, 20, BufferedImage.TYPE_INT_ARGB),
|
||||||
// new BufferedImage(32, 20, BufferedImage.TYPE_INT_ARGB),
|
new BufferedImage(32, 20, BufferedImage.TYPE_4BYTE_ABGR),
|
||||||
// new BufferedImage(32, 20, BufferedImage.TYPE_4BYTE_ABGR),
|
new BufferedImage(32, 20, BufferedImage.TYPE_BYTE_GRAY)
|
||||||
new BufferedImage(32, 20, BufferedImage.TYPE_BYTE_GRAY),
|
|
||||||
new BufferedImage(cmyk, cmyk.createCompatibleWritableRaster(32, 20), cmyk.isAlphaPremultiplied(), null)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -187,7 +187,7 @@ public class JPEGSegmentImageInputStreamTest {
|
|||||||
assertEquals(2, iis.read(buffer, 0, buffer.length));
|
assertEquals(2, iis.read(buffer, 0, buffer.length));
|
||||||
assertEquals(2, iis.getStreamPosition());
|
assertEquals(2, iis.getStreamPosition());
|
||||||
|
|
||||||
iis.seek(2000); // Just a random position beyond EOF
|
iis.seek(2000); // Just a random postion beyond EOF
|
||||||
assertEquals(2000, iis.getStreamPosition());
|
assertEquals(2000, iis.getStreamPosition());
|
||||||
|
|
||||||
// So far, so good (but stream position is now really beyond EOF)...
|
// So far, so good (but stream position is now really beyond EOF)...
|
||||||
|
|||||||
-102
@@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.jpeg;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.awt.image.DataBuffer;
|
|
||||||
import java.awt.image.Raster;
|
|
||||||
import java.awt.image.WritableRaster;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
public class LuminanceToGrayTest {
|
|
||||||
@Test
|
|
||||||
public void testConvertByteYcc() {
|
|
||||||
LuminanceToGray convert = new LuminanceToGray();
|
|
||||||
|
|
||||||
WritableRaster input = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1, 1, 3, null);
|
|
||||||
WritableRaster result = null;
|
|
||||||
|
|
||||||
byte[] pixel = null;
|
|
||||||
for (int i = 0; i < 255; i++) {
|
|
||||||
input.setDataElements(0, 0, new byte[] {(byte) i, (byte) (255 - i), (byte) (127 + i)});
|
|
||||||
result = convert.filter(input, result);
|
|
||||||
pixel = (byte[]) result.getDataElements(0, 0, pixel);
|
|
||||||
|
|
||||||
assertNotNull(pixel);
|
|
||||||
assertEquals(1, pixel.length);
|
|
||||||
byte[] expected = {(byte) i};
|
|
||||||
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConvertByteYccK() {
|
|
||||||
LuminanceToGray convert = new LuminanceToGray();
|
|
||||||
|
|
||||||
WritableRaster input = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1, 1, 4, null);
|
|
||||||
WritableRaster result = null;
|
|
||||||
|
|
||||||
byte[] pixel = null;
|
|
||||||
for (int i = 0; i < 255; i++) {
|
|
||||||
input.setDataElements(0, 0, new byte[] {(byte) i, (byte) (255 - i), (byte) (127 + i), (byte) 255});
|
|
||||||
result = convert.filter(input, result);
|
|
||||||
pixel = (byte[]) result.getDataElements(0, 0, pixel);
|
|
||||||
|
|
||||||
assertNotNull(pixel);
|
|
||||||
assertEquals(1, pixel.length);
|
|
||||||
byte[] expected = {(byte) i};
|
|
||||||
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConvertByteYccA() {
|
|
||||||
LuminanceToGray convert = new LuminanceToGray();
|
|
||||||
|
|
||||||
WritableRaster input = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1, 1, 4, null);
|
|
||||||
WritableRaster result = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 1, 1, 2, null);
|
|
||||||
|
|
||||||
byte[] pixel = null;
|
|
||||||
for (int i = 0; i < 255; i++) {
|
|
||||||
input.setDataElements(0, 0, new byte[] {(byte) i, (byte) 255, (byte) (127 + i), (byte) (255 - i)});
|
|
||||||
result = convert.filter(input, result);
|
|
||||||
pixel = (byte[]) result.getDataElements(0, 0, pixel);
|
|
||||||
|
|
||||||
assertNotNull(pixel);
|
|
||||||
assertEquals(2, pixel.length);
|
|
||||||
byte[] expected = {(byte) i, (byte) (255 - i)};
|
|
||||||
assertArrayEquals(String.format("Was: %s, expected: %s", Arrays.toString(pixel), Arrays.toString(expected)), expected, pixel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user